Оглавление
§ Инструкции MOV
Пожалуй, самой простой инструкцией, которую я могу считать после NOP, это MOV. Ее сделать легко, поскольку потребуется лишь скопировать с одного в другой источник данные. К тому же, достаточно простым кодом можно сразу же охватить все 64 MOV. Ниже представлен этот код.18'b01xx_xxxx: case (t) 2 3 0: begin cp <= hl; sw <= 1; if (m53 && m20) pc <= pc; end 4 1: begin 5 6 n <= opc[5:3]; 7 b <= !m53; 8 we <= m53; 9 d <= op20; 10 out <= op20; 11 12 end 13 4: begin sw <= 0; t <= (m53 || m20) ? 5 : 0; end 14 6: begin t <= 0; end 15 16endcaseЭтот код охватывает даже HALT, останов процессора. На проводе m53 появляется 1 тогда, когда в качестве операнда приемника (слева) указана память. Аналогично с m20, но указана память из операнда источника (справа). Если указаны и операнд приемник, и источник как память, то процессор останавливает свое выполнение в том плане, что не двигается никуда PC и он постоянно читает из HL байт и пишет обратно байт в HL.
На такте #1 классическая схема записи в регистр или память — все зависит от того, какой будет приемник. Если m53=1, то есть, приемник это память, то we=1, b=0, и op2 (через out) записывается в память. Если же там регистр, то он выбирается в
n
и туда записывается d
(8 бит).На такте #4 выбирается количество тактом. В случае если либо в операнде приемнике, либо в источнике указана память, то такая инструкция будет 7Т исполняться, иначе 5Т.
§ Арифметико-логическое устройство
Это ядро, можно даже сказать, сердце процессора. Именно обращение к инструкциям перемещения данных и работы с ними, обработки, занимают большую часть всей программы. Обычно именно по этой причине модули АЛУ греются в процессорах больше, так как количество переходов состояния из 0 в 1 и наоборот здесь наиболее частое.Всего 8 инструкции АЛУ:
-
ADD (ADI)
— сложение A + операнд -
ADC (ACI)
— сложение A + операнд + CarryFlag -
SUB (SUI)
— вычитание A - операнд -
SBB (SBI), CMP (CPI)
— вычитание A - операнд - CarryFlag -
AND (ANA, ANI)
— побитовое A & операнд -
XOR (XRA, XRI)
— побитовое A ^ операнд -
OR (ORA, ORI)
— побитовое A | операнд
Отличие инструкции SUB от CMP в том, что результат не записывается для CMP, но флаги пишутся для обоих. Составим небольшой код, по сути, являющийся мультиплексором на 8 входов.
1wire [8:0] alur = 2 opc[5:3] == ADD ? a + op20 : // ADD 3 opc[5:3] == ADC ? a + op20 + psw[CF] : // ADC 4 opc[5:3] == SBB ? a - op20 - psw[CF] : // SBB 5 opc[5:3] == AND ? a & op20 : // ANA 6 opc[5:3] == XOR ? a ^ op20 : // XRA 7 opc[5:3] == OR ? a | op20 : // ORA 8 a - op20; // SUB|CMPВ зависимости от выбранного
opc[5:3]
(ALU MODE), будет записана определенная операция в alur. Основное вычисление производится именно здесь. Теперь необходимо рассчитать флаги.1wire sf = alur[7]; 2wire zf = alur[7:0] == 0; 3wire hf = a[4] ^ op20[4] ^ alur[4]; 4wire af = (a[4] | op20[4]) & (opc[5:3] == AND); 5wire pf = ~^alur[7:0]; 6wire cf = alur[8];Объяснение флагов.
- Флаг SF просто копирует бит 7 из результата alur
- ZF проверяет наличие 0 на младших 8 битах результата
- HF высчитывает полуперенос по стандартной формуле перексоривания 4-го бита результата и операнда
- Флаг AF здесь стоит особняком. Для XOR, OR логических операторов результат в HF=0, кроме AND, где результат будет равен битовому OR между 4-м битом двух операндов. Я не знаю, зачем это там было сделано.
- Флаг PF вычисляется обычно и означает четность
- CF просто копирует бит 8 из результат (заем или перенос)
1localparam 2 CF = 0, PF = 2, HF = 4, ZF = 6, SF = 7; 3 4localparam 5 ADD = 0, ADC = 1, SUB = 2, SBB = 3, 6 AND = 4, XOR = 5, OR = 6, CMP = 7;И последний штрих, это вычисление флагов по результату.
1wire [7:0] aluf = 2 opc[5:3] == AND || opc[5:3] == XOR || opc[5:3] == OR ? 3 {sf, zf, 1'b0, af, 1'b0, pf, 1'b1, 1'b0} : // AND, XOR, OR 4 {sf, zf, 1'b0, hf, 1'b0, pf, 1'b1, cf}; // ADD, ADC, SUB, SBB, CMPНа самом деле, тут только 2 случая. Если это логические операции (AND, XOR, OR), то вместо HF пишется AF, и в CF=0. Для арифметических операции (ADD, ADC, SUB, SBB, CMP), все флаги затронуты. Больше тут ничего не требуется.
Теперь перейдем к основной части, это к исполнению инструкции. На удивление, она довольно проста.
18'b10xx_xxxx: case (t) 2 3 0: begin cp <= hl; sw <= 1; end 4 1: begin d <= alur; b <= (opc[5:3] != CMP); n <= 7; psw <= aluf; end 5 4: begin sw <= 0; t <= m20 ? 5 : 0; end 6 6: begin t <= 0; end 7 8endcaseАлгоритм.
- Такт 0, по классике, выставляется указатель в памяти и переключается на него
- Такт 1, запись результата из alur в d, но запись в регистр A (n=7) производится только тогда, когда выбранная инструкция не CMP. Для флагов сохраняется всегда.
- Такт 4, если операнд был взят из памяти, то прибавляется +2Т к выполнению
Приложение к материалам