CPU0-Mini:3 個指令的版本

Verilog

基本語法

型態

全域變數

基本元件

多樣的寫法

指定

assign

always

initial

運算式

分枝

迴圈

模組

函數

Task

陣列

輸出入

觀察

真值表

測試程式

訊息顯示

注意事項

模擬程序

硬體工程

程式範例

Xor

Xor3

全加器

加法器

加減器

快速加法器

乘法器

ALU

閂鎖器

脈衝偵測

計數器

多工器

暫存器群

記憶體

延遲問題

浮點數

狀態機

程式計數器

CPU0-Mini

CPU0

pipeline

工具

QuartusII

Icarus

Veritek

訊息

相關網站

參考文獻

最新修改

簡體版

English

解說:一個指令的執行流程

  1. 提取階段:共同
    • IR = [PC], PC=PC+4
  2. 解碼階段:共同
    • 從 IR 中取出 op,ra,rb,rc,cx 等欄位
  3. 執行階段:每個指令不同
    • LD : Ra <= [Rb + cx]
    • ST : Ra => [Rb+cx]
    • ADD: Ra = Rb + Rc
    • JMP: PC = PC+cx

說明:由於記憶體讀取需要耗費不只一個時脈週期,所以通常會用兩個周期,1. 發出讀取請求,2. 接收讀取結果。

Verilog 程式:cpu0m.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] addr32, A, B, C, aluOut, ipc; // ipc:instruction PC

    `define PC  R[15]
    `define LD  8'h00
    `define ST  8'h01
    `define ADD 8'h13
    `define JMP 8'h26    

    always @(posedge clock) begin
        if (reset) begin
            `PC = 0;
            tick = 0;
          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];
                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 + cx16; // 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 + cx16;  // 寫入位址 = 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]
                            aluOut = B+C; // 執行加法
                        end
                        `JMP: begin // 指令:JMP cx ; 語意:PC = PC+cx
                            addr32 = cx24; // 取出 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]
                        `LD: begin // 指令:LD ra, rb, cx ; 語意:R[ra] = m[rb+cx]
                            mdr = dbus; // 取得記憶體傳回的 dbus = m[rb+cx]
                            R[ra] = mdr; // 存入到目標暫存器 R[ra] 中
                            A = mdr;
                            m_en = 0; // 讀取完畢
                        end
                        `ST: begin // 指令:ST ra, rb, cx ; 語意:m[rb+cx]=R[ra]
                            m_en = 0; // 寫入完畢
                        end
                        `ADD: begin // 指令:ADD ra, rb, rc ; 語意:R[ra]=R[rb]+R[rc]
                            R[ra] = aluOut;
                        end
                        `JMP: begin // 指令:JMP cx ; 語意:PC = PC+cx
                        end
                        default:    begin
                        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]);
                    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;

    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'h001F0018; // 0000       LD   R1, K1
            {m[4],m[5],m[6],m[7]}    = 32'h002F0010; // 0004       LD   R2, K0
            {m[8],m[9],m[10],m[11]}  = 32'h003F0014; // 0008       LD   R3, SUM
            {m[12],m[13],m[14],m[15]}= 32'h13221000; // 000C LOOP: ADD  R2, R2, R1
            {m[16],m[17],m[18],m[19]}= 32'h13332000; // 0010       ADD  R3, R3, R2
            {m[20],m[21],m[22],m[23]}= 32'h26FFFFF4; // 0014       JMP  LOOP
            {m[24],m[25],m[26],m[27]}= 32'h00000000; // 0018 K0:   WORD 0
            {m[28],m[29],m[30],m[31]}= 32'h00000001; // 001C K1:   WORD 1
            {m[32],m[33],m[34],m[35]}= 32'h00000000; // 0020 SUM:  WORD 0
            data = 32'hZZZZZZZZ;                         
        end else 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;
wire [7:0] op;
wire signed [31:0] A, B, C, aluOut;
wire [3:0] ra, rb, rc;

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 #5000 $finish;

endmodule

執行結果

D:\OpenComputer\verilog>iverilog cpu0m.v -o cpu0m

D:\OpenComputer\verilog>vvp cpu0m
 130ns 00000000 : LD   1, f,0018; R[1]=   1
 250ns 00000004 : LD   2, f,0010; R[2]=   0
 370ns 00000008 : LD   3, f,0014; R[3]=   0
 490ns 0000000c : ADD  2, 2,   1; R[2]=   1, B=   0, C=   1
 610ns 00000010 : ADD  3, 3,   2; R[3]=   1, B=   0, C=   1
 730ns 00000014 : JMP        -12; PC=0000000c
 850ns 0000000c : ADD  2, 2,   1; R[2]=   2, B=   1, C=   1
 970ns 00000010 : ADD  3, 3,   2; R[3]=   3, B=   1, C=   2
1090ns 00000014 : JMP        -12; PC=0000000c
1210ns 0000000c : ADD  2, 2,   1; R[2]=   3, B=   2, C=   1
1330ns 00000010 : ADD  3, 3,   2; R[3]=   6, B=   3, C=   3
1450ns 00000014 : JMP        -12; PC=0000000c
1570ns 0000000c : ADD  2, 2,   1; R[2]=   4, B=   3, C=   1
1690ns 00000010 : ADD  3, 3,   2; R[3]=  10, B=   6, C=   4
1810ns 00000014 : JMP        -12; PC=0000000c
1930ns 0000000c : ADD  2, 2,   1; R[2]=   5, B=   4, C=   1
2050ns 00000010 : ADD  3, 3,   2; R[3]=  15, B=  10, C=   5
2170ns 00000014 : JMP        -12; PC=0000000c
2290ns 0000000c : ADD  2, 2,   1; R[2]=   6, B=   5, C=   1
2410ns 00000010 : ADD  3, 3,   2; R[3]=  21, B=  15, C=   6
2530ns 00000014 : JMP        -12; PC=0000000c
2650ns 0000000c : ADD  2, 2,   1; R[2]=   7, B=   6, C=   1
2770ns 00000010 : ADD  3, 3,   2; R[3]=  28, B=  21, C=   7
2890ns 00000014 : JMP        -12; PC=0000000c
3010ns 0000000c : ADD  2, 2,   1; R[2]=   8, B=   7, C=   1
3130ns 00000010 : ADD  3, 3,   2; R[3]=  36, B=  28, C=   8
3250ns 00000014 : JMP        -12; PC=0000000c
3370ns 0000000c : ADD  2, 2,   1; R[2]=   9, B=   8, C=   1
3490ns 00000010 : ADD  3, 3,   2; R[3]=  45, B=  36, C=   9
3610ns 00000014 : JMP        -12; PC=0000000c
3730ns 0000000c : ADD  2, 2,   1; R[2]=  10, B=   9, C=   1
3850ns 00000010 : ADD  3, 3,   2; R[3]=  55, B=  45, C=  10
3970ns 00000014 : JMP        -12; PC=0000000c
4090ns 0000000c : ADD  2, 2,   1; R[2]=  11, B=  10, C=   1
4210ns 00000010 : ADD  3, 3,   2; R[3]=  66, B=  55, C=  11
4330ns 00000014 : JMP        -12; PC=0000000c
4450ns 0000000c : ADD  2, 2,   1; R[2]=  12, B=  11, C=   1
4570ns 00000010 : ADD  3, 3,   2; R[3]=  78, B=  66, C=  12
4690ns 00000014 : JMP        -12; PC=0000000c
4810ns 0000000c : ADD  2, 2,   1; R[2]=  13, B=  12, C=   1
4930ns 00000010 : ADD  3, 3,   2; R[3]=  91, B=  78, C=  13

Facebook

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