Hardware Programming Language) разработан специально
20.01.2003
Язык HPL ( Hardware Programming Language) разработан специально для описания низкоуровневых протоколов обмена с различными устройствами.
Рассмотрим реализацию языка HPL в трансляторе программатора Orange.
Cимволом (*) обозначены примеры в данном документе.
Cимволом (W) обозначены операторы и команды, поддерживаемые только Windows версией.
Символ ';' является признаком комментария - конец строки начиная с этого символа не обрабатывется. Все пробелы внутри текста удаляются, за исключением текстовых строк, заключенных в кавычки "". Ключевые слова пишутся только в верхнем регистре (большими буквами).
- Числа. Числа могут задаваться в двоичном, десятичном и шестнадцатеричном формате:
(*) 1234 - десятичная константа
(*) 010101B - двоичная
(*) 0x1234 или 01234H - шестнадцатеричная.
- Адрес. Ключевое слово 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 - полный размер памяти.
Если значение, передаваемое специальным регистром не используется, он может использоваться как универсальный внутри секций.
Кроме этого, дополнительно можно использовать необязательные секции:
[SETUP] - начальная установка, вызывается однократно при загрузке модуля
[INIT] - инициализация, вызывается однократно перед всеми операциями.
[WRITEINIT] - инициализации записи, вызывается один раз перед началом записи EEPROM.
[WRITEEND] - завершение записи, вызывается один раз после записи всех слов EEPROM.
[READBLOCK] - Чтение блока
[WRITEBLOCK] - Запись блока
[END] - завершение операции, вызывается один раз для любой операции.
При необходимости могут быть описаны дополнительные пользовательские секции, которые добавляются в меню под своим именем. Их названия также записываются в скобках []. При использовании пробелов имена следует дополнительно заключать в кавычки:
(*)["Test 1"]
Можно использовать локальные секции (функции). Для описания функций перед именем добавляется символ '_' :
(*) [_START]
Функции должны быть описаны в модуле до их использования. Вызов функции осуществляется по имени:
(*) _START.
Передача параметров возможна с использованием регистров. Разрешено использовать внутри функций вызовы других функций. Не рекомендуется использование рекурсивных вызовов.
Секции чтения и записи вызываются при выполнении операций Read и Write для каждого слова.
Порядок вызова секций в режиме чтения:
[INIT]
FOR (ADR=0,ADR {
[READ]
}
[END]
Порядок вызова секций в режиме записи:
[INIT]
[WRITEINIT]
FOR (ADR=0,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", "GET", "LOOP", "ADR", "DATA", "MARK", "POWER" Символ # перед именем является признаком инверсии сигнала:
(*) PINO=#DTA,0
Дополнительно можно указать реальный вывод микросхемы, к которому подключен сигнал:
(*) PINO=SDA,1,5
Это необходимо для создания графического изображения микросхем, подключаемых через адаптеры.
- Задержка после каждой операции установки пина (в микросекундах):
(*) CDELAY=10
Позволяет регулировать скорость обмена. Реальные задержки могут получаются насколько больше заданных.
- Номер панельки для установки EEPROM (по схеме Orange-1)
(*) SOCKET=1
Если параметр SOCKET не указан, он считается равным 0. Можно создавать свои новые Socket, но для того, чтобы условное графическое изображение микросхемы отображалось в окне Chip Info, таблица выводов должна быть внесена в драйвер или описана в модуле. - Дополнительная информация о модуле, которая отображается в нижнем окне. Не более одной строки
(*) INFO="Новый модуль"
- Общее число выводов в корпусе EEPROM (по умолчанию 8)
(*) ALLPINS=14
- Объявления регистров, доступных для просмотра и редактирования через меню (Buffer->Registers). Имена регистров не должны совпадать. Если регистры используются локально внутри секций, объявлять их не нужно.
(*) R0=Protect - где "Protect" - имя регистра
После имени регистра через запятую может быть указан режим отображения значения регистра: H - hex, D - Dec, B - Bin, (W) L - List (W) C - CheckBox
(*) R1=CODE,H
Для типов H,D,B,C дополнительно может быть указано число отображаемых знаков:
(*) R2=FLAGS,B8
(*) R3=Box,C4
Для типа L добавляется список текстовых строк.
Значение регистра соответствует порядковому номеру выбранной строки начиная с 0.
(*) R0=Mode,L,On,Off
- POWER - режим управления питанием:
1 - автоматическое включение/выключение
0 - управление из модуля.
Краткое описание инструкций приведено ниже:
- Установка пина константой, битом данных, адреса или регистра:
(*) SDA=1
(*) SDA=DATA[2]
(*) SCL=ADR[3]
(*) PIN=R2[3]
- Проверка текущего состояния пина (линий ввода) или бита регистра R0-R7
(*) DAT?1
(*) R2[4]?0
или всего регистра:
(*) R4?0x1234
Если после операции сравнения в скобках {} описан блок инструкций, то он выполняется при равенстве бита(регистра) и константы, иначе выполняется инструкция следующая за скобками. Если такой блок не описан, при несовпадении проверяемого значения выполнение операции прерывается с выводом сообщения "Error: Chip not respond!" и номером строки HPL файла, на котором произошла остановка.
(*) R2[4]?0 {P1=0}, P2=1
Если 4 бит регистра R2 равен 0, то выполняется инструкция P1=0, а потом P2=1, если бит равен 1 - то сразу P2=1
Если перед сравниваемым числом стоит символ !, то условие меняется на противоположное. (Блок выполняется при несовпадении значений).
(*) R2?!1234H {P1=0}
Если R2 не равен 1234H, то выполняется инструкция P1=0, если R2 = 1234H, выполняется следующая инструкция.
- Установка константы. Значения констант должны лежать в пределах 0...65535.
(*) CONST=159
- Операции с регистрами.
- Операции присвоения (копирования):
Регистр-регистр (*) R2=R5
Регистр-данные (*) R2=DATA
Данные-регистр (*) DATA=R3
Разрядность данных в зависимости от установленного типа микросхемы составляет 8 либо 16 бит.
- Арифметические и логические операции
(В операциях может участвовать константа или другой регистр):
установка "=" (*) 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
- Операции присвоения (копирования):
- LOOP - Циклы. Переменная циклов может быть 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 Ввод значений. На экран выводится окно с запросом данных. Строка в скобках задает заголовок окна. Одновременно могут быть введены сразу несколько значений в заданные регистры. Имена регистров и формат данных соответствуют описаным в начальной секции.
(*) GET=("Enter value",R7,R8)
- MARK Установка и получение отметки (выделения) текущего слова. Адрес соответствует значению ADR.
(*) MARK=R1
(*) R2=MARK
- EXIT - Завершение текущей секции.
- VCC - Управление напряжением питания (включение, выключение, установка):
(*) VCC=1 - включить
(*) VCC=0 - выключить
(*) VCC=3000 - установить напряжение 3,0 V (значение в милливольтах)