Описание на програмния език HPL rev 2.0

03.05.2004


Програмния език HPL (Hardware Programming Language) е разработен специално
за описване на низковолтови протоколи за обмен с различни устройства.

Ще разгледаме реализацията на езика HPL в транслатора на програматора Orange.
Примерите са обозначени със символа (*),

Символа ';' (точка и запетая) служат, като признак за комментар -
края на реда започващ с този символ не се обработва .

> Числа. Числа могат да се задават в двоичен, десетичен и
шестнадесетеричен формат :
(*) 1234 - десятична константа
(*) 010101B - двоична
(*) 0x1234 или 01234H - шестнадесетерична.

> Адрес. Ключoвата дума ADR съдържа текущото значение на
адресния регистър (32 разряда), по който се изпълнява
четене/запис на данните.
За адресния регистър могат да се използуват операции
за настройки (само в потребителските секции) и инкремента
(в секциите за блоково четене и запис).

> Данни. За достъп до данните в буфера по текущия адрес се
използува ключовата дума DATA. Данните са достъпни като думи
(8 или 16 бита в зависимост от избрания тип памет) или като разряди .

> Регистри. За изпълнение на математически и логически операций,
описване на константи и съхранение на данните може да се използуват
16 регистъра R0...R9,RA...RF.
Регистрите R0...R9 са универсални, а регистрите RA-RF са със специално
предназначение. Те се използуват за следните пераметри:
RA - изпращане на параметри
RB - размер на блока за четене/запис
RC - запазен(резервиран)
RD - номер на областта за микросхемите , притежаващи няколко области памет,
например, за микроконтролерите.
RE - глобален код за операции (1-READ,2-VERIFY,3-WRITE,4-USER)
RF - пълния размер на паметта за избрания тип микросхема.

Ако значението, предавано от специалния регистър не се използува,
то той може да се използува като универсален във вътрешна секция .


Описанието на протокола се състои от няколко секции, задължителни от
тях са три: начална, [READ] - четене на дума и [WRITE] - запис на дума .

Освен това, допълнително може да се използуват незадължителните секции:

[SETUP] - начална настройка, извиква се еднократно при зареждане на модула
[INIT] - инициализация, извиква се еднократно преди всички операции.
[WRITEINIT] - инициализация за запис, извиква се един път преди началота
на запис в EEPROM.
[WRITEEND] - завършване на записа, извиква се един път след записа на
всички думи в EEPROM.
[READBLOCK] - Четене на блока
[WRITEBLOCK] - Запис на блока
[END] - завършване на операциите, извиква се един път за всяка операция.

При необходимост може да бъдат описани допълнителни потребителски
секции, които да се извикват еднократно при избор от менюто.
Тяхното име също се записва в скоби [].

Може да се използуват локални секции (функции). За описване на
функции пред името се добавя символа '_' :
(*) [_START]
Функциите трябва да са описани в модула преди тяхното използване.
Извикването на функциите се осъществява по тяхното име:
(*) _START.
Предването на параметри е възможно с използуването на регистрите.
Разрешено е да се използува вътре във функциите извикване на
други функции.
Не се препоръчва да се използува рекурсивни повиквания .

Секциите за четене и запис се извикват при изпълнение на операции
Read и Write за всяка дума .

В режим на четене порядъка на повикване на секции е следния :
[INIT]
FOR (ADR=0,ADR<CHIPSIZE;ADR++)
{
[READ]
}
[END]

Порядъка за повикване на секции в режим на запис :
[INIT]
[WRITEINIT]
FOR (ADR=0,ADR<CHIPSIZE;ADR++)
{
[WRITE]
IF (Проверка на записа)
[READ]
}
[WRITEEND]
[END]

Порядъка за повикване на потребителски команди :
[INIT]
[USERSECTION]
[END]

В началната секция се описват:

¦ Входните и изходните сигнали за подключване към EEPROM (pins):
(*) PINO=SCL,0 - Изход, SCL - име на сигнала, 0 - номер на бита за драйвера
(*) PINI=SDA,1 - Вход, SDA - име на сигнала, 1 - номер на бита за драйвера

Входните и изходните сигнали може да имат едно и също име.
Дължината на името не трябва да е по-голямо от осем символа.
Имената не трябва да съвпадат с резервираните ключови думи :
"PINO","PINI","CDELAY","SOCKET","CONST","REG","LOOP","ADR","DATA","PRINT",
"GET".

Символа # пред името е признак за инверсия на сигнала:
(*) PINO=#DTA,0

Допълнително можно да се укаже реалното краче (pin) на микросхемата,
към който е включен сигнала:
(*) PINO=SDA,1,5
Това е необходимо за създаване на графическо изображения на микросхемите,
включвани через адаптери .

¦ Задръжка след всяка операция за настройка на крака(pin)(в микросекунди):
(*) CDELAY=10
Позволява да се регулира скороста на обмена. Реалнитее задръжки могат
да се получат малко по-големи от зададените.

¦ Номера на цокъла (гнездото) за поставяне на EEPROM
(*) SOCKET=1

Ако параметъра SOCKET не е указан, то се счита за равен на 0.
Може да се създават свои нови Socket, но за да може
условното графическо изображение на микросхемата да се изобразява
в прозореца Chip Info, таблицата на изводите трябва да бъде записана в
в драйвера или описана в модула. Конкретния номер на цокъла в
други версии на hardware може да не съвпадат с дадения номер.

¦ Допълнителна информация за модула, която се изобраява в долния
прозорец. Не повече от един ред.
(*) INFO="Нов модул"

¦ Общо число на изводите в корпуса на EEPROM (по подразбиране - 8)
(*) ALLPINS=14


¦ Обявяване на регистрите, достъпни за разглеждане и редактиране
през менюто (Buffer->Registers). Имената на регистрите не трябва
да се повтарят и да съвпадат с други.
Ако регистрите се използуват локално вътре в секцията , то не е
нужно да се обявяват .

(*) R0=Protect - където "Protect" - е името на регистъра

След името на регистъра чрез запетайка може да се укаже режима
за изобразяване на регистъра :

H - hex, D - Dec, B - Bin

(*) R1=CODE,H

Всички осталнали секции имат еднакъв формат на запис.
В един ред може дъ бъдат описани няколко инструкции,
които трябва да се разделят със запетая .

Кратко описание на инструкциите :

¦ Настройка константата за краката, битовете данни, адреса или регистъра:
(*) SDA=1
(*) SDA=DATA[2]
(*) SCL=ADR[3]
(*) PIN=R2[3]

¦ Операция сравняване.

Може да се използуват следните типове сравнение :
1) равенство на текущето состояния на бита (линия на въвеждане)
или бита на регистъра R0-RF и константи:
(*) DAT?1
(*) R2[4]?0
2) равенство на два регистъра или регистър и константа:
(*) R4?0x1234
(*) R4?R5

3) сравнение по-голямо/по-малкое между два регистъра или между регистър и константа:
(*) R4?<0x1234
(*) R4?>R5

Ако след операциите за сравнение в скоби {} е описан блок с инструкций,
то той се изпълнява при изпълненоно условие за проверка и константи, в противен
случай се изпълнява инструкцията след скобите.
Ако такъв блок не е описан, при несъвпадение на проверяемото значение
операцията се прекратява и извежда съобщение "Error: Chip not respond!"
и номера на реда в HPL файла, на който е спряло изпълнението .

(*) R2[4]?0 {P1=0}, P2=1
Ако 4 бит на регистъра R2 е равен на 0, то ще се изпълнява инструкцията P1=0,
а след това P2=1, ако 4 бит е равен на 1 - то веднага ще се изпълни P2=1

Ако пред сравняваното число има символ !, то условието за равенство се заменя
на противоположно. (Блока се изпълнява при несъвпадение на значенията).

(*)R2?!1234H {P1=0}
Ако R2 не равено на 1234H, то ще се изпълнява инструкцията P1=0,
ако R2 = 1234H, ще се изпълнява следващата инструкция.


¦ Зареждане на константи. Значението на константите трябва да е в предела 0...65535.
(*) CONST=159

¦ Операции с регистрите.
1) Операции присвоение (копиране):
Регистър-регистър (*) R2=R5
Регистър-данни (*) R2=DATA
Данни-регистър (*) DATA=R3
Разрядността на данните в зависимост от указания типа микросхема е 8 или 16 бита.

2) Аритметически и логические операции
(В операциите может да участвуват константи или друг регистър):
зареждане "=" (*) R0=356H
събиране "+" (*) R0=+123 ; R0=R0+123
изваждане "-" (*) R0=-R1 ; R0=R0-R1
умножение "*" (*) R0=*R1 ; R0=R0*R1
деление "/" (*) R0=/5 ; R0=R0/5
взимане на остатъка "%" (*) R0=%10 ; R0=R0%10
циклично преместване "<<",">>" (*) R0=>>1 ; сдвиг R0 вправо на 1 разряд
Логическо И - AND "&" (*) R0=*R2 ; R0=R0 and R2
Логическо ИЛИ - OR "|" (*) R0=|R2 ; R0=R0 or R2
Исключващо ИЛИ - XOR "^" (*) R0=^R2 ; R0=R0 xor R2

В операциите деление и взимане на остатъка е забранено да се използува
константта 0 или регистър, съдържащ 0 !

3) Битови операции с регистрите
(*) R0[R1]=1 - бита на регистъра R0, равен на R1 да се установит в 1


¦ Цикли. Променливата на циклите може да бъде 3 вида: адрес,
данни четене/запис и константа. Освен тово може да бъде описан
универсален цикъл, без да се указват променливи,
в този случай достъпа се осъществява чрез брояч (индекс) на цикъла I.
Универсалните цикли могат бъдат вложени, във вътрешен
цикъл непосредствено достъпен само за брояча на вътрешния цикъл.
За универсалните цикли границите могът да бъдат също така зададени чрез
регистри. За съвместимост с бъдещите версии се препоръчва да се
исползуват само универсални цикли !


Константата трябва да бъде зададена преди началото на цикъла
с помощта на инструкцията CONST
Границите на цикъла трябва да лежат в пределите :
0...32767 - за универсалните циклов
0...32767 - за циклите CONST
0...1023 - за циклите DATA
0...31 - за циклите ADR
При изпълнение на кода за универсални цикли не се контролира изхода на
индексите зад предела на реалния размер DATA, ADR и CONST.
Границите на цикъла може да се задават или с две числа или с два регистъра.
В последния случай изменението границите на регистрите вътре в цикъла не оказва
влияние на хода на изпълнение на цикъла.

Скобите "{","}" ограничават тялото на цикъла.

(*) LOOP=(15,0) {DI=R0[I],...}
линията на извода DI последователно приема
значение на бит 15..0 значение на регистъра R0.

(*) LOOP=(7,0) {DI=ADR[I],...}
(*) LOOP=ADR(7,0) {DI=I,...} - стария вариант
линията на извода DI последователно приема
значение на бит 7..0 от текущето значение на адресната дума.

(*) LOOP=0,15) {DATA[I]=DO,..}
(*) LOOP=DATA(0,15) {I=DO,..} - стария вариант
последователно прочита на бит 0..15 думата с данни от линията на въвеждане DO.

(*) R1=10H
LOOP=(5,0) {D=R1[I],..}
(*) CONST=10H
LOOP=CONST(5,0) {D=I,..} - стария вариант на линията за въвеждане
на извода D последователно приема значение на бит 5..0 константите (10H)

(*) LOOP=(R1,R2) {R3[I]=DATA[I]}
Копирне на битове от R1 до R2 на адресната дума в съответните битове
на регистъра R3

(*) LOOP=(0,7){ P1=0,LOOP=(6,1){P1=0,P1=1} }
Вложени цикли.

¦ BREAK - изход от текущия цикъл.
(*) LOOP=(7,0) {PI?0{BREAK}}

¦ Задръжка (в микросекунди). Стойността на задръжката может да бъде
в пределите 1мкс...65с.
(*) P=200

¦ Извеждане на съобщение. Извеждането на съобщение в прозорец на екрана, задължително
трябва да бъде затворена с кавички . Вътре в реда може да се използуват
стандартни модификатори аналогични на използваните в езика C за printf().
(За всички числови аргументи е необходим параметър l (long int)).

X - шестнадесетерично значение
u - десетично значение

Транслатора не проверява правилноста на предаваните аргументи !

(*) PRINT=("Hello, World")
(*) PRINT=("Code=%04lX",R1) - Извеждане значението на регистъра R1 в
шестнадесетеричен вид - при необходимост се допълва с нули до 4 цифри.

Може също да се използуват допълнителни модификатори,
определящи типа на прозореца :
E - Error - съобщение за грешка
(*) PRINT=E("Hello, Mr. Bug!")

S - Status - запис в статусния прозорец
(*) PRINT=S("Progress %03lu",R0)

A - Ask - запитване за потвърждаване от потребителя
Значението се връща в регистъра RA (Ok=1,Cancel=0)
PRINT=A("Are you ready ?")

¦ Извеждане на значения . На экрана се отваря прозорец с запитване за данните.
Реда в скобите задава името на прозореца . Едновременно могат да бъдат
въведени наведнъж няколко значения в зададените регистри. Имената на
регистрите и формата на данните съответствуват на описаните в началната секция.

(*) GET=("Enter value",R7,R8)

¦ Настройка за маркиране (подчертаване) на текущата дума .
Адреса съответства на значението ADR.

(*) MARK=R1

¦ Четене на маркираната (подчертаната) текуща дума.
Адреса съответства на значението ADR.

(*) R2=MARK

¦ Завършване на текущата секция: EXIT

¦ Забрана/Разрешение за прекъсване: IDISABLE/IENABLE
Използва се за изпълнение на критични към времето операции.

За по подробно изучаване конструкцията на езика може да се използват
файловете *.hpl ,които се получават при закупуването на програматора .