22 Мар 2026, Вс

МиМ. Эмулятор EmuZWin

Скачать

Запуск своей программы:

F4 в окне ассемблера (компиляция) -> F11 в основном окне (перезагрузка) -> F12 в основном окне (запуск отладчика) -> F9 в окне отладчика (запуск программы)

Описание ассемблера находится в файле ZX_Assembler.htm

Перевод описания на русский язык:

Встроенный ассемблер EmuZWin
Поддерживаемые операторы и директивы.

(С) Владимир Кладов, 2003-2006

Начиная с версии v2.2, можно просмотреть полный список всех операторов и директив, поддерживаемых встроенным ZX Ассемблером, прямо в окне ассемблера.

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

  • Одна строка может содержать одну или несколько инструкций ассемблера или одну директиву. Перенос строк не допускается, за исключением нескольких особых случаев (ENUM, FOR). Также строка может быть пустой или содержать только комментарий (начинающийся с ';' или с '', но для '' - только если он находится в первой колонке строки).
  • Любая строка с инструкцией может иметь метку, которая представляет собой идентификатор, начинающийся с буквы или одного из символов '@','_','!','~','#','%','$','!', '\', '[', ']' или OEM-символа с шестнадцатеричным кодом C0-FF (таким образом, разрешены идентификаторы на русском языке) и (опционально) за которым следуют любые символы, кроме ':', ';' и других символов, которые могут быть интерпретированы как символы арифметических или логических операций.
  • Метка может отделяться от инструкции символом ':', но это необязательно (пробелы разрешены). Поэтому, если метка совпадает с каким-либо зарезервированным словом, она должна быть отделена ':' от остальных символов в строке (это позволяет использовать зарезервированное слово как метку). Но инструкции или директивы без параметров (или директивы, которые могут не иметь параметров) всё равно не могут использоваться в качестве меток (например, loop). Допускается иметь только одну метку в строке, без инструкции.
  • Оператор, у которого нет метки, должен начинаться (по крайней мере) с одного пробела или табуляции. Таким образом, оператор без метки может начинаться с левого края строки (необязательно добавлять пробелы или табуляции в начале строки). Если строка содержит несколько инструкций ассемблера или директив, они могут разделяться символом ':' (это также необязательно и необходимо только в некоторых случаях, чтобы отделить выражение в последнем операнде от следующей инструкции).
  • Все метки чувствительны к регистру. (Так что Abc, abc и ABC - разные имена). Но коды операций (op-codes), директивы, имена регистров, флаги условий (Z, NZ и т.д.) и шестнадцатеричные цифры не чувствительны к регистру.
  • Числовые константы обычно должны (но не всегда!) начинаться с цифр 0..9 (шестнадцатеричные числа могут распознаваться, даже если начинаются с шестнадцатеричных цифр A..F, если они заканчиваются одним из маркеров основания: H, h, .H или .h). Основание по умолчанию - десятичное, но если встречается хотя бы один шестнадцатеричный символ 'a'..'f', для такой константы используется основание 16. Если числовая константа заканчивается на 'h' (или 'H'), также используется основание 16. Также допускаются двоичные числа в форме, например, 00001001.B с завершающим '.B' или '.b'. И то же самое для восьмеричных чисел с суффиксом '.O' или '.o' (и для десятичных .D и для шестнадцатеричных .H): например, 71.O означает восьмеричное число, равное 39.H (=57.D=111001.B). Также шестнадцатеричные числа допускаются в форме #xxxx (начинающиеся с '#' и содержащие шестнадцатеричные цифры) и в форме $xxxx (но последний случай только если соответствующая опция включена в настройках ассемблера). И для двоичных чисел формат %xxxx может быть разрешен в настройках ассемблера.
  • Если идентификатор все еще не определен после первого прохода и содержит только шестнадцатеричные цифры, он считается шестнадцатеричным числом. (Таким образом, можно написать OUT FE для кодирования инструкции OUT (FE),A).
  • Строковые константы заключаются в одинарные (') или двойные (") кавычки, а удвоенные кавычки в строке означают один такой символ. Для кодирования самих символов ' и " используйте другие кавычки для строки. Одно- или двухсимвольная строка может использоваться везде вместо числа (обратите внимание, что второй символ в такой строке представляет старший байт 16-битного слова, так что 'AB' = $4241).
  • Выражения разрешены везде как непосредственные операнды, смещения, метки переходов и т.д.
  • В любом месте выражения может использоваться специальная функция sizeof(имя_структуры) как обычная константа (см. директиву STRUCT ниже).
  • Специальная метка '.' (один символ точки) всегда означает "адрес самой команды". Специальная метка '$' означает "адрес следующей инструкции".
  • Локальные метки разрешены, начиная с одного из 6 символов '.', '_', '@', '!', '?', '\' (каждый может быть разрешен отдельно в настройках ассемблера). Локальные метки вообще не проверяются на дублирование. Чтобы перейти к ближайшей локальной метке (или использовать её в выражении), просто используйте её имя. Но если есть две такие метки, одна выше, а другая ниже инструкции перехода, используется последняя (сначала метки ищутся вперед). Чтобы указать направление, используйте имя локальной метки в форме B[локальная] или F[локальная] (B - назад, F - вперед; строчные b[локальная] и f[локальная] также разрешены; можно использовать символы '<' и '>' вместо 'B' и 'F', но только в инструкциях GOTO, JP и JR, и в таком случае допускается только одна метка, а не выражение).
  • В выражениях допускаются следующие бинарные операции:
    + сложение
    - вычитание
    * умножение
    / деление
    % остаток от деления
    & и (побитовое AND)
    | или (побитовое OR)
    ^ исключающее или (XOR)
    < меньше (истина = FFFF, ложь = 0)
    <= меньше или равно
    > больше
    >= больше или равно
    <> или != или ~= не равно
    = равно
    << сдвиг влево
    >> сдвиг вправо
    Круглые скобки можно использовать для управления порядком вычислений в выражениях как обычно. Если скобок нет, используются приоритеты операций от высшего к низшему:
    << >>
    * / %
    + -
    & ^
    |
    < > <= >= = <>

Следующие директивы и инструкции ассемблера поддерживаются внутренним ассемблером. (Символ '#' используется для обозначения того, что операндом может быть любое числовое выражение). Поскольку в большинстве случаев оператор можно продолжить на следующей строке, отмечены только директивы, имеющие некоторые ограничения на этот счет.

ORG ENTRYPOINT EQU x=y .=y, $=y ENUM DEFINE DEFB DEFM DEFW DEFS
DEFG DEFD ENCODE CTEXT FILE INCLUDE MACRO ERROR DISPLAY PROC DUP
FOR IF IFcond LOOP BREAK CONTINUE GOTO PUSH POP POPNOINVERT POPINVERT
END

ORG [{ RAMn | ROMn },] #целевой_адрес [, #адрес_назначения]

Определяет целевой адрес сборки и адрес назначения вывода.
RAMn и ROMn используются для определения банка RAM (n=0..7) или банка ROM (n=0..1).
Если указан отдельный адрес_назначения, скомпилированные байты помещаются по этому адресу,
хотя сам код компилируется для целевого_адреса.

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

ENTRYPOINT #выражение

Определяет точку входа для автоматической установки PC при успешной компиляции кода.

метка[:] EQU #выражение

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

метка[:] = #выражение

Определяет переменную-метку, равную данному выражению. Её можно переопределить
директивой '=' любое количество раз в коде. Переменные могут использоваться
в любых выражениях как обычные метки.

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

. = #выражение
или
$ = #выражение

Специальная форма присваивания, использующая текущий адрес компиляции в качестве левой
части присваивания. В результате следующий код будет компилироваться
с адреса, указанного выражением. Все метки и переменные, используемые в выражении,
должны быть известны на первом проходе компиляции (т.е. прямые ссылки вперед не допускаются,
как и для ORG, если только вы не отключили опцию "Строгий контроль адресов").
Главное отличие от директивы ORG в том, что этот адрес не будет помещен в список меток для переключения адреса PC.

ENUM метка1[=#выр1][,метка2[=#выр2]]...

Создает ряд констант метка1, метка2, … Если выр2, выр3 и т.д. опущены,
последующие константы присваиваются с инкрементом на 1 от предыдущих. Если выр1 опущено,
по умолчанию используется значение 0.

метка[:] DEFINE любой текст до конца строки

Об использовании параметров макроса, идентификаторов, определенных с DEFINE, или переменной цикла предпроцессора FOR см. ниже.

DEFB [[(#счетчик_повтора1)]{#выр1|'строка1'|?}][,[(#счетчик_повтора2)][{#выр2|'строка2'}]]...

Список байт. Для строки для каждого символа всегда генерируется один байт.
Если директива ENCODE определила кодировку, все символы кодируются перед помещением в память.
По умолчанию DEFB 'abc',0 скомпилируется в 4 байта: 61h,62h,63h,0.
Если для значения или строки указан (счетчик_повтора), оно повторяется указанное количество раз (если 0 или меньше, не генерируется вообще).
Если используется символ '?', соответствующая память не инициализируется и пропускается при генерации кода.

DEFM[{ #выражение | 'строка' }] [, [{ #выражение | 'строка' }] ]...

Список байт. Для строки для каждого символа всегда генерируется один байт.
Отличие от DEFB в том, что код последнего символа каждой строковой константы имеет установленный 7-й бит.
Так, DEFM 'abc' скомпилируется в 3 байта: 61h, 62h, E3h.

DEFW [[(#счетчик_повтора1)]{#выр1}][,[(#счетчик_повтора2)][{#выр2}]]...

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

DEFS #счетчик_повтора [, { #выражение | 'строка' | "строка" } ]...

Список байт, как для DEFB, но весь список значений генерируется #счетчик_повтора раз.
То же самое, что DUP #счетчик_повтора DEFB список EDUP

Если указан только #счетчик_повтора без значений, #счетчик_повтора раз компилируется 0.

DEFG ssssssss [ ssssssss ]...

Специальная (новая) директива для определения двоичных байт. s = '.' для представления 0,
любой другой символ для представления 1. Пробелы используются для разделения байт до
конца строки. Но числа также обрабатываются как байты (хотя они должны разделяться только пробелами).
Если следующая строка начинается с '.', 'x' или 'X', предполагается, что DEFG занимает несколько строк, и байты помещаются в память по столбцам. Эта директива может быть полезна для "рисования" шрифтов прямо в исходном коде, например:

DEFG ........ .X......
DEFG .XXXXX.. .X......
DEFG ......X. .XXXXX..
DEFG ..XXXXX. .X....X.
DEFG .X....X. .X....X.
DEFG ..XXXX.X .XXXXX..
DEFG ........ ........

(это компилируется в 0,40h,7Ch,40h,и т.д.)

или:

DEFG ........ .X......
.XXXXX.. .X......
......X. .XXXXX..
..XXXXX. .X....X.
.X....X. .X....X.
..XXXX.X .XXXXX..
........ ........

(в этом случае байты: 0,7Ch,2,3Eh,42h,3Dh,0,40h,и т.д., т.е. байты размещаются по столбцам).

DEFD xxxxxx [[,] xxxxxx ]...

Директива для определения упакованных шестнадцатеричных чисел. Например, DEFD 1234567890 то же самое,
что и DEFB 12h,34h,56h,78h,90h. Если элемент списка не начинается с шестнадцатеричной цифры,
он вычисляется как обычное выражение. Если запятая не используется, директива заканчивается,
когда следующий элемент не начинается с шестнадцатеричной цифры.

ENCODE #из1,#в1[,#из,#в]...

Специальная директива для кодирования символов в строках в желаемую кодировку
(например, русские или другие национальные символы во многих случаях лучше кодировать,
используя значения ниже 80h или переназначая большинство из них на похожие латинские буквы).
Кодировка, заданная директивой ENCODE, действует до тех пор, пока не будет переназначена следующей директивой ENCODE.
#изN и #вN могут быть любыми выражениями, обрабатываемыми как байтовые значения.

CTEXT текст
текст
...
текст
ENDTEXT

Специальная директива для кодирования текста в компактной форме. Замыкающие символы
в каждой строке сохраняются с установленным 7-м битом. Конечный маркер ENDTEXT должен
начинаться в первой колонке строки.

метка[:] STRUCT
[метка1[:]] {DEFB|DEFW|имя_структуры} [(#счетчик_повтора)[?]]
...
[меткаN[:]] {ESTRUCT|ENDSTRUCT}

Создает ряд констант метка.метка1, метка.метка2, …, которые позже могут
использоваться как обычные константы в любых выражениях. метка1 устанавливается в значение 0, а последующие
метки зависят от размера предыдущих определенных полей. Также специальная функция sizeof(метка)
становится доступной в выражениях для каждой определенной структуры. Также возможно
использовать метка1, метка2 и т.д. как самостоятельные имена.

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

FILE путь_к_файлу[,начало[,длина]]

путь_к_файлу - это путь к двоичному файлу для помещения его в память (может быть заключен в двойные кавычки ("путькфайлу")). Двоичный файл (или указанная длина) не может превышать 65536 байт, и он помещается как есть, байт за байтом. путь_к_файлу также может быть списком каталогов; в таком случае они добавляются в список путей поиска, где ассемблер ищет файлы для включения.

INCLUDE путь_к_файлу

путь_к_файлу - это путь к текстовому файлу для включения его как части исходного кода. путь_к_файлу может быть заключен в двойные кавычки ("путькфайлу"). путь_к_файлу также может быть списком каталогов; в таком случае они добавляются в список путей поиска, где ассемблер ищет файлы для включения.

метка[:] MACRO список_параметров
...
[метка2[:]] {ENDM|ENDMACRO|EMAC}

Определяет макрос. список_параметров может содержать:

  • во-первых, список фиксированных параметров (должны передаваться в том же порядке);
  • во-вторых, параметры в форме имя=[значение_по_умолчанию].
    Для именованных параметров они могут передаваться при вызове макроса в любом порядке,
    но всегда в форме имя=значение. Именованные параметры, имеющие значение по умолчанию,
    можно опускать при вызове макроса. Формальные параметры могут быть любыми разрешенными идентификаторами,
    передаваемые значения могут быть либо выражениями, либо строками в одинарных или двойных кавычках (для случая двойных кавычек содержимое в кавычках передается без кавычек). Заголовок MACRO и директивы ENDM|ENDMACRO|EMAC должны быть единственными операторами в строке исходного кода. Макрос должен быть определен в исходном коде до любого вызова его. Определение макроса может находиться в любом месте исходного кода, даже ниже мест, где он используется, и видимо всегда, даже если находится в необработанной условной ветке. Не пересекайте уровень макроса с другими уровнями директив предпроцессора. (Напр. mmm MACRO ... IF expr ENDM EIF - неверно!)

Любые метки, определенные в MACRO, должны быть локальными (иначе возможны проблемы при использовании макроса более одного раза).

Об использовании параметров макроса, идентификаторов, определенных с DEFINE, или переменной цикла предпроцессора FOR см. ниже.

ERROR [#серьезность],'текст'[,#проходы]
или
ERROR [#серьезность],"текст"[,#проходы]

Генерирует пользовательскую ошибку. Может использоваться, например, в макросе для указания на неверные переданные параметры.
серьезность: 0 - предупреждение (сообщение отображается, но не влияет на компиляцию); 1 - обычная ошибка (код больше не будет генерироваться, но компилятор не останавливается немедленно); 2 или выше - фатальная ошибка, компилятор немедленно останавливается с отображением текста. Если #проходы не определено, сообщение отображается на всех проходах компилятора. В противном случае проходы выражаются и используются как маска: бит 0 установлен, если показывать на проходе 1, бит 1 - на проходе 2, бит 2 - на проходе 3. Так, если проходы = 2, сообщение отображается только на проходе 1; если проходы = 6 - на проходах 2 и 3.

DISPLAY 'текст'[,#выр[,#проходы]]
или
DISPLAY "текст"[,#выр[,#проходы]]
или
DISPLAY #выр[,#проходы]
или
DISPLAY "текст",#выр[,"текст"[,#выр]]...[,#проходы]

Отображает текст со значением #выр (если присутствует), конкатенированным (в десятичном и шестнадцатеричном виде). Как и для ERROR, #проходы (если присутствует) определяет маску флагов, указывающую компилятору, на каких проходах отображать текст. Можно определить несколько пар текст/значение для отображения в одной строке.

метка[:] PROC
...
[метка2[:]] {ENDP|ENDPROC|EPROC}

Определяет процедуру. Фактически это используется для ограничения видимости меток, определенных внутри определения PROC, для остальной части исходного кода: все такие метки (включая метка2) становятся локальными и известны только внутри самой процедуры. Процедуры могут быть вложенными, без ограничений на уровень вложенности.

DUP #выр
...
{EDUP|ENDDUP}

Дублирует все инструкции, определенные между директивами DUP и EDUP, #выр раз (но если #выр <= 0, все инструкции пропускаются и не генерируют код, занимая 0 байт кода, и в таком случае все директивы там также не влияют на код, хотя могут проверяться на корректность).

FOR переменная=список_значений
...
{EFOR|ENDFOR}

Дублирует все инструкции, определенные между директивами FOR и EFOR, для каждого указанного значения, присваивая это значение переменной переменная на каждом шаге, как если бы это было сделано с помощью директивы метка DEFINE текст. Список значений может содержать любые выражения, строки в двойных или одинарных кавычках (при присваивании строки в двойных кавычках присваивается только сама строка без кавычек), а также диапазон в форме #от ДО #до [ШАГ #шаг]. Инструкция FOR должна быть последней в строке. Список значений может быть продолжен на следующих строках (для продолжения списка завершите его запятой в конце).

Об использовании параметров макроса, идентификаторов, определенных с DEFINE, или переменной цикла предпроцессора FOR см. ниже.

IF #выр [THEN]
...
[ELSEIF #выр1 [THEN]
...]...
[ELSE
...]
{EIF|ENDIF}

Условная компиляция, зависящая от результатов вычисления #выр, #выр1, … Если любое #вырK не равно 0, компилируется соответствующая часть кода, а остальные пропускаются.

IFcond [THEN]
...
[ELSE
...]
{EIF|ENDIF}

cond - одно из условий Z80 (Z, NZ, C, NC, PO, PE, P, M). Это скорее псевдо-инструкция, а не просто макрос. Она генерирует код для перехода к ветке ELSE (или EIF, если ELSE не определена), если условие cond не выполняется, и если определена ELSE, также генерируется переход к EIF в конце ветки THEN. По возможности используются короткие переходы. В случае, если BREAK или CONTINUE являются единственной инструкцией в ветке THEN, код оптимизируется для использования одной инструкции перехода.

LONGIFcond [THEN]
...
[LONGELSE
...]
{EIF|ENDIF}

То же, что и IFcond, но всегда используются длинные переходы (JP). LONGELSE может использоваться с IFcond и LONGIFcond с обычным ELSE, и то, что используется (ELSE или LONGELSE), влияет только на переход в конце ветки "THEN" к концу ветки "ELSE".

[метка[:]] WHILE
...
{EWHILE|EWHILEB|EWHILENZ|EWHILEZ|EWHILENC|EWHILEC|EWHILEPO|EWHILEPE|EWHILEP|EWHILEM}

(в ранних версиях это называлось LOOP...ELOOP|ELOOPB; если хотите, вы можете объявить LOOP DEFINE WHILE, ELOOP DEFINE EWHILE, ELOOPB DEFINE EWHILEB - для обеспечения работы старого кода)

Генерирует код для бесконечного цикла (случай EWHILE), обычного DJNZ (случай ELOOPB) или для условного цикла (EWHILEcond).
Если DJNZ не может быть использован (ELOOPB) из-за большого расстояния перехода, используются почти эквивалентные инструкции: DEC B:JP NZ,loop (4 байта). В любом месте цикла операторы BREAK [метка] или CONTINUE [метка] могут использоваться для выхода из цикла или продолжения цикла.
Использование метки в операторах BREAK и CONTINUE позволяет выполнить переход наружу из вложенного цикла LOOP.

BREAK [метка]

См. директиву WHILE выше.

CONTINUE [метка]

См. директиву WHILE выше.

GOTO [условие,][метка]

Это эквивалент инструкции JR/JP, но компилятор решает, использовать ли короткий переход или расстояние слишком велико (или условие не подходит для короткого перехода). Важное ограничение здесь: любое выражение не может использоваться в качестве операнда, только метка, локальная или глобальная.

PUSH rp1[,rp2]...
или
PUSH rp1 [rp2]...

Генерирует последовательность PUSH rp1:PUSH rp2:... для всех перечисленных имен пар регистров (допускаются AF, BC, DE, HL, IX, IY).

POP rp1[[,]rp2]...
или
POP rp1 [rp2]...

Генерирует последовательность ...:POP rp2:POP rp1 (пары регистров по умолчанию извлекаются в обратном порядке. Используйте директивы POPNOINVERT и POPINVERT для управления этим порядком для данной директивы POP.

POPNOINVERT

См. директиву POP выше.

POPINVERT

См. директиву POP выше.

END

Завершает код. Любой код после этой директивы компилироваться не будет.

Использование параметров макросов (в самом макросе), имен, определенных директивой DEFINE, или переменной цикла предпроцессора FOR.

  • В любом месте области видимости такой идентификатор заменяется на (строковое) значение, присвоенное ему, т.е. он подставляется в каждой строке со своим значением (даже в строке в кавычках). Область видимости зависит от подставляемого идентификатора: для параметра макроса он видим в теле макроса при вызове макроса, для переменной FOR - до EFOR / ENDFOR, а для имени, определенного директивой DEFINE, - от определения до конца исходного кода.
  • Чтобы разрешить конкатенацию значения с другими символами, используйте .имя или имя. или .имя. - при подстановке имени со своим значением соседние точки будут удалены. Чтобы закодировать саму точку '.', используйте две точки подряд, например: имя..xxxx.
  • Чтобы разрешить извлечение только части значения, используйте следующую форму: "имя"[ nnn ] или "имя"[ nnn, LLL ], где nnn и LLL - десятичные положительные числа. nnn=1 означает первый символ, LLL можно использовать для определения длины извлекаемой подстроки (если > 1). Важно: символ '[' должен следовать непосредственно за закрывающей кавычкой '"' без пробелов.
  • Также возможно использовать такие значения в операциях сравнения в любом месте выражения в форме: "имя1" op "имя2" или "имя1" op строка (где op может быть одной из операций сравнения: =, <>, <, <=, >, >=). Например: IF "RP" = DE THEN ...
Мы используем cookie-файлы для наилучшего представления нашего сайта. Продолжая использовать этот сайт, вы соглашаетесь с использованием cookie-файлов.
Принять