Files
obsidian/Computer Science/Архитектуры/f32a.md
T
roma-dxunvrs fb5f9d4cf2 Add f32a
2026-09-18 13:47:58 +03:00

7.4 KiB
Raw Blame History

  • 32-битная стековая архитектура
  • Главный принцип - команды не имеют операндов в коде. Все данные неявно берутся с веришны стека, результат кладется обратно в стек.
  • Небольшая пасхалка на Evaluate Reverse Polish Notation

Регистры, флаги и стеки

  • Имеет два независимых аппаратных стека и два регистра-указателя

Стеки

  • Data Stack - место где происходят вычисления
  • T - вершина стека данных
  • S - второй элемент на стеке данных
  • Return Stack - стек возврата
  • R - вершина стека возвратов

Регистры

  • A - указатель адреса памяти с поддержкой автоинкремента
  • B - второй указатель памяти

Флаги

  • C - перенос
  • EAM - режим расширенной арифметики

[!info] Все регистры, флаги и стеки можно выводить в отчете: A:dec, stack:dec, rstack:hex, C, EAM и так далее

[!info] Получение максимальной глубины стека, которая была достигнута на конкретном шаге через: f32a:data-stack-max и f32a:return-stack-max

Система команд

  • Комментарии - \
  • Опкод - 1 байт. Если есть операнд, то еще 4 байта

1. Операции со стеком

  • dup - дублировать вершину ([X] -> [X, X])
  • drop - удалить вершину ([X, Y] -> [X])
  • over - скопировать второй элемент наверх ([X, Y] -> [X, Y, X])

2. Операции над памятью

  • <value> (или lit <value>) - положить константу на Data Stack (от слова literal)

  • a! / b! - снять значение со стека и записать в регистр A / B

  • a - скопировать значение из регистра A на стек

  • @p <addr> - прочитать из адреса на стек

  • !p <addr> - снять со стека и записать по адресу

  • @ / ! - чтение/запись по адресу, который лежит в регистре A

  • @+ / !+ - чтеение/запись по адресу в A и инкремент A

  • @b / !b - чтение/запись по адресу, который лежит в регистре B

3. Арифметика

  • + - сумма, снимает два верхних числа, складывает, кладет на вершину стека. Если в режиме EAM, то прибавляет еще и флаг переноса. Устанавливает флаг переноса в любом случае
  • +* - один шаг умножения
  • +/ - один шаг деления
  • 2* - сдвиг влево вершины стека
  • 2/ - сдвиг вправо вершины стека
  • inv - побитовая инверсия вершины стека
  • eam - снять число с Data Stack и записать его в EAM

4. Побитовые операции

  • and - побитовое И над T и S (снимает их)
  • xor - исключающее ИЛИ

5. Управление вычислительным процессом

  • ; - возврат из подпрограммы (снять адрес с Return Stack и прыгнуть)
  • <label> - вызов подпрограммы (адрес возврата кладется на Return Stack + прыжок)
  • <label> ; - прыжок (без записи адреса возврата)
  • next <label> - цикл for, проверяет вершину стека возврата R, если R != 0, уменьшает его на 1 и прыгает на метку. Если R==0, удаляет R и выходит из цикла
  • if <label> - снимает значение с Data Stack, если оно ноль, то прыжок
  • -if <label> - снимает значение с Data Stack, если оно >=0. то прыгает
  • halt - стоп

6. Взаимодействие со стеком возврата

  • r> - снять элемент с Return Stack и положить на Data Stack
  • >r - снять элемент с Data Stack и положить на Return Stack

Подробнее про умножение и деление

+*

  • Как работает умноежение чисел в двоичной системе (A*S): смотрим на каждый бит числа A, если бит 1, то прибавляем S к результату, если бит 0, то пропускаем, в конце сдвигаем результат
  • Как использует эта команда данные
    1. Регистр A - множитель
    2. S (второй элемент стека данных) - множимое
    3. T (первый элемент стека данных) - накапливается ответ, сначала 0
  • Теперь эта команда по шагам
    1. Процессор смотрит на младший бит A
    2. Если там 1, то прибавляет S к T (T = T + S). Если 0 - ничего не прибавляет
    3. Сдвигает регистр A вправо на 1 бит (A >> 1). Тот бит, который мы только что проверили выбрасывается
    4. Сдвигает результат T вправо на 1 бит (T >> 1)
    5. Сдвинутый из T бит вставляется в старший бит A (A[31])
  • После 32 повторений такой команды, в регистре A и на вершине стека T образуется 64-битное число - полный результат умножения. В A - младшая половина ответа, а в T - старшая

+/

  • Деление в двоичной системе: сдвигаем влево и пытаемся вычесть делитель. Если вычитается - пишем 1, если нет - 0
  • Как использует данные команда
    1. Регистр A - делимое
    2. Mem[B] - делитель
    3. S - старшая часть числа, здесь будет остаток
    4. T - кладем 0, здесь будет частное
  • Команда по шагам
    1. Сдвигаем остаток S влево на 1 бит
    2. Забираем старший бит из A и вставляем в младший бит S
    3. Сдвигаем A влево
    4. Сдвигаем T влево
    5. Если можно вычесть делитель (S >= Mem[B]), то ставим в младший бит ответа единицу (T[0]=1), если нельзя - бит ответа оставляем нулем
  • После 32 повторений на стеке в T будет лежать частное, в S - остаток от деления.