CPU Architecture
- Arithmetic Engine
- Registers
- Instruction Decoder
- Calculations
- Program
- Conditions
- Immediate values
- Turing Complete
Arithmetic Engine
tip
Разблокирует фабрику компонентов, что позволит создавать собственные компоненты для уровней CPU Architecture.
Arithmetic Logic Unit (ALU) Арифметико-логическое устройство
Коротко что это значит:
- Arithmetic — сложение, вычитание, инкремент, декремент
- Logic — AND, OR, XOR, NOT, сравнения
- Unit — отдельный функциональный блок процессора
Задача:
Добавить еще два варианта в схему Logic Engine:
- ADD для сложения двух восьмибитных чисел
- SUB для вычитания двух восьмибитных чисел
Для 8 комбинаций, нам хватит первых трех младших битов
V| OPCODE : -|--------------- 0| xxxxx000 OR 1| xxxxx001 NAND 2| xxxxx010 NOR 3| xxxxx011 AND 4| xxxxx100 ADD 5| xxxxx101 SUB[x x x x x D2 D1 D0 ]
Реализация ALU через NAND.

Схема созданного вами компонента определяет его функционал, а планировка определяет форму. Имеено по этой причине, нельзя было двигать красные компоненты на схеме, так как они участвуют в форме нового компонента.
Реализация ALU через OR.

Circuit Simulation ALU
Необходимые компоненты схемы ALU:
- 3 Bit Decoder
- Bit Switch
- Adding Bytes
- 8 bit NEG
- 8 bit NOT
- 8 bit NAND или OR (но расход mosfet транзисторов больше)
Проверка:
Input 1: 00000100 # 4
Input 2: 00000011 # 3
---------------------------
Instructions xxxx0000 # OR
Output 00000111 # 7
Instructions xxxx0001 # NAND
Output 11111111 # 255 или -1
Instructions xxxx0010 # NOR
Output 11111000 # 248 или -8
Instructions xxxx0011 # AND
Output 00000000 # 0
Instructions xxxx0100 # ADD
Output 00000111 # 7
Instructions xxxx0101 # SUB
Output 00000001 # 1
Registers
Пришло время создать свой главный проект, реализующий компьютерную архитектуру OVERTURE. Это будет настоящая машина, полная по Тьюрингу, истинный компьютер во всех смыслах!
Этот уровень — реализация инструкции MOV между регистрами, где адреса источника и назначения закодированы в 8-ми битной инструкции.
Задача: Создайте схему распределения/получения данных соответствующую спецификации
На схеме вам дается:
- 8-ми битный компонент для получения инструкции
- 5 ячеек памяти в виде 8-ми битных регистров
- внешний вход 8-ми битных данных
- внешний выход 8-ми битных данных
На этом уровне вам нужно создать схему которая может копировать из источника в место назначения.
Байт инструкции на этом уровне определяет источник Source и место назначения Destination.
Инструкция — это 8 бит, но используются 6 из них:
[ x x | S2 S1 S0 | D2 D1 D0 ] [ x x | Source | Destination ]

В качестве источника и получателя может выступать один из 6 регистров, которые мы обозначим соответственно REG 0,... REG 5.
Кроме того, этот уровень имеет отдельный входной компонент, который может быть источником, и выходной компонент, который может быть пунктом назначения.
Назначение адреса для источника Source:
OPCODE Source:
S2 S1 S0
--------------
0 0 0 REG 0
0 0 1 REG 1
0 1 0 REG 2
0 1 1 REG 3
1 0 0 REG 4
1 0 1 REG 5
1 1 0 INPUT # использовать внешний вход
1 1 1 UNUSED
Назначение адреса для назначения Destination:
OPCODE Destination:
D2 D1 D0
--------------
0 0 0 REG 0
0 0 1 REG 1
0 1 0 REG 2
0 1 1 REG 3
1 0 0 REG 4
1 0 1 REG 5
1 1 0 OUTPUT # использовать внешний выход
1 1 1 UNUSED
Например такие инструкции:
xx000110 => Source 000 (REG 0) и Destination 110 (OUTPUT)что означает взять данные изREG 0и переслать их во внешнийOUTPUTxx011001 => Source 011 (REG 3) и Destination 001 (REG 1)что означает взять данные изREG 3и переслать их вREG 1xx110110 => Source 110 (INPUT) и Destination 110 (OUTPUT)что означает взять данные из внешнегоINPUTи переслать их во внешнийOUTPUT

Circuit Simulation Registers
Необходимые компоненты:
Instruction Decoder
Декодер 2 на 4
Схема, которую вы построили на уровне Registers, может копировать значения между регистрами, в то время как "Арифметический Блок" (ALU) может выполнять различные операции над 2-мя входами.
Но вам нужно делать и то и другое в одной и той же схеме.
Задача: Постройте "декодер", который будет определять в каком режиме наш компьютер находится, основываясь на 2-х битах которые вы до сих пор не использовали.
Что бы отличать 4 инструкции MODE, они будут кодировать первыми (старшими) двумя битами:
[ M1 M0 | S2 S1 S0 | D2 D1 D0 ]
[ MODE | Source | Destination ]
OPCODE MODE:
---------------------------------
00xxxxxx Immediate values
01xxxxxx вычислить (ALU) CALC
10xxxxxx копировать COPY
11xxxxxx условия Conditions
Определите текущий режим работы по входным данным, затем отправьте 1 на соответствующий выход.

Или используйте Byte Splitter для получения доступа к исходным битам, а затем 3-битный декодер для декодирования высоких бит на четыре выхода.

Calculations
Пришло время объединить "Арифметический Блок" (ALU) который вы сделали ранее Arithmetic Engine и схему регистров Registers.
Вычислительная схема была сохранена (ALU) и декодер 2 на 4 (DEC) в заводе компонентов и теперь могут быть добавлены как компоненты в схему.
Если вы забыли какое соединение что делает, посмотрите на схему в заводе компонентов.
Задача: Используйте декодер (Декодер 2 на 4) который вы построили ранее для OPCODE для MODE, чтобы понять что делать с регистрами
REG1,REG2,REG3: копировать COPY (opcode = 10) или вычислять (ALU) CALC (opcode = 01). (для упрощения уровня, в режиме CALC регистры заданы жестко т.е. конкретные, их пока не адресуем)Вот 4 режима (напоминание):
[ M1 M0 | S2 S1 S0 | D2 D1 D0 ] [ MODE | Source | Destination ] OPCODE MODE: --------------------------------------- 0 0 Immediate values (не нужен сейчас) 0 1 вычислить (ALU) CALC 1 0 копировать COPY 1 1 условия Conditions (не нужен сейчас)На этом уровне вам нужно беспокоиться только о режимах копирования COPY и вычисления (ALU) CALC
Когда вы находитесь в режиме вычислений (ALU) CALC, используйте
REG 1иREG 2в качестве входов, а результат сохраните вREG 3.Не забудьте что у декодера 3 на 8 есть выключающий бит при HIGH сигнале, так как нам в режиме CALC не нужны из OPCODE инструкции Source и Destination, ведь мы жестко фиксировали работу с регистрами
REG1,REG2,REG3. Но в режиме COPY, декодеры 3 на 8 должны использоваться для адресации регистров либо внешнего входа/выхода.Еще, в этом уровне, модифицированные регистры, у них есть дополнительно ножка "Always output", т.е. всегда можно его прочитать без необходимости выставлять сигнал HIGH на ножке Load.
Для двух старших бит можно использовать декодер 2 на 4 который мы построили ранее на уровне Instruction Decoder он тоже принимает 8 бит но реагирует только на первых два старших, в принципе его можно переделать, для этого нам и дали завод компонентов, заменим 8-ми битный вход на 2-х битный. Или можно взять еще один декодер 3 на 8, но это избыточный вариант.
Наш компонет ALU принимает 8 бит инструкцию, входом для нее будет служить младшие биты которые мы используем для адресации выхода Destination: D2 D1 D0
(COPY тут не реализовано)

Либо можно вообще не заниматься двойным передокированием младших битов инструкции D2 D1 D0, и напрямую пустить в ALU все 8 бит инструкции.
И все же нужно верно использовать инструкцию COPY, которая должна управлять активацией Source, Destination

А вот переделанный декодер для входа на 2 бита вместо 8 бит

Program
Компонент ввода инструкций был удален. Он заменен компонентом программирования Program Memory.
Раньше мы использовали ручной ввод инструкции (Instruction Input) прямой передачей 8 бит. Теперь нам выдают Program Memory (ПЗУ ROM (Read-Only Memory)) который содержит в своей постоянной памяти 8-ми битные инструкции. Что бы их достать нам нужно их поочередно брать по индексу, для этого нам нужно использовать счетчик который будет с каждым такстом увеличиваться и мы будем получать следующую инструкцию из блока Program Memory.
В блоке Program Memory инструкции хранятся в определенной последовательности. Это и есть последовательное выполнение программы.
Для этого уровня вам необходимо использовать компонент 8-ми битный счётчика, который вы разблокировали ранее.

Conditions
Задача: На этом уровне на вход подаётся значение и 3 бита условия (8 возможных комбинации).
3 бита определяют условие, как показано ниже.
Проверьте значение по выбранному условию и выведите 1 если оно выполняется, иначе 0.
V| OPCODE: Выведите 1 когда: -|----------------------------------------- 0| 0 0 0 Никогда т.е. ничего не делать 1| 0 0 1 Если значение = 0 2| 0 1 0 Если значение < 0 3| 0 1 1 Если значение ≤ 0 4| 1 0 0 Всегда, просто вывести 1 5| 1 0 1 Если значение ≠ 0 6| 1 1 0 Если значение ≥ 0 7| 1 1 1 Если значение > 0
Убедитесь, что вы находитесь в режиме -1 , а не в режиме +255.
Связь с условными переходами (JMP / JZ / JN)
Есть:
- VALUE — обычно результат ALU (последняя операция)
- OPCODE (3 бита) — код условия
- Выход Conditions — COND_OK
- COND_OK = 1 → условие выполнено → переход разрешён
- COND_OK = 0 → переход запрещён
success
Нужны всего 2 флага:
- ZERO (Z) это VALUE=0 получить можно так: все биты через OR потом NOT т.е. NOR
- NEGATIVE (N) это просто старший бит VALUE (бит 7)
И далее нужно получить POSITIVE (P): P = NOT N AND NOT Z
Схема Conditions — это и есть “блок условий процессора”. Он отвечает на один вопрос: разрешён ли переход? (1 или 0)
| Ассемблер | Условие | OPCODE | Проверка |
|---|---|---|---|
| никогда | 000 | 0 | |
| JMP | всегда | 100 | 1 |
| JZ | == 0 | 001 | Z |
| JNZ | != 0 | 101 | !Z |
| JN | < 0 | 010 | N |
| JP | > 0 | 111 | P |
| JLE | ≤ 0 | 011 | N OR Z |
| JGE | ≥ 0 | 110 | !N |
O0 = C0 & 0
O1 = C1 & Z
O2 = C2 & N
O3 = C3 & (N | Z)
O4 = C4 & 1
O5 = C5 & !Z
O6 = C6 & !N
O7 = C7 & P
COND_OK = O0 | O1 | O2 | O3 | O4 | O5 | O6 | O7

Immediate values
Нам нужен способ напрямую передавать числа из нашей программы в регистры.
Ключевая идея уровня - Инструкция сама является данными!
(Как в уровне Calculations, мы использовали младшие биты предназначенные для адреса Destination xxxxxD2D1D0 в режиме MODE 01 не для адреса Destination, а для блока ALU)
[ M1 M0 | S2 S1 S0 | D2 D1 D0 ] [ MODE | Source | Destination ] OPCODE MODE: ------------ 0 0 Immediate values непосредственные значения
Задача: При режиме "Immediate values" преобразовать 6 младших бит инструкции в байт и передать его в
REG0Если линии остаются активными, когда не должны — будет короткое замыкание. Это значит: При Immediate Mode: только Immediate должен писать в REG0. В других режимах: Immediate вообще не должен влиять на шину
IMMEDIATE = NOT M1 AND NOT M0
Если 6 бит инструкции после бит MODE и есть наши данные S2 S1 S0 | D2 D1 D0 то мы можем иметь значение от 0 до 63 включительно (xxxxxx = 2⁵ + 2⁴ + 2³ + 2² + 2¹ + 2⁰ = 32 + 16 + 8 + 4 + 2 + 1 = 64)
Тогда мы берем 6 младших бит инструкции и превращаем их в байт, и записываем в REG0
Нам нужно:
- используя компонент
Switch 8 bit(MUX) решить какие данные пустить вREG0 - используя компонент переключателя 1 bit (подойдет и
Switch 8 bit(MUX)) разрешить региструREG0сохранить данные, так как биты адресации Destination мы теперь используем как часть данных

Turing Complete
tip
Разблокирует компонент RAM (ПЗУ).
В инструкции два старших бита M1 M0 отвечают за режимы MODE, в котором нам нужно реализовать 11xxxxxx Conditions.
До этого момента все программы ограничивались выполнением байт за байтом.
До сих пор только код из Program влиял на память (REG0,...), теперь память должна влиять на код.
До этого:
- PC (Program Counter счётчик) всегда делал PC = PC + 1
- Код → влиял на данные
С добавлением условной логики Conditions, наш компьютер теперь может выполнить любой алгоритм и вычислить все что вычислимо.
Теперь:
- Данные → могут влиять на код
- Мы можем изменить PC из инструкции
- Это и есть условные переходы (branch / jump)
Последний недостающий кусок CPU которую нам нужно добавить, это механизм для изменения текущего значения счётчика через инструкции, при определённых услових.
В режим Conditions мы попадаем при инструкции 11xxxxxx
В этом режиме, значение REG3 проверяется на условие заданное тремя младшими битами инструкции xxxxxD2D1D0.
Если условие выполняется, мы записываем значение REG0 в счётчик.
Изменение значения счетка с помощью условия означает, что мы можем пропускать инструкции основываясь на условиях или запускать инструкции в цикле.
Эти условия соответствуют компоненту Conditions который был сохранён в завод компонентов:
0 0 0 Никогда т.е. не должны ничего делать
0 0 1 Если REG3 = 0
0 1 0 Если REG3 < 0
0 1 1 Если REG3 ≤ 0
1 0 0 Всегда
1 0 1 Если REG3 ≠ 0
1 1 0 Если REG3 ≥ 0
1 1 1 Если REG3 > 0
Реализация:
- Данные для проверки условий в компоненте Conditions. Берём
REG3— это результат вычислений (для этого нужен 1 битный переключатель (подойдет иSwitch 8 bit(MUX)) чтобы в компонент вычисления условий Conditions пошли данные изREG3) - Если условие = 1 → берем данные с
REG0и записываем в PC - Иначе → PC просто увеличится на 1, как обычно

компонент RAM в circuitjs
RAM: A0, A1, A2 — это адресные входы (куда подаётся адрес ячейки) D0, D1, D2... D7 — это выходы данных (откуда читается содержимое ячейки)
Правильная логика управления RAM:
| Сигнал | Значение | Режим работы |
|---|---|---|
| WE = 1 | HIGH | ЗАПИСЬ — данные с входов D0-D7 записываются в память |
| WE = 0 | LOW | ЧТЕНИЕ — данные из памяти выводятся на выходы D0-D7 |
| OE = 1 | HIGH | Разрешение выхода — данные появляются на выходах |
| OE = 0 | LOW | Высокий импеданс — выходы отключены (Z-состояние) |
RAM:
0: 0 0 0 0
7: 15
Вход это адрес ячейки:
A2=1 # 2²=4
A1=1 # 2¹=2
A0=1 # 2⁰=1
Это означает адрес: 111 в двоичном = 7 в десятичном.
2² + 2¹ + 2⁰ = 4 + 2 + 1 = 7
Выход значения формируется из 8-ми бит:
D7=0
D6=0
D5=0
D4=0
D3=1 # 2³=8
D2=1 # 2²=4
D1=1 # 2¹=2
D0=1 # 2⁰=1
2³ + 2² + 2¹ + 2⁰ = 8 + 4 + 2 + 1 = 15
Для загрузки файла, RAM ожидает бинарный формат:
printf '\x00\x00\x00\x00\x00\x00\x00\x0F' > data.bin
Что создаст файл с:
0: 0 0 0 0 0 0 0 15
Что тоже самое:
7: 15
адрес: значение
Формат данных:
1: 4
2: 10
трансформируется в:
1: 4 10