§ Программа на Verilog
Здесь будут коды процессора.Ревизия #5 :: 17 авг 2024 + INC, DEC d
Ревизия #6 :: 20 авг 2024 + ROR d,u; ROR d,i
/* verilator lint_off WIDTHTRUNC */ /* verilator lint_off WIDTHEXPAND */ /* verilator lint_off CASEX */ /* verilator lint_off CASEINCOMPLETE */ module core ( input clock, // Тактовая частота 25 мгц input reset_n, // Сброс процессора input ce, // ChipEnabled output [7:0] address, // Адрес input [7:0] in, // Данные output reg [7:0] wb, // Что писать в память или регистр output reg we, // Запрос записи в память output reg rr // Запрос чтения из памяти ); assign address = mm ? cp : pc; localparam ADD = 2'b00, SUB = 2'b01, AND = 2'b10, XOR = 2'b11, TST = 2'b00, ORI = 2'b01; // Список всех регистров // --------------------------------------------------------------------- reg [1:0] t; reg mm, rw; reg [1:0] rn; // Номер регистра для записи reg [7:0] opc, pc, cp; // Опкод, Program Counter, Current Pointer reg [7:0] a = 8'h71, b = 8'h23, x = 8'h52, y = 8'hAF; reg zf = 1'b0, // Флаг нуля cf = 1'b0; // Флаг переноса // Предвычисления // --------------------------------------------------------------------- wire [7:0] opcode = t ? opc : in; wire [7:0] pcn = pc + 1; // Именование проводов wire [1:0] dst = opcode[1:0], src = opcode[3:2], o54 = opcode[5:4]; wire o0 = opcode[0], o1 = opcode[1], o2 = opcode[2], o3 = opcode[3], o4 = opcode[4], o5 = opcode[5], o7 = opcode[7]; // Регистр слева wire [7:0] rd = dst == 2'b00 ? a : dst == 2'b01 ? b : dst == 2'b10 ? x : y; wire [7:0] rs = src == 2'b00 ? a : src == 2'b01 ? b : src == 2'b10 ? x : y; wire [8:0] alu = o54 == ADD ? (rd + rs) : o54 == SUB ? (rd - rs) : o54 == AND ? (rd & rs) : (rd ^ rs); wire [8:0] asb = src == ADD ? (rd + in) : rd - in; wire [7:0] lgc = src == ORI ? (rd | in) : src == XOR ? (rd ^ in) : (rd & in); wire [8:0] inc = o2 ? rd - 1 : rd + 1; // ROR d,s :: ROR d,u wire [16:0] ror = {rd, rd, rd[0]} >> (o7 ? in[2:0] : rs[2:0]); // --------------------------------------------------------------------- always @(posedge clock) if (reset_n == 1'b0) begin t <= 0; pc <= 0; mm <= 0; rw <= 0; rr <= 0; end // Исполнение опкодов else if (ce) begin we <= 0; rw <= 0; rr <= 0; rn <= dst; // Сохранить опкод if (t == 0) opc <= in; casex (opcode) // 1T 00 MOV d, s // 2T 01 MOV d, [s] // 3T 10 MOV [d], s // 3T 11 MOV [d], [s] 8'b00xx_xxxx: case (t) 0: begin t <= |o54; // Если есть обращение к памяти mm <= |o54; // То установить указатель rw <= o54 == 0; // Если нет памяти, то регистр S => D rr <= o4; // Запрос чтения из памяти cp <= rs; // Указатель на чтение из памяти wb <= rs; // Либо запись в регистр, если RW=1 pc <= pcn; end 1: begin t <= o5 ? 2 : 0; // Запись и убрать MM wb <= o4 ? in : rs; // Что писать mm <= o5; // Убрать mm, если в регистр we <= o5; // Либо в память rw <= !o5; // Запись в регистр cp <= rd; // И куда писать в память end 2: begin t <= 0; mm <= 0; end endcase // 2T 00 MOV d,u // 3T 01 MOV d,[u] // 4T 10 MOV [d],u // 4T 11 MOV [d],[u] 8'b0100_xxxx: case (t) 0: begin t <= o2 ? 1 : 2; pc <= pcn; end 1: begin t <= 2; mm <= 1; cp <= in; rr <= 1; end 2: begin t <= src ? 3 : 0; // Выбрана память rw <= !o3; // Запись в регистр mm <= o3; // Выбрать cp, если есть запись we <= o3; // Или запись в память wb <= in; // Что писать cp <= rd; // Запись в [d] pc <= pcn; end 3: begin t <= 0; mm <= 0; end endcase // 3T 0 MOV [u],d // 4T 1 MOV [u],[d] 8'b0101_1xxx: case (t) 0: begin t <= o2 ? 1 : 2; pc <= pcn; end 1: begin t <= 2; mm <= 1; cp <= rd; wb <= in; rr <= 1; end 2: begin t <= 3; mm <= 1; we <= 1; wb <= o2 ? in : rd; // [d] или d cp <= o2 ? wb : in; // [u] pc <= pcn; end 3: begin t <= 0; mm <= 0; end endcase // 2T ADD d, u // 2T CMP d, u 8'b0101_0xxx: case (t) 0: begin t <= 1; pc <= pcn; end 1: begin t <= 0; pc <= pcn; rw <= !o2; wb <= asb; {cf, zf} <= {asb[8], asb[7:0] == 0}; end endcase // 1T ROR d, s 8'b0110_xxxx: begin rw <= 1; // Запись в регистр pc <= pcn; wb <= ror[8:1]; // Результат сдвига zf <= ror[8:1] == 0; // Если 0 cf <= ror[0]; // Есть перенос end // 2T TST, ORI, AND, XOR d, u 8'b0111_xxxx: case (t) 0: begin t <= 1; pc <= pcn; end 1: begin t <= 0; pc <= pcn; rw <= |src; // Пишется все, кроме TST wb <= lgc; zf <= lgc == 0; cf <= lgc[7]; // Копировать знак => CF end endcase // 1T ADD, SUB, AND, XOR 8'b10xx_xxxx: begin rw <= 1; pc <= pcn; wb <= alu; // Записать результат в регистр cf <= alu[o5 ? 7 : 8]; // Логические копируют 7й бит zf <= alu[7:0] == 0; // Всем проставлять ZF end // 2T Jcc u // 2T JMP u // 2T JMP d, u 8'b1100_00xx, 8'b1100_1000, 8'b1100_11xx: case (t) 0: begin t <= 1; pc <= pcn; end 1: begin t <= 0; pc <= ((o1 ? zf : cf) == o0) || o3 ? in : pcn; rw <= &src; wb <= pcn; end endcase // 1T JMP d 8'b1100_01xx: begin pc <= rd; end // CLC, CMC 8'b1100_1010: begin cf <= cf & 0; end 8'b1100_1011: begin cf <= cf ^ 1; end // 1T INC|DEC d 8'b1101_0xxx: begin pc <= pcn; rw <= 1; wb <= inc[7:0]; cf <= inc[8]; zf <= inc[7:0] == 0; end // 2T ROR d,u // 3T ROR d,[u] 8'b1101_10xx: case (t) 0: begin t <= o2 ? 1 : 2; pc <= pcn; end 1: begin t <= 2; mm <= 1; cp <= in; end 2: begin t <= 0; rw <= 1; pc <= pcn; wb <= ror[8:1]; zf <= ror[8:1] == 0; cf <= ror[0]; end endcase endcase end // Запись в регистры always @(negedge clock) begin if (rw) case (rn) 2'b00: a <= wb; 2'b01: b <= wb; 2'b10: x <= wb; 2'b11: y <= wb; endcase end endmodule