CPU Architecture 2
- XOR
- Byte XOR
- Byte Constant
- Equality
- Unsigned Less
- Signed Less
- Wide Instructions
- Wire Spaghetti
- Opcodes
- Immediate Values
- Conditionals
XOR
Задача:
Используя инструкции вашего компьютера, дважды считайте входные данные и выполните операцию XOR над этими двумя значениями.
Воспользуемся одним из способов получения XOR: A XOR B = (A NAND B) && (A || B)
Assembly Editor:
0b10110001 # copy input to reg_1
0b10110010 # copy input to reg_2
# A XOR B = (A NAND B) && (A || B)
0b01000001 # calc (A NAND B) to reg_3
0b10011000 # copy reg_3 to reg_0
0b01000000 # calc (A || B) to reg_3
0b10011001 # copy reg_3 to reg_1
0b10000010 # copy reg_0 to reg_2
0b01000011 # calc (A NAND B) && (A || B) to reg_3
0b10011110 # copy reg_3 to output
Byte XOR
tip
Разблокирует 8 Bit XNOR, 8 Bit XOR
Задача:
Создайте схему которая выполняет операцию XOR для двух байт

Byte Constant
Задача:
Создайте схему которая всегда выводит значение
164
Нужно использовать компонент Byte Combiner который "собирает" биты в байт.
Equality
tip
Разблокирует 8 Bit Equality
Задача:
Создайте схему которая на выходе дает 1 если два 8-ми битных входа одинаковые либо 0 и 0, либо 1 и 1
Классическое логическое решение использовать XOR, так как его таблица истинности соответвует задаче.
# 1 bit
OUT = NOT (A XOR B)
Но другой вариант решения, обычно быстрее в контексте CPU, и может быть выгоднее по железу, если сумматор уже существует. Он основан на использовании цепочки переноса полного сумматора, которая «протекает» только если все биты равны.
X = A AND B = 1010
Y = A NOR B = 0101
X + Y = 1111
+ carry_in 1 = 10000
carry_out = 1 → равно
X = A AND B = 1000
Y = A NOR B = 0101
X + Y = 1101
+ carry_in 1 = 1110
carry_out = 0 → не равно

Unsigned Less
tip
Разблокирует 8 Bit Less (Unsigned)
Задача:
Создайте схему которая на выходе дает 1 если первое значение меньше второго. Интерпретируейте байти как беззнаковые.
Дано:
- два 8-битных числа A и B
- интерпретация без знака (0…255)
Нужно:
OUT = 1 ⇔ A < BOUT = 0 ⇔ A ≥ B
Чтобы узнать, меньше ли
AчемB(беззнаковое сравнение), делаютA - B. Для этого в процессорах используют дополнение до двух: инвертируютBи прибавляют 1. Суммирование сAпроисходит в полном сумматоре. ЕслиB > A, возникает заём (borrow), который в архитектуре фиксируется какcarry_out = 0. ЕслиA ≥ B,carry_out = 1.Таким образом:
A - B = A + (~B) + 1 UnsignedLess = NOT(carry_out)
A < B ?
A = 00000011 # 3
B = 00000100 # 4
~B = NOT(B) = 11111011
00000011 (A)
+ 11111011 (~B)
+ 00000001 (carry_in)
------------
0 11111111 (результат carry_out = 0)
Ответ: A мешьше чем B
A < B ?
A = 00000100 # 4
B = 00000011 # 3
~B = NOT(B) = 11111100
00000100 (A)
+ 11111100 (~B)
+ 00000001 (carry_in)
------------
1 11111101 (результат carry_out = 1)
Ответ: A больше или равно B

Signed Less
tip
Разблокирует 8 Bit Less (Signed)
Задача:
Создайте схему которая на выходе дает 1 если первое значение меньше второго. Интерпретируейте байти как знаковые.
Особенность: простой carry для вычитания работает только для беззнаковых чисел. Для signed надо учитывать старший бит (MSB) = знак и overflow.
A < B (signed) тогда и только тогда, когда:
- Их знаковые биты различаются и:
Aотрицательное, аBположительное →A < B = trueAположительное, аBотрицательное →A < B = false
- Если знаки одинаковы → сравнить их высшие 7 бит как unsigned
- если
A[6:0] < B[6:0]→ результат зависит от знака - иначе наоборот
- если

strategywiki.org/wiki/Turing_Complete/Signed_Less
Wide Instructions
tip
Разблокирует компонент Program
Уровень учит работать с пропускной способностью памяти, превращать последовательные данные в параллельные.
8 bit xxxxxxxx xxxxxxxx => | xxxxxxxxxxxxxxxx => 16 bit instruction
Проблема "узкого горлышка".
При 8-ми битной шине мы "скармливаем" за один такт только 8-ми битное число для всей инструкции, в которой должны уместиться указания: и что делать и с каких адресов брать данные и в какие адреса писать результат, все это должно уместиться в xxxxxxxx. К стати счетчик PC поэтому и инкрементируется +1 за такт. В итоге мы выполняем работу за один такт процессора, что очегь быстро, но указать процессору что делать за этот такт мы можем мало.
Память может выдавать один байт за один такт. Если нам нужно больше данных для передачи информации через инструкцию за раз, мы можем применить механизм широких инструкций, склеив байты прежде чем их отдать т.е. мы ждем несколько тиков пока инструкция не станет нужной разрядности.
Например что бы из 8-ми битной инструкции (была у нас все это время) которая дают только 8 бит значение xxxxxxxx получить 16 бит значение xxxxxxxxxxxxxxxx, мы можем предварительно склеить два 8-ми битных значения в буфере и уже готовое 16-и битное значение отдать. Логика буфера, на четных тактах устанавливаем значение в регистре, а на нечетных добавляем новое значение к старому и отдаем на выход. И так мы получаем 16-ти битную шину, и наш счетчик PC уже должен делать инкремент +4. В итоге мы двигаемся медленнее чем 8-ми юитные инструкции но более умно.
Задача:
Создайте устройство которое сохраняет выход программы на четных тактах и выводит оба байта на нечетных тактах.
Мы делаем широкие инструкции, объединяя два байта в одну 16‑битную «команду»
Нам нужен регистровый буфер, который:
- На чётном такте (у четных чисел младший бит равен 0): сохраняет байт в REG_0
- На нечетном такте (1, 3, 5 …):
- выводим REG_0 в один из OUTPUT
- выводим текущую инстркцию в другой OUTPUT

Wire Spaghetti
Задача:
Пришло время создавать архитектуру LEG (Logical Execution Grid / или просто наша собственная CPU‑архитектура в Turing Complete).
ISA (Instruction Set Architecture) — это архитектура набора команд, фундаментальный интерфейс между программным обеспечением и аппаратурой процессора.
ISA архитектура: LEG — это компьютер, который берет 4 байта за такт из программы Первый байт описывает операцию (называемую OPCODE) * байт 1 → Opcode Поскольку многие операции принимают 2 аргумента (ADD, OR и т.д.), второй и третий байты используются для указания аргументов * байт 2 → Argument 1 (какой исчтоник направить в ALU (input 1) адрес/регистр/IO) * байт 3 → Argument 2 (какой исчтоник направить в ALU (input 2) адрес/регистр/IO) Поскольку большинство операций возвращают одно значение результата, четвертый байт предназначен для указания результата * байт 4 → Result address (куда направить результат ALU) [ Opcode 8bit][ Argument 1 8bit][ Argument 2 8bit][ Result address 8bit]
question
В архитектуре нужно предусмотреть инструкцию для копирования. Иначе все операции с данными будут идти через ALU с операцией ADD Something + 0

- Создайте новую схему
- Поместите на схему компонент PROGRAM с 4-мя выходами
- Поместите на схему компонент Counter, установите инкремент на 4 и подключите его к PROGRAM
- Поместите на схему шесть регистров
- Отредактируйте связи PROGRAM (Link components) с другими компонентами:
- Подключите регистры с 0-го до 5-го pin
- Counter (PC) к 6-му pin
- Output к 7-му pin
На этом уровне OPCODE всегда равен 0 (т.е. нужно реализовать только операцию ADD).
Это означает, что мы выполняем операцию ADD с Argument 1 и Argument 2 и сохраняем результат в место куда указывает Result address 4-й байт из вывода PROGRAM.
Значение выходов Argument 1 и Argument 2 или Result address из PROGRAM, относится к одному из следующих мест:
- 0: Register 0
- 1: Register 1
- 2: Register 2
- 3: Register 3
- 4: Register 4
- 5: Register 5
- 6: Counter (PC)
- 7: Input (для
Argument 1иArgument 2) или Output (дляResult address)
На следующем уровне будем реализовывать еще больше команд OPCODE для чего потребуется другой ALU
Для прохождения уровня мы можем использовать уже существующий компонент ALU для операции ADD.
Решение основанно на MUX8Bit который аккумулирует все исчтоники ввода, что избавляет нас от множества tri-state buffers разделяя общую шину.

Вспомогательный компонет MUX8Buf, нужен что бы не перегружать схему линиями питания:

Turing Complete - CPU Architecture 2 (www.youtube.com)
Opcodes
Задача:
Реализовать opcodes:
0 ADD 1 SUB 2 AND 3 OR 4 NOT 5 XORp.s. операция NOT игнорирует второй аргумент
У нас уже есть готовый компонет ALU, но с другими opcodes и без операций NOT и XOR. Создадим на его основе новый компонент.
Компонент ALU_CPU2:
000 ADD
001 SUB
010 AND
011 OR
100 NOT
101 XOR
110 NAND
111 NOR

Immediate Values
Иногда бывает полезно загрузить значение непосредственно из программы, а не из регистров. Это называется загрузкой непосредственного значения (Immediate Values). В архитектуре LEG мы указываем, когда хотим это сделать, непосредственно в коде операции.
Это можно сделать следующим образом:
- Когда 8-й бит (MSB) opcode
0xxxxxxxравен HIGH, используйтеArgument 1в качестве непосредственного значения, а не в качестве адреса регистра.- т.е. теперь в байте
Argument 1содержатся данные
- т.е. теперь в байте
- Если 7-й бит opcode
x0xxxxxxравен HIGH, используйтеArgument 2в качестве непосредственного значения, а не в качестве адреса регистра.- т.е. теперь в байте
Argument 2содержатся данные
- т.е. теперь в байте


Обновим ALU, 8-ми битный вход ему избыточен, достаточно 3 бита.

Conditionals
Задача:
Добавить Conditionals (условные выражения). Суть, сравниваются два 8-ми битных аргумента (
Argument 1иArgument 2) и если условие верно, то счетчик PC перезаписывается адресом прыжкаJump_address.Компонет Program выдает 4 байта:
[Opcode][Argument 1][Argument 2][Jump_address]В дополнение к предыдущим операциям opcode, добавьте:
0bxx1xx000 32 IF_EQUAL (Если равно) 0bxx1xx001 33 IF_NOT_EQUAL (Если не равно) 0bxx1xx010 34 IF_LESS (Если менее) 0bxx1xx011 35 IF_LESS_OR_EQUAL (Если менее или равно) 0bxx1xx100 36 IF_GREATER (Если более) 0bxx1xx101 37 IF_GREATER_OR_EQUAL (Если более или равно)Используйте беззнаковое меньше/больше для сравнений.
Например:
IF_LESS REG_0 REG_1 16- эта инструкция прыгает на 16 байт если REG_0 меньше чем REG_1
(Хоть нам и рекомендовали реализовать новые возможности opcodes в существующем компоненте ALU, все же мы реализуем отдельный компонент.)
Создадим новый компонент для условий COND_CPU2:
- можно сразу реализовать вариант для Unsigned/Signed (но Signed не будет использоваться)
- оптимизация, работа условия
34 IF_LESS (Если менее)не нуждается в результате32 IF_EQUAL (Если равно)в отличии от всех других случаев, поэтому можем отключить эту линию. Так же, можно выбирать только один из расчетов Unsigned/Signed в моменте. - opcode можно реализовать через неполный дешифратор 4х6
У нас получился COND — с возможностями CMP и JUMP, слитые в одну супер-инструкцию, мы можем за один такт и сравнивать два источника, и принимаешь решение о прыжке.
Пример будущей инструкции для COND:
# 4 bit instruction
0b01100000 #1 cond REG_1 == 4
0b00000001 #2 arg1 source REG_1
0b00000100 #3 arg2 source Immediate values
jump_address_ram #4 jump address (rewrite PC)

ALU может писать в общую шину, только если не работает при этом компонент COND_CPU2, поэтому смотрим на 6-й бит (32) opcode если он установлен, значит это режим для условий COND_CPU2 и мы должны перекрыть вывод ALU в шину.

Conditionals (www.youtube.com)