12:08
Реализация процессора LIS — Лисья нора
§ Код ядра
Ядро было начало в 2020, а закончено 11.09.2025. Как долго я его... ждал, чтобы сделать за 5 часов./* verilator lint_off WIDTHTRUNC */ /* verilator lint_off WIDTHEXPAND */ /* verilator lint_off CASEINCOMPLETE */ module core ( input clock, input reset_n, input ce, // Программа ---------------------------- output [31:0] A, // Указатель на память input [ 7:0] I, // Входящие данные из памяти output reg [ 7:0] O, // Исходящние данные output reg W, // Сигнал на запись // Регистры A, B ------------------------ output reg [ 7:0] Ap, // Адрес A input [31:0] Ai, // Значение A output reg [31:0] Ao, // Значение на запись output reg Aw, // Запись A output reg [ 7:0] Bp, // Адрес B input [31:0] Bi, // Значение B // Стек --------------------------------- output reg [ 7:0] Sp, // Значение стека input [31:0] Si, // Чтение output reg [31:0] So, // Запись output reg Sw // Сигнал записи ); // Флаги localparam OF=3, SF=2, ZF=1, CF=0; // Остановка выполнения инструкции `define TERM begin cp <= 0; t <= 0; end `define OP20 opcode[2:0] assign A = cp ? ap : pc; // ----------------------------------------------------------------------------- reg cp; // Указатель на память программ=0 или данных=1 reg [31:0] pc, ap; // Программный счетчик и адрес в памяти (данные) reg [31:0] ax, bx, cx; // Перемещение памяти reg [ 3:0] flags; // Флаги OSZC reg [ 7:0] opcache; // Сохранение в кеш опкода reg [ 4:0] t; // Фаза выполнения инструкции // ----------------------------------------------------------------------------- wire [ 7:0] opcode = t ? opcache : I; wire [31:0] pcn = pc + 1; wire [31:0] apn = ap + 1; wire [31:0] sign = {{24{I[7]}}, I}; // ----------------------------------------------------------------------------- wire [32:0] Aluo = `OP20 == 3'h0 ? Ai + Bi : `OP20 == 3'h1 ? Ai + Bi + flags[CF] : `OP20 == 3'h3 ? Ai - Bi - flags[CF] : `OP20 == 3'h4 ? Ai & Bi: `OP20 == 3'h5 ? Ai ^ Bi: `OP20 == 3'h6 ? Ai | Bi: Ai - Bi; // SUB, CMP // Расчет переполнения результата при вычислении wire is_add = opcode[2:1] == 2'b00; wire overflow = (Ai[31] ^ Bi[31] ^ is_add) & (Ai[31] ^ Aluo[31]); // Вычисление конечных флагов wire [ 3:0] Aluf = {overflow, Aluo[31], Aluo[31:0] == 0, Aluo[32]}; wire [ 7:0] cond = { (flags[SF] ^ flags[OF]) | flags[ZF], flags[SF] ^ flags[OF], flags[SF], flags[CF] & flags[ZF], flags[ZF], flags[CF], 2'b00 }; // ----------------------------------------------------------------------------- // Инструкции, которые не имеют цикличности wire rr_nocycle = opcode[2:1] == 2'b01 || opcode[2:0] == 3'h7; // Выбор источника для сдвига wire [66:0] rr_in = `OP20 == 3'h0 ? {flags[CF], Ai[31:0], Ai[31:0]} : // ROL `OP20 == 3'h1 ? {Ai[31:0], Ai[31:0], flags[CF]} : // ROR `OP20 == 3'h2 ? {flags[CF], Ai[31:0]} : // SHL << `OP20 == 3'h3 ? {Ai[31:0], flags[CF]} : // SHR >> `OP20 == 3'h4 ? {flags[CF], Ai[31:0], flags[CF], Ai[31:0]} : // RCL `OP20 == 3'h5 ? {Ai[31:0], flags[CF], Ai[31:0], flags[CF]} : // RCR `OP20 == 3'h7 ? {{33{Ai[31]}}, Ai[31:0], flags[CF]} : 0; // SAR // 0..31|32 wire [ 5:0] rr_sh = Bi[31:5] && rr_nocycle ? 33 : Bi[4:0]; // Сдвиг налево или направо wire [66:0] rr_lf = rr_in << rr_sh; wire [66:0] rr_rt = rr_in >> rr_sh; // Результаты сдвига wire [31:0] rr_rs = `OP20 == 3'h0 ? rr_lf[63:32] : // ROL `OP20 == 3'h2 ? rr_lf[31:0] : // SHL `OP20 == 3'h4 ? rr_lf[64:33] : // RCL rr_rt[32:1]; // ROR, SHR, SAR, RCR // Результаты вычисления флага CF wire rr_cf = `OP20 == 3'h0 ? rr_lf[64] : // ROL `OP20 == 3'h2 ? rr_lf[32] : // SHL `OP20 == 3'h4 ? rr_lf[66] : // RCL rr_rt[0]; // ROR, SHR, SAR, RCR // ----------------------------------------------------------------------------- wire [63:0] mul = Ai * Bi; wire [32:0] div = bx - Bi; wire [31:0] est = div[32] ? bx : div; // ----------------------------------------------------------------------------- always @(posedge clock) // Сброс процессора if (reset_n == 1'b0) begin pc <= 0; Sp <= 0; {cp, t} <= 0; // OSZC flags <= 4'b0001; end // Активация else if (ce) begin W <= 1'b0; Aw <= 1'b0; Sw <= 1'b0; t <= t + 1; // Зафиксировать опкод if (t == 0) begin opcache <= I; pc <= pcn; end // Выполнение инструкции case (opcode) // [6T] MOV A, u32 :: 00 AA IMM32 8'h00: case (t) 1: begin pc <= pcn; Ap <= I; end 2,3,4: begin pc <= pcn; Ao <= {I, Ao[31:8]}; end 5: begin pc <= pcn; Ao <= {I, Ao[31:8]}; Aw <= 1; t <= 0; end endcase // [3T] MOV A, B :: 01 BB AA 8'h01: case (t) 1: begin pc <= pcn; Bp <= I; end 2: begin pc <= pcn; Ap <= I; Ao <= Bi; Aw <= 1; t <= 0; end endcase // [3T] MOV A, u8/s8 :: 02 AA ** 8'h02, 8'h03: case (t) 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Ao <= opcode[0] ? sign : I; Aw <= 1; t <= 0; end endcase // 4T MOVB A,[B] :: 04 BB AA // 5T MOVW A,[B] :: 05 BB AA // 6T MOVD A,[B] :: 06 BB AA 8'h04, 8'h05, 8'h06: case (t) 1: begin pc <= pcn; Bp <= I; end 2: begin pc <= pcn; Ap <= I; ap <= Bi; cp <= 1; end 3: begin Ao <= I; ap <= apn; if (opcode == 8'h04) begin Aw <= 1; `TERM; end end 4: begin Ao[15:8] <= I; ap <= apn; if (opcode == 8'h05) begin Aw <= 1; `TERM; end end 5: begin Ao[23:16] <= I; ap <= apn; end 6: begin Ao[31:24] <= I; Aw <= 1; cp <= 0; t <= 0; end endcase // 5T MOVB [A],B :: 07 BB AA // 6T MOVW [A],B :: 08 BB AA // 8T MOVD [A],B :: 09 BB AA 8'h07, 8'h08, 8'h09: case (t) 1: begin pc <= pcn; Bp <= I; end 2: begin pc <= pcn; Ap <= I; ap <= Bi; end 3: begin O <= Ai[ 7:0]; W <= 1; cp <= 1; end 4: begin O <= Ai[15:8]; W <= (opcode != 8'h07); ap <= apn; if (opcode == 8'h07) `TERM end 5: begin O <= Ai[23:16]; W <= (opcode != 8'h08); ap <= apn; if (opcode == 8'h08) `TERM end 6: begin O <= Ai[31:24]; W <= 1; ap <= apn; end 7: begin t <= 0; cp <= 0; end endcase // 6T+2T*C :: COPY A,B,C 8'h0A: case (t) // Загрузка значений регистров 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Ap <= I; ax <= Ai; end 3: begin pc <= pcn; Ap <= I; bx <= Ai; end 4: begin cx <= Ai; cp <= 1; end // Чтение-запись (2T) 5: begin ap <= ax; W <= 0; ax <= ax + 1; if (cx == 0) `TERM; end 6: begin ap <= bx; W <= 1; bx <= bx + 1; O <= I; cx <= cx - 1; t <= 5; end endcase // 5T :: MUL умножение 8'h0B: case (t) 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Bp <= I; end // Запись младшего результата 3: begin Aw <= 1; Ao <= mul[ 31:0]; ax <= mul[63:32]; flags[ZF] <= mul[31:0] ? 0 : 1; flags[SF] <= mul[31]; end // Запись старшего результата 4: begin Aw <= 1; Ao <= ax; Ap <= Bp; flags[OF] <= mul[63:32] ? 1 : 0; t <= 0; end endcase // 32+4 :: DIV беззнаковое деление 8'h0C: case (t) 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Bp <= I; ax <= Ai; bx <= 0; cx <= 32; end 3: begin if (cx == 0) begin Ap <= Bp; Bp <= Ap; Ao <= est; Aw <= 1; end ax <= {ax[30:0], ~div[32]}; bx <= {est[30:0], ax[31]}; cx <= cx - 1; t <= cx ? 3 : 4; end // Результат доступен здесь, на последнем такте 4: begin Ap <= Bp; Ao <= ax; Aw <= 1; t <= 0; end endcase // 4T :: *ALU* AA BB :: Арифметическое Логическое Устройство 8'h10, 8'h11, 8'h12, 8'h13, 8'h14, 8'h15, 8'h16, 8'h17: case (t) 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Bp <= I; end 3: begin Ao <= Aluo[31:0]; Aw <= `OP20 != 7; flags <= Aluf; t <= 0; end endcase // 4T :: Инструкции сдвига 8'h18, 8'h19, 8'h1A, 8'h1B, 8'h1C, 8'h1D, 8'h1F: case (t) 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Bp <= I; end 3: begin Ao <= rr_rs; Aw <= 1; flags <= {flags[OF], rr_rs[31], rr_rs[31:0] == 0, rr_cf}; t <= 0; end endcase // 3T :: 1E AA s8 :: INC A, s8 8'h1E: case (t) 1: begin pc <= pcn; Ap <= I; end 2: begin pc <= pcn; Ao <= Ai + sign; Aw <= 1; t <= 0; end endcase // 2T Безусловные переходы 8'h20: case (t) 1: begin pc <= pcn + sign; t <= 0; end endcase // 3T Переход на 16 бит 8'h21: case (t) 1: begin pc <= pcn; ax <= I; end 2: begin pc <= pcn + {{16{I[7]}}, I, ax[7:0]}; t <= 0; end endcase // 5T Абсолютный переход на 32х битный 8'h22: case (t) 1,2,3: begin pc <= pcn; ax <= {I, ax[31:8]}; end 4: begin pc <= {I, ax[31:8]}; t <= 0; end endcase // 3T Косвенный переход по значению указанного регистра 8'h23: case (t) 1: begin Ap <= I; end 2: begin pc <= Ai; t <= 0; end endcase // 1T / 2T Условный переход 8'h24, 8'h25, 8'h26, 8'h27, 8'h28, 8'h29, 8'h2A, 8'h2B, 8'h2C, 8'h2D, 8'h2E, 8'h2F: case (t) 0: begin if (cond[ opcode[3:1] ] == opcode[0]) begin pc <= pcn + 1; t <= 0; end end 1: begin pc <= pcn + sign; t <= 0; end endcase // 4T + n :: PUSH r=(0..255) ... 8'h30: case (t) 1: begin pc <= pcn; cx <= I; end 2: begin pc <= pcn; Ap <= I; end 3: begin t <= cx ? 3 : 0; pc <= cx ? pcn : pc; Sp <= Sp - 1; Sw <= 1; So <= Ai; Ap <= I; cx <= cx - 1; end endcase // 3T + n :: POP r=(0..255) ... 8'h31: case (t) 1: begin pc <= pcn; cx <= I; end 2: begin t <= cx ? 2 : 0; pc <= pcn; Ap <= I; Ao <= Si; Aw <= 1; Sp <= Sp + 1; cx <= cx - 1; end endcase // 5T CALL u32 8'h32: case (t) 1,2,3: begin pc <= pcn; ax <= {I, ax[31:8]}; end 4: begin pc <= {I, ax[31:8]}; So <= pcn; Sw <= 1; Sp <= Sp - 1; t <= 0; end endcase // 3T CALL A 8'h33: case (t) 1: begin Ap <= I; end 2: begin pc <= Ai; So <= pcn; Sw <= 1; Sp <= Sp - 1; t <= 0; end endcase // 1T RET 8'h34: begin pc <= Si; Sp <= Sp + 1; t <= 0; end endcase end endmodule