§ Программа на 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