BNF:
<program> ::= <EOF> | <section_list> <EOF>
<section_list> ::= <section> <section_list> | <section>
<section> ::= "section" <identifier> <line_list>
<line_list> ::= <line> <line_list> | <line>
<line> ::= <line_not_empty> | <line_not_empty> <EOL> | <EOL>
<line_not_empty> ::= <line_instruction> <comment> | <line_instruction> | <comment> | <section>
<line_instruction> ::= <label_decl> <instruction> | <label_decl> | <instruction>
<label_decl> ::= <label> ":"
<label> ::= <identifier>
<identifier> ::= <letter> | <letter> <letter_or_digit_list>
<comment> ::= ";" <char_not_eol_list>
<instruction> ::= <no_arg_instr> | <one_arg_instr>
<no_arg_instr> ::= <no_arg_op>
<one_arg_instr> ::= <one_arg_op> <operand>
<operand> ::= <indirect_operand> | <direct_operand>
<direct_operand> ::= <label> | <immediate>
<indirect_operand> ::= "[" <direct_operand> "]"
<immediate> ::= <int_lit> | <char_lit>
<int_lit> ::= <digit_list> | "-" <digit_list>
<digit_list> ::= <digit> <digit_list> | <digit>
<char_lit> ::= "'" <letter> "'" | "'" <digit> "'"
<letter_or_digit_list> ::= <letter_or_digit> | <letter_or_digit> <letter_or_digit_list>
<letter_or_digit> ::= <letter> | <digit>
<char_not_eol_list> ::= <letter_digit_space> | <letter_digit_space> <char_not_eol_list>
<letter_digit_space> ::= <letter> | <space>
<space> ::= " " | "\t"
<letter> ::= [a-z] | [A-Z]
<digit> ::= [0-9]
<EOF> ::= "1A"
<EOL> ::= "\n"
<no_arg_op> ::= "inc" | "dec" | "itoc" | "ctoi" | "halt"
<one_arg_op> ::= "add" | "sub" | "div" | "mod" | "mul" | "ld" | "st" | "cmp" | "je" | "jne" | "js" | "jmp" | "in" | "out"
section <name>
- создать секцию с именем<name>
. Данные внутри секций идут последовательно..text
- секция для кода.data
- секция для данных
label:
- метка (для выполнения иструкций перехода)._start:
- обязательная метка, сигнализирующая начало программы, может находиться где угодно, главное чтобы указывала на инструкцию.- На одни и те же инструкции (команды и данные) могут быть указаны несколько меток, однако метки не могут дублироваться, и одни и те же метки указывать на разные инструкции.
- Область видимости глобальная.
inc
- инкрементировать значения в аккумуляторе.
Instruction | Description |
---|---|
inc |
AC := AC + 1 |
dec
- декрементировать значение в аккумуляторе.
Instruction | Description |
---|---|
dec |
AC := AC - 1 |
itoc
- перевести integer в код символа ASCII.
Instruction | Description |
---|---|
itoc |
AC := AC + ord('0') |
ctoi
- перевести код символа ASCII в integer.
Instruction | Description |
---|---|
itoc |
AC := AC - ord('0') |
add
- сложить значение в аккумуляторе с операндом.
Instruction | Description |
---|---|
add m32 |
AC := AC + m32 |
add imm32 |
AC := AC + imm32 |
sub
- вычесть значение в аккумуляторе с операндом.
Instruction | Description |
---|---|
sub m32 |
AC := AC - m32 |
sub imm32 |
AC := AC - imm32 |
div
- беззнаковое деление.
Instruction | Description |
---|---|
div m32 |
AC := AC / m32 |
div imm32 |
AC := AC / imm32 |
mod
- остаток от беззнакового деления.
Instruction | Description |
---|---|
mod m32 |
AC := AC % m32 |
mod imm32 |
AC := AC % imm32 |
mul
- беззнаковое умножение.
Instruction | Description |
---|---|
mul m32 |
AC := AC * m32 |
mul imm32 |
AC := AC * imm32 |
ld
- загрузить значение в аккумулятор (флаги не выставляются).
Instruction | Description |
---|---|
ld m32 |
AC := m32 |
ld imm32 |
AC := imm32 |
st
- загрузить значение в ячейку из аккумулятора.
Instruction | Description |
---|---|
st imm32 |
*imm32 := AC |
cmp
- сравнить числа. Работает какsub
, однако значение в аккумуляторе не модифицируется.
Instruction | Description |
---|---|
cmp m32 |
AC - m32 |
cmp imm32 |
AC - imm32 |
je
- переход, если равно.
Instruction | Description |
---|---|
je imm32 |
Jump if equals |
jne
- переход, если не равно.
Instruction | Description |
---|---|
jne imm32 |
jb
- переход, если знак (отрицательное число).
Instruction | Description |
---|---|
jb imm32 |
jbe
- переход, если не знак.
Instruction | Description |
---|---|
jbe imm32 |
jg
- переход, если знак (отрицательное число).
Instruction | Description |
---|---|
jg imm32 |
jge
- переход, если не знак.
Instruction | Description |
---|---|
jge imm32 |
jmp
- безусловный переход.
Instruction | Description |
---|---|
jmp imm32 |
in
- считать байт с порта в младший байт аккумулятора.
Instruction | Description |
---|---|
in imm32 |
imm32 - номер порта |
out
- записать младший байт аккумулятора на порт.
Instruction | Description |
---|---|
out imm32 |
imm32 - номер порта |
halt
- остановка программы.
Instruction | Description |
---|---|
halt |
m32
- адрес в памяти, из которого мы берем значение. Здесь можно использовать метки, в отличие от обычногоasm
в данной ЛР они имеют абсолютный адрес. Синтаксически на asm:
cmd [label] ; [label] - m32
cmd label ; label - imm32
cmd - команда
imm32
- неизменяемое число, будь то константа или адрес метки, который может быть получен во время генерации кода.
; здесь комментарий
- однострочный комментарий до конца строки
cmd/var: <int_lit>
- команда с аргументом или переменная с целочисленным значениемcmd/var: '<char_lit>'
- символ ASCII. Поддерживаются управляющие символы\n
,\q
,\r
,\t
.
- Не реализованы, но и не требовалось.
Модель памяти процессора (фон-Неймана):
-
Память команд и данных. Машинное слово -- 32 бит, знаковое. Линейное адресное пространство. Реализуется списком чисел и инструкций, идущих друг за другом с интервалом в 32 бита.
-
Отдельного разделения на память команд и данных нет. При попытке исполнения инструкции переменной программа падает на исключении.
-
Scope в языке глобальный, вся память является статической.
-
Размер машинного слова - 32 бит. Адресация абсолютная, поскольку нет ограничения на размер регистра из-за представления struct.
-
Структура памяти однородная, так как port-mapped. Запись на порт осуществляется посредством отдельных команд.
-
Пользователю доступен только аккумуляторный регистр.
- Память отображается модулем, генерирующим код, статически. Инструкции не перемешиваются. Пробелов между инструкциями нет. Каждая инструкция занимает 1 машинное слово.
Memory (for data and instructions)
+-----------------------------+
| ... |
| 0x00: var1 | <- var_label: value1
| 0x20: cmd1 | <- cmd1: args
| 0x40: cmd2 | w- cmd2: args
| 0x60: var2 | w- var_label: value2
| ... |
+-----------------------------+
Особенности процессора:
-
Машинное слово -- 32 бит, знаковое.
-
Память данных и команд:
- Адресуется через регистр data_register, program_counter.
- Может быть записана из аккумулятора.
- Может быть прочитана в регистр data_register или instruction_register.
-
Ввод-вывод - port-mapped. Осуществляется посредством взаимодействия с accumulator. Номер порта - контанта.
-
Program_counter - счетчик команд. Инкрементируется с каждой инструкцией, может быть перезаписан командой перехода.
-
Tick_counter - счетчик номера такта с начала обработки инструкции.
-
Инструкции обрабатываются последовательно друг за другом. У каждой иструкции есть этапы
FETCH
,DECODE
,EXECUTE
. -
Прерываний нет.
-
Машина поддерживает только абсолютную адресацию.
-
Присутствуют флаги Z (zero), N (neg) для команд перехода.
-
Комментарии по командам выше. Одинаковые команды имеют разный опкод в зависимости от принимаемых аргументов. Аргументы бывают
Indirect
,Direct
. -
Реализуется в модуле isa.
Syntax | Mnemonic | Кол-во тактов | Comment |
---|---|---|---|
inc |
inc |
3 | - |
dec |
dec |
3 | - |
itoc |
itoc |
3 | - |
ctoi |
ctoi |
3 | - |
add <m32> |
add_m |
4 | - |
add <imm32> |
add_imm |
3 | - |
sub <m32> |
sub_m |
4 | - |
sub <imm32> |
sub_imm |
3 | - |
div <m32> |
div_m |
4 | - |
div <imm32> |
div_imm |
3 | - |
mod <m32> |
mod_m |
4 | - |
mod <imm32> |
mod_imm |
3 | - |
mul <m32> |
mul_m |
4 | - |
mul <imm32> |
mul_imm |
3 | - |
ld <m32> |
ld_m |
4 | - |
ld <imm32> |
ld_imm |
3 | - |
st <m32> |
st_imm |
3 | - |
cmp <m32> |
cmp_m |
4 | - |
cmp <imm32> |
cmp_imm |
3 | - |
je <imm32> |
je |
3 | - |
jne <imm32> |
jne |
3 | - |
jb <imm32> |
js |
3 | - |
jbe <imm32> |
js |
3 | - |
jg <imm32> |
js |
3 | - |
jge <imm32> |
js |
3 | - |
jmp <imm32> |
jmp |
3 | - |
in <imm32> |
in_imm |
3 | - |
out <imm32> |
out_imm |
3 | - |
halt |
halt |
3 | - |
- Примечание: лишний такт для некоторых команд, работающих с прямыми адресами, наблюдается из-за декодирования операндов инструкции.
FETCH
- 1 тактDECODE
- 1 или более тактовEXECUTE
- 1 или более тактов (условимся что 1 на все операции, дажеdiv
,mul
)
- Машинный код сериализуется в список JSON.
- Один элемент списка, одна инструкция.
- Адрес инструкции -- индекс списка +
base_address
. Используется для команд перехода и выбора следующей инструкции.
Пример:
- Variable:
{
"address": 0,
"value": 2
}
- Instruction:
{
"address": 608,
"args": [
64
],
"opcode": "st_imm"
}
где:
address
- адрес, по которому в памяти расположена данная инструкция;value
- значение переменной;args
- аргументы команды, соответствующие opcode;opcode
- код операции;
Все команды десериализуются в class Instruction
, определенный в модуле isa.
-
Интерфейс командной строки:
translator.py <input_file> <target_file>
-
Реализовано в модуле: translator.
-
Этапы трансляции (функция translate):
- Токенизирование: преобразование исходного кода в последовательность лексем (
LexerNode
). - Парсинг: на основании токенов строится дерево AST. Парсер умеет бросать ошибки и намекать, в чем проблема, в случае невалидных исходников (
class Parser
). - Проверка дерева, сгенерированного парсером, на соответствие аргументов инструкций и наличия самих инструкций в словаре
ISACommands
, типа инструкций в соответствующих секциях (так в секции.data
нельзя определить команду), проверка границ чисел. - Генерация машинного кода на основании дерева AST парсера.
- Токенизирование: преобразование исходного кода в последовательность лексем (
-
Парсер и лексер реализуют обработку исходных кодов в соответствие с
ebnf
; -
Один символ языка -- одна инструкция;
-
Инструкции и их аргументы прямо отображаются на опкод.
[
{
"ltype": "EOL",
"off": 18,
"raw": "\n"
},
{
"ltype": "Identifier",
"off": 19,
"raw": "_start"
},
{
"ltype": "Syntax",
"off": 25,
"raw": ":"
},
{
"ltype": "EOF",
"off": 26,
"raw": null
}
]
{
"type": "Program",
"sections": [
{
"type": "Section",
"value": ".text",
"instructions": [
{
"type": "Command",
"labels": [
"_start"
],
"cmd": "ld",
"args": [
{
"type": "DirectArgument",
"value": 0
}
]
},
{
"type": "Command",
"labels": [
".loop"
],
"cmd": "in",
"args": [
{
"type": "DirectArgument",
"value": 0
}
]
},
{
"type": "Command",
"labels": [],
"cmd": "out",
"args": [
{
"type": "DirectArgument",
"value": 1
}
]
},
{
"type": "Command",
"labels": [],
"cmd": "jmp",
"args": [
{
"type": "DirectArgument",
"value": ".loop"
}
]
}
]
}
]
}
Exception: Parser
{
"type": "Error",
"context": "Program",
"childs": [
{
"type": "Error",
"context": "Section",
"childs": [
{
"type": "Error",
"context": "Keyword",
"message": "Got Identifier",
"lexem": {
"ltype": "Identifier",
"off": 19,
"raw": "_start"
}
}
]
}
]
}
Реализована в machine.
+---------------------------------+
cdev cdev | |
^ ^ (+1) +---+ |
| | | +--------+ | |<---+
+-------+ +---------------+--+----| PC |<------|MUX|
+->| IMUX | dr_out o | | +--------+ | |<---o
| +-------+ ^ | | +---+ dr_out
| ^ +--------+ | | +-----------+ ^
| out | +--->| AC | | | addr +-------------+ | |
+--|---->[ ] | +--------+ +----+----->| | | +-------+
| | | | | | data_in | | ==(0) |
| | +----------------------+------------|---------->| | | +--------+ |
| | cdev cdev | | | | MEM | oe | | | |
| | | | | | | | |<---+ v v | |
| | v v +-----+ | +--------+ | | wr | +-----+ | |
| | +-------+ | MUX |<-+ | | DR |<----+ | |<-+ | | MUX |<-----|----+ |
| +->| MUX | +-----+ | | +--------+ | | | | | +-----+ | | |
| | +-------+ ^ ^ | | | | | | | | | | | |
| | | | | | | | | +-------------+ | | v | | |
| | | | | | v v | | | | +--------+ | | |
| | +-[ ]-----+ | | +-----+-------+ +---+ | | | | TC | | | |
| | in^ | | | ALU / FLAGS | | |<----------+ | | +--------+ | | |
| | | | | +-----+-------+ |MUX| | | | | | | |
| | | | | | | | |<--+ | | | | | | |
| | | | | | | +---+ | | | | +----(+1)-+ | |
| | | +----------+ | ^ | v | | | | |
| | | | | | | +---------+ | | | tc_latch/sel| |
| | | | | | | | IR | | | | +------+ |
| |io_sel | | | | | +---------+ | | | | |
| | | ac_latch/sel| | | | | | | | | +-------+
| | | | v dr_latch/sel| | v | | v | | pc_latch/sel
+-------------------------------------------------------------------------------------------------------+
| |
| Instruction Decoder and Dispatcher |
| |
+-------------------------------------------------------------------------------------------------------+
Реализована в классе DataPath. Отдельно выделен класс Alu, являющийся арифметико-логическое устройство.
MEM (memory) - основная память.
- data_in - входные данные, которые мы хотим записать.
- addr - адрес, с которого хотим прочитать или куда хотим записать.
- oe - чтение.
- wr - запись.
DR (data_register) - регистр данных. Предназначен для косвенных операций. Также в него пишется прямой аргумент, чтобы не вести отдельную линию к аккумулятору.
- dr_latch/sel - выбор линии мультиплексора, захват значения, результат в начале следующего такта.
AC - аккумуляторный регистр.
- ac_latch/sel - выбор линии мультиплексора, захват значения, результат в начале следующего такта.
ALU/FLAGS - объединенная на схеме структура.
- ALU - арифметико-логическое устройство.
- FLAGS - флаги. N (neg) - после выполнения операции с АЛУ результат отрицательный, Z (zero) - после выполнения 0.
IO - ввод вывод.
- cdev - порты к символьным устройствам ввода-вывода, которые принимают за раз машинное слово. На схеме отделены порты ввода и порты вывода.
- io_sel - выбор линии, куда производится запись.
- in - сигнализирует чтение.
- out - сигнализирует запись.
- Выставление in и out сразу - неопределенное поведение.
Прочее:
- IMUX - Inverse Multiplexor.
- MUX - Multiplexor.
Реализован в классе ControlUnit.
- Hardwired.
- Моделируется на уровне тактов.
Instruction Decoder and Dispatcher - декодировщик инструкций и установщик сигналов.
- При выполнении очередного такта выставляет значения на линии.
IR (instruction_register) - регистр инструкций, в которой хранится текущая выполняемая инструкция.
TC (tick_counter) - счетчик тиков с начала выполнения инструкции.
- tc_latch/sel - выбор линии, захват значения до начала следующего такта.
PC (program_counter) - счетчик инструкций.
- pc_latch/sel - выбор линии, захват значения до начала следующего такта.
- dr_out - выходящее значение с регистра данных для установки в PC.
- Для журнала состояния используется стандартный модуль logging.
- Текущее состояние (
RUNNABLE
,HALTED
) - отражает в каком состоянии сейчас находится машина. - При выполнении инструкции
halt
машина переходит в состояниеHALTED
. - При выполнении исключительной ситуации бросается
Exception
. - Управление симуляцией реализовано в функции
Simulate
.
Реализованы в test/integrational_test.py
.
Алгоритмы, на которых производится тестирование:
- cat
- hello
- prob2 with user input
$ cat cat.asm
section .text
_start:
ld 0
.loop:
in 0 ; read from port 0
cmp 0
je end
out 1
jmp .loop
end:
halt
$ cat cat_in-foo
{
"0": {
"in": [
"foo",
0
]
},
"1": {
"out": []
}
}
$ ./machine.py cases/cat cases/cat_in-foo cases/cat_out
DEBUG:root:TICK: 0, PC: 0, TC: -1, DP: { AC: -1, DR: -1, FLG: { Z: 0, N: 0 } }, IR: {'address': -1, 'opcode': None, 'args': None, 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 1, PC: 0, TC: -1, DP: { AC: -1, DR: -1, FLG: { Z: 0, N: 0 } }, IR: {'address': 0, 'opcode': ld_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 2, PC: 32, TC: 0, DP: { AC: -1, DR: -1, FLG: { Z: 0, N: 0 } }, IR: {'address': 0, 'opcode': ld_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 3, PC: 32, TC: 1, DP: { AC: -1, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 0, 'opcode': ld_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 4, PC: 32, TC: 1, DP: { AC: 0, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 5, PC: 64, TC: 0, DP: { AC: 0, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[0].in >> 102 ('f')
DEBUG:root:TICK: 6, PC: 64, TC: 1, DP: { AC: 0, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 7, PC: 64, TC: 1, DP: { AC: 102, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 8, PC: 96, TC: 0, DP: { AC: 102, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 9, PC: 96, TC: 1, DP: { AC: 102, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 10, PC: 96, TC: 1, DP: { AC: 102, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 11, PC: 128, TC: 0, DP: { AC: 102, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 12, PC: 128, TC: 1, DP: { AC: 102, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 13, PC: 128, TC: 1, DP: { AC: 102, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 14, PC: 160, TC: 0, DP: { AC: 102, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[1].out << 102 ('f')
DEBUG:root:TICK: 15, PC: 160, TC: 1, DP: { AC: 102, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 16, PC: 160, TC: 1, DP: { AC: 102, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 17, PC: 192, TC: 0, DP: { AC: 102, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 18, PC: 192, TC: 1, DP: { AC: 102, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 19, PC: 32, TC: 1, DP: { AC: 102, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 20, PC: 64, TC: 0, DP: { AC: 102, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[0].in >> 111 ('o')
DEBUG:root:TICK: 21, PC: 64, TC: 1, DP: { AC: 102, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 22, PC: 64, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 23, PC: 96, TC: 0, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 24, PC: 96, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 25, PC: 96, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 26, PC: 128, TC: 0, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 27, PC: 128, TC: 1, DP: { AC: 111, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 28, PC: 128, TC: 1, DP: { AC: 111, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 29, PC: 160, TC: 0, DP: { AC: 111, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[1].out << 111 ('o')
DEBUG:root:TICK: 30, PC: 160, TC: 1, DP: { AC: 111, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 31, PC: 160, TC: 1, DP: { AC: 111, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 32, PC: 192, TC: 0, DP: { AC: 111, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 33, PC: 192, TC: 1, DP: { AC: 111, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 34, PC: 32, TC: 1, DP: { AC: 111, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 35, PC: 64, TC: 0, DP: { AC: 111, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[0].in >> 111 ('o')
DEBUG:root:TICK: 36, PC: 64, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 37, PC: 64, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 38, PC: 96, TC: 0, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 39, PC: 96, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 40, PC: 96, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 41, PC: 128, TC: 0, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 42, PC: 128, TC: 1, DP: { AC: 111, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 43, PC: 128, TC: 1, DP: { AC: 111, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 44, PC: 160, TC: 0, DP: { AC: 111, DR: 192, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[1].out << 111 ('o')
DEBUG:root:TICK: 45, PC: 160, TC: 1, DP: { AC: 111, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 128, 'opcode': out_imm, 'args': [1], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 46, PC: 160, TC: 1, DP: { AC: 111, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 47, PC: 192, TC: 0, DP: { AC: 111, DR: 1, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 48, PC: 192, TC: 1, DP: { AC: 111, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 160, 'opcode': jmp, 'args': [32], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 49, PC: 32, TC: 1, DP: { AC: 111, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 50, PC: 64, TC: 0, DP: { AC: 111, DR: 32, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:ports[0].in >> 0 ('')
DEBUG:root:TICK: 51, PC: 64, TC: 1, DP: { AC: 111, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 32, 'opcode': in_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 52, PC: 64, TC: 1, DP: { AC: 0, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 53, PC: 96, TC: 0, DP: { AC: 0, DR: 0, FLG: { Z: 0, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 54, PC: 96, TC: 1, DP: { AC: 0, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 64, 'opcode': cmp_imm, 'args': [0], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 55, PC: 96, TC: 1, DP: { AC: 0, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 56, PC: 128, TC: 0, DP: { AC: 0, DR: 0, FLG: { Z: 1, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 57, PC: 128, TC: 1, DP: { AC: 0, DR: 192, FLG: { Z: 1, N: 0 } }, IR: {'address': 96, 'opcode': je, 'args': [192], 'value': None}, STAGE: Stage.FETCH, STAT: Status.RUNNABLE
DEBUG:root:TICK: 58, PC: 192, TC: 1, DP: { AC: 0, DR: 192, FLG: { Z: 1, N: 0 } }, IR: {'address': 192, 'opcode': halt, 'args': [], 'value': None}, STAGE: Stage.DECODE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 59, PC: 224, TC: 0, DP: { AC: 0, DR: 192, FLG: { Z: 1, N: 0 } }, IR: {'address': 192, 'opcode': halt, 'args': [], 'value': None}, STAGE: Stage.EXECUTE, STAT: Status.RUNNABLE
DEBUG:root:TICK: 60, PC: 224, TC: 1, DP: { AC: 0, DR: 192, FLG: { Z: 1, N: 0 } }, IR: {'address': 192, 'opcode': halt, 'args': [], 'value': None}, STAGE: Stage.FETCH, STAT: Status.HALTED
DEBUG:root:Operations count: 60
Для каждого модуля по файлу с модульными тестами.
coverage
-- формирование отчёта об уровне покрытия исходного кода.pytest
-- утилита для запуска тестов.pep8
-- утилита для проверки форматирования кода.E501
(длина строк) отключено, но не следует этим злоупотреблять.pylint
,mypy
-- утилиты для проверки качества кода. Некоторые правила отключены в отдельных модулях с целью упрощения кода.black
-- форматирование текста.
Docker:
- Gitlab
python-tools
- выделенный image. Включает в себя все перечисленные утилиты. - Github
ca-lab3:rlatest
. Конфигурация: Dockerfile
ФИО | алг. | LoC | code байт | code инстр. | инстр. | такт. | вариант |
---|---|---|---|---|---|---|---|
Кулаков Никита Васильевич | cat | 11 | 683 | 7 | 20 | 60 | `asm |
Кулаков Никита Васильевич | hello | 28 | 2621 | 27 | 27 | 81 | `asm |
Кулаков Никита Васильевич | prob2 | 58 | 5057 | 56 | 644 | 2163 | `asm |
- LoC считаю чистыми, то есть удаляя комментарии и ставя метки в одну строчку с командами.