Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Вт июл 16, 2019 20:13

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 2 ] 
Автор Сообщение
 Заголовок сообщения: Brad Rodriguez: Как написать свой (кросс-)ассемблер
СообщениеДобавлено: Ср окт 08, 2008 07:38 
Не в сети
Moderator
Moderator

Зарегистрирован: Ср май 10, 2006 15:37
Сообщения: 1132
Откуда: Chelyabinsk ( Ural)
Благодарил (а): 0 раз.
Поблагодарили: 9 раз.
взята c url: http://akps.ssau.ru/forth/tc/tj.html ( не работающий).
оригинальный url:

Как написать свой (кросс-)ассемблер
(c) Brad Rodriguez

Введение

В предыдущем выпуске журнала я описал как "загрузить" себя на новый процессор используя простой отладочный монитор. Но как вы сможете писать код для этого нового процессора, если вы не можете найти ассемблер или он вас не устраивает ? Напишите свой !
ФОРТ -- идеальный язык для этого. Для TSM320 например я написал кросс-ассемблер всего за два часа, включая длинный обеденный перерыв. Обычно это занимает около двух дней, но для одного из процессоров (Zilog Super8) потребовалось пять дней. Но когда у вас больше времен чем денег, это не важно.

В части 1 этой статьи я опишу основные принципы ФОРТ-ассемблеров -- структурированные, однопроходные, постфиксные. Многое из этого применимо для любого процессора, и это концепции почти любого ФОРТ-ассемблера.

В части 2 я покажу как писать ассемблер для специфичного процессора Motorola 6809. Этот ассемблер прост но не тривиален, занимает 15 страниц исходного кода. Кроме всего прочего, этот пример покажет как реализовывать инструкции с множественными режимами адресации. Изучив этот пример, вы сможете понять как использовать особенности вашего процессора.

Зачем использовать ФОРТ?

Мне кажется что ФОРТ -- простейший язык для написания ассемблера.
Прежде всего ФОРТ имеет текстовый интерпретатор для разбора текстовых строк и выполнения соответствующих команд. Преобразование текстовых строк в байты кода -- как раз и есть задача ассемблера. Операнды и режимы адресации также реализуются через ФОРТ-слова.

ФОРТ также включает определяющие слова, которые позволяют легко описать большие наборы слов с общим действием. Эта возможность очень полезна при определении мнемоник ассемблера.

Так как при работе ассемблера доступны все слова ФОРТ а, они могут быть использованы при использовании ассемблера не только для вычисления адресов и операндов, и и для выполнения более сложных действий.

В общем так как ассемблер полностью реализуется через слова ФОРТ а, определения ФОРТ а аналогичны макро-определениям.


Простейший пример: ассемблирование NOP

Для понимания того как ФОРТ транслирует мнемоники в машинный код, рассмотрим простейший случай: инструкцию NOP (0x12 для 6809, 0x90 для 80x86).

Обычный ассемблер при нахождении строки "NOP" должен добавить соответствующий байт в выходной файл и увеличить указатель на 1. Операнды и комментарии игнорируются. Я также пока буду игнорировать метки.

В ФОРТ е выходным файлом обычно является словарь в памяти или при кросс-ассемблировании блок памяти: образ памяти целевой системы. Так, определим слово NOP соответствующим образом: "скомпилировать опкод NOP и увеличить указатель".
Код:
: NOP,    0x12 C, ;

Обратите внимание что в этом примере используется возможность SP-FORTH воспринимать числа с префиксом 0x (шестнадцатеричные числа) независимо от текущей системы счисления, заданной в переменной BASE. Если ваша ФОРТ-система не имеет такой возможности, для удобства в начале кода ассемблера можно использовать слово HEX.

Также следует обратить внимание на то, что при использовании целевого компилятора для кросс-разработки слово C, должно быть переопределено так, чтобы оно компилировало байт в образ памяти целевой системы.

Для ассемблерных опкодов часто задаются имена ФОРТ-слов имеющие в конце символ ",", как это сделано выше. Это делается из-за того что многие ФОРТ-слова (например AND, XOR, OR) конфликтуют с мнемониками ассемблера. Простейшее решение -- слегка изменить мнемоники (символ "," в ФОРТ е обозначает что что-то компилируется (добавляется) в словарь).

Класс наследуемых опкодов

Большинство процессором имеют много инструкций подобных NOP, которые не требуют операндов. Все они могут быть определены в ФОРТ е через двоеточие, но это значительно увеличивает объем исходного кода. Намного более эффективным является использование механизма определяющих слов для того, чтобы задать для всех таких слов общее поведение. В терминах ООП это значит создание экземпляров единственног класса.Это далется с использованием слов CREATE и DOES>.

В приведенном примере параметр (разный для каждого созданного слова) обычный опкод, который должен быть скомпилирован для каждой инструкции.

Код:
: cmd0ops                     \ определение имени класса команды без опреандов
    CREATE                    \ этот код выполняется при создании слов
        C, ( byte -- )        \ сохранить байт для нового определяющего слова
    DOES>  ( -- addr )        \ этот код определяющего слова (общее действие)
        C@ ( addr -- byte)    \ получить сохраненный при создании слова опкод
        C, ( byte -- )        \ скомпилировать опкод
;


Примеры использования определяющего слова cmd0ops:
Код:

0x12 cmd0ops NOP,
0x3A cmd0ops ABX,
0x3D cmd0ops MUL,


Обратие особое внимание на то, что этот пример дан для обычного ФОРТ -ассемблера, а не кросс-ассемблера, то есть генерируемый код компилируется в основной словарь ФОРТ-системы. При кросс-компиляции (использовании целевого компилятора) нужно сделать несколько финтов ушами -- например нужно использовать разные варианты слова C, в блоках CREATE и DOES> слова cmd0ops, которые должны компилировать опкод соответственно в словарь ФОРТ-системы и в область памяти целевой системы.

Эта техника дает некоторую экономию памяти почти без потери скорости, но реальное удобство будет видно при определении сложных инструкций, которые требуют параметры и модификаторы режимов адресации.

Обработка операднов инструкций

Большинство команд ассемблера требуют один или более операндов. Для этих команд ассемблер должен быть способен разбирать текст из входного потока и интерпретировать его как операнды. Для постфиксного ФОРТ-ассемблера используется более простой способ, использующий готовый механизм интерпретации ФОРТ-системы.

Итак ФОРТ будет использоваться для разбора операндов. Числа обрабатываются как обычно (в любой системе счисления), для EQU выражений могут использоваться обучные константы ФОРТ CONSTANT. Так как операнды определяют формат ассемблируемой команды, они должны быть обработаны до команды ассемблера. Результаты разбора операндов обычно оставляются на стеке данных и используются командами ассемблера для определения формата команды и используемого оп-кода. Для ФОРТ-ассемблера используется уникальный ( ну не совсем уникальный -- GNU assembler тоже постфиксный) постфиксный формат команд: операнды, за которыми следует команда ассемблера.

Для примера рассмотрим инструкцию ORCC процессора 6809, которая использует простой числовой параметр:
Код:
: ORCC,   0x1A C,  C, ;
\ пример использования: 0x34 ORCC,

Выполнение этой команды состоит из двух этапов:
1 компилируется опкод инструкции ORCC 0x1A;
2 компилируется параметр инструкции 0x34, взятый со словаря.
Эта команда предполагает что на стеке уже лежит числовой параметр, полученный в результате разбора операндов, которые в нашем случае имеют вид простого hex числа 0x34 в исходном коде.

Достоинство такого ассемблера -- доступна вся мощь ФОРТ а, которая может быть использована для формирования операндов, например:
Код:
0x01 CONSTANT CY-FLAG    \ используем константы ФОРТа для задания операндов
0x02 CONSTANT OV-FLAG
0x04 CONSTANT Z-FLAG

CY-FLAG Z-FLAG + ORCC,   \ команда ORCC проверит флаги CY и Z

Из примера видно что расширение разбора операндов для определяющих слов ассемблера достаточн просто.

Обработка режимов адресации

Для современных процессоров для одной команды используется несколько форматов и различные оп-коды в зависимости от режима адресации. ФОРТ-ассемблеры решают эту проблему несколькими способами в зависимости от типа процессора. Все эти способы используют методологию ФОРТ а: операторы определения режима адресации являются ФОРТ-словами. Когда эти слова исполняются, они изменяют формат ассемблируемой инструкции.

1 помещение дополнительных параметров на стек.

Это наиболее удобно если всегда должен указываться режим адресации. Слова режима адресации оставляют на стеке некоторые константы, которые обрабатываются словами ассемблера. Иногда эти значения могут быть "магическим числом", добавляемым к опкоду для изменения режима адресации команды. Кодга это неприменимо, используется выбор формата команды в блоке CASE. В общем случае скомпилированные инструкции могут иметь разнуб длину в зависимости от режима адресации.

2 установка флагов или значений в фиксированных переменных.

Это наиболее удобно если режим адресации опционален. Не зная что был указан режим адресации, вы не можете знать что значение на стеке "магическое число" или просто значение операнда. Решение этой пролемы: режим адресации указывать помещая соответствующую ему константу в определенную переменную (часто называемую MODE). После выполнения каждой команды ассемблера эта переменная инийиализируется значением по умолчанию. Если используется команда ассемблера, у которой может быть несколько режимов адресации, то она определяет содержимое этой переменной.

3 модификация значений параметров непосредственно на стеке.

Это иногда возможно для реализации слов указывающих режим адресации, которые работают модифицируя значения операндов. Этот метод используется редко.

Все эти три метода я использовал с некоторыми расширениями для реализации ассемблера 6809.

Для большинства процессоров имена регистров задаются обычными константами ФОРТ а, и оставляют на стеке свои значения. Для некоторых процессоров также удобно иметь имена регистров, определяющие режим "регистровой адресации". Это легко сделать определяя имена регистров как определяющие слова, которые создают слова, устанавливающие режим адресации (а стеке или в переменной MODE).

Некоторые процессоры позволяют использовать несколько режимов адресации в одной инструкции. Если чисто режимов адресации фиксировано, они могут оставляться на стеке. Если чисто переменное, необходимо знать сколько их был указано, и нужно использовать несколько переменных MODE$_{n}$. Для процессора Super8 я должен был отслеживать не только сколько режимов адресации указано, но и сколько операндов. Я сделал это сохраняя позицию стека отдельно для каждого режима адресации.

Рассмотрим инструкцию 6809 ADD. Для упрощения игнорируем индексированные режимы адресации, и реализуем только три режима: непосредственный (immediate), прямой (direct) и расширенный (extended):
Код:
           исходный код     ассемблируется как
------------------------------------------------
immediate  <число> # ADD,   8B nn
direct     <адрес> <> ADD,  9B nn
extended   <адрес> ADD,     BB aa aa


Так как режим extended не имеет оператора режима адресации, режим адресации оказывается уже определенным. Слова ФОРТ а # и <> устанавливают режим адресации.

Рассмотрим систему команд 6809. Если опкод immediate является основным значением, то опкод в direct режиме равен базовому +0x10, в indexed режиме +0x20 и в extended режиме +0x30. Это справедливо для почти всех инструкций, использующих эти режимы адресации. Исключение составляют те опкод, для которых опкоды в режиме direct имяют форму 0x0?.

Такие особенности системы команд нужно использовать. Это общее правило при написании ассемблеров: найдите или сделайте сами таблицу опкодов, и найдите закономерности -- особенно те, которые применимы для режимов адресации или других модификаторов инструкций (таких как коды условий).

В нашем случае нужно использовать следующие значения переменной MODE:

Код:
VARIABLE MODE
: #     0x00 MODE ! ;
: <>    0x10 MODE ! ;
: RESET 0x30 MODE ! ; \ значение по умолчанию


Значение по умолчанию 0x30 (extended режим) устанавливается словом RESET. Это слово будет использоваться после того как будет ассемблирована каждая инструкция.
Теперь может быть написана команда ассемблера ADD,. Давайте посмотрим ее старую версию и напишем определяющие слова для создания команд ассемблера.

Код:
: GENERAL-OP    ( <базовый опкод> -- )
     CREATE C,
     DOES>              \ ( <операнд> -- )
     C@                 \ получить базовый опкод
     MODE @ +           \ добавляем "магическое число"
     C,                 \ ассемблируем опкод
     MODE @ CASE
        0x00 OF C, ENDOF \ операнд байт
        0x10 OF C, ENDOF \ операнд байт
        0x30 OF ,  ENDOF \ операнд слово (2 байта)
     ENDCASE
     RESET              \ выбор режима адресации по умолчанию
;

8B GENERAL-OP ADD,


Каждый экземпляр GENERAL-OP будет иметь различный базовый опкод. Когда ADD, выполняется, он будет получать этот базовый опкод, добавлять к нему значение MODE, и комплировать полученный байт. Дале он будет брать операнд, находящийся на стеке, и компилировать его в зависимости от выбранного режима адресации как байт или слово. В конце MODE будет сброшен в значение по умолчанию.

Отметим что уже определен весь код, который нужно использовать для определения инструкций того же семейства что и ADD:

Код:
0x89 GENERAL-OP ADC,
0x84 GENERAL-OP AND,
0x85 GENERAL-OP BIT,


Сохранение памяти при использовании определяющих слов по сравнению с обучными словами определенными через двоеточие очевидно. Все команды ассемблера, приведенные выше, используют единственный блок кода после DOES>, вызов которого из этих слов занимает всего несколько байт.

На самом деле это не мой код реального ассемблера 6809 -- существуют дополнительные особые случаи, которые необходимо реализовать. Но он показывает что сохраняя что достаточно сделать чтобы сохранить информацию о режиме и как свободно использовать конструкцию CASE чтобы реализовать наиболее простые наборы команд.

Реализация структур управления

Структурное программирование наделало очень много шума, и было написано множество макропакетов "структурного ассемблирования" для распространенных ассемблеров. Но ФОРТ-ассемблерам изначально присущи такие свойства как отсутствие меток, структурный ассемблерный код, что объяснятся той причиной что на ФОРТ е проще реализовать структурный ассемблер чем метки.

Структуры, обычно включаемые в ФОРТ-ассемблеры, аналогичны структурам высокоуровневого ФОРТ а. Для их отличия к ним добавляется запятая, как это было сделано для ассемблерных команд.

BEGIN, UNTIL,

Эта самая простая для понимания ассемблерная структура. Ассемблерный код должен защиклиться до метки BEGIN до того как будет удовлетворено некоторое условие. Синтаксис для ФОРТ-ассемблера:

BEGIN, <код> <условие> UNTIL,

Код условия предположительно определен как операнд или режим адресации для интсрукции перехода.

Очевидно что UNTIL должен комплировать условный переход. Условия перехода должны быть инвертированы так что если условие удовлетворяется, то переход игнорируется, в отличие от перехода когда условие ложно. Ассемблерный код для обычного ассемблера должен иметь вид:

Код:
xxx: ...
     ...
     ...
     JR  ~cc,xxx    \ ~cc то же что и NOT(cc)


Существует два свойства, помогающие реализовать эту струткуру. Слово THERE ( аналог HERE) при целевой компиляции возвращает текущий указатель компиляции. Числа могут храниться на стеке не влияя на реботу ФОРТ а, и доставаться по необходимости.

Итак BEGIN, должен запоминать позицию указателя компиляции помещая ее в стек, а UNTIL, будет ассемблировать условный переход по запомненному на стеке адресу.

Код:
: BEGIN, ( -- a )        HERE ;
: UNTIL, ( a cc -- )     NOTCC JR, ; \ флаг перехода инвертируется


Как видно по стековой нотации BEGIN, оставляет на стеке текущий адрес, и UNTIL, использует запомненный адрес и код условия для компиляции условного перехода. Слово NOTCC предварительно инвертирует код условия. Слово JR, использует адрес перехода и (инвертированный) код условия для формирования соответствущего кода условного перехода 6809.

Такая реализация позволяет использовать вложенные условные циклы:

Код:
BEGIN,
     ...
     BEGIN,
          ...
     cc UNTIL,
     ...
cc UNTIL,


Вложенный UNTIL, ссылается на вложенный BEGIN,, формируая код цикла внутри кода охватывающего цикла.

BEGIN, AGAIN,

ФОРТ также поддерживает конструкцию бесконечного цикла BEGIN AGAIN. Определение этой конструкции для ассемблера аналогично, за тем исключением что код условия не используется, и компилируется безуслоный переход на начало цикла.

DO, LOOP,

Многие процессоры предоставляют некоторые инструкции цикла. Так как их нет у 6809, расмотрим Zilog Super8. Он имеет инструкцию DJNZ (декремент и переход если не ноль), которая может использовать любой из 16 регистров как счетчик цикла. Для процессора 80x86 эта инструкция работает только с регистром (E)CX. Цикл на структурном ассемблере будет иметь вид:
Код:
DO, ... r LOOP,


где r регистр используемый как счетчик цикла.
Код:
: DO,   ( -- a)     HERE ;
: LOOP, ( a r -- )  DJNZ, ;


В некоторых ФОРТ-ассемблерах DO, также ассемблирует код инициализации счетчика цикла, но это уменьшает гибкость.

IF, THEN,

Эта конструкция -- простейшая конструкция, использующая ссылки вперед. Если условие истинно, она должна выполняться, иначе управление передается на первую инструкцию после THEN,.
Ассемблерный код для ФОРТ-синтаксиса
Код:
cc IF,  ... ... ...  THEN,

будет иметь вид
Код:
     JP   ~cc,xxx
     ...
     ...
     ...
xxx:


Обратите внимание что код условия должен быть инвертирован аналогично UNTIL,.
В однопроходном ассемблере необходимый переход вперед не может быть скомпилирован сразу, так как адрес перехода еще неизвестен. Эта проблема решается путем ассемблирования пустого перехода типа JMP 0 и помещения на стек адреса операнда команды JMP. Позже слово THEN, сможет взять этот адрес и пропатчить скомплирированный JMP, соответствующм образом модифицировав его операнд.
Код:
: IF, (cc -- a)
     NOT 0 SWAP JP,      \ условный переход
     HERE 2 -            \ помещаем на стек HERE-<размер операнда>
;

: THEN, (a --)
     HERE SWAP !         \ запоминаем по адресу операнда JP текущий HERE
;


IF, инвертирует код условия и компилирует условный переход на нулевой адрес, кладя адрес операнда на стек. После компиляции условного перехода HERE указывает на байт после него, поэтом нужно вычесть размер операнда условного перехода. THEN, затем модифицирует команду условного перехода, изменяя адрес перехода на реальный.
Приведенный вариант THEN, -- самый простой вариант для процессоров, использующих условный переход по абсолютному 16-битному адресу. У многих процессоров есть только команда условного перехода по относительному адресу $127 байт от адреса команды перехода. В этом случае размер операнда равен одному байту, а THEN, должен предварительно вычесть из HERE адрес на стеке.

IF, ELSE, THEN,

Улучшенный вариант IF, THEN, дополняется блоком кода, выполняемом если условие не выполняется:
Код:
cc IF,  ... ...  ELSE,  ... ...  THEN,


Ассемблерный код этой конструкции имеет вид:
Код:
     JP   ~cc,xxx
     ...            ; код "если"
     ...
     JP   yyy
xxx: ...            ; код "иначе"
     ...
yyy:



ELSE, должен модифицировать действия IF, и THEN, следующим образом:

1 переход вперед в IF, долен быть модифицирован чтобы выполнялся переход на начало блока ELSE, ("xxx");
2 адрес, положенный на стек THEN, должен быть записан в операнд безусловного перехода в конце блока IF, ("JP yyy").

ELSE, также должен компилировать безусловный переход.
Код:
: ELSE (a -- a)
     0 T JP,        \ безусловный переход
     HERE 2 -       \ поместить в стек адрес операнда перехода для THEN,
     SWAP           \ получить адрес перехода IF,
     HERE SWAP !    \ заменить его на текущий адрес
;

Условие перехода T обозначает TRUE, то есть безусловный переход. При определении ELSE, может быть использован код IF, и THEN, если таже определено условие F FALSE:
Код:
: ELSE (a -- a)     F IF, SWAP THEN, ;


SWAP адресов в стеке инвертирует последовательность модификации инструкций перехода так, что THEN, модифицирует переход внутри кода ELSE,:
Код:
IF,(1)   ...   IF,(2)  THEN,(1)   ...   THEN,(2)
               \______________/
                  внутри ELSE,


BEGIN, WHILE, REPEAT,

Наиболее сложной ассемблернй структурой является цикл ПОКА, в котором условие проверяется в начале цикла, а не в конце.

Код:
BEGIN, <код> cc WHILE, <код цикла> REPEAT,


На практике между BEGIN, и WHILE, может быть вставлен любой код, а не только задание условия.
WHILE, должен скомпилировать условный переход по инверсному условию на код за REPEAT,. Если код условия cc удовлетворяется, этот переход должен игнорироваться и выполняться код цикла.

REPEAT, должен компилировать безусловный переход на BEGIN,.

Код:
BEGIN,(1)  ...  cc IF,(2)  ...  AGAIN,(1)  THEN,(2)


Это может быть сделано с использованием существующих слов:
Код:
: WHILE, (a cc -- a a)   IF, SWAP ;
: REPEAT, (a a -- )      AGAIN, THEN, ;


Заголовок ФОРТ-определения

В большинстве приложений машинный код, созданный ФОРТ-ассемблером, помещается в словарь с помощью CODE <имя>, который создает словарную статью с именем <имя> и связывает ее со словарным списком.

Слово CODE получает имя слова из входного потока, создает определение в словаре с этим именем, и настраивает указатель словаря на начало поля кода этого имени.

Стандартный ФОРТ использует слово CODE не только для выделения начала ассемблерного определения в словаре, но и дополнительной инициализации ассемблера (установке переменных типа MODE).

Кросс-компиляция

До сих пор мы предполагали что в словарь компилируется машинный код системы, на которой и исполняется.

Для кросс-компиляции обычно выполняется компиляция в отдельную область памяти. Эта область может иметь или не иметь словарной структуры, но она отделена от словаря хост-машины, и скомплированный код не может быть исполнен.

Чаще всего для этого используется набор слов для доступа к целевому пространству памяти по аналогии с обычным долступом к памяти в ФОРТ е. Для этого могут быть использованы обычные слова с префиксом "T":

TDP (указатель компиляции DP целевой системы) THERE (аналог HERE для целевой системы) \ если VALUE-переменная, TDP не нужен)

Иногда вместо использования префиска "T" эти слова определяются в отдельном словаре целевого компилятора. Словарная структура ФОРТ а позволяет иметь несколько наборов совпадающих по имени слов с различным действием.

Компиляция на диск

Целевая компиляция также может выполняться сразу на диск (в файл) без использования буфера памяти целевой системы, но из-за использования прямого побайтного доступа к файлу это может значительно замедлить работу компилятора. Особенно это заметно если не используется кеширование дисковых операций.

Безопасная компиляция

Некоторые реализации ФОРТ а используют безопасную компиляцию, которая пытяется отловить ошибки типа несбалансированных структур управления типа

Код:
IF, ... cc UNTIL,


В этом примере UNTIL, некорректно использует адрес, помещенный на стек IF,.
Обычный метод проверки сбалансированности структур управления -- помещение на стек данных или на отдельный стек констант, уникальных для каждого управляющего слова, которые проверяются другими словами:
Код:
IF, помещает 1;
THEN, проверяет на 1;
ELSE, проверяет на 1 и оставляет 1;
BEGIN, оставляет 2;
UNTIL, проверяет 2;
AGAIN, проверяет 2;
WHILE, проверяет 2 и оставляет 3;
REPEAT, оставляет 3
DO, оставляет 4;
LOOP, проверяет 4.

Стоимость такой безопасности -- увеличение сложности манипуляций со стеком в таких словах как ELSE, и WHILE,. Ткже программист может захотеть последовательность в которой управляющие структуры are resolved вручную манипулируя стеком. Безопасность делает это более сложным.

Метки

Даже в эру структурного программирования некоторые программисты используют метки в ассемблерном коде.

Принципиальная проблема с именоваными метками в ФОРТ-ассемблере -- так как метки это ФОРТ-слова, они должны быть скомпилированы в словарь во время незавершенной компиляции другого слова в машинном коде, например:
Код:
CODE TEST  ...  <машиннный код>  ...
HERE CONSTANT LABEL1
...  <машинный код>  ...
LABEL1 NZ JP,


Как видно из примера определение метки LABEL1 должно создавать словарную статью внутри серидины CODE. Вот несколько решений 1 метки определяются только вне машинного кода. 2 используются некие предопределенные переменные для временного хранения меток. 3 для меток используется отдельное словарное пространство, например как это сделано по схеме TRANSIENT . 4 для машинного кода используется отдельное пространство словаря. Это наиболее часто используемый метод при мета-компиляции. Большинство мета-компиляторов ФОРТ а поддерживают метки с некоторыми сложностями.

Табличный ассемблер

Большинство ФОРТ-ассемблеров могут отрабатывать режимы адресации и инструкции используя структуры типа CASE. Их можно назвать процедурными ассемблерами.

Некоторые процессоры типа 68000 имеют настолько сложные наборы инструкций и режимов адресации, что становится сложным строить деревья выбора при ассемблеировании их команд. В таких случаях более подходящим является использование таблиц, что уменьшает используемую память и процессорное время.

Я не буду описывать такие процессоры -- табличные ассемблеры писать намного сложнее.

Префиксные ассемблеры

Иногда использование префиксных ассемблеров необходимо. Например мне однажды пришлось переводить многие килобайты ассемблерного кода для Super8 для обычного Zilogовского ассемблера для ФОРТ-ассемблера. Существует трюк позволяющий имитировать префиксный ассемблер при использовании методов, описанных в этой статье.

В основном этот трюк можно определить как отложенное выполнение ассемблирования после того как были обработаны операнды. Это делается следующим словом ассемблера.

Так каждое слово ассемблера модифицируется так что оно 1 сохраняет свой код или адрес кода, компилирующего команду; 2 выполняет компилирующий команду код для предыдущего слова ассемблера.
Код:
...  JP  operand    ADD  operands  ...


JP сохраняет указатель на свой код в какой-либо переменной. Далее обрабатываются операнды. ADD берет информацию, запомненную JP и выполняет действие JP, которое использует операнды на стеке. Когда код JP завершается, ADD сохраняет свой адрес, и процесс продолжается.

Особо должны отрабатываться первые и последние команды в ассемблерном блоке. Если используются переменные режима, то их сохранение и восстановление станоится кошмаром.

Вывод

Я рассмотрел наиболее простые методики используемые в ФОРТ-ассемблерах. Изучение готового ассемблера может дать вам информацию как писать собственный ассемблер, но лучший способ изучения -- действие.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср окт 08, 2008 18:00 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 4986
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 18 раз.
Поблагодарили: 56 раз.
хочу от себя добавить, что достаточно простым образом постфиксный ассемблер становится классическим префиксным.
на форуме данный вопрос уже поднимался недавно.

А вот что интересно, высокоуровневые ассемблерные макросы типа IF LOOP и подобные им почему-то особо не прижились.

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 2 ] 

Часовой пояс: UTC + 3 часа [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB