Поддержка ХММ-команд в файле iaxmm.inc
Поддержка ХММ-команд в файле iaxmm.inc
С точки зрения структуры включаемый файл iaxmm.inc представляет собой набор макрокоманд двух типов — основных и вспомогательньях. Названия основных макрокоманд полностью совпадают с названиями ХММ-команд, и эти макрокоманды обеспечивают моделирование определенных XlMM-команд. Вспомогательные макрокоманды расположены в начале файла и предназначены для обеспечения работы основных макрокоманд. В частности, :эти макрокоманды устанавливают тип операндов, указанных при обращении к (основной макрокоманде, причем делают это исходя из режима функционировашия транслятора — 16-или 32-разрядного. Другое важное действие — установление соответствия между названиями ХММ-регистров и регистров общего назначения. Дело в том, что для моделирования ХММ-команд в 16- или 32-разрядном режиме работы ассемблера используются разные регистры общего назначения — 1 6-разрядные регистры в 16-разрядном режиме, и 32-разрядные в 32-разрядном режиме.
Рассмотрим процесс моделирования ХММ-команд. В! качестве основы для моделирования выступает команда основного процессора!. Эта команда должнаудовлетворять определенным требованиям. Каковы они? В поисках ответа посмотрим на машинные коды ХММ-команд в литературе [40, 41]. Видно, что общими у них являются два момента:
из которых равен Ofh;
Для моделирования ХММ-команд нужно подобрать такую команду основного процессора, которая удовлетворяет этим двум условиям. Во включаемом файле iaxmm.inc в качестве таких команды присутствуют две — CMPXCHG и ADD. В процессе моделирования на место нужного байта кода операции этих команд помещаются байты со значениями кода операции соответствующей ХММ-команды. Когда микропроцессор «видит», что очередная команда является ХММ-командой, то он начинает трактовать коды регистров в машинной команде как коды ХММ-регистров и ссылки на память, размерностью соответствующей данной команде. В машинном формате команды нет символических названий регистров, которыми мы пользуемся при написании исходного текста программы, например АХ или ВХ. В этом формате они определенным образом кодируются. Например, регистр АХ кодируется в поле REG машинной команды как 000. Если заменить код операции команды, в которой одним из операндов является регистр АХ, на код операции некоторой ХММ-команды, то это же значение в поле reg микропроцессор будет трактовать как регистр RXMMO. Таким образом, в ХММ-командах коды регистров воспринимаются соответственно коду операции. В табл. 10.1 приведены коды регистров общего назначения и соответствующих им ХММ-регистров. В правом столбце этой таблицы содержится условное обозначение ХММ-регистров, принятое в файле iaxmm.inc. Это же соответствие закреплено рядом определений в этом файле, которые иллюстрирует следующая программа.
DefineXMMxRegs Macro IFDEF APPJ.6BIT
rxmmO TEXTEQU<AX>
rxmml TEXTEQU<CX>
rxmm2 TEXTEQU<DX>
rxmm3 TEXTEQU<BX>
rxmm4 TEXTEQU<SP>
rxmm5 TEXTEQU<BP>
гхттб TEXTEQU<SI>
rxmm7 TEXTEQU<DI>
RXMMO TEXTEQU<AX>
RXMM1 TEXTEQU<CX>
RXMM2 TEXTEQU<DX>
RXMM3 TEXTEQU<BX>
RXMM4 TEXTEQU<SP>
RXMM5 TEXTEQU<BP>
P.XMM6 TEXTEQU<SI>
RXMM7 TEXTEQU<DI>
rxmml TEXTEQU<ECX>
rxmm2 TEXTEQU<EDX>
rxmm3 TEXTEQU<EBX>
rxmm4 TEXTEQU<ESP>
rxmm5 TEXTEQU<EBP>
гхттб TEXTEQU<ESI>
ГХШП7 TEXTEQU<EDI>
RXMMO TEXTEQU<EAX>
RXMM1 TEXTEQU<ECX>
NRXMM2 TEXTEQU<EDX>
RXMM3 TEXTEQU<EBX>
RXMM4 TEXTEQU<ESP>
RXMM5 TEXTEQU<EBP>
RXMM6 TEXTEQU<ESI>
RXMM7 TEXTEQU<EDI> ENDIF endm
Таблица 10.1. Кодировка регистров в машинном коде команды
Код в поле reg |
Регистр целочисленного устройства |
ХММ-регистр |
000 | АХ/ЕАХ | RXMM0 |
001 | СХ/ЕСХ | RXMM1 |
010 | DX/EDX | RXMM2 |
Oil | ВХ/ЕВХ | RXMM3 |
100 | SP/ESP | RXMM4 |
101 | ВР/ЕВР | RXMM5 |
110 | SI/ESI | RXMM6 |
111 | DI/EDI | RXMM7 |
Рассмотрим, как в файле iammx.inc описано макроопределение для моделирования ХММ-команды скалярной пересылки MOVSS.
:F3 OF 10 /г movss xrrnil. xmm2/m32 :F3 OF 11 /r movss xmm2/m32. xnrnl movss macro dst:req. src:req
XMMld_st_f3 opc_Mo«s. dst, src endm
Понимание структуры приведенного макроопределения не должно вызвать у читателя трудностей. Начать следует с того, что данная команда содержит вложенный вызов макрокоманды XMMld_st_f3, у которой две задачи — определить вариант сочетания операндов, после чего сформировать правильный код операции и подставить его на место соответствующих байтов в команде CMPXCHG. В результате этих действий команда CMPXCHG «превращается» в ХММ-команду MOVSS.
1. XMMld_St f3 macro op:req.dst:req, src:req
2. local x. у
3. Defin'eXMMxRegs
4. IF (OPATTR(dst)) AND OOOlOOOOy -.register
5. x: lock cmpxchg src. dst
6. у: org x
7. byte OF3H.0Fh. op& Id
8. org у
9. ELSE
10. x: lock cmpxchgdst. src
11. y: orgx
12. byte 0F3H.0Fh. op&_st
13. orgy
14. ENDIF
15. UnDefineXMMxRegs
16. endm
Центральное место в макроопределении ХММ1 d_st_f3 занимают команда целочисленного устройства (в данном случае — CMPXCHG) и директива ORG. Первое действие данной макрокоманды — выяснить тип операнда приемника (dst) в макрокоманде MOVSS, так как он может быть и регистром, и ячейкой памяти. Это необходимо для правильного определения кода операции, которая будет управлять направлением потока данных. После того как определен приемник данных, с помощью условного перехода осуществляется переход на ветвь программы, где будет выполняться собственно формирование соответствующего ХММ-команде
MOVSS кода операции.
Формирование кода операции ХММ-команды MOVSS производится с помощью директивы org, которая предназначена для изменения значения счетчика адреса. В строках 6 или 11 директива org устанавливает значение счетчика адреса равным адресу метки х. Адрес метки х является адресом первого байта машинного кода команды CMPXCHG. Директива db в следующих строках размещает по этому адресу байтовые значения 0F3H,0Fh, ор&_1 d или 0F3H,0Fh, op&st, в зависимости от того, какое действие производится — загрузка (_ld) или сохранение (_st). Значение opc_Movss, с помощью которого формируются значения op&_st и ор&_1 d, определены в начале файла iaxmm.inc:
opcjtovssjd - 010Н
opc_Movss_st - 011H
Для дотошных читателей заметим еще один характерный момент. Для его полного понимания необходимо хорошо представлять себе формат машинной команды и назначение его полей. Достаточно полная информация об этом приведена в литературе [39, 40]. Обратите внимание на порядок следования операндов в заголовке макрокоманды, который построен по обычной для команд ассемблера схеме: коп назначение, источник. В команде CMPXCHG порядок обратный. Этого требует синтаксис команды. Это хорошо поясняет назначение бита d во втором байте кода операции, который характеризует направление передачи данных в микропроцессор (то есть в регистр) или в память (из микропроцессора (регистра)). Вы можете провести эксперимент. Проанализируйте машинные коды команды MOV:
CMPPS RXMM1. RXMM2/ml28, 18 CMPSS RXMM1, RXMM2/m32. i8
Из перечисленных выше групп команд можно вывести следующую обобщенную структуру команды:
метка: код_операции операнд1. операнд2, операндЗ] ;текст комментария
Данная структура почти совпадает со структурой обычных команд ассемблера. В соответствии с общими принципами трансляции препроцессор будет работать с исходной программой в несколько этапов.
2. Синтаксический анализ.
3. Генерация кода.
Необходимо отметить, что по принципу действия разрабатываемый нами препроцессор относится к интерпретаторам. Читатель наверняка понимает, в чем состоит разница между интерпретатором и компилятором. Объект для работы компилятора — исходный текст программы в полном объеме. Выход компилятора — объектный модуль, то есть машинное представление исходной программы, пригодное для компоновки с другими модулями или получения исполняемого модуля. Интерпретатор работает с отдельными строками исходной программы. Распознав синтаксическую правильность строки, интерпретатор исполняет ее. В частности, интерпретация характерна для обработки входных строк командного процессора. Поэтому на примере данной задачи читатель может научиться достаточно профессионально организовывать языковое взаимодействие с пользователями своих программ.
В главе 2 описаны основные шаги разработки компилятора. Для интерпретатора разница невелика, в чем мы убедимся ниже.
Для распознавания лексем входной программы разработаем сканер, следуя для этого следующему алгоритму.
2. Определить классы литер.
3. Определить условия выхода из сканера для каждого класса лексем.
4. Каждому классу лексем поставить в соответствие грамматику класса 3.
5. Для каждой грамматики, построенной на шаге 4, построить конечный автомат, который будет распознавать лексему данного класса.
6. Выполнить объединение («склеивание») конечных автоматов для всех классов лексем.
7. Составить матрицу переходов для «склеенного» конечного автомата.
8. «Навесить» семантику на дуги «склеенного» конечного автомата.
9. Выбрать коды лексической свертки для терминалов грамматики и формат таблицы идентификаторов.
10. Разработать программу сканера.