Cpu0s2

Verilog

基本語法

型態

全域變數

基本元件

多樣的寫法

指定

assign

always

initial

運算式

分枝

迴圈

模組

函數

Task

陣列

輸出入

觀察

真值表

測試程式

訊息顯示

注意事項

模擬程序

硬體工程

程式範例

Xor

Xor3

全加器

加法器

加減器

快速加法器

乘法器

ALU

閂鎖器

脈衝偵測

計數器

多工器

暫存器群

記憶體

延遲問題

浮點數

狀態機

程式計數器

CPU0-Mini

CPU0

pipeline

工具

QuartusII

Icarus

Veritek

訊息

相關網站

參考文獻

最新修改

簡體版

English

輸入指令檔:cpu0s.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 程式:cpu0s2.v

// 參考文獻:http://ccckmit.wikidot.com/ocs:cpu0
module cpu0(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, output reg [1:0] m_w1);
    reg signed [31:0] R [0:15];
    reg [7:0] op;
    reg [3:0] a, b, c;
    reg signed [11:0] cx12;
    reg signed [15:0] cx16;
    reg signed [23:0] cx24;
    reg [4:0] c5;
    reg signed [31:0] c12, c16, c24, Ra, Rb, Rc, ipc; // ipc:instruction PC

    // 暫存器簡稱
    `define PC   R[15]   // 程式計數器
    `define LR   R[14]   // 連結暫存器
    `define SP   R[13]   // 堆疊暫存器
    `define SW   R[12]   // 狀態暫存器
    // 狀態暫存器旗標位元
    `define N    `SW[31] // 負號旗標
    `define Z    `SW[30] // 零旗標
    `define C    `SW[29] // 進位旗標
    `define V    `SW[28] // 溢位旗標
    `define I    `SW[7]  // 硬體中斷許可
    `define T    `SW[6]  // 軟體中斷許可
    `define M    `SW[0]  // 模式位元
    // 寬度形態常數
    `define INT32 2'b11     // 寬度 32 位元
    `define INT24 2'b10     // 寬度 24 位元
    `define INT16 2'b01     // 寬度 16 位元
    `define BYTE  2'b00     // 寬度  8 位元
    // 指令編碼表
    parameter [7:0] LD=8'h00,ST=8'h01,LDB=8'h02,STB=8'h03,LDR=8'h04,STR=8'h05,
    LBR=8'h06,SBR=8'h07,LDI=8'h08,CMP=8'h10,MOV=8'h12,ADD=8'h13,SUB=8'h14,
    MUL=8'h15,DIV=8'h16,AND=8'h18,OR=8'h19,XOR=8'h1A,ROL=8'h1C,ROR=8'h1D,
    SHL=8'h1E,SHR=8'h1F,JEQ=8'h20,JNE=8'h21,JLT=8'h22,JGT=8'h23,JLE=8'h24,
    JGE=8'h25,JMP=8'h26,SWI=8'h2A,CALL=8'h2B,RET=8'h2C,IRET=8'h2D,
    PUSH=8'h30,POP=8'h31,PUSHB=8'h32,POPB=8'h33;

    task memReadStart(input [31:0] addr, input w1); begin // 讀取記憶體 Word
       mar = addr;     // read(m[addr])
       m_rw = 1;     // 讀取模式:read 
       m_en = 1;     // 啟動讀取
       m_w1 = w1;
    end    endtask

    task memReadEnd(output [31:0] data); begin // 讀取記憶體完成,取得資料
       mdr = dbus; // 取得記憶體傳回的 dbus = m[addr]
       data = mdr; // 傳回資料
       m_en = 0; // 讀取完畢
    end    endtask

    // 寫入記憶體 -- addr:寫入位址, data:寫入資料
    task memWriteStart(input [31:0] addr, input [31:0] data, input w1); begin 
       mar = addr;    // write(m[addr], data)
       mdr = data;
       m_rw = 0;    // 寫入模式:write
       m_en = 1;     // 啟動寫入
       m_w1  = w1;
    end    endtask

    task memWriteEnd; begin // 寫入記憶體完成
       m_en = 0; // 寫入完畢
    end endtask

    task regSet(input [3:0] i, input [31:0] data); begin
        if (i!=0) R[i] = data;
    end endtask

    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)    
                1: begin  // Tick 1 : 指令擷取,將 PC 丟到位址匯流排上,memory.read(m[PC])
                    memReadStart(`PC, `INT32);
                    ipc  = `PC;
                    `PC = `PC+4;
                end
                2: begin  // Tick 2 : 指令解碼,ir = m[PC]
                    memReadEnd(ir); // IR = dbus = m[PC]
                    {op,a,b,c,cx12} = ir;
                    cx24 = ir[23:0];
                    cx16 = ir[15:0];
                    c5  = ir[4:0];
                    c12 = cx12; // 取出 cx12 並轉為 32 位元有號數 c12
                    c16 = cx16; // 取出 cx16 並轉為 32 位元有號數 c16
                    c24 = cx24; // 取出 cx24 並轉為 32 位元有號數 c24
                    Ra = R[a];
                    Rb = R[b];
                    Rc = R[c];
                end
                3: begin // Tick 3 : 指令執行
                    case (op)
                        // 載入儲存指令
                        LD:  memReadStart(Rb+c16, `INT32);         // 載入word;    LD Ra, [Rb+Cx];     Ra<=[Rb+ Cx]
                        ST:  memWriteStart(Rb+c16, Ra, `INT32); // 儲存word;    ST Ra, [Rb+ Cx];     Ra=>[Rb+ Cx]
                        LDB: memReadStart(Rb+c16, `BYTE);        // 載入byte;    LDB Ra, [Rb+ Cx];     Ra<=(byte)[Rb+ Cx]
                        STB: memWriteStart(Rb+c16, Ra, `BYTE);     // 儲存byte;    STB Ra, [Rb+ Cx];    Ra=>(byte)[Rb+ Cx]
                        LDR: memReadStart(Rb+Rc, `INT32);        // LD的Rc版;     LDR Ra, [Rb+Rc];    Ra<=[Rb+ Rc]
                        STR: memWriteStart(Rb+Rc, Ra, `INT32);    // ST的Rc版;    STR Ra, [Rb+Rc];    Ra=>[Rb+ Rc]
                        LBR: memReadStart(Rb+Rc, `BYTE);        // LDB的Rc版;    LBR Ra, [Rb+Rc];    Ra<=(byte)[Rb+ Rc]
                        SBR: memWriteStart(Rb+Rc, Ra, `BYTE);    // STB的Rc版;    SBR Ra, [Rb+Rc];    Ra=>(byte)[Rb+ Rc]
                        LDI: R[a] = Rb+c16;                     // 立即載入;    LDI Ra, Rb+Cx;        Ra<=Rb + Cx
                        // 運算指令
                        CMP: begin `N=(Ra-Rb<0);`Z=(Ra-Rb==0); end // 比較;        CMP Ra, Rb;         SW=(Ra >=< Rb)
                        MOV: regSet(a, Rb);                 // 移動;            MOV Ra, Rb;         Ra<=Rb
                        ADD: regSet(a, Rb+Rc);                // 加法;            ADD Ra, Rb, Rc;     Ra<=Rb+Rc
                        SUB: regSet(a, Rb-Rc);                // 減法;            SUB Ra, Rb, Rc;     Ra<=Rb-Rc
                        MUL: regSet(a, Rb*Rc);                // 乘法;             MUL Ra, Rb, Rc;     Ra<=Rb*Rc
                        DIV: regSet(a, Rb/Rc);                // 除法;             DIV Ra, Rb, Rc;     Ra<=Rb/Rc
                        AND: regSet(a, Rb&Rc);                // 位元 AND;        AND Ra, Rb, Rc;     Ra<=Rb and Rc
                        OR:  regSet(a, Rb|Rc);                // 位元 OR;            OR Ra, Rb, Rc;         Ra<=Rb or Rc
                        XOR: regSet(a, Rb^Rc);                // 位元 XOR;        XOR Ra, Rb, Rc;     Ra<=Rb xor Rc
                        SHL: regSet(a, Rb<<c5);                // 向左移位;        SHL Ra, Rb, Cx;     Ra<=Rb << Cx
                        SHR: regSet(a, Rb>>c5);                // 向右移位;        SHR Ra, Rb, Cx;     Ra<=Rb >> Cx
                        // 跳躍指令
                        JEQ: if (`Z) `PC=`PC+c24;            // 跳躍 (相等);        JEQ Cx;        if SW(=) PC  PC+Cx
                        JNE: if (!`Z) `PC=`PC+c24;            // 跳躍 (不相等);    JNE Cx;     if SW(!=) PC  PC+Cx
                        JLT: if (`N&&!`Z)`PC=`PC+c24;        // 跳躍 ( < );        JLT Cx;     if SW(<) PC  PC+Cx
                        JGT: if (!`N&&`Z) `PC=`PC+c24;        // 跳躍 ( > );        JGT Cx;     if SW(>) PC  PC+Cx
                        JLE: if (`N || `Z) `PC=`PC+c24;        // 跳躍 ( <= );        JLE Cx;     if SW(<=) PC  PC+Cx    
                        JGE: if (!`N || `Z) `PC=`PC+c24;    // 跳躍 ( >= );        JGE Cx;     if SW(>=) PC  PC+Cx
                        JMP: `PC = `PC+c24;                     // 跳躍 (無條件);    JMP Cx;     PC <= PC+Cx
                        SWI: begin `LR=`PC;`PC= c24; `I = 1'b1; end // 軟中斷;    SWI Cx;         LR <= PC; PC <= Cx; INT<=1
                        CALL:begin `LR=`PC;`PC=`PC + c24; end // 跳到副程式;    CALL Cx;     LR<=PC; PC<=PC+Cx
                        RET: begin `PC=`LR; end                // 返回;            RET;         PC <= LR
                        IRET:begin `PC=`LR;`I = 1'b0; end    // 中斷返回;        IRET;         PC <= LR; INT<=0
                        // 堆疊指令    
                        PUSH:begin `SP = `SP-4; memWriteStart(`SP, Ra, `INT32); end // 推入 word;    PUSH Ra;    SP-=4;[SP]<=Ra;
                        POP: begin memReadStart(`SP, `INT32); `SP = `SP + 4; end    // 彈出 word;    POP Ra;     Ra=[SP];SP+=4;
                        PUSHB:begin `SP = `SP-1; memWriteStart(`SP, Ra, `BYTE); end    // 推入 byte;    PUSHB Ra;     SP--;[SP]<=Ra;(byte)
                        POPB:begin memReadStart(`SP, `BYTE); `SP = `SP+1; end        // 彈出 byte;    POPB Ra;     Ra<=[SP];SP++;(byte)
                    endcase
                end
                4: begin // 讀取寫入指令完成,關閉記憶體
                    case (op)
                        LD, LDB, LDR, LBR, POP, POPB  : memReadEnd(R[a]); // 讀取記憶體完成
                        ST, STB, STR, SBR, PUSH, PUSHB: memWriteEnd(); // 寫入記憶體完成
                    endcase
                    $display("%4dns %8x : %8x R[%02d]=%-d", $stime, ipc, ir, a, R[a]);
                    if (op==RET && `PC < 0) begin
                        $display("RET to PC < 0, finished!");
                        $finish;
                    end
                    tick = 0;
                end                
            endcase
        end
        pc = `PC;
    end
endmodule

module memory0(input clock, reset, en, rw, input [1:0] m_w1, 
                input [31:0] abus, dbus_in, output [31:0] dbus_out);
reg [7:0] m [0:130];
reg [31:0] data;

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

    always @(clock or abus or en or rw or dbus_in) 
    begin
        if (abus >=0 && abus <= 127) begin
            if (en == 1 && rw == 0) begin // r_w==0:write
                data = dbus_in;
                case (m_w1)
                    `BYTE:  {m[abus]} = dbus_in[7:0];
                    `INT16: {m[abus], m[abus+1] } = dbus_in[15:0];
                    `INT24: {m[abus], m[abus+1], m[abus+2]} = dbus_in[24:0];
                    `INT32: {m[abus], m[abus+1], m[abus+2], m[abus+3]} = dbus_in;
                endcase
            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, reset;
wire [2:0] tick;
wire [31:0] pc, ir, mar, mdr, dbus;
wire m_en, m_rw;
wire [1:0] m_w1;

cpu0 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), .m_w1(m_w1));

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

initial
begin
  clock = 0;
  reset = 1;
  #20 reset = 0;
  #10000 $finish;
end

always #10 clock=clock+1;

endmodule

執行結果

D:\oc\cpu0>iverilog cpu0s2.v -o cpu0s2

D:\oc\cpu0>vvp cpu0s2
WARNING: cpu0s2.v:167: $readmemh(cpu0s.hex): Not enough words in the file for th
e requested range [0:130].
00000000: 001f0024
00000004: 002f001c
00000008: 003f0020
0000000c: 0840000a
00000010: 13221000
00000014: 13332000
00000018: 10240000
0000001c: 21fffff0
00000020: 2c000000
00000024: 00000000
00000028: 00000001
0000002c: 00000000
  90ns 00000000 : 001f0024 R[01]=1
 170ns 00000004 : 002f001c R[02]=0
 250ns 00000008 : 003f0020 R[03]=0
 330ns 0000000c : 0840000a R[04]=10
 410ns 00000010 : 13221000 R[02]=1
 490ns 00000014 : 13332000 R[03]=1
 570ns 00000018 : 10240000 R[02]=1
 650ns 0000001c : 21fffff0 R[15]=16
 730ns 00000010 : 13221000 R[02]=2
 810ns 00000014 : 13332000 R[03]=3
 890ns 00000018 : 10240000 R[02]=2
 970ns 0000001c : 21fffff0 R[15]=16
1050ns 00000010 : 13221000 R[02]=3
1130ns 00000014 : 13332000 R[03]=6
1210ns 00000018 : 10240000 R[02]=3
1290ns 0000001c : 21fffff0 R[15]=16
1370ns 00000010 : 13221000 R[02]=4
1450ns 00000014 : 13332000 R[03]=10
1530ns 00000018 : 10240000 R[02]=4
1610ns 0000001c : 21fffff0 R[15]=16
1690ns 00000010 : 13221000 R[02]=5
1770ns 00000014 : 13332000 R[03]=15
1850ns 00000018 : 10240000 R[02]=5
1930ns 0000001c : 21fffff0 R[15]=16
2010ns 00000010 : 13221000 R[02]=6
2090ns 00000014 : 13332000 R[03]=21
2170ns 00000018 : 10240000 R[02]=6
2250ns 0000001c : 21fffff0 R[15]=16
2330ns 00000010 : 13221000 R[02]=7
2410ns 00000014 : 13332000 R[03]=28
2490ns 00000018 : 10240000 R[02]=7
2570ns 0000001c : 21fffff0 R[15]=16
2650ns 00000010 : 13221000 R[02]=8
2730ns 00000014 : 13332000 R[03]=36
2810ns 00000018 : 10240000 R[02]=8
2890ns 0000001c : 21fffff0 R[15]=16
2970ns 00000010 : 13221000 R[02]=9
3050ns 00000014 : 13332000 R[03]=45
3130ns 00000018 : 10240000 R[02]=9
3210ns 0000001c : 21fffff0 R[15]=16
3290ns 00000010 : 13221000 R[02]=10
3370ns 00000014 : 13332000 R[03]=55
3450ns 00000018 : 10240000 R[02]=10
3530ns 0000001c : 21fffff0 R[15]=32
3610ns 00000020 : 2c000000 R[00]=0
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