Add f32a
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
- 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` - остаток от деления.
|
||||
Reference in New Issue
Block a user