Язык ассемблера 16-битного процессора. Справочник

Документ описывает входной язык ассемблера для процессора по спецификации cpu16_spec_r6 (ревизия 6) и служит нормативным описанием для реализации ассемблера. Слова «должен», «запрещено», «ошибка» нормативные. Остальное пояснения и примеры.

Нумерация разделов «Спецификация, разд. N» ссылается на документ архитектуры.

1. Структура исходного файла

Файл состоит из строк. Каждая строка имеет вид:

[метка:] [команда или директива] [; комментарий]
        .org    0          ; директива
start:  LD      SP, #$FF00 ; метка, команда, комментарий
loop:                      ; метка отдельно
        JMP     loop

Регистр символов

Что Различается ли регистр
мнемоники, имена регистров, директивы, lo, hi нет (ld, LD, Ld одно и то же)
метки и символы .equ да (Loop и loop разные символы)

2. Лексика

Идентификаторы

Числа

Запись Основание Примеры
123 десятичное 0, 65535
$FF, 0xFF шестнадцатеричное $FF00, 0x1234
%1010, 0b1010 двоичное %1111_0000 недопустимо, подчёркиваний нет
'A' код символа 'a', '\n', '\''

Правило для $: если сразу за $ идёт шестнадцатеричная цифра, это число. Иначе $ обозначает счётчик адреса (разд. 3). % в начале операнда или после оператора начинает двоичное число. Оператора остатка от деления нет.

Строки и символы

msg:    .asciz  "Привет, ёлка! ╔═╗"     ; кириллица и рамки - в кодировке машины
        .byte   'Ж', '\xD0'             ; $C6 и байт $D0 напрямую

3. Выражения

Выражение вычисляется в знаковой целочисленной арифметике не уже 32 бит. Допустимы числа, символы, метки, $ и вызовы функций.

Приоритет (высший сверху) Операторы
1 унарные +, -, ~
2 *, / (деление с отбрасыванием дробной части к нулю)
3 +, -
4 <<, >> (арифметический сдвиг вправо)
5 &
6 ^
7 |

Приведение к приёмнику

Итоговое значение должно помещаться в приёмник, иначе ошибка. Отрицательные значения записываются в дополнительном коде.

Приёмник Допустимый диапазон
слово (.word, disp, длинная константа) −32768..65535
байт (.byte) −128..255
короткая константа (4 бита) 0..15
короткий условный переход (JR) −64..+63 слова
короткий CALL −8..+7 слов

4. Символы и метки

        .equ    CONSOLE, $FF20
        .equ    IF_BIT, $08

start:  LD      R0, #1
@wait:  SUB     R0, #1
        JNZ     @wait        ; локальная метка внутри start
other:  JMP     @wait        ; ошибка: в этой области @wait не определена

5. Регистры

Имя Номер Примечание
R0..R11 0..11 общего назначения
R12, LR 12 регистр связи
R13, SP 13 указатель стека
R14, IP 14 указатель команд
R15, FLAGS 15 регистр флагов

Имена-синонимы полностью равноправны: SP и R13 дают одну и ту же кодировку.

6. Операнды и режимы адресации

Слово команды: OPCODE:5 R1:4 R2:4 R2MOD:3 (старший бит слева). Операнд-источник («второй операнд») определяет поля R2 и R2MOD и, возможно, второе слово disp.

Синтаксис MOD R2 Второе слово Смысл
Rn 0 n нет значение регистра
#выр (0..15) 1 значение нет короткая константа
#выр (иначе) 3 14 (IP) значение длинная константа
[Rn] 2 n нет слово/байт по адресу Rn
[Rn++] 3 n нет то же, затем Rn += шаг
[--Rn] 4 n нет Rn −= шаг, затем обращение
[выр] 5 0 адрес абсолютный адрес
[Rn+выр], [Rn-выр] 6 n смещение регистр плюс смещение
Rn+выр, Rn-выр 7 n смещение сумма без обращения к памяти

Правила:

Выбор формы #выр

Для команд LD, MOV, ADD, ADC, SUB, SBC, AND, OR, XOR, CMP, TEST:

Решение принимается ассемблером по правилам разд. 10. Для остальных команд форма фиксирована, см. ниже.

7. Команды

Общее правило порядка операндов: в команде ОП Ra, B первый операнд занимает поле R1, второй поле R2/MOD (+ второе слово). Исключение составляют команды записи и обмена со словом ST, STB, XCHB: там первым пишется адрес в памяти, вторым регистр, причём регистр попадает в R1 (как и в псевдокоманде PUSH).

7.1. Загрузка, выгрузка, обмен

Запись Действие
LD Rd, src Rd = слово операнда
LDZX Rd, src Rd = байт операнда, расширенный нулём
LDSX Rd, src Rd = байт операнда, расширенный знаком
ST [mem], Rs слово Rs в память
STB [mem], Rs младший байт Rs в память
XCHB [mem], Rs атомарный обмен: Rs = старый байт памяти (нулевое расширение), память = младший байт Rs
        LD      R1, R2           ; копия регистра
        LD      R3, #1000        ; длинная константа
        LDZX    R0, [R4++]       ; байт с постинкрементом на 1
        LDSX    R0, [R4+2]
        ST      [$0200], R1      ; слово по абсолютному адресу
        STB     [R5], R0         ; младший байт R0
        XCHB    [lock], R1       ; атомарный обмен байтом

7.2. Арифметика и логика

Запись Действие Флаги
ADD Rd, src Rd = Rd + src ZF CF SF OF
ADC Rd, src Rd = Rd + src + CF ZF CF SF OF
SUB Rd, src Rd = Rd − src ZF CF(заём) SF OF
SBC Rd, src Rd = Rd − src − CF ZF CF(заём) SF OF
AND Rd, src, OR, XOR побитовые операции ZF SF, CF=0, OF=0
CMP Ra, src как SUB, результат не пишется ZF CF SF OF
TEST Ra, src как AND, результат не пишется ZF SF, CF=0, OF=0
NEG Rd Rd = 0 − Rd ZF CF SF OF
NOT Rd Rd = ~Rd флаги не меняются
BSX Rd знаковое расширение младшего байта Rd флаги не меняются
MUL Rd, src Rd = младшее слово Rd × src ZF SF; CF = OF = 1, если старшее слово ≠ 0
MULHU Rd, src Rd = старшее слово беззнакового Rd × src ZF SF, CF=0, OF=0
DIVU Rd, src Rd = Rd / src (беззнаковое) ZF SF, CF=0; OF=1 при делении на 0
REMU Rd, src Rd = Rd mod src (беззнаковое) ZF SF, CF=0; OF=1 при делении на 0

NEG, NOT, BSX имеют один операнд и кодируются сборным опкодом MISC: операция в поле R2, поле R2MOD равно 0, команда однословная.

MUL, MULHU, DIVU, REMU - обычные команды группы АЛУ: допустимы все формы операнда, #выр выбирается короткой или длинной формой так же, как у ADD. Деление на 0 исключения не вызывает: DIVU даёт $FFFF, REMU оставляет делимое, OF = 1 (проверка - JO). Знаковых вариантов нет, они выполняются программно.

        ADD     R0, R1           ; регистр
        ADD     R0, #5           ; короткая константа
        SUB     R2, [R3]         ; из памяти
        AND     R0, #$00FF       ; длинная константа
        CMP     R0, #0
        TEST    R1, R1
        NEG     R2
        MUL     R0, #10          ; умножение на константу
        DIVU    R1, [R3]         ; делитель из памяти
        JO      div_by_zero

7.3. Сдвиги

Запись Действие
SHL Rd, cnt логический сдвиг влево
SHR Rd, cnt логический сдвиг вправо
SAR Rd, cnt арифметический сдвиг вправо
ROR Rd, cnt циклический сдвиг вправо

cnt это #выр (только 0..15, всегда MOD=1) или регистр Rn (используются младшие 4 бита). Другие формы операнда допустимы по общим правилам (память, Rn+выр), но на практике не применяются.

        SHL     R0, #4
        SHR     R0, R1           ; на число из R1
        ROR     R2, #8           ; обмен байтов слова

7.4. Псевдокоманды

Псевдокоманды раскрываются в реальные команды без собственного опкода.

Запись Раскрывается в Слов
MOV Rd, src LD Rd, src как LD
LEA Rd, Rs+выр LD Rd, Rs+выр (MOD=7) 2
LEA Rd, [Rs+выр] то же 2
NOP LD R0, R0 (слово $0000) 1
RET LD IP, LR 1
PUSH Rs ST [--SP], Rs 1
POP Rd LD Rd, [SP++] 1
INC Rd ADD Rd, #1 1
DEC Rd SUB Rd, #1 1
STI OR FLAGS, #$08 (разрешить прерывания) 1
CLI AND FLAGS, #$07 (запретить прерывания) 1
STC OR FLAGS, #$02 (установить CF) 1
CLC AND FLAGS, #$0D (сбросить CF) 1
CMC XOR FLAGS, #$02 (инвертировать CF) 1

7.5. Передача управления

Целью является значение операнда (адрес). Поле R1 хранит условие (Jxx) или игнорируется (CALL).

Запись Условие Код R1
JMP всегда 0
JZ, JE ZF=1 1
JNZ, JNE ZF=0 2
JC, JB CF=1 (ниже, беззнаковое) 3
JNC, JAE CF=0 4
JA CF=0 и ZF=0 5
JBE CF=1 или ZF=1 6
JS SF=1 7
JNS SF=0 8
JO OF=1 9
JNO OF=0 10
JL SF≠OF (меньше, знаковое) 11
JGE SF=OF 12
JG ZF=0 и SF=OF 13
JLE ZF=1 или SF≠OF 14

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

Формы цели

Запись MOD Слов Смысл
выр (метка, число, выражение) авто 1 или 2 переход на адрес выр: короткая или длинная относительная форма (см. ниже)
Rn 0 1 адрес в регистре
[Rn] 2 1 адрес берётся из слова по адресу Rn
[выр] 5 2 адрес берётся из слова по адресу выр (таблица переходов)
[Rn+выр] 6 2 адрес из слова по адресу Rn+выр
Rn+выр 7 2 адрес Rn+выр (для IP+выр сырое смещение от следующей команды)
#выр 3 (R2=IP) 2 абсолютный адрес, принудительно длинная форма

Недопустимы [Rn++] и [--Rn].

Автоматический выбор для выр (цель T, $ адрес команды):

        JMP     start            ; авто
        JNZ     loop
        CALL    func
        JMP     R3               ; по регистру
        JMP     [vector]         ; косвенный через слово памяти
        CALL    #$8000           ; абсолютный адрес
        JZ      IP+6             ; сырое смещение: на 6 байт после следующей команды

7.6. Прерывания и ожидание

Запись Кодирование Слов
TRAP #n MOD=1, R2=n; n в 0..15 1
TRAP Rn MOD=0, вектор берётся из младших 4 бит Rn 1
IRET сборный опкод MISC, подкод 3; поля R1 и MOD равны 0 1
WFI сборный опкод MISC, подкод 4; поля R1 и MOD равны 0 1

Для TRAP #выр значение вне 0..15 ошибка.

        TRAP    #9               ; программный вызов, вектор 9
        WFI                      ; ждать прерывания
        IRET

8. Допустимость операндов

Ассемблер обязан с понятным сообщением отвергать все запрещённые кодировки обоих классов: зарезервированные и ограниченно непредсказуемые (Спецификация, разд. 6.2 и 6.3). Программам они запрещены, даже если конкретная реализация процессора исполняет их без прерывания. Рекомендуется использовать при проверке ту же функцию допустимости, что и в эмуляторе.

8.1. Допустимые формы по группам

Группа Rn #выр [Rn] [Rn++] [--Rn] [выр] [Rn+выр] Rn+выр
LD, MOV, ALU, CMP, TEST, MUL, MULHU, DIVU, REMU, сдвиги да да да да да да да да
LDZX, LDSX да 0..15 да да* да* да да нет
ST, STB, XCHB нет нет да** да* да* да да нет
Jxx, CALL (цель) да да (абс.) да нет нет да да да
TRAP да 0..15 нет нет нет нет нет нет

* для байтовых команд (LDZX, LDSX, STB, XCHB) запрещено при Rn = SP или IP; для ST запрещено при Rn = IP. ** [IP] запрещено для ST, STB, XCHB.

Для сдвигов #выр только 0..15 (MOD=1).

TRAP в языке поддерживает только формы #n и Rn. Остальные формы операнда, которые процессор для TRAP допускает (Спецификация, разд. 6.1), в языке не предусмотрены как практически бесполезные.

8.2. Дополнительные запреты

Нарушение каждого пункта ошибка ассемблирования (на процессоре это зарезервированная или ограниченно непредсказуемая кодировка):

  1. Rn = FLAGS допустим только в форме Rn (MOD=0). В формах [Rn], [Rn++], [--Rn], [Rn+выр], Rn+выр недопустим (Спецификация, 6.3 п. 1).
  2. [--IP] недопустим (6.3 п. 2).
  3. Длинный #выр (непосредственное значение через IP) допустим только для LD, MOV, ALU, CMP, TEST, Jxx, CALL. Для сдвигов, LDZX, LDSX и TRAP #выр бывает только короткой константой 0..15; у ST, STB, XCHB непосредственного операнда нет (6.2 п. 3, 6.3 п. 3).
  4. [IP] недопустим для ST, STB, XCHB (6.3 п. 4).
  5. Байтовые команды с [Rn++] и [--Rn] при Rn = SP или IP недопустимы (6.3 п. 5).
  6. Переходы (Jxx, CALL) с целью [Rn++] или [--Rn] недопустимы (6.2 п. 3, 6.3 п. 6).
  7. Jxx и JR с кодом условия 15 в языке отсутствуют: такой мнемоники нет (6.2 п. 2).
  8. Для любой команды не допускается лишний операнд или нехватка операндов.
  9. Поля, которые команда не использует, ассемблер всегда кодирует нулями (Спецификация, разд. 3 и 6.2 п. 4): MOD у NEG, NOT, BSX, IRET, WFI (у них поле R2 - подкод сборного опкода MISC); R1 у IRET, WFI, CALL, TRAP; R2 при MOD=5. Мнемоники MISC в языке нет. Синтаксиса, позволяющего задать в них другие значения, нет.

9. Директивы

Имя директивы начинается с ., регистр не важен.

Директива Действие
.org выр установить счётчик адреса. Выражение 0..65535, не должно зависеть от меток
.word в1, в2, ... (.dw) слова, little-endian; перед первым словом адрес автоматически выравнивается на границу слова; каждое значение −32768..65535
.byte в1, в2, ... (.db) байты; каждое значение −128..255
.ascii "стр", ... байты строк (в кодировке машины) без завершающего нуля
.asciz "стр", ... то же, после каждой строки добавляется байт 0
.space n [, fill] n байт значения fill (по умолчанию 0); n не зависит от меток
.align n [, fill] явное выравнивание: добавить байты fill (по умолчанию 0) до адреса, кратного n; n ≥ 1, не зависит от меток
.equ имя, выр определить константу
.include "файл" вставить файл; путь относительно каталога включающего файла; глубина вложенности не более 16
        .org    $0000
        .byte   1, 2, 3         ; адреса 0, 1, 2; счётчик теперь 3 (нечётный)
tbl:    .word   $1234, tbl      ; байт заполнения по адресу 3, tbl = 4
msg:    .asciz  "Hi\n"          ; 4 байта (адреса 8..11), без выравнивания
buf:    .space  15              ; адреса 12..26, счётчик 27 (нечётный)
        NOP                     ; байт заполнения по адресу 27, NOP по адресу 28

10. Размер команд и подбор форм (нормативно)

Длина команды:

2 слова, если MOD ∈ {5, 6, 7} или (MOD = 3 и R2 = IP); иначе 1 слово.

Размер зависит от значений выражений только у двух групп:

  1. #выр в LD, MOV, ALU, CMP, TEST: короткая (1 слово) или длинная (2 слова).
  2. Цель-выражение у Jxx (JR или длинная относительная форма) и у CALL (MOD=1 или длинная относительная форма).

Остальное (сдвиги с #, LDZX, LDSX, TRAP, все регистровые и скобочные формы) имеет фиксированный размер, определяемый только синтаксисом.

Алгоритм

  1. Разобрать файл в список элементов. Вычислить размеры фиксированных элементов.
  2. Присвоить каждому элементу переменного размера состояние КОРОТКО.
  3. Цикл:
    1. Вычислить адреса всех элементов и значения меток исходя из текущих состояний.
    2. Для каждого элемента в состоянии КОРОТКО проверить, умещается ли он при текущих значениях (константа 0..15; для Jxx смещение в −64..+63 слова, для CALL в −8..+7 слов; цель чётна). Если нет, перевести элемент в состояние ДЛИННО.
    3. Если хотя бы один элемент изменил состояние, повторить цикл.
  4. Выполнить финальный проход: закодировать все элементы, проверить диапазоны (разд. 3), допустимость (разд. 8) и перекрытия.

Состояние ДЛИННО необратимо (переход обратно в КОРОТКО запрещён). Поэтому цикл завершается не более чем за N+1 итераций (N число элементов переменного размера). Результат детерминирован. Неопределённый символ ошибка, обнаруживаемая в финальном проходе.

Аргументы .org, .space, .align вычисляются один раз до цикла (они не зависят от меток). Значения .equ, зависящие от меток, пересчитываются на каждой итерации.

Байты неявного выравнивания и заполнение .align определяются текущим счётчиком адреса, поэтому пересчитываются на каждой итерации при вычислении адресов (шаг 3.1). На завершение цикла это не влияет: оно обеспечивается необратимостью перехода КОРОТКО → ДЛИННО.

11. Результат ассемблирования

Образ памяти это набор байтов с адресами 0..65535.

Выход Описание
двоичный образ (-o) плоский файл от адреса base (по умолчанию 0) до наибольшего выведенного адреса включительно; пропуски заполняются нулями (--fill, по умолчанию 0)
листинг (-l, необязательно) построчно: адрес, выведенные слова/байты, исходная строка
карта символов (-m, необязательно) список меток и констант с адресами/значениями

Пример листинга:

0000  0000 0000          start:  LD      SP, #$FF00      ; (пример формата)

12. Диагностика

Формат: файл:строка: error: сообщение. Ассемблер должен сообщить обо всех найденных ошибках (не только о первой) и вернуть ненулевой код возврата, если хотя бы одна есть.

Категория Пример сообщения
синтаксис неизвестная мнемоника 'LDD', ожидалась запятая, незакрытая скобка, неверный синтаксис операнда
операнды неверное число операндов, форма [R3++] недопустима для STB при SP/IP
символы неопределённый символ 'foo', повторное определение 'foo', циклическое определение 'X'
диапазоны значение 300 не помещается в байт, константа сдвига должна быть 0..15
выравнивание цель перехода нечётна (например, JMP 101 или переход на метку перед .byte)
образ перекрытие вывода по адресу $0200, выход за пределы 64 КБ
директивы .org зависит от метки
вычисления деление на нуль

13. Короткие примеры

13.1. Вывод строки (порт консоли $FF20, см. 13.12)

        .equ    CONSOLE, $FF20
        .org    0
start:  LD      SP, #$FF00
        LD      R0, #msg
@next:  LDZX    R1, [R0++]
        CMP     R1, #0
        JZ      @done
        STB     [CONSOLE], R1
        JMP     @next
@done:  WFI
msg:    .asciz  "Hello!\n"

13.2. Сумма массива

        LD      R0, #table       ; указатель
        LD      R1, #5           ; счётчик
        LD      R2, #0           ; сумма
loop:   ADD     R2, [R0++]       ; сумма += *p++ (шаг 2)
        DEC     R1
        JNZ     loop
        WFI
table:  .word   10, 20, 30, 40, 50

13.3. Подпрограммы и сохранение LR

        LD      SP, #$FF00
        LD      R0, #7
        CALL    twice_plus_one
        WFI

twice_plus_one:
        PUSH    LR               ; вложенный вызов: сохранить LR
        ADD     R0, R0
        CALL    inc_r0
        POP     LR
        RET

inc_r0: INC     R0
        RET                      ; листовая подпрограмма: LR не сохраняем

13.4. 32-битное сложение

        ; R1:R0 += R3:R2
        ADD     R0, R2
        ADC     R1, R3

13.5. Беззнаковые и знаковые сравнения

        CMP     R0, R1
        JB      below            ; R0 < R1 как беззнаковые
        JL      less             ; R0 < R1 как знаковые
        JAE     above_or_equal   ; беззнаковое >=
        JGE     greater_or_equal ; знаковое >=

13.6. Копирование строки байтами

; R0 = источник, R1 = приёмник
copy:   LDZX    R2, [R0++]
        STB     [R1++], R2
        CMP     R2, #0
        JNZ     copy
        RET

13.7. Таблица переходов

        ; R0 = индекс 0..2
        ADD     R0, R0           ; индекс * 2
        JMP     [R0+table]       ; адрес берётся из слова table[R0]
table:  .word   case0, case1, case2

13.8. Спинлок на XCHB

acquire:
        LD      R1, #1
@try:   XCHB    [lock], R1       ; R1 = старое значение, lock = 1
        CMP     R1, #0
        JNZ     @try
        RET

release:
        LD      R1, #0
        STB     [lock], R1
        RET

lock:   .byte   0

13.9. Сдвиги и константы флагов

        .equ    IF, $08
        SHL     R0, #4
        ROR     R2, #8           ; обмен байтов
        OR      FLAGS, #IF       ; то же, что STI (1 слово)
        AND     FLAGS, #$0F & ~IF ; то же, что CLI: 1 слово, побочно OF=0
        AND     FLAGS, #~IF      ; CLI без побочного эффекта: ~$08 = $FFF7, 2 слова

        PUSH    FLAGS            ; критическая секция: сохранить IF и OF
        CLI
        ; ...
        POP     FLAGS            ; восстановить всё, включая OF

13.10. Прерывания: векторы и обработчик

        .org    0
        LD      SP, #$FF00
        STI
idle:   WFI
        JMP     idle

irq0:   PUSH    R0               ; обработчик обязан сам сохранить регистры
        LD      R0, [ticks]
        INC     R0
        ST      [ticks], R0
        POP     R0
        IRET                     ; восстанавливает флаги и IP
ticks:  .word   0
svc:    IRET                     ; обработчик программного вызова TRAP #9

        .org    $FF00            ; таблица векторов: 16 слов
        .word   irq0, 0, 0, 0, 0, 0, 0, 0     ; векторы 0..7: внешние IRQ
        .word   0, svc, 0, 0, 0, 0, 0, 0      ; вектор 8 ERRCMD, 9..15 программные

13.11. Относительная адресация (не зависит от места загрузки)

        LEA     R0, IP+(msg-$-4) ; R0 = адрес msg; $ адрес этой команды, +4 длина
        LD      R1, [IP+(val-$-4)]
        WFI
msg:    .asciz  "xy"             ; 3 байта: счётчик становится нечётным
val:    .word   $BEEF            ; выровнено автоматически, val чётный

13.12. Ввод с консоли

Порт консоли $FF20 (соглашение эмулятора и отладчика, не часть архитектуры процессора):

В эмуляторе cpu16 ввод берётся из stdin (./cpu16 prog.bin < input.txt), в браузерном отладчике — из панели консоли.

; эхо: копирует ввод в вывод до точки
loop:   LDZX    R1, [$FF20]      ; байт ввода или 0
        CMP     R1, #0
        JZ      loop             ; ввода пока нет
        STB     [$FF20], R1
        CMP     R1, #'.'
        JNZ     loop
        WFI

13.13. Печать числа в десятичном виде

        .equ    CONSOLE, $FF20
        .org    0
        LD      SP, #$FF00
        LD      R0, #40000
        CALL    print_dec        ; печатает 40000
        LD      R1, #10
        STB     [CONSOLE], R1
        WFI

; R0 - число без знака; R0, R1 и R2 портятся
print_dec:
        LD      R2, #0           ; счётчик цифр в стеке
@div:   LD      R1, R0
        REMU    R1, #10          ; очередная цифра (младшая)
        DIVU    R0, #10
        ADD     R1, #'0'
        PUSH    R1
        INC     R2
        CMP     R0, #0
        JNZ     @div
@out:   POP     R1               ; цифры из стека - от старшей к младшей
        STB     [CONSOLE], R1
        DEC     R2
        JNZ     @out
        RET

14. Примеры кодирования

Эти слова могут использоваться как контрольные значения при тестировании. d второе слово команды.

Запись Слова
NOP (LD R0, R0) 0000
LD R1, R2 0090
LD R3, #5 01A9
LD R3, #$1234 01F3, 1234
ADD R0, [R1++] 400B
ST [R2+4], R0 2016, 0004
STB [$FF20], R1 2885, FF20
XCHB [lock], R1 1885, lock
PUSH R0 206C
POP R0 006B
RET 0760
SHL R0, #4 9021
ROR R2, #8 A941
NEG R2 B100
JMP вперёд на 3 слова (JR) 3003
JNZ назад на 2 слова (JR) 317E
CALL вперёд на 3 слова (короткая) D019
JZ длинная относительная C8F7, disp
JMP #addr (абсолютная) C873, addr
JMP [R0+tbl] C806, tbl
CALL длинная относительная D077, disp
LEA R0, IP+d 0077, d
STI (OR FLAGS, #$08) 6FC1
CLI (AND FLAGS, #$07) 67B9
AND FLAGS, #$FFF7 (CLI без побочного эффекта) 67F3, FFF7
STC (OR FLAGS, #$02) 6F91
CLC (AND FLAGS, #$0D) 67E9
CMC (XOR FLAGS, #$02) 7791
TEST FLAGS, #$08 8FC1
TRAP #9 D849
IRET B018
WFI B020
NOT R1 B088
BSX R3 B190
MUL R0, R1 E008
MULHU R2, #5 E929
DIVU R3, #1000 F1F3, 03E8
REMU R4, [R5+2] FA2E, 0002

Опкоды (старшие 5 бит слова):

Код Мнемоника Код Мнемоника
0 LD 16 CMP
1 LDZX 17 TEST
2 LDSX 18 SHL
3 XCHB 19 SHR
4 ST 20 SAR
5 STB 21 ROR
6 JR
8 ADD 22 MISC: NEG, NOT, BSX, IRET, WFI (подкод в R2)
9 ADC 23 —
10 SUB 24 —
11 SBC 25 Jxx
12 AND 26 CALL
13 OR 27 TRAP
14 XOR 28 MUL
29 MULHU
30 DIVU
31 REMU

15. Формальная грамматика (EBNF)

file        = { line } ;
line        = [ label ] [ statement ] [ comment ] newline ;
label       = ( ident | local ) ":" ;
local       = "@" ident ;
comment     = ";" { any char } ;
statement   = instruction | directive ;

instruction = mnemonic [ operand { "," operand } ] ;
operand     = reg
            | "#" expr
            | "[" memref "]"
            | reg ( "+" | "-" ) expr
            | expr ;                      (* голое выражение только у Jxx и CALL *)
memref      = reg [ "++" ]
            | "--" reg
            | reg ( "+" | "-" ) expr
            | expr ;

directive   = "." dname [ dargs ] ;
dargs       = expr { "," expr }                        (* .word, .byte, .org, .space, .align *)
            | string { "," string }                    (* .ascii, .asciz *)
            | ident "," expr                           (* .equ *)
            | string ;                                 (* .include *)

expr        = term { ( "|" | "^" | "&" | "<<" | ">>" | "+" | "-" ) term } ;   (* с приоритетами разд. 3 *)
term        = unary { ( "*" | "/" ) unary } ;
unary       = [ "+" | "-" | "~" ] primary ;
primary     = number | char | ident | local | "$" | "(" expr ")" | ( "lo" | "hi" ) "(" expr ")" ;

reg         = "R0".."R15" | "LR" | "SP" | "IP" | "FLAGS" ;

16. Что не входит в версию 1

Макросы, условная ассемблация, секции и компоновка объектных файлов, форматы вывода кроме плоского образа (Intel HEX можно добавить позже), предупреждения (все нарушения ошибки), символы в регистровой записи вида R+R.