Поленов Кирилл Александрович P3213
asm | risc | harv | mc | tick | binary | stream | mem | pstr | prob2
25/30 баллов. Не ответил на вопрос "как схемотехнически устроен IO Controller"
Язык ассемблерного типа для RISC системы команд
<program> ::= <data_section> <code_section>
<data_section> ::= "." "data" { <data_definition> }
<code_section> ::= "." "code" { <instruction> | <macro_definition> | <macro_invocation> }
<instruction> ::=
"lui" <register> "," { <string> | <number> }
| "addi" <register> "," <register> "," { <string> | <number> } [ <comment> ]
| "ori" <register> "," <register> "," { <string> | <number> } [ <comment> ]
| "sw" <register> "," <register> "," { <number> } [ <comment> ]
| "lw" <register> "," <register> "," { <number> } [ <comment> ]
| "add" <register> "," <register> "," <register> [ <comment> ]
| "sub" <register> "," <register> "," <register> [ <comment> ]
| "mul" <register> "," <register> "," <register> [ <comment> ]
| "mulh" <register> "," <register> "," <register> [ <comment> ]
| "div" <register> "," <register> "," <register> [ <comment> ]
| "and" <register> "," <register> "," <register> [ <comment> ]
| "or" <register> "," <register> "," <register> [ <comment> ]
| "xor" <register> "," <register> "," <register> [ <comment> ]
| "jal" <register> "," <label> [ <comment> ]
| "jalr" <register> "," <register> "," <label> [ <comment> ]
| "beq" <register> "," <register> "," <label> [ <comment> ]
| "bne" <register> "," <register> "," <label> [ <comment> ]
| "bgt" <register> "," <register> "," <label> [ <comment> ]
| "blt" <register> "," <register> "," <label> [ <comment> ]
| "halt" [ <comment> ]
| <label> [ <comment> ]
<macro_definition> ::= "%" "macro" <identifier> [ "(" <macro_parameter_list> ")" ] { <instruction> } "%" "endmacro" [ <comment> ]
<macro_parameter_list> ::= <identifier> { "," <identifier> }
<macro_invocation> ::= <identifier> [ "(" <macro_argument_list> ")" ] [ <comment> ]
<macro_argument_list> ::= <macro_argument> { "," <macro_argument> }
<macro_argument> ::= <label> | <string> | <number> | <register>
<data_definition> ::= <label> <data_value> { "," <data_value> } [ <comment> ]
<data_value> ::= <string> | <number>
<register> ::= { "t" | "s" | "a" } <number> | "r0" | "ra" | "bp" | "sp"
<label> ::= <identifier> ":"
<identifier> ::= <letter> { <letter> | <digit> }
<number> ::= <digit> { <digit> }
<string> ::= "\"" { <character> } "\""
<letter> ::= "a" | "b" | "c" | ... | "z"
| "A" | "B" | "C" | ... | "Z"
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<character> ::= <any printable ASCII character except quotation mark>
<comment> ::= ";" { <any printable ASCII character> }%hi(literal)- загрузить верхние 20 бит литерала%lo(literal)- загрузить нижние 12 бит литерала
.data
message: "Hello, world!"
.code
lui bp, %hi(message) ; загрузить верхние 20 бит адреса метки message
ori bp, bp, %lo(message) ; загрузить нижние 12 бит адреса метки message без расширения знака.org <address>- задать начальный адрес секции.data- создает секцию памяти данных.code- создает секцию памяти команд%macro <macro definition> %endmacro- пара директив задающие пользовательскую макрооперацию
%macro load_str_ptr(address)
lui bp, %hi(%1)
ori bp, bp, %lo(%1)
%endmacro
%macro load_and_add(rd, rs, offset, value)
lw %1, %2, %3
addi %1, %1, %4
%endmacro
.data
message: "Hello, world!"
.code
load_str_ptr(message) ; Вызов макроса load_str_ptr с аргументом message
load_and_add(s1, s2, 0, 5) ; Вызов макроса load_and_add с несколькими аргументами
halt| Команда | Описание |
|---|---|
lui <rd>, <k> |
Загрузить верхние 20 бит литерала в регистр |
sw <rs2>, <rs1>, <offset> |
Сохранить слово из rs2 по адресу из rs1 со смещением offset |
lw <rd>, <rs1>, <offset> |
Загрузить слово в rd c адреса из rs1 со смещением offset |
addi <rd>, <rs1>, <k>* |
Сложить содержимое регистра rs1 с литералом k и поместить результат в регистр rd |
add <rd>, <rs1>, <rs2> |
Сложить содержимое регистра rs1 с содержимым регистра rs2 и поместить результат в регистр rd |
sub <rd>, <rs1>, <rs2> |
Вычесть содержимое регистра rs1 из содержимого регистра rs2 и поместить результат в регистр rd |
mul <rd>, <rs1>, <rs2> |
Умножить содержимое регистра rs1 на содержимое регистра rs2 и поместить результат в регистр rd |
mulh <rd>, <rs1>, <rs2> |
Умножить содержимое регистра rs1 на содержимое регистра rs2 и поместить верхние 32 бита результата в регистр rd |
div <rd>, <rs1>, <rs2> |
Разделить содержимое регистра rs1 на содержимое регистра rs2 и поместить результат в регистр rd |
and <rd>, <rs1>, <rs2> |
Совершить логическое И содержимого регистра rs1 и содержимого регистра rs2 и поместить результат в регистр rd |
or <rd>, <rs1>, <rs2> |
Совершить логическое ИЛИ содержимого регистра rs1 и содержимого регистра rs2 и поместить результат в регистр rd |
ori <rd>, <rs1>, <k>* |
Совершить логическое ИЛИ содержимого регистра rs1 и литерала k и поместить результат в регистр rd |
xor <rd>, <rs1>, <rs2> |
Совершить исключающее ИЛИ содержимого регистра rs1 и содержимого регистра rs2 и поместить результат в регистр rd |
jal <rd>, <k>*1 |
Перейти на адрес pc + k, сохранив адрес возврата в регистр rd. Аналог call и jump |
jalr <rd>, <rs1>, <k>*1 |
Перейти на адрес из rs1, сохранив адрес возврата в регистр rd. Аналог call и return |
beq <rs1>, <rs2>, <k> |
Перейти на адрес pc + k, если содержимое rs1 равно содержимому rs2 |
bne <rs1>, <rs2>, <k> |
Перейти на адрес pc + k, если содержимое rs1 не равно содержимому rs2 |
bgt <rs1>, <rs2>, <k> |
Перейти на адрес pc + k, если содержимое rs1 больше содержимого rs2. Для сравнения знаковых чисел |
blt <rs1>, <rs2>, <k> |
Перейти на адрес pc + k, если содержимое rs1 меньше содержимого rs2. Для сравнения знаковых чисел |
halt |
Остановить процессор |
* - расширяет знак литерала k
*1 - Если подать регистр r0 как аргумент <rd>, адрес возврата не будет сохранен.
- Ассемблер соответствует строгой модели вычислений. Все аргументы вычисляются до применения к ним функций
- В выражениях, состоящих из нескольких операций, приоритет выполнения операций определяет программист
В языке не существует как таковых областей видимости, однако есть пара моментов:
- Секция данных и команд не имеют прямого доступа друг к другу
- На аппаратном уровне невозможно прочитать команду из памяти команд как данные и наоборот
- Язык является беcтиповым. Все сущности считаются последовательностью бит различной длины в пределах машинного слова
- Регистры являются универсальными контейнерами для хранения переменных в виде битовых последовательностей
- Интерпретация содержимого регистров зависит от инструкций, которые к ним применяются. К примеру инструкция
addподразумевает, что операндами являются числа. Инструкцияlwподразумевает, что один регистров-операндов содержит адрес в памяти - Отсутствие статической проверки типов
- Отсутствие неявных преобразований
Однако в контексте ассемблера битовые последовательности можно разделить на следующие категории:
- Знаковые числа
- Адреса
- Символы
- Строки (последовательности символов)
Литералы соответствуют одной из категорий перечисленных выше
- Размер машинного слова - 32 бита
- Модель памяти соответствует Гарвардской архитектуре
- Присутствует 3 вида памяти: Память инструкций, Память данных, Память микрокоманд
- Адреса памяти данных и памяти команд представляют собой беззнаковые 32 битные числа
- Обращение к памяти происходит только по абсолютному адресу
- Память команд является read-only на аппаратном уровне
- Память Команд
- Инструкции имеют фиксированную длину - 32 бита
- Инструкции хранятся в ячейках размером 32 бита
- Память Данных
- Данные хранятся в ячейках размером 32 бита
- Обращение к памяти происходит только через регистры
ALUне имеет прямого доступа к памяти- Модель включает в себя 32 регистра
- За управление регистрами отвечает
Register File - Регистр
r0-Zero register(значение всегда равно 0) - Регистр
r31- системный для временного храненияimm/offsetзначений - Стек не является аппаратной частью и располагается в конце памяти данных. Для аргументов и возвращаемых значений функций следует использовать регистры согласно соглашению
- По умолчанию все переменные отображаются в память данных в порядке их инициализации в секции
.data - Переменные могут быть отображены на регистры только при явной загрузке в регистры
- Порядок расположения литералов в памяти данных соответствует порядку их объявления в секции
.data - Литералы превышающие 32 бита хранятся в памяти следующим образом:
Data Memory
+-----------------------------+
| ... |
| n lit_low |
| n+1 lit_high |
| ... |
+-----------------------------+
Где lit_low нижние 32-бита литерала, lit_high верхние 32-бита литерала
Instruction memory
+-----------------------------+
| 00 binary instr |
| 01 binary instr |
| ... |
+-----------------------------+
Data Memory
+-----------------------------+ +-------+
| 00 data | <--|IN_BUF |
| 01 data | <--|OUT_BUF|
| ... | +-------+
| 10 data |
| 11 data |
| ... |
+-----------------------------+
| Stack |
+-----------------------------+
| ??? end |
| ... |
| MAX begin |
+-----------------------------+
Microprogram memory
+-----------------------------+
| 00 signals |
| 01 signals |
| ... |
+-----------------------------+
| type | destination register | operation | source register 1 | source register 2 | op extension |
|---|---|---|---|---|---|
| 7 bits | 5 bits | 3 bits | 5 bits | 5 bits | 7 bits |
type = 1000000
| Инструкция | Operation code | Op extension code |
|---|---|---|
add |
001 |
0000001 |
sub |
001 |
0000010 |
mul |
010 |
0000001 |
mulh |
010 |
0000010 |
div |
010 |
0000011 |
and |
011 |
0000001 |
or |
011 |
0000010 |
xor |
011 |
0000011 |
| type | destination register | operation | source register 1 | immediate value/offset [0-11] bits |
|---|---|---|---|---|
| 7 bits | 5 bits | 3 bits | 5 bits | 12 bits |
type = 0100000
| Инструкция | Operation code |
|---|---|
lw |
001 |
addi |
010 |
ori |
011 |
jalr |
100 |
halt |
101 |
| type | offset [0-4] bits | operation | source register 1 | source register 2 | offset [5-11] bits |
|---|---|---|---|---|---|
| 7 bits | 5 bits | 3 bits | 5 bits | 5 bits | 7 bits |
type = 0010000
| Инструкция | Operation code |
|---|---|
sw |
001 |
| type | offset [0-4] bits | operation | source register 1 | source register 2 | offset [5-11] bits |
|---|---|---|---|---|---|
| 7 bits | 5 bits | 3 bits | 5 bits | 5 bits | 7 bits |
type = 0001000
| Инструкция | Operation code |
|---|---|
beq |
001 |
bne |
010 |
bgt |
011 |
blt |
100 |
| type | destination register | immediate value [12-31] bits |
|---|---|---|
| 7 bits | 5 bits | 20 bits |
type = 0000100
| Инструкция | Operation code |
|---|---|
lui |
- |
| type | destination register | immediate value [0-19] bits |
|---|---|---|
| 7 bits | 5 bits | 20 bits |
type = 0000010
| Инструкция | Operation code |
|---|---|
jal |
- |
| Регистр | Бин. код |
|---|---|
r0 |
00000 |
ra |
00001 |
sp |
00010 |
bp |
00011 |
t0 |
00100 |
t1 |
00101 |
t2 |
00110 |
t3 |
00111 |
t4 |
01000 |
t5 |
01001 |
t6 |
01010 |
s0 |
01011 |
s1 |
01100 |
s2 |
01101 |
s3 |
01110 |
s4 |
01111 |
s5 |
10000 |
s6 |
10001 |
s7 |
10010 |
s8 |
10011 |
s9 |
10100 |
s10 |
10101 |
s11 |
10110 |
a0 |
10111 |
a1 |
11000 |
a2 |
11001 |
a3 |
11010 |
a4 |
11011 |
a5 |
11100 |
a6 |
11101 |
a7 |
11110 |
r31 |
11111 |
r0- системный регистр всегда хранящий 0ra- адрес возвратаsp- указатель вершины стекаbp- указатель на буфер строкиt0-t6- регистры для временного хранения внутри функции. Caller-saved регистрыs0- может использоваться как указатель на фрейм стекаs0, s1-s11- регистры для сохранения значений перед вызовом функции и восстановить после. Callee-saved регистрыa0-a7- регистры для передачи аргументов/возвращаемых значений в функциюr31- системный регистр для временного храненияimm/offset
| Инструкция | Тип | Результат | Описание |
|---|---|---|---|
lui <rd>, <k> |
U-type | rd <- k << 12 |
Загрузить верхние 20 бит литерала в регистр |
sw <rs2>, <rs1>, <offset> |
S-Type | rs2 -> mem[rs1 + offset] |
Сохранить слово из rs2 по адресу из rs1 со смещением offset |
lw <rd>, <rs1>, <offset> |
I-type | rd <- mem[rs1 + offset] |
Загрузить слово в rd c адреса из rs1 со смещением offset |
| Инструкция | Тип | Результат | Описание |
|---|---|---|---|
addi <rd>, <rs1>, <k>* |
I-type | rd <- rs1 + k |
Сложить содержимое rs1 с литералом k и поместить результат в регистр rd |
add <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 + rs2 |
Сложить содержимое rs1 с содержимым rs2 и поместить результат в регистр rd |
sub <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 - rs2 |
Вычесть содержимое rs1 из содержимого rs2 и поместить результат в регистр rd |
mul <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 * rs2 |
Умножить содержимое rs1 на содержимое rs2 и поместить результат в регистр rd |
mulh <rd>, <rs1>, <rs2> |
R-type | rd <- (rs1 * rs2) >> 32 |
Умножить содержимое rs1 на содержимое rs2 и поместить верхние 32 бита результата в регистр rd |
div <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 / rs2 |
Разделить содержимое rs1 на содержимое rs2 и поместить результат в регистр rd |
* - расширяет знак литерала k
| Инструкция | Тип | Результат | Описание |
|---|---|---|---|
ori <rd>, <rs1>, <k>* |
I-type | rd <- rs1 | k |
Совершить логическое ИЛИ содержимого rs1 и литерала k и поместить результат в регистр rd |
and <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 & rs2 |
Совершить логическое И содержимого rs1 и содержимого rs2 и поместить результат в регистр rd |
or <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 | rs2 |
Совершить логическое ИЛИ содержимого rs1 и содержимого rs2 и поместить результат в регистр rd |
xor <rd>, <rs1>, <rs2> |
R-type | rd <- rs1 ^ rs2 |
Совершить исключающее ИЛИ содержимого rs1 и содержимого rs2 и поместить результат в регистр rd |
* - расширяет знак литерала k
| Инструкция | Тип | Результат | Описание |
|---|---|---|---|
jal <rd>, <k>* |
J-type | rd <- pc + 4, pc <- pc + k |
Перейти на адрес pc + k, сохранив адрес возврата в регистр rd. Аналог call и jump |
jalr <rd>, <rs1>, <k>* |
I-type | rd <- pc + 4, pc <- rs1 |
Перейти на адрес из rs1, сохранив адрес возврата в регистр rd. Аналог call и return |
halt |
I-type | - | Остановить процессор |
beq <rs1>, <rs2>, <k> |
B-type | if rs1 == rs2 then pc <- pc + k |
Перейти на адрес pc + k, если содержимое rs1 равно содержимому rs2 |
bne <rs1>, <rs2>, <k> |
B-type | if rs1 != rs2 then pc <- pc + k |
Перейти на адрес pc + k, если содержимое rs1 не равно содержимому rs2 |
bgt <rs1>, <rs2>, <k> |
B-type | if rs1 > rs2 then pc <- pc + k |
Перейти на адрес pc + k, если содержимое rs1 больше содержимого rs2 |
blt <rs1>, <rs2>, <k> |
B-type | if rs1 < rs2 then pc <- pc + k |
Перейти на адрес pc + k, если содержимое rs1 меньше содержимого rs2 |
* - Если подать регистр r0 как аргумент rd, адрес возврата не будет сохранен.
- Instruction fetch: 3 такта
mpc + 1 -> mpc,pc + 1 -> pcins_mem[pc] -> decoder,lookUpTableIndex(decoder) -> IR,mpc + 1 -> mpcIR -> mpc
- Instruction execution: N тактов
| Инструкция | Кол-во тактов | Потактовое выполнение |
|---|---|---|
lui <rd>, <k> |
1 | k << 12 -> rd |
sw <rs2>, <rs1>, <offset> |
3 | offset -> r31,rs1 + r31 -> r31,rs2 -> data_mem[r31] |
lw <rd>, <rs1>, <offset> |
3 | offset -> r31,rs1 + r31 -> r31,data_mem[r31] -> rd |
addi <rd>, <rs1>, <k> |
2 | k -> r31,rs1 + r31 -> rd |
add <rd>, <rs1>, <rs2> |
1 | rs1 + rs2 -> rd |
sub <rd>, <rs1>, <rs2> |
1 | rs1 - rs2 -> rd |
mul <rd>, <rs1>, <rs2> |
1 | rs1 * rs2 -> rd |
mulh <rd>, <rs1>, <rs2> |
1 | (rs1 * rs2) >> 32 -> rd |
div <rd>, <rs1>, <rs2> |
1 | rs1 / rs2 -> rd |
ori <rd>, <rs1>, <k> |
2 | k -> r31,rs1 | r31 -> rd |
and <rd>, <rs1>, <rs2> |
1 | rs1 & rs2 -> rd |
or <rd>, <rs1>, <rs2> |
1 | rs1 | rs2 -> rd |
xor <rd>, <rs1>, <rs2> |
1 | rs1 ^ rs2 -> rd |
jal <rd>, <k> |
3 | pc + 1 -> rd,k -> r31,pc + r31 -> pc |
jalr <rd>, <rs1>, <k> |
3 | pc + 1 -> rd,k -> r31,rs1 + r31 -> pc |
halt |
1 | Stop machine |
beq <rs1>, <rs2>, <k> |
3 | k -> r31,rs1 - rs2 -> NZ,if Z then pc + r31 -> pc |
bne <rs1>, <rs2>, <k> |
3 | k -> r31,rs1 - rs2 -> NZ,if Z then pc + 1 -> pc |
bgt <rs1>, <rs2>, <k> |
3 | k -> r31,rs1 - rs2 -> NZ,if NZ=00 then pc + r31 -> pc |
blt <rs1>, <rs2>, <k> |
3 | k -> r31,rs1 - rs2 -> NZ,if NZ=10 then pc + r31 -> pc |
| Микрокоманда | Описание |
|---|---|
latch_ir |
Прочитать команду из памяти команд и защелкнуть соответствующий ей индекс LookUpTable в IR |
latch_mpc |
Защелкнуть значение в MPC |
sel_mpc_inc_one |
Управляющий сигнал для выбора 1 в качестве инкремента для MPC |
sel_mpc_inc_two_if_z |
Управляющий сигнал для выбора 2 в качестве инкремента для MPC если Z == 1 |
sel_mpc_inc_two_if_greater |
Управляющий сигнал для выбора 2 в качестве инкремента для MPC если NZ == 00 |
sel_mpc_inc_two_if_lower |
Управляющий сигнал для выбора 2 в качестве инкремента для MPC если NZ == 10 |
sel_mpc_increment |
Управляющий сигнал для выбора инкремента MPC |
sel_mpc_look_up_index |
Управляющий сигнал для выбора записи операции из IR в MPC |
sel_mpc_zero |
Управляющий сигнал для выбора записи 0 в MPC |
latch_regn |
Защелкнуть значение в регистр |
latch_reg31 |
Защелкнуть значение в регистр r31 |
sel_left_reg |
Управляющий сигнал для выбора регистра на левый выход Register File |
sel_right_reg |
Управляющий сигнал для выбора регистра на правый выход Register File |
sel_left_reg31 |
Управляющий сигнал для выбора регистра r31 на левый выход Register File |
sel_right_reg31 |
Управляющий сигнал для выбора регистра r31на правый выход Register File |
sel_data_src_alu |
Управляющий сигнал для выбора результата из ALU для записи в Register File |
sel_data_src_mem |
Управляющий сигнал для выбора данных из памяти данных для записи в Register File |
sel_data_src_cu |
Управляющий сигнал для выбора данных из Control Unit для записи в Register File |
sel_pc_inc |
Управляющий сигнал для выбора инкремента PC |
sel_pc_alu |
Управляющий сигнал для выбора записи в PC результата из ALU |
sel_alu_r_rf |
Управляющий сигнал для выбора подачи правого выхода Register File на правый вход ALU |
sel_alu_l_rf |
Управляющий сигнал для выбора подачи левого выхода Register File на левый вход ALU |
sel_alu_r_inc |
Управляющий сигнал для выбора подачи единицы на правый вход ALU |
sel_alu_l_pc |
Управляющий сигнал для выбора подачи PC на левый вход ALU |
alu_add |
Выполнить сложение в ALU |
alu_sub |
Выполнить вычитание в ALU |
alu_mul |
Выполнить умножение в ALU |
alu_mulh |
Выполнить умножение, а затем логический сдвиг вправо на 32 в ALU |
alu_div |
Выполнить деление в ALU |
alu_and |
Выполнить логическое И в ALU |
alu_or |
Выполнить логическое ИЛИ в ALU |
alu_xor |
Выполнить исключающее ИЛИ в ALU |
latch_pc |
Защелкнуть значение в PC |
write_data_mem |
Прочитать ячейку из памяти данных |
read_data_mem |
Записать данные в ячейку памяти данных |
halt |
Остановить процессор |
Интерфейс командной строки: translator.go <input_file> <target_code_file> <target_data_file> Реализовано в
модуле: translator.go
Он выполняет несколько ключевых шагов:
-
Удаление комментариев: Функция
cleanCommentsудаляет комментарии, что упрощает дальнейшую обработку. -
Подстановка макросов: Функция
expandMacrosподставляет макросы в места их вызова и удаляет их определения из кода. -
Далее происходит составление таблицы меток в памяти команд и памяти данных, а также обработка директив
.org, .data, .codeв функцииProcessAssemblyCode -
Подстановка смещений, раскрытие директив
%hi%loпроисходит в функцииResolveSymbols. Одновременно с этим заполняется выходной файл памяти данных и отладочный файл с дампом памятей -
Конвертация инструкций в бинарные представления и их запись в выходной файл памяти команд в функции
ConvertProgramToBinary -
Запуск трансляции: Основная функция
mainсчитывает исходный файл, выполняет трансляцию и записывает результат в целевые файлы.
- Реализован mem-mapped IO
- По умолчанию индексы
mmioInиmmioOutравны0и1соответственно. Ячейки можно конфигурировать через константыmmioInиmmioOutв файле memory.go - Конфигурацию ячеек следует проводить предельно внимательно с использованием директивы
.org. В противном случае могут произойти коллизии ячеек mem-mapped IO с ячейками памяти данных, что вызывает неопределенное поведение - Ввод-вывод производится путем обращения к ячейкам
mmioInиmmioOutвData Memory - При обращении к ячейкам
mmioOutиmmioOutпроисходит считывание и запись в буфер соответственно - Для работы с вводом-выводом используются те же команды, что и для обычной работы с памятью:
lw,sw - Если в
inбуфере кончаются элементы - процессор прекращает работу
Состоит из:
- ALU
- Register File
- Data memory
- Instruction memory
- IO Controller
- Program Counter (PC)
- Sign Extender для расширения знака
imm/offsetзначений всех инструкций кромеori
Сигналы:
latch_reg_n- защелкнуть значение в регистрnalu_op- сигнал операции АЛУlatch_pc- защелкнуть значение вPCwrite_mem- записать значение в памятьread_mem- считать значение из памятиsel_pc- селектор мультиплексора кPC(инкремент или запись значения из АЛУ)sel_data_src- селектор мультиплексора кregister file(запись результата из АЛУ, записьimm/offsetизCU, запись значения из памяти)sel_alu_r- селектор мультиплексора на правый вход АЛУ (единица, выход изregister file)sel_alu_l- селектор мультиплексора на левый вход АЛУ (PC, выход изregister file)
Флаги:
NZ- 2-битовый флаг.Nвыставляется, если результат на выходе АЛУ отрицательный,Zвыставляется, если результат на выходе АЛУ 0. 1-й битN, 2-й битZ
- системный регистр
r0имеет подтяжку 0 и неизменяем - системный регистр
r31нужен для временного храненияimm/offset r1-r30регистры для использования программистом
Сигналы:
latch_reg_nописан в разделе DataPathsel_left_reg- селектор подачи содержимого регистра на левый вход АЛУsel_left_reg- селектор подачи содержимого регистра на правый вход АЛУ
Состоит из:
-
Instruction decoder- декодер бинарной инструкции. Определяет индекс начальной для инструкции микрокоманды вLookUpTable, отправляет вSignal Dispatcherиндексы регистров, аimm/offsetзначения вDataPath.- Содержит
LookUpTableмаппинга инструкций на соответствующие им микропрограммы.
- Содержит
-
IR (Index Register)- регистр для хранения индексаLookUpTable -
MPC (MicroProgram Counter)- счетчик микропрограмм -
MP memory- память микропрограмм -
Signal Dispatcher- отправляет управляющие сигналы микропрограмм вDataPathи анализирует флаги результата
Процесс выполнения программы:
- На вход
CUпоступает бинарная инструкция из памяти инструкций - По совокупности типа команды, опкода и расширение опкода из
LookUpTableдостается индекс микропрограммы для инструкции. Индексы регистров уходят вSignal Dispatcher,imm/offsetзначения вDataPath - Индекс из
LookUpTableуходит вIRоперанды вOR - Значение из
IRуходит вMPC. По нему из памяти микрокоманд достается микропрограмма Signal Dispatcherотправляет управляющие сигналы микропрограммы вDataPath
Сигналы:
latch_ir- защелкнуть значение вIRlatch_mpc- защелкнуть значение вMPCsel_mpc_inc- селектор инкрементаmpc(mpc + 1, mpc + 2). Нужен для Branch-Type команд, которые зависят от флаговNZsel_mpc- выбрать следующее значение дляmpc(mpc inc,LookUpTableIndex fromIR, 0)
Выполнение микропрограмм происходит в функции dispatchSignal. Цикл декодирования инструкций происходит в функции
decodeInstruction.
cat- печатать данные, поданные через вводcat_macro- печатать данные, поданные через ввод. В алгоритме присутствует примера макросаdwrod_mul- умножение двух чисел, не помещающихся в 32-битную сеткуhello- вывести hello worldhello_user_name- Запросить у пользователя его имя, считать его, вывести на экран приветствиеprob2- Найти разность между квадратом суммы и суммой квадратов первых ста натуральных чиселsort- Пользователь загружает в систему список чисел, который выводится в отсортированном формате
- Тестирование осуществляется при помощи golden test-ов
- Модуль запускающий тестирование находится в goldentest
- Конфигурации тестов находятся в директории testdata
- Запустить тесты:
cd /goldentest
go test -v
Составляющие тест-кейса на примере программы prob2
in_src: |-
; Найти разность между квадратом суммы и суммой квадратов первых ста натуральных чисел.
.org 2
.data
in_addr: 0
out_addr: 1
limit: 46340 ; его квадрат суммы максимально занимает 32 бита
.code
lui t2, %hi(in_addr)
addi t2, t2, %lo(in_addr)
lw t2, t2, 0
...
mem_dump: |
<memory> - <address> - <HEXCODE> - <mnemonic>/<value_dec>>
Таблицы символов (адресация по словам):
Память данных:
in_addr: 2
limit: 4
out_addr: 3
Память команд:
calc: 19
end: 22
loop: 13
--------------------------------------------------------
dataMem 2: 0 0
dataMem 3: 1 1
dataMem 4: B504 46340
progMem 0: 08600000 lui t2, 0
progMem 1: 40646002 addi t2, t2, 2
progMem 2: 40626000 lw t2, t2, 0
progMem 3: 08500000 lui t1, 0
progMem 4: 40545003 addi t1, t1, 3
progMem 5: 40525000 lw t1, t1, 0
progMem 6: 08300000 lui bp, 0
...
out_code: |
000000000000600801000000026064400200000000606240030000000000500804000000035054400500000000505240060000000000300807000000043034400800000000303240090000000060c2400a0000000060c2400b0000008ac106100c000000017075410d000000057607100e00000081dbd2800f000000817b45801000000001e2e280110000000170754112000000faff0f041300000081d6d4801400000002d7f280150000008057022016000000fffffb41
out_data: |
020000000000000003000000010000000400000004b50000
in: |
100
stdout: |
Stop Reason: HALT
Instructions executed: 618
Microprograms executed: 14014
Output decimal: [25164150]
Output hex: 17FF976
log: |
...in_src- исходный код программы на разработанном языкеmem_dump- дамп памяти после трансляцииout_code- содержимое бинарного файла\<program name\>_code.binout_data- содержимое бинарного файла\<program name\>_data.binin- строка на ввод процессораstdout- вывод работы процессораlog- журнал выполнения
Пример тестирования:
go test -v
=== RUN TestPrograms
=== RUN TestPrograms/cat
=== RUN TestPrograms/cat_macro
=== RUN TestPrograms/dword_mul
=== RUN TestPrograms/hello
=== RUN TestPrograms/hello_user_name
=== RUN TestPrograms/prob2
=== RUN TestPrograms/sort
--- PASS: TestPrograms (0.37s)
--- PASS: TestPrograms/cat (0.05s)
--- PASS: TestPrograms/cat_macro (0.04s)
--- PASS: TestPrograms/dword_mul (0.04s)
--- PASS: TestPrograms/hello (0.07s)
--- PASS: TestPrograms/hello_user_name (0.06s)
--- PASS: TestPrograms/prob2 (0.06s)
--- PASS: TestPrograms/sort (0.05s)
PASS
ok goldentest 0.558s
translator.exe <input_file> <target_code_file> <target_data_file>
machine.exe <compiled_code> <compiled_data> Optional(<input_file>)


