CPU0-Mini 處理器

CPU0-Mini 是 CPU0 的陽春版。

CPU0 有 36 個指令,如果實作成 Verilog 會有點大,不容易理解其設計理念,因此我們從 CPU0 中抽出 4 個指令,以形成一顆更簡單的 CPU,稱為 CPU0-Mini。

CPU0-Mini 實作的指令有 「LD, ST, ADD, JMP」等四個,已經可以用來寫一些非常簡單的小程式,以下是一個 CPU0-Mini 的程式範例。

0000          LD   R2, K0         L  0 002F000C
0004          LD   R1, K1         L  0 001F000C
0008 LOOP:                          FF
0008          ADD  R2, R2, R1     A 13 13221000
000C          JMP  LOOP           J 26 26FFFFF8
0010 K0:      WORD 0              D F2 00000000
0014 K1:      WORD 1              D F2 00000001
0018 SUM:     WORD 0              D F2 00000000

CPU0-Mini 的 Verilog 程式碼:computer0m.v

module computer0m(input clock, reset, output [31:0] pc, 
             output [2:0] tick, output [31:0] ir,
                 output [31:0] mar, output [31:0] mdr,
                 inout [31:0] dbus, output m_en, m_rw, 
                 output [7:0] op, output signed [23:0] addr24);

cpu0m cpu (.clock(clock), .reset(reset), .pc(pc), .tick(tick), .ir(ir), 
.mar(mar), .mdr(mdr), .dbus(dbus), .m_en(m_en), .m_rw(m_rw), 
.op(op), .addr24(addr24));

memory0m mem (.clock(clock), .reset(reset), .en(m_en), .rw(m_rw), 
.abus(mar), .dbus_in(dbus), .dbus_out(dbus));

endmodule         

module cpu0m(input clock, reset, output reg [31:0] pc, 
             output reg [2:0] tick, output reg [31:0] ir,
                 output reg [31:0] mar, output reg [31:0] mdr,
                 inout [31:0] dbus, output reg m_en, m_rw,
                 output reg [7:0] op, output reg signed [23:0] addr24);
   reg signed [31:0] addr32;
    reg [3:0] ra, rb;
    reg [15:0] cx;
    reg [31:0] R [0:15];

    `define PC R[15]

    always @(posedge clock) begin
        if (reset) begin
            `PC = 0;
            tick = 0;
            m_en = 1;
          end
        else begin
            tick = tick+1;
            case (tick)
            // 指令擷取階段 Tick 1..3 : memory.read(m[PC])
                1:    begin  // Tick 1:將 PC 丟到位址匯流排上
                    mar = `PC; // MAR = PC
                    m_rw = 1; // m_rw=1 is read mode, read(m[MAR]) => read(m[PC])
                    `PC = `PC+4; // PC = PC + 4
                end
                2:    begin  // Tick 2:將 PC 丟到位址匯流排上
                    mdr = dbus;
                    ir = mdr; // IR = dbus = m[PC]
                    op = ir[31:24];
                    addr24 = ir[23:0];
                    ra = ir[23:20];
                    rb = ir[19:16];
                    cx = ir[15:0];
                end
                3:    begin  // Tick 3:將 PC 丟到位址匯流排上
                end
            // 指令執行階段 Tick 4..6 : execute(IR)
                4:    begin  // Tick 4:將 PC 丟到位址匯流排上
                    case (op) // 解讀 OP: Tick 4
                        8'h00: begin // 指令:LD ra, rb, cx ; 語意:R[ra] = R[rb+cx]
                            m_rw = 1; // 讀取模式:read 
                            mar = R[rb] + cx; // mar = 讀取位址 = R[rb]+cx
                        end
                        8'h01: begin // 指令:ST ra, rb, cx ; 語意:R[ra] = R[rb+cx]
                            m_rw = 0; // 寫入模式:write
                            mar = R[rb] + cx;  // 寫入位址 = R[rb]+cx
                            mdr = R[ra]; // 寫入資料:R[ra]
                        end
                        8'h26: begin // 指令:JMP cx ; 語意:PC = PC+cx
                            addr32 = addr24; // 取出 cx 並轉為 32 位元有號數
                            `PC = `PC+addr32; // 跳躍目標位址=PC+cx
                        end
                        default:    begin
                        end
                    endcase
                end
                5:    begin // 解讀 OP: Tick 5
                    case (op) // LD ra, rb, cx ; R[ra] = R[rb+cx] ; mdr = R[rb+cx]
                        8'h00: begin
                            mdr = dbus;
                            R[ra] = mdr;
                        end
                        8'h26: begin
                        end
                        default:    begin
                        end
                    endcase
                end
                6:    begin
                    tick = 0;
                end
                default:    begin
                end
            endcase
        end
        pc = `PC;
    end
endmodule

module memory0m(input clock, reset, en, rw, 
            input [31:0] abus, input [31:0] dbus_in, output [31:0] dbus_out);
reg [7:0] m [0:128];
reg [31:0] data;

    always @(clock or reset or abus or en or rw or dbus_in) 
    begin
        if (reset == 1) begin
            {m[0],m[1],m[2],m[3]}     = 32'h002F000C; // 0000:        LD   R2, K0
            {m[4],m[5],m[6],m[7]}     = 32'h001F000C; // 0004:        LD   R1, K1
            {m[8],m[9],m[10],m[11]}   = 32'h13221000; //         LOOP: 
            {m[12],m[13],m[14],m[15]} = 32'h26FFFFF8; // 0008:        ADD  R2, R2, R1
            {m[16],m[17],m[18],m[19]} = 32'h00000000; // 000C:        JMP  LOOP
            {m[20],m[21],m[22],m[23]} = 32'h00000001; // 0010: K0:  WORD 0
            {m[24],m[25],m[26],m[27]} = 32'h00000000; // 0014: K1:  WORD 1
            data = 32'hZZZZZZZZ;                             // 0018: SUM: WORD 0
        end else if (abus >=0 && abus < 128) begin
            if (en == 1 && rw == 0) begin // r_w==0:write
                data = dbus_in;
                {m[abus], m[abus+1], m[abus+2], m[abus+3]} = dbus_in;
            end
            else if (en == 1 && rw == 1) // r_w==1:read
                data = {m[abus], m[abus+1], m[abus+2], m[abus+3]};
            else
                data = 32'hZZZZZZZZ;
        end else
            data = 32'hZZZZZZZZ;
    end
    assign dbus_out = data;
endmodule

CPU0-Mini 的測試程式:computer0mTest.v

`timescale 1ns/10ps

module computer0mTest;
reg clock;
reg reset;
wire [2:0] tick;
wire [31:0] pc;
wire [31:0] ir;
wire [31:0] mar;
wire [31:0] mdr;
wire [31:0] dbus;
wire m_en, m_rw;
wire [7:0] op;
wire [23:0] addr24;

computer0m DUT (.clock(clock), .reset(reset), .pc(pc), .tick(tick), .ir(ir), 
.mar(mar), .mdr(mdr), .dbus(dbus), .m_en(m_en), .m_rw(m_rw), 
.op(op), .addr24(addr24));

initial
begin
  clock = 0;
  reset = 1;
end

initial #100 reset = 0;

always #50 clock=clock+1;

endmodule
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License