Надо создать элементарный процессор

Aug 11, 2024 07:15

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

Набор инструкции будет крайне простой: арифметические (ADD, SUB), логические (AND, XOR), переход (JMP), перемещение (MOV). Даже с помощью такого небольшого количества инструкции и 4 регистров (каждый будет по 8 бит), можно будет даже что-то написать. Конечно, написать можно будет мало чего, но все же, не совсем пустота на пустом месте.

Довольно важно читать и писать в память по определенным индексам. Памяти будет крайне мало, всего лишь 256 байт, при этом это будет и память кода, и память данных, они совмещены (так называемая архитектура Фон-Неймана). Данные могут быть кодом, а код -- данными. Для индексного регистра я отведу один регистр. Назову регистры так A, B, X, Y. Всего 4 регистра, которые будут суммарно занимать 32 бита (4 регистра на 8 бит каждый).

Например. Есть 3 способа копировать данные:

MOV r, r  -- из регистра в регистр
MOV [i], r -- из регистра в память
MOV r, [i] -- из памяти в регистр

Соответственно, для этого будут отдельные опкоды:

0000_ddss - MOV d, s
0001_ddss - MOV [d], s
0010_ddss - MOV d, [s]
0011_00dd - MOV d, u

Там где d, s -- это номера регистров, 00=A, 01=B, 10=X, 11=Y. То есть байт 00010111(b) будет расшифровываться как MOV [B], Y, перемещение содержимого регистра Y в память по адресу B. Там где MOV d, u это копирование из следующего за опкодом байта в регистр d.

Аналогично с арифметикой и логикой

0100_ddss ADD d, s
0101_ddss SUB d, s
0110_ddss AND d, s
0111_ddss XOR d, s

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

Помимо регистров, в процессоре есть также специальный регистр флагов, где хранятся отметки о последней выполненной операции. Например, флаг CF (Carry Flag) говорит о том, что при выполнении операции, к примеру, ADD, произошел перенос и если это случилось, что этот флаг содержит 1. Или ZF (Zero Flag) сигнализирует о том, что результат 0. Использование флагов очень удобно для сравнения чисел, например, и для условных ветвлений.

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

Условный переход, это такой, когда проверяется некоторый флаг и в зависимости о того, установлен он или нет, происходит (или не происходит) переход.

1000_00cc JMP <условие>, метка
1001_0000 JMP метка
1010_00dd JMP d

Есть 3 разных перехода. Первый переход условный. Он проверяет либо CF, либо ZF на наличие там 0 или 1. Пример:

1000_0000 JMP NC, метка  -- переход по метке (1 байт), если CF=0
1000_0001 JMP C, метка  -- переход по метке (1 байт), если CF=1
1000_0010 JMP NZ, метка  -- переход по метке (1 байт), если ZF=0
1000_0011 JMP Z, метка  -- переход по метке (1 байт), если ZF=1

Количество памяти у нас тут весьма ограничено, так что, в связи с тем что это именно учебный процессор, то мало чего тут можно сделать и переходы всего лишь в пределах 256 байт.

Что сказать про переход по косвенной метке (JMP d), то это переход на то число, которое содержит в себе регистр. К примеру, возьмем и напишем программочку:

30 52 | MOV A, $52
50      | JMP A

Это значит, что сначала в регистр А загрузится число $52 (шестнадцатеричное), а потом выполнится переход на метку $52, потому что в регистра А это число находится.

Вот собственно, и весь набор команд. Он крайне скромен, и я потом попробую что-то сделать на этом процессоре однажды. Но это не точно.

ПЛИС, Планы

Previous post Next post
Up