Встроенный ассемблер
Встроенный ассемблер позволяет программисту задавать реализацию слов непосредственно в машинном коде данной ЭВМ. Это дает ему возможность, с одной стороны, повышать быстродействие программы до максимально возможного уровня за счет перевода интенсивно используемых слов непосредственно в машинный код, а с другой — использовать особенности архитектуры данной ЭВМ и «напрямик» связываться с операционной системой и внешним окружением.
Примеры обоих случаев дает сама форт-система. Очевидно, что слова, выполняющие арифметические операции или действия с вершиной стека, естественно реализовывать непосредственно в машинном коде, поскольку скорость их исполнения в значительной степени определяет быстродействие системы. Вместе с тем слово 1+, увеличивающее на единицу значение на вершине стека, можно определить как в машинном коде (особенно если в данной ЭВМ есть специальная команда увеличения значения на единицу), так и через двоеточие:
: 1+ ( A ---> A+1 ) 1 + ;
В последнем случае, если к тому же слово 1 реализовано в виде отдельной словарной статьи 1 CONSTANT 1, шитый код займет всего три ячейки, что может быть короче аналогичной программы в машинном коде. Разумеется, при этом исполнение будет дольше за счет интерпретации последовательности из трех ссылок вместо прямого исполнения соответствующих машинных команд. Также очевидно, что, например, форт-слова для обмена с терминалом естественно задать на машинном уровне через обращения к соответствующим функциям операционной системы или непосредственно к аппаратуре.
Для определения слов непосредственно в машинном коде стандарт языка Форт предусматривает следующие слова:
ASSEMBLER ---> CODE ---> END-CODE ---> ;CODE ---> (компиляция)
составляющие стандартное ассемблерное расширение обязательного набора слов.
Слово ASSEMBLER (ассемблер) является именем списка слов, содержащего слова, с помощью которых строится машинный код (мнемоники машинных команд, обозначения регистров, способы адресации и т.д.).
Слово CODE (код) является определяющим для слов нижнего уровня и обычно определяется так:
: CODE ( ---> ) CREATE HERE LATEST NAME> ! ASSEMBLER ;
Оно используется в сочетании со словом END-CODE (конец кода): CODE <имя> <машинный-код> END-CODE, где «имя» является именем определяемого слова, а «машинный-код» — записью его реализации в машинном коде в соответствии с принятыми соглашениями.
Поле кода такой словарной статьи содержит адрес ее поля параметров, в котором располагается данный машинный код.
Наконец, слово ;CODE, имеющее признак немедленного исполнения, позволяет задавать исполняющую часть определяющих слов непосредственно в машинном коде:
: ;CODE ( ---> ) COMPILE (;CODE) [COMPILE] [ ASSEMBLER ; IMMEDIATE
Оно используется внутри определения через двоеточие для определяющего слова аналогично слову DOES>:
: <имя> <создающая-часть> ;CODE <машинный-код> END-CODE
и отделяет высокоуровневую создающую часть от исполняющей части, заданной в машинном коде. Во время исполнения скомпилированного словом ;CODE слова (;CODE) адрес машинной программы, составляющей исполняющую часть, будет заслан в поле кода определяемого слова, которое таким образом получит интерпретатор, реализованный в машинном коде. На практике именно таким способом задают стандартные определяющие слова — :, CONSTANT и VARIABLE.
Конкретный вид машинной программы зависит от архитектуры данной ЭВМ. Общим правилом является то, что этот текст представляет собой последовательность слов, которые исполняются текстовым интерпретатором, в результате чего на вершине словаря формируется соответствующий двоичный машинный код. Машинные команды записываются в естественной для Форта обратной польской форме: сначала операнды, а затем слово, обозначающее мнемонику команды.
Операнды — это слова, вычисляющие на стеке размещения операндов: номера регистров, адреса в памяти и их модификации, значения непосредственных операндов и т.д.
Мнемоника команды, обычно состоящая из традиционного обозначения данной команды и запятой, снимает со стека размещения своих операндов и компилирует соответствующий двоичный код.
Включение запятой в имя слова для кода команды, с одной стороны, подчеркивает тот факт, что данное слово компилирует команду, а с другой стороны, позволяет отличать, например, часто встречающиеся мнемоники ADD, СН и т.д. от чисел, заданных в шестнадцатиричной системе.
В табл. 2.1 приведена запись одних и тех же машинных команд в традиционном ассемблере и встроенном ассемблере разных форт-систем для нескольких распространенных типов ЭВМ. Как и в случае реализации структур управления, во встроенный ассемблер можно включить дополнительные средства контроля, которые, учитывая формат машинных команд, проверяют правильность задания их операндов.
Таблица 2.1. Сравнительная запись машинных команд в традиционном ассемблере и встроенном ассемблере форт-системы
СМ-4 | CMPB #12, (R1)+ JMP NEXT RTS |
12 # R1 )+ CMPB, NEXT JMP, RTS, |
ЕС ЭВМ | STM 14,12,12(13) BALR 15,0 B NEXT |
14 12 12 (, 13 STM, 15 0 BALR, NEXT B, |
К580 | MOV A,B LXI H,15 POP H |
A B MOV, H 15 LXI, H POP, |
БЭСМ-6 | , UTC, =I5 , XTA, 3, UTC, 777 |
0 0 5 # # UTC, 0 0 XTA, 3 777 UTC, |
Встроенный ассемблер форт-систем часто делают «структурным», т.е. включают в него операторы ветвления и циклы, выполняющие переходы по значению управляющих разрядов в специальном регистре. По аналогии с такими же средствами языка Форт эти структуры задают с помощью тех же слов с добавлением запятой: IF, THEN, ELSE, BEGIN, UNTIL, и т.д. При этом вводят слова, обозначающие различные состояния управляющих сигналов, а слова, реализующие структурные операторы компилируют команды переходов, соответствующие указанным состояниям.
Такой подход позволяет во многих случаях избежать введения сложного механизма переходов на метку, поскольку ассемблерные вставки, для трансляции которых и существует встроенный ассемблер, состоят, как правило, из нескольких команд.
Программа в машинном коде, заданная через слова CODE или ;CODE, получает управление от адресного интерпретатора и после ее завершения возвращает управление интерпретатору на точку NEXT. Для связи с адресным интерпретатором в списке слов ASSEMBLER обычно предусматривается ряд констант, обозначающих точки входа, номера регистров и другие ресурсы адресного интерпретатора. Аналогичным образом предусматривается связь с операционной системой, встроенным постоянным программным обеспечением и аппаратурой.
В общем объеме больших программ на Форте ассемблерные коды составляют незначительную часть (в реализации самой форт-системы, например, 10-30%), но вместе с тем такая возможность делает программиста максимально свободным в выборе средств для реализации своих идей.