CPU0-Mini:10 個指令的版本

Verilog

基本語法

型態

全域變數

基本元件

多樣的寫法

指定

assign

always

initial

運算式

分枝

迴圈

模組

函數

Task

陣列

輸出入

觀察

真值表

測試程式

訊息顯示

注意事項

模擬程序

硬體工程

程式範例

Xor

Xor3

全加器

加法器

加減器

快速加法器

乘法器

ALU

閂鎖器

脈衝偵測

計數器

多工器

暫存器群

記憶體

延遲問題

浮點數

狀態機

程式計數器

CPU0-Mini

CPU0

pipeline

工具

QuartusII

Icarus

Veritek

訊息

相關網站

參考文獻

最新修改

簡體版

English

輸入指令檔:cpu0m10.hex

00 1F 00 24 // 0000       LD   R1, K1
00 2F 00 1C // 0004       LD   R2, K0
00 3F 00 20 // 0008       LD   R3, SUM
08 40 00 0A // 000C        LDI  R4, 10
13 22 10 00 // 0010 LOOP: ADD  R2, R2, R1
13 33 20 00 // 0014       ADD  R3, R3, R2
10 24 00 00 // 0018       CMP  R2, R4
21 FF FF F0 // 001C       JNE  LOOP
2C 00 00 00 // 0020       RET
00 00 00 00 // 0024 K0:   WORD 0
00 00 00 01 // 0028 K1:   WORD 1
00 00 00 00 // 002C SUM:  WORD 0

Verilog 程式:cpu0m10.v

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

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));

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

endmodule         

module cpu0m(input clock, reset, output reg [2:0] tick, 
             output reg [31:0] ir, pc, mar, mdr,
             inout [31:0] dbus, output reg m_en, m_rw);
    reg signed [31:0] R [0:15];
    reg [7:0] op;
    reg [3:0] ra, rb, rc;
    reg signed [11:0] cx12;
    reg signed [15:0] cx16;
    reg signed [23:0] cx24;
    reg signed [31:0] scx12, scx16, scx24, A, B, C, ipc; // ipc:instruction PC

    `define SW     R[12]
    `define SP     R[13]
    `define LR     R[14]
    `define PC   R[15]
    `define LD   8'h00
    `define ST   8'h01
    `define LDI  8'h08
    `define ADD  8'h13
    `define JMP  8'h26    
    `define JEQ  8'h20    
    `define JNE  8'h21
    `define CMP  8'h10
    `define CALL 8'h2B
    `define RET  8'h2C        
    `define N    `SW[31]
    `define Z    `SW[30]

    always @(posedge clock) begin
        if (reset) begin
            `PC = 0;
            tick = 0;
            R[0] = 0;
            `LR = -1;
          end
        else begin
            tick = tick+1;
            m_en = 0;
            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])
                    m_en = 1;
                    ipc  = `PC;
                    `PC = `PC+4; // PC = PC + 4
                end
                2:    begin  // Tick 2:ir = m[PC]
                    mdr = dbus;
                    ir = mdr; // IR = dbus = m[PC]
                    {op,ra,rb,rc,cx12} = ir;
                    cx24 = ir[23:0];
                    cx16 = ir[15:0];
                    scx12 = cx12; // 取出 cx12 並轉為 32 位元有號數
                    scx16 = cx16; // 取出 cx16 並轉為 32 位元有號數
                    scx24 = cx24; // 取出 cx24 並轉為 32 位元有號數
                end
                3:    begin  // Tick 3:取出暫存器 R[ra], R[rb], R[rc] 內容
                    m_en = 0;
                    A = R[ra];
                    B = R[rb];
                    C = R[rc];
                end
            // 指令執行階段 Tick 4..6 : execute(IR)
                4:    begin 
                    case (op) // 解讀 OP: Tick 4
                        `LD: begin // 指令:LD ra, rb, cx ; 語意:R[ra] = m[rb+cx]
                            mar = B + scx16; // mar = 讀取位址 = R[rb]+cx
                            m_rw = 1; // 讀取模式:read 
                            m_en = 1;
                        end
                        `ST: begin // 指令:ST ra, rb, cx ; 語意:m[rb+cx]=R[ra]
                            mar = B + scx16;  // 寫入位址 = R[rb]+cx
                            mdr = A; // 寫入資料:R[ra]
                            m_rw = 0; // 寫入模式:write
                            m_en = 1;
                        end
                        `ADD: begin // 指令:ADD ra, rb, rc ; 語意:R[ra]=R[rb]+R[rc]
                            R[ra] = B+C; // 執行加法
                        end
                        `JMP: begin // 指令:JMP cx ; 語意:PC = PC+cx
                            `PC = `PC+scx24; // 跳躍目標位址=PC+cx
                        end
                        `LDI: begin // 指令:LDI Ra, Rb+Cx; 語意:Ra=Rb+Cx
                            R[ra] = B+scx16;
                        end
                        `CMP: begin // 指令:CMP ra, rb ; 語意:SW=(Ra >=< Rb)
                            `N = (A-B < 0);
                            `Z = (A-B == 0);
                        end
                        `JEQ: begin // 指令:JEQ cx ; 語意:if SW(=) PC=PC+Cx
                            if (`Z) `PC = `PC+scx24; // 跳躍目標位址=PC+cx
                        end
                        `JNE: begin // 指令:JEQ cx ; 語意:if SW(=) PC=PC+Cx
                            if (`Z==1'b0) `PC = `PC+scx24; // 跳躍目標位址=PC+cx
                        end
                        `CALL: begin // 指令:CALL cx; 語意:LR=PC; PC=PC+Cx
                            `LR = `PC;
                            `PC = `PC + scx24;
                        end
                        `RET: begin // 指令:RET ; 語意:PC=LR
                            `PC = `LR;
                        end
                    endcase
                end
                5:    begin // 解讀 OP: Tick 5
                    case (op) // LD ra, rb, cx ; R[ra] = R[rb+cx] ; mdr = R[rb+cx]
                        `LD: begin // 指令:LD ra, rb, cx ; 語意:R[ra] = m[rb+cx]
                            mdr = dbus; // 取得記憶體傳回的 dbus = m[rb+cx]
                            R[ra] = mdr; // 存入到目標暫存器 R[ra] 中
                            m_en = 0; // 讀取完畢
                        end
                        `ST: begin // 指令:ST ra, rb, cx ; 語意:m[rb+cx]=R[ra]
                            m_en = 0; // 寫入完畢
                        end
                    endcase
                end                
                6:    begin
                    case (op) // 解讀 OP: Tick 6; 列印
                        `LD:  $display("%4dns %8x : LD  %2x,%2x,%4x; R[%x]=%4d", 
                                        $stime, ipc, ra, rb, cx16, ra, R[ra]);
                        `ST:  $display("%4dns %8x : ST  %2x,%2x,%4x; R[%x]=%4d", 
                                        $stime, ipc, ra, rb, cx16, ra, R[ra]);
                        `ADD: $display("%4dns %8x : ADD %2x,%2x,%4x; R[%x]=%4d, B=%4d, C=%4d", 
                                        $stime, ipc, ra, rb, rc, ra, R[ra], B, C);
                        `JMP: $display("%4dns %8x : JMP %10d; PC=%8x", 
                                        $stime, ipc, cx24, R[15]);
                        `LDI: $display("%4dns %8x : LDI %2x,%2x,%4x; R[%x]=%4d", 
                                        $stime, ipc, ra, rb, cx16, ra, R[ra]);
                        `CMP: $display("%4dns %8x : CMP %2x %2x; N=%b Z=%b", 
                                        $stime, ipc, ra, rb, `N, `Z);
                        `JEQ: $display("%4dns %8x : JEQ %10d; PC=%8x", 
                                        $stime, ipc, cx24, R[15]);
                        `JNE: $display("%4dns %8x : JNE %10d; PC=%8x", 
                                        $stime, ipc, cx24, R[15]);
                        `CALL:$display("%4dns %8x : CALL %10d; PC=%8x", 
                                        $stime, ipc, cx24, R[15]);
                        `RET: begin
                            $display("%4dns %8x : RET; PC=%8x", $stime, ipc, R[15]);
                            if (`PC < 0) begin
                                $display("RET to PC < 0, finished!");
                                $finish;
                            end                            
                        end
                    endcase
                    tick = 0;
                end
                default:    begin
                end
            endcase
        end
        pc = `PC;
    end
endmodule

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

initial begin
end
    always @(reset) 
    begin
        if (reset == 1) begin
            $readmemh("cpu0m10.hex", m);
            for (i=0; i < 128; i=i+4) begin
                if (m[i] !== 8'hx)
                    $display("%8x: %x", i, {m[i], m[i+1], m[i+2], m[i+3]});
            end
        end
    end

    always @(clock or abus or en or rw or dbus_in) 
    begin
        if (abus >=0 && abus < 125) 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

module main;
reg clock;
reg reset;
wire [2:0] tick;
wire [31:0] pc, ir, mar, mdr, dbus;
wire m_en, m_rw;

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));

initial
begin
  clock = 0;
  reset = 1;
end

initial #20 reset = 0;

always #10 clock=clock+1;

initial #10000 $finish;

endmodule

執行結果

D:\oc\cpu0m>iverilog cpu0m10.v -o cpu0m10

D:\oc\cpu0m>vvp cpu0m10
WARNING: cpu0m10.v:179: $readmemh(cpu0m10.hex): Not enough words in the file for
 the requested range [0:128].
00000000: 001f0024
00000004: 002f001c
00000008: 003f0020
0000000c: 0840000a
00000010: 13221000
00000014: 13332000
00000018: 10240000
0000001c: 21fffff0
00000020: 2c000000
00000024: 00000000
00000028: 00000001
0000002c: 00000000
 130ns 00000000 : LD   1, f,0024; R[1]=   1
 250ns 00000004 : LD   2, f,001c; R[2]=   0
 370ns 00000008 : LD   3, f,0020; R[3]=   0
 490ns 0000000c : LDI  4, 0,000a; R[4]=  10
 610ns 00000010 : ADD  2, 2,   1; R[2]=   1, B=   0, C=   1
 730ns 00000014 : ADD  3, 3,   2; R[3]=   1, B=   0, C=   1
 850ns 00000018 : CMP  2  4; N=1 Z=0
 970ns 0000001c : JNE        -16; PC=00000010
1090ns 00000010 : ADD  2, 2,   1; R[2]=   2, B=   1, C=   1
1210ns 00000014 : ADD  3, 3,   2; R[3]=   3, B=   1, C=   2
1330ns 00000018 : CMP  2  4; N=1 Z=0
1450ns 0000001c : JNE        -16; PC=00000010
1570ns 00000010 : ADD  2, 2,   1; R[2]=   3, B=   2, C=   1
1690ns 00000014 : ADD  3, 3,   2; R[3]=   6, B=   3, C=   3
1810ns 00000018 : CMP  2  4; N=1 Z=0
1930ns 0000001c : JNE        -16; PC=00000010
2050ns 00000010 : ADD  2, 2,   1; R[2]=   4, B=   3, C=   1
2170ns 00000014 : ADD  3, 3,   2; R[3]=  10, B=   6, C=   4
2290ns 00000018 : CMP  2  4; N=1 Z=0
2410ns 0000001c : JNE        -16; PC=00000010
2530ns 00000010 : ADD  2, 2,   1; R[2]=   5, B=   4, C=   1
2650ns 00000014 : ADD  3, 3,   2; R[3]=  15, B=  10, C=   5
2770ns 00000018 : CMP  2  4; N=1 Z=0
2890ns 0000001c : JNE        -16; PC=00000010
3010ns 00000010 : ADD  2, 2,   1; R[2]=   6, B=   5, C=   1
3130ns 00000014 : ADD  3, 3,   2; R[3]=  21, B=  15, C=   6
3250ns 00000018 : CMP  2  4; N=1 Z=0
3370ns 0000001c : JNE        -16; PC=00000010
3490ns 00000010 : ADD  2, 2,   1; R[2]=   7, B=   6, C=   1
3610ns 00000014 : ADD  3, 3,   2; R[3]=  28, B=  21, C=   7
3730ns 00000018 : CMP  2  4; N=1 Z=0
3850ns 0000001c : JNE        -16; PC=00000010
3970ns 00000010 : ADD  2, 2,   1; R[2]=   8, B=   7, C=   1
4090ns 00000014 : ADD  3, 3,   2; R[3]=  36, B=  28, C=   8
4210ns 00000018 : CMP  2  4; N=1 Z=0
4330ns 0000001c : JNE        -16; PC=00000010
4450ns 00000010 : ADD  2, 2,   1; R[2]=   9, B=   8, C=   1
4570ns 00000014 : ADD  3, 3,   2; R[3]=  45, B=  36, C=   9
4690ns 00000018 : CMP  2  4; N=1 Z=0
4810ns 0000001c : JNE        -16; PC=00000010
4930ns 00000010 : ADD  2, 2,   1; R[2]=  10, B=   9, C=   1
5050ns 00000014 : ADD  3, 3,   2; R[3]=  55, B=  45, C=  10
5170ns 00000018 : CMP  2  4; N=0 Z=1
5290ns 0000001c : JNE        -16; PC=00000020
5410ns 00000020 : RET; PC=ffffffff
RET to PC < 0, finished!

Facebook

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