單字節指令:
操作碼 OP 4位 | 目的寄存器 Rd 2位 | 源寄存器 Rs 2位 |
雙字節指令:
操作碼 OP 4位 | 目的寄存器 Rd 2位 | 源寄存器 Rs 2位 |
立即數字段 8位 | ||
本CPU模型有13條指令,其中0-9為單字節指令,10-13為雙字節指令。
使用Verilog實現的時候,會在內存之中預先設置好執行的指令,然后模擬仿真,觀察結果。
序號 | 指令助記符 | 功能 | 操作碼 | 舉例 | 機器碼 |
0 | IN Rd | 輸入 IN←Rd | 0000 | IN R2 | 0000 10 00 |
1 | OUT Rs | 輸出 OUT←Rs | 0001 | OUT R1 | 0001 00 01 |
2 | MOV Rd, Rs | 寄存器傳輸 Rd←Rs | 0010 | MOV R1,R2 | 0010 10 01 |
3 | ADD Rd, Rs | 加運算 Rd←Rs+Rd 并設置Cy,Zero標志 | 0011 | ADD R3,R0 | 0011 11 00 |
4 | AND Rd, Rs | 與運算 Rd←Rs & Rd 并設置Zero標志 | 0100 | AND R1,R0 | 0100 01 00 |
5 | MUL | 原碼一位乘法運算 {HIGH,LOW}←RD*RS | 0101 | MUL RD RS | 0101 01 10 |
6 | STI | 開中斷 | 0110 | STI | 0110xxxx |
7 | CLI | 關中斷 | 0111 | CLI | 0111xxxx |
8 | IRET | 中斷返回 | 1000 | IRET | 1000xxxx |
9 | HLT | 停機 | 1001 | HLT | 1001xxxx |
10 | LDI | Rd←立即數 | 1010 | LDI R1 59 | 101001xx 01011001 |
11 | LAD | 讀內存Rd←MEM | 1011 | LAD R1 | 10110100 |
12 | STA | 寫內存MEM←Rs | 1100 | STA R2 | 11001000 |
13 | JMP target | 無條件轉移 PC←地址 | 1101 | JMP 59 | 110101xx 01011001 |
14 | JC target | 條件轉移,有進位時轉移 如果 FC= =1’b1, PC←立即數,程序實現轉移。 否則 不修改PC,程序順序執行。 | 1110 | JC 50 | 11100000 01010000 |

ALU運算器:
當ALU_B為1時,ALU輸出,否則處于高阻態
S1、S0控制ALU的運算種類

FC進位標志寄存器:
當做加法指令時,進位保存在FC中
用于條件跳轉指令的判斷條件。

MAR地址寄存器、A、B運算暫存器:
輸出沒有三態控制,即只要輸入到寄存器,輸出就有值了。

程序計數器PC:
當LDPC為1時,在時鐘上升沿,接收數據。
當INC_PC為1時,在時鐘上升沿,實現PC+1。
當PC_B為1時,輸出數據。否則高阻態。

內存:
/CE=1 /WE=x,不操作。
/CE=0 /WE=0 寫內存;/CE=0 /WE=1 讀內存。
讀內存,由內存到MDR,再由MDR到總線。
寄存器IR:

寄存器R3~R0:
以R0為例:當R_B為1時,R輸出(根據指令判斷),
否則處于高阻態。
當LDR0為1時,在時鐘上升沿,接收數據。

分為兩個節拍
T1:在T1上升沿,微程序控制器工作,設置微指令各字段的值。根據各字段的值,設置微控制信號;各微控制信號,控制各寄存器傳輸到總線BUS。
T2:在T2的上升沿,當LDXXX的信號有效時,將數據從總線輸入到寄存器中

運算器 2位 | 向總線輸出 3位 | 從總線輸入 3位 | 下地址 6位 |
S1 S0 | XXX_B | LDXXX | uMA |
XXX_B為1時,XXX部件輸出到總線上。
LDXXX為1時,當T2上升沿到來時,將總線上的數據輸入到XXX部件。
LDXXX字段
|
|
|
|
0 | 0 | 0 | NOP |
0 | 0 | 1 | LDA |
0 | 1 | 0 | LDB |
0 | 1 | 1 | LDR |
1 | 0 | 0 | LDOUT |
1 | 0 | 1 | LDMAR |
1 | 1 | 0 | LDIR |
1 | 1 | 1 | LDPC |
XXX_B字段
|
|
| |
0 | 0 | 0 | NOP |
0 | 0 | 1 | ALU_B |
0 | 1 | 0 | R_B |
0 | 1 | 1 | PC_B |
1 | 0 | 0 | STI |
1 | 0 | 1 | CLI |
1 | 1 | 0 | MEM_B |
1 | 1 | 1 | IN_B |
C字段
|
|
|
|
0 | 0 | 0 | NOP |
0 | 0 | 1 | P<1> |
0 | 1 | 0 | P<2> |
0 | 1 | 1 | P<3> |
1 | 0 | 0 | P<4> |
1 | 0 | 1 | P<5> |
1 | 1 | 0 | 保留 |
1 | 1 | 1 | 保留 |

module CPU(clk,reset,interrupt,T1,T2,PC,MAR,IR,uMA,A,B,ALU,R0,R1,R2,R3,LDR,LDIR,BUS,FC); input clk,reset,interrupt; output T1,T2,PC,MAR,IR,uMA,A,B,ALU,R0,R1,R2,R3,LDR,LDIR,BUS,FC; reg[7:0] MEM0,MEM1,MEM2,MEM3,MEM4; //內存中的普通程序 reg[7:0] R0,R1,R2,R3,ALU,A,B,PC,BUS,MAR,IR; reg[1:0] S; // 2位ALU控制字段 reg[2:0] LDXXX,XXX_B; // 三個控制字段 reg[5:0] uMA; // 6位微地址字段 //T1時刻直接XXX_B、設置LDXXX控制信號, T2時刻根據LDXXX信號 從BUS傳數據 reg LDA,LDB,LDR,LDPC,LDOUT,LDMAR,LDIR,INC_PC,FC; // 微控制信號 reg T1; wire T2; //產生時序T1 T2;初始內存中的機器指令 always @(posedge clk) begin if(reset) begin T1 <= 1'b0; //內存初始賦值(輸入機器指令)MEM MEM0 <= 8'b10100000; //立即數傳值->R0 MEM1 <= 8'b10000000; MEM2 <= 8'b10100100; //立即數傳值->R1 MEM3 <= 8'b10000000; MEM4 <= 8'b00110001; //R0+R1 ->R0 end else //設置時序 T1 <= ~T1; end //設置時序 assign T2=~T1; //T1 設置微代碼各字段 always @(posedge T1) begin if(reset) uMA <= 6'b000000; else begin case(uMA) 6'h00: begin S <= 2'b00; XXX_B <= 3'b101; LDXXX <= 3'b000; INC_PC <= 1'b0; uMA <= 6'h01; end 6'h01: begin S <= 2'b00; XXX_B <= 3'b000; LDXXX <= 3'b000; INC_PC <= 1'b0; uMA <= 6'h02; end 6'h02: begin S <= 2'b00; XXX_B <= 3'b011; LDXXX <= 3'b101; INC_PC <= 1'b1; uMA <= 6'h03; end 6'h03: begin S <= 2'b00; XXX_B <= 3'b110; LDXXX <= 3'b110; INC_PC <= 1'b0; uMA <= 6'h04; end 6'h04: begin S <= 2'b00; XXX_B <= 3'b000; LDXXX <= 3'b000; INC_PC <= 1'b0; case({IR[7],IR[6],IR[5],IR[4]}) 4'b0011: uMA <= 6'h08; //ADD 4'b1010: uMA <= 6'h16; //LDI endcase end 6'h08: //RD->A begin S <= 2'b00; XXX_B <= 3'b010; LDXXX <= 3'b001; INC_PC <= 1'b0; uMA <= 6'h09; end 6'h09://RS->B begin S <= 2'b00; XXX_B <= 3'b010; LDXXX <= 3'b010; INC_PC <= 1'b0; uMA <= 6'h0A; end 6'h0A: //A+B->RD begin S <= 2'b01; XXX_B <= 3'b001; LDXXX <= 3'b011; INC_PC <= 1'b0; uMA <= 6'h01; end 6'h16: //LDI begin S <= 2'b00; XXX_B <= 3'b011; LDXXX <= 3'b101; INC_PC <= 1'b1; uMA <= 6'h17; end 6'h17: begin S <= 2'b00; XXX_B <= 3'b110; LDXXX <= 3'b011; INC_PC <= 1'b0; uMA <= 6'h01; end endcase end end //設置每字段的控制信號 always @(S or LDXXX or XXX_B) begin //ALU運算控制 case(S) 2'b00: begin ALU <= ALU; end 2'b01: begin {FC,ALU} <= A + B; end endcase // A字段控制 LDXX case(LDXXX) 3'b000: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0000000; end 3'b001: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b1000000; end 3'b010: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0100000; end 3'b011: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0010000; end 3'b100: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0001000; end 3'b101: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0000100; end 3'b110: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0000010; end 3'b111: begin {LDA,LDB,LDR,LDOUT,LDMAR,LDIR,LDPC} <= 7'b0000001; end endcase // B字段控制 XX_B case(XXX_B) 3'b000: begin BUS <= BUS; end 3'b001: begin BUS <= ALU; end 3'b010: begin case({IR[1],IR[0]}) 2'b00: BUS <= R0; 2'b01: BUS <= R1; 2'b10: BUS <= R2; 2'b11: BUS <= R3; endcase end 3'b011: begin BUS <= PC; end 3'b100: begin STI <= 1'b1; CLI <= 1'b0; end 3'b101: begin STI <= 1'b0; CLI <= 1'b1; end 3'b110: begin case(MAR) 8'h00: BUS <= MEM0; 8'h01: BUS <= MEM1; 8'h02: BUS <= MEM2; 8'h03: BUS <= MEM3; 8'h04: BUS <= MEM4; endcase end 3'b111: BUS <= IN; endcase endendmodul七、仿真
內存指令: MEM0 <= 8'b10100000; //立即數傳值->R0 MEM1 <= 8'b10000000; MEM2 <= 8'b10100100; //立即數傳值->R1 MEM3 <= 8'b10000000; MEM4 <= 8'b00110001; //R0+R1 ->R0
八、結語
本文只實現了簡單的功能加法、立即數傳值指令,介紹如何使用Verilog 模擬微程序控制器,進而實現一個簡單CPU的功能。實現微程序流程圖中的所有指令的源代碼,在我的GitHub 之中,歡迎大家參考。
新聞熱點
疑難解答