§ Код ядра

Ядро было начало в 2020, а закончено 9 фев 2025. Как долго я его... ждал, чтобы сделать за 5 часов.
История версии
  • Версия 16.02.2025, добавлены инструкции FINT, FLD для преобразования чисел в Int32 < — > Float32
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off CASEINCOMPLETE */

module core
(
    input               CLK,
    input               RST_N,
    input               ENA,
    output              DBG,
    // Программа ------------------------
    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;

assign A    = cp ? ap : pc;
assign DBG  = (t == 0);

// ---------------------------------------------------------------------
reg             cp;
reg     [31:0]  pc, ap, si, di, cx;
reg     [ 3:0]  flags;
reg     [ 7:0]  opcache;
reg     [ 2:0]  alu;
reg     [ 4:0]  t;
// ---------------------------------------------------------------------
wire    [ 7:0]  opcode  = t ? opcache : I;
wire    [31:0]  pcn     = pc + 1;
wire    [31:0]  apn     = ap + 1;
wire            cf      = flags[CF];
wire            zf      = flags[ZF];
wire            sf      = flags[SF];
wire            of      = flags[OF];
wire    [ 7:0]  cond    = {zf | (sf ^ of), (sf ^ of), 1'b0, sf, (cf | zf), zf, cf, 1'b0};
wire    [63:0]  mul     = Ai * Bi;
wire            mulf    = {|mul[63:32], mul[31], mul == 0, flags[CF]};
wire    [31:0]  diva    = {si[30:0], di[31]};
wire    [32:0]  divb    = diva - Bi;
wire    [63:0]  divc    = {divb[32] ? diva : divb[31:0], di[30:0], ~divb[32]};

// Вычисление значения АЛУ
// ---------------------------------------------------------------------
wire    [32:0]  Ri =
    alu == 0 ? Ai + Bi :
    alu == 1 ? Ai + Bi + flags[CF] :
    alu == 3 ? Ai - Bi - flags[CF] :
    alu == 4 ? Ai & Bi :
    alu == 5 ? Ai ^ Bi :
    alu == 6 ? Ai | Bi : Ai - Bi;

// Результат отфлаговывания
wire        add_i = alu == 0 || alu == 1;
wire        lgc_i = alu == 4 || alu == 5 || alu == 6;
wire        flg_o = (Ai[31] ^ Bi[31] ^ add_i) & (Ai[31] ^ Ri[31]);

// Знаковое сложение
wire [31:0] S8  = {{24{I[7]}}, I};
wire [32:0] As  = Ai + S8;
wire        Aso = (Ai[31] ^ I[7] ^ 1) & (Ai[31] ^ As[31]);

// Общая функция вычисления флагов после выполнения АЛУ
wire [3:0]  Rf = {lgc_i ? flags[OF] : flg_o, Ri[31], Ri[31:0] == 0, lgc_i ? cf : Ri[32]};

// Сдвиговые инструкции
// ---------------------------------------------------------------------
wire [ 5:0] mxr = (Bi[31:5] ? 32 : Bi[4:0]);
wire [64:0] rol = {cf, Ai, Ai}      << Bi[4:0];
wire [64:0] ror = {Ai, Ai, cf}      >> Bi[4:0];
wire [32:0] shl = {Ai}              << mxr;
wire [32:0] shr = {Ai, cf}          >> mxr;
wire [65:0] rcl = {cf, Ai, cf, Ai}  << Bi[4:0];
wire [65:0] rcr = {Ai, cf, Ai, cf}  >> Bi[4:0];
wire [64:0] sar = {{32{Ai[31]}}, Ai, cf} >> mxr;

// Результат сдвига
wire [31:0] rrr =
    alu == 0 ? rol[63:32] : alu == 1 ? ror[ 32:1] :
    alu == 2 ? shl[ 31:0] : alu == 3 ? shr[ 32:1] :
    alu == 4 ? rcl[64:33] : alu == 5 ? rcr[ 32:1] : sar[ 32:1];

// Значение флага C после сдвига
wire rrc =
    alu == 0 ? rol[64] : alu == 1 ? ror[0] :
    alu == 2 ? shl[32] : alu == 3 ? shr[0] :
    alu == 4 ? rcl[32] : alu == 5 ? rcr[0] : sar[0];

// Float Point Unit
// ---------------------------------------------------------------------

// Определить количество лидирующих нулей
wire [31:0] fldsv = Ai[31] ? -Ai : Ai;
wire [ 4:0] fldsx = {|fldsv[31:16], |flds0[31:24], |flds1[31:28], |flds2[31:30], flds3[31]};

// Передвинуть влево на количество бит 16,8,4,2,1
wire [31:0] flds0 = fldsx[4] ? fldsv : {fldsv[15:0], 16'b0};
wire [31:0] flds1 = fldsx[3] ? flds0 : {flds0[23:0], 8'b0};
wire [31:0] flds2 = fldsx[2] ? flds1 : {flds1[27:0], 4'b0};
wire [31:0] flds3 = fldsx[1] ? flds2 : {flds2[29:0], 2'b0};
wire [31:0] flds4 = fldsx[0] ? flds3 : {flds3[30:0], 1'b0};
wire [ 7:0] fldp  = 127 + fldsx;
wire [ 7:0] filp  = Ai[30:23] - 127;

// Преобразование числа int в float
wire [31:0] fld = fldsv ? {Ai[31], fldp[7:0], flds4[30:8]} : 32'b0;

// Из float -> integer
wire [53:0] fildt = filp < 30 ? {1'b1, Ai[22:0]} << filp : (filp[7] ? 0 : 31'h7FFFFFFF);
wire [31:0] fild  = Ai[31] ? -fildt[53:23] : fildt[53:23];

// ---------------------------------------------------------------------
always @(posedge CLK)
// Сброс процессора
if (RST_N == 1'b0) begin pc <= 0; Sp <= 0; {cp,t} <= 0; flags <= 4'b0000; end
// Активация
else if (ENA) begin

    Aw <= 0;
    Sw <= 0;
    W  <= 0;
    t  <= t + 1;

    // Защелкивание опкода
    if (t == 0) begin opcache <= I; pc <= pcn; end

    case (opcode)

        // [6T] MOV A, u32 -- загрузка 32х битного значения в регистр
        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 -- скопировать 32х битный регистр B -> A
        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

        // [4T] MOVB A, [B] -- получение BYTE из памяти
        // [5T] MOVW A, [B] -- получение WORD из памяти
        // [7T] MOVD A, [B] -- получение DWORD из памяти
        8'h02, 8'h03, 8'h04: case (t)

            1: begin pc <= pcn; Bp <= I; end
            2: begin pc <= pcn; Ap <= I; ap <= Bi; cp <= 1; end
            3: begin Ao[ 31:0] <= I; Aw <= 1; ap <= apn; if (opcode == 2) {t,cp} <= 0; end
            4: begin Ao[ 15:8] <= I; Aw <= 1; ap <= apn; if (opcode == 3) {t,cp} <= 0; end
            5: begin Ao[23:16] <= I; Aw <= 1; ap <= apn; end
            6: begin Ao[31:24] <= I; Aw <= 1; cp <= 0; t <= 0; end

        endcase

        // [5T] MOVB [A], B -- сохранение BYTE в память
        // [6T] MOVW [A], B -- сохранение WORD в память
        // [8T] MOVD [A], B -- сохранение DWORD в память
        8'h05, 8'h06, 8'h07: case (t)

            1: begin pc <= pcn; Bp <= I; end
            2: begin pc <= pcn; Ap <= I; end
            3: begin ap <= Ai;  O  <= Bi[7:0];   W <= 1; cp <= 1; end
            4: begin ap <= apn; O  <= Bi[15:8];  W <= 1; if (opcode == 5) {t,cp,W} <= 0; end
            5: begin ap <= apn; O  <= Bi[23:16]; W <= 1; if (opcode == 6) {t,cp,W} <= 0; end
            6: begin ap <= apn; O  <= Bi[31:24]; W <= 1; end
            7: begin cp <= 0; t <= 0; end

        endcase

        // [3T] MOVU A,u8
        // [3T] MOVS A,s8
        8'h08, 8'h09: case (t)

            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Ao <= opcode == 9 ? {{24{I[7]}}, I} : I; Aw <= 1; t <= 0; end

        endcase

        // 5T+2C MOVS S,D,C -- блочное копирование памяти
        8'h1E: case (t)

            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Bp <= I; si <= Ai; end
            3: begin pc <= pcn; Bp <= I; di <= Bi; end
            4: begin cx <= Bi;  cp <= 1; end

            // Запрос чтения и запрос записи
            5: begin ap <= si; si <= si + 1; if (cx == 0) {t,cp} <= 0; end
            6: begin ap <= di; di <= di + 1; cx <= cx - 1; O <= I; W <= 1; t <= 5; end

        endcase

        // [5T] MUL A,B => H,L -- Умножение
        8'h0A: case (t)

            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Bp <= I; end
            3: begin pc <= pcn; Ap <= I; Aw <= 1; Ao <= mul[63:32]; di <= mul[31:0]; flags <= mulf; end
            4: begin pc <= pcn; Ap <= I; Aw <= 1; Ao <= di; t <= 0; end

        endcase

        // [36T] DIV A,B => H,L -- Деление
        8'h0B: case (t)

            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Bp <= I; end
            3: begin pc <= pcn; cx <= 31; {si, di} <= {32'b0, Ai}; end
            4: begin {si, di} <= divc; cx <= cx - 1; t <= cx ? 4 : 5; end
            5: begin pc <= pcn; Ap <= I; Ao <= si; Aw <= 1; end
            6: begin Aw <= 1;   Ap <= I; Ao <= di; t  <= 0; end

        endcase

        // [5T] CALL u32 -- вызов процедуры
        8'h0C: case (t)

            1,2,3: begin ap <= {I, ap[31:8]}; pc <= pcn; end
            4:     begin pc <= {I, ap[31:8]}; Sp <= Sp - 1; So <= pcn; Sw <= 1; t <= 0; end

        endcase

        // [1T] RET -- возврат из процедуры
        8'h0D: case (t)

            0: begin pc <= Si; Sp <= Sp + 1; t <= 0; end

        endcase

        // [4T+n] PUSH n regs -- запись в стек потока регистров, n=0 это 1 регистр
        8'h0E: case (t)

            1: begin pc <= pcn; cx <= I; end
            2: begin pc <= pcn; Ap <= I; end // Предзагрузка значения
            3: begin pc <= cx ? pcn : pc; Ap <= I; Sw <= 1; So <= Ai; Sp <= Sp - 1; cx <= cx - 1; t <= cx ? 3 : 0; end

        endcase

        // [3T+n] POP n regs -- чтение из стека потока регистров
        8'h0F: case (t)

            1: begin pc <= pcn; cx <= I; end
            2: begin pc <= pcn; Ap <= I; Aw <= 1; Ao <= Si; Sp <= Sp + 1; cx <= cx - 1; t <= cx ? 2 : 0; end

        endcase

        // [4T] (ADD|ADC|SUB|SBC|AND|XOR|OR) A,B,C
        8'h10, 8'h11, 8'h12, 8'h13,
        8'h14, 8'h15, 8'h16: case (t)

            1: begin pc <= pcn; Ap <= I; alu <= opcode[2:0]; end
            2: begin pc <= pcn; Bp <= I; end
            3: begin pc <= pcn; Ap <= I; Ao <= Ri; Aw <= 1; flags <= Rf; t <= 0; end

        endcase

        // [3T] ADDS A,s8
        8'h2B: case (t)

            1: begin pc <= pcn; Ap <= I; alu <= 0; end
            2: begin pc <= pcn; Ao <= As; Aw <= 1; flags <= {Aso, As[31], As[31:0] == 0, As[32]}; t <= 0; end

        endcase

        // [4T] (ROL|ROR|SHL|SHR|RCL|RCR|SAR) A,B
        8'h18, 8'h19, 8'h1A, 8'h1B,
        8'h1C, 8'h1D, 8'h1F: case (t)

            0: begin alu <= opcode[2:0]; end
            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Bp <= I; end
            3: begin Ao <= rrr; Aw <= 1; flags <= {flags[OF], rrr[31], rrr == 0, rrc}; t <= 0; end

        endcase

        // [2T] JR b8
        8'h20: case (t)

            1: begin pc <= pcn + S8; t <= 0; end

        endcase

        // [5T] JMP u32
        8'h21: case (t)

            1,2,3: begin pc <= pcn; ap <= {I, ap[31:8]}; end
            4:     begin pc <= {I, ap[31:8]}; t <= 0; end

        endcase

        // [3T] JMP AA
        8'h2A: case (t)

            1: begin Ap <= I; pc <= pcn; end
            2: begin pc <= Ai; t <= 0; end

        endcase

        // [1/2T] JUMP COND b8
        8'h22, 8'h23, // JC,  JNC
        8'h24, 8'h25, // JZ,  JNZ
        8'h26, 8'h27, // JBE, JA
        8'h28, 8'h29, // JS,  JNS
        8'h2C, 8'h2D, // JL,  JNL
        8'h2E, 8'h2F: // JLE, JG
        case (t)

            0: if (cond[opcode[3:1]] == opcode[0])
               begin pc <= pcn + 1;  t <= 0; end
            1: begin pc <= pcn + S8; t <= 0; end

        endcase

        // [4T] (ADD|ADC|SUB|SBC|AND|XOR|OR|CMP) A,B
        8'h30, 8'h31, 8'h32, 8'h33,
        8'h34, 8'h35, 8'h36, 8'h37: case (t)

            0: begin alu <= opcode[2:0]; end
            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Bp <= I; end
            3: begin Ao <= Ri;  Aw <= ~&alu; flags <= Rf; t <= 0; end

        endcase

        // [3T] 3C FINT A,B -- преобразование числа FLOAT -> INT
        // [3T] 3D FLD A,B  -- преобразование числа INT -> FLOAT
        8'h3C, 8'h3D: case (t)

            1: begin pc <= pcn; Ap <= I; end
            2: begin pc <= pcn; Ap <= I; Aw <= 1; Ao <= opcode == 8'h3D ? fld : fild; t <= 0; end

        endcase

    endcase

end

endmodule