Теперь будет большой пост про разработку и оптимизацию моей 4-битной архитектуры. Вот спойлер к тому, что уже удалось запустить на моей архитектуре через эмулятор. А в следующем посте будет змейка)

В моем компьютере будет 3 регистра: 4-битный X – основной регистр: в нем будут инструкции для арифметики, данные из оперативы будут подгружаться в него и другие небольшие операции. Второй 4-битный регистр T – счетчик в циклах и на нем проверка в условных прыжках. И наконец 16-битный MAR (Memory Address Register) – регистр адреса памяти, который в том числе позволяет мне делать длинные вычисления (об этом чуть позже).
Immediate operands
Создание набора инструкций – интересная задача: выбрать оптимальный базис из 16 инструкций, на котором я смогу писать все нужные алгоритмы и делать это достаточно удобно. Первое улучшение качества жизни – добавление констант в код. Допустим, я хочу написать X = 5 в коде, чтобы потом сделать какую-то операцию. Для этого я могу хранить сначала один ниббл самой инструкции SET, а потом уже ее параметр: 5 в следующем ниббле. В архитектуре X86 так и работает (immediate operands). Такая модификация очень сильно упрощает написание кода. Например, теперь можно делать прыжки на конкретные строки, а не только относительные. То есть цикл на моей архитктуре будет выглядеть вот так:
MARK LOOP // Сохранение номера строчки на который прыгать под названием LOOP
// Логика цикла
INC // T += 1
TJMP LOOP // If (T != 0) JMP LOOP
А еще, так как оперативную память найти на 4 бита очень трудно, то у меня будут 8 битные RAM и ROM. Это на самом деле очень приятно, так как это значит, что инструкция и ее параметр будут занимать одну ячейку памяти. Это сильно упростит устройство компьютера.
Работа с RAM/ROM/матрицей
У моего компьютера будет Гарвардская архитектура, то есть отдельно ROM для программы и каких-то нужных файлов и отдельно RAM для промежуточных вычислений и переменных. Плюс ROM — данные в нём не теряются при потере питания, а плюс RAM — высокая скорость доступа.. В мою архитектуру нужно было добавить инструкции для работы с обоими. А еще есть матрица и кнопки для ввода/вывода информации, для которых я тоже изначально думал сделать свои инструкции. Но тут я немного подсмотрел архитектуры у других компьютеров: Вместо того, чтобы поддерживать инструкции для RAM, ROM и матрицы, можно работать с ними как с одной сущностью. Например, часто бывает индекс памяти MAR (Memory Address Register) – 16 бит, но при этом сами чипы памяти – 15 бит. Это сделано, чтобы первый бит в MAR отвечал за то – это будет RAM или ROM. Тем самым получается нужно поддерживать только один набор инструкции для работы с обоими типами памяти. У меня еще добавляется матрица и генератор псевдо-рандомных чисел. Поэтому первые 2 бита MAR отвечают за тип обращения, а оставшиеся 14 – за сам адрес.
Длинная арифметика
Так, как у меня всего 16 чисел в регистрах, то сразу возникла пробема длинной арифметики: если мне не хватает регистров, чтобы проитерироваться по моей матрице 16×16, то как вообще мне с ней работать? Изначально я думал сделать матрице свой небольшой контроллер, который бы делал flush пикселя и сдвигал текущий пиксель на следующий. Тем самым можно было бы все обновлять. Но это не сильно удобнее и требует свой контроллер для матрицы.
Поэтому я сделал MAR 16-битным регистром с поддержкой своих простых операций сложения и вычитания – то есть длинная арифметика. Поскольку по нему нужно лишь последовательно передвигаться по нему, то мне достаточно только эти 2 операции. Кроме того, я переоформил их как прибавление 1 к конкретному биту MAR (то есть +/- 2^d). А чтобы прочитать этот регистр в мой 4-битный X есть команда, которая принимает какой ниббл MAR я хочу прочитать и записать в X. Тем самым, чтобы вывести пиксель в матрицу мне достаточно записать значение в MAR, где первые 2 бита отвечают за матрицу, а последние 8 – кодируют конкретный пиксель. Очень удобно и просто реализовать.
И если вы считаете, что я считерил сделав MAR 16 битным в своем 4-битном компьютере, то взгляните например на микропроцессор 6502: в нем регистры 8 бит, но для работы с памятью тоже выделено 16 бит)
Instruction set
Вот как выглядит моя архитектура в текущий момент:
| Category | Command | Description | Comments |
|---|---|---|---|
| Misc | NOP | Do nothing for one cycle | |
| Misc | SET k | X = k | Set constants in code |
| Misc | SWP | X, T = T, X | |
| Jumps | JMP k | PC = k | Unconditional jump |
| Jumps | TJMP k | if (T == 0) PC += 2 else PC = k | Conditional jump |
| Arithmetic | ADDI k | X = (X + k) mod 16 | |
| Arithmetic | INC | T = T + 1 | |
| Arithmetic | AND k | X = X & k | Bit and (if k = 0 => AND with T) |
| Arithmetic | XOR k | X = X | k | Bit xor (if k = 0 => XOR with T) |
| Arithmetic | SFT | X = X >> 1 | Bit shift right (div by 2) |
| Memory | LD | X = RAM[MAR] | |
| Memory | WT | RAM[MAR] = X | |
| Memory | SMAR d | MAR = X with shift d | |
| Memory | IMAR d | MAR = (MAR + (1 << d)) mod 16384 | Decrease MAR |
| Memory | DMAR d | MAR = (MAR – (1 << d)) mod 16384 | Increase MAR |
| Memory | GMAR d | X = (MAR >> d) & 0xF | Get the specified nibble from MAR to X |
Leave a Reply