单周期十条指令CPU设计与verilog实现(Modelsim)
目錄
- 一、實驗目的
- 二、實驗內容
- 三、實驗原理
- 1. 規定
- 2. 原理圖
- 四、實驗步驟
- 1. CPU各部件實現
- pc
- insMem
- acc
- alu
- cu
- dataMem
- 2. CPU例化實現
- 3. 編寫測試文件
- 4. 仿真結果及分析
- 1. 清除累加器指令CL
- 2. 累加器取反指令COM
- 3. 算術右移一位指令SHR
- 4. 循環左移一位指令CSL
- 5. 加法指令ADD
- 6. 存數指令STA
- 7. 取數指令LDA
- 8. 無條件轉移指令JMP
- 9. 有條件轉移指令BAN
- 10. 停機指令STP
一、實驗目的
通過設計并實現支持 10 條指令的CPU,進一步理解和掌握CPU設計的基本原理和過程。
二、實驗內容
設計和實現一個支持如下十條指令的單周期CPU。
非訪存指令
- 清除累加器指令CLA
- 累加器取反指令COM
- 算術右移一位指令SHR:將累加器 ACC中的數右移一位,結果放回 ACC
- 循環左移一位指令CSL:對累加器中的數據進行操作
- 停機指令STP
訪存指令
- 加法指令ADD X:[X] + [ACC] –>ACC,X為存儲器地址,直接尋址
- 存數指令STA X,采用直接尋址方式
- 取數指令LDA X,采用直接尋址
轉移類指令
- 無條件轉移指令JMP imm:signExt(imm)->PC
- 有條件轉移(負則轉)指令BAN X:ACC 最高位為 1 則(PC)+X->PC,否則 PC 不變
三、實驗原理
1. 規定
-
機器字長、指令字長和存儲字長均為16位
-
指令格式為:
-
指令及其操作碼對照表
非訪存指令 訪存指令 轉移類指令 清除累加器指令CLA 0000加法指令ADD 0100無條件轉移指令JMP 0111累加器取反指令COM 0001存數指令STA 0101有條件轉移指令BAN 1000算術右移一位指令SHR 0010取數指令LDA 0110循環左移一位指令CSL 0011停機指令STP: 1001
2. 原理圖
四、實驗步驟
1. CPU各部件實現
pc
輸入:
| clk | rst | stop | ct | uct |
|---|---|---|---|---|
| 時鐘 | 時鐘 | 停機 | 條件轉移 | 無條件轉移 |
輸出:
| offset | pc |
|---|---|
| 12位轉移指令偏移量 | 12位指令地址碼 |
//pc
module pc(input wire clk, rst, stop, ct, uct, //時鐘、重置、停機、條件轉移、無條件轉移input wire [11:0] offset, //12位轉移指令偏移量output reg [11:0] pc //12位指令地址碼
);assign stop = 0; //初始化開機狀態// assign clk = (stop==1)?1'bz:0; //停機則將clk置0always@(posedge clk) beginif(rst == 1)pc = 0;elsepc = pc + 1;endalways@(negedge clk) beginif(uct == 1) //無條件轉移pc = offset-1;if(ct == 1) //條件轉移pc = pc+offset-1;endendmodule
insMem
輸入:
| addr |
|---|
| 12位指令地址碼 |
輸出:
| Ins |
|---|
| 16位指令 |
//insMem
module insMem(input wire [11:0] addr, //12位指令地址碼output wire [15:0] Ins //16位指令
);reg[15:0] insMem[4096:0]; //2^12個存儲單元,每個存儲單元16位initial begininsMem[0] = 16'b0000000000000000; //0000 0000 0000 0000 清除累加器指令CLAinsMem[1] = 16'b0001000000000000; //0001 0000 0000 0000 累加器取反指令COMinsMem[2] = 16'b0010000000000000; //0010 0000 0000 0000 算術右移一位指令SHRinsMem[3] = 16'b0011000000000000; //0011 0000 0000 0000 循環左移一位指令CSLinsMem[4] = 16'b0100000000000001 ; //0100 0000 0000 0001 加法指令ADDinsMem[5] = 16'b0101000000000000; //0101 0000 0000 0000 存數指令STAinsMem[6] = 16'b0110000000000000; //0110 0000 0000 0000 取數指令LDAinsMem[7] = 16'b0111000000001001; //0111 0000 0000 1001 無條件轉移指令JMPinsMem[9] = 16'b1000000000001001; //1000 0000 0000 1001 有條件轉移BANinsMem[10] = 16'b100100000000000; //1111 0000 0000 0000 停機指令STPendassign Ins = insMem[addr];endmodule
acc
輸入:
| clk | acc_wr | data_in |
|---|---|---|
| 時鐘 | acc讀寫控制 | 16位輸入數據 |
輸出:
| data_out |
|---|
| 16位輸出數據 |
//acc
module acc(input wire clk, acc_wr, //時鐘、acc讀寫控制input wire [15:0] data_in, //16位輸入數據output wire [15:0] data_out //16位輸出數據
);reg [15:0] acc; //16位accinitial beginacc = 1; //acc初始化1endassign data_out = acc; always@(negedge clk) beginif(acc_wr == 1)acc = data_in;endendmodule
alu
輸入:
| in1 | in2 | alu_op |
|---|---|---|
| 操作數1 | 操作數2 | 操作選擇信號 |
輸出:
| ct | Z |
|---|---|
| 條件轉移 | 結果 |
//alu
module alu(input wire [15:0] in1, in2, //操作數in1和in2input wire [3:0] alu_op, //操作選擇信號alu_opoutput reg ct, //條件轉移ctoutput reg [15:0] Z //Z
);initial beginct = 0;Z = 0; //初始化結果Z為0endalways@* begincase (alu_op)4'b0000: Z = 0; //清除累加器指令CLA4'b0001: Z = ~in1; //累加器取反指令COM 4'b0010: Z = in1[15] == 1 ? {1'b1, in1[15:1]} : {1'b0, in1[15:1]}; //算術右移一位指令SHR4'b0011: Z = {in1[14:0], in1[15]}; //循環左移一位指令CSL4'b0100: Z = in1 + in2; //加法指令ADD4'b0101: Z = in1; //存數指令STA4'b0110: Z = in2; //取數指令LDA4'b1000: ct = in1[15]==1?1:0; //有條件轉移BAN4'b1001: ; //停機指令endcaseendendmodule
cu
輸入:
| operate |
|---|
| 4位指令操作碼 |
輸出:
| stop | uct | acc_wr | dataMem_wr | alu_op |
|---|---|---|---|---|
| 停機信號 | 非條件轉移uct | acc讀寫控制 | 數據存儲器讀寫控制 | alu操作選擇 |
//cu
module cu(input wire [3:0] operate, //4位指令操作碼output reg stop, uct, acc_wr, dataMem_wr, //停機信號、非條件轉移uct、acc讀寫控制、數據存儲器讀寫控制output reg [3:0] alu_op //alu操作選擇
);initial beginstop = 0;uct = 0;acc_wr = 0;dataMem_wr = 0;alu_op = 4'b1111;endalways @(operate) begincase(operate)4'b0000: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100000; //清除累加器指令CLA4'b0001: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100001; //累加器取反指令COM 4'b0010: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100010; //算術右移一位指令SHR4'b0011: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100011; //循環左移一位指令CSL4'b0100: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100100; //加法指令ADD4'b0101: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00010101; //存數指令STA4'b0110: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100110; //取數指令LDA4'b0111: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b01000111; //無條件轉移指令JMP4'b1000: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00001000; //有條件轉移BAN4'b1001: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b10000000; //停機STOPendcaseendendmodule
dataMem
輸入:
| dataMem_wr | clk | addr | data_in |
|---|---|---|---|
| dataMem使能 | 時鐘 | 12位指令地址 | 16位輸入數據 |
輸出:
| data_out |
|---|
| 16位輸出數據 |
//dataMem
module dataMem(input wire dataMem_wr, clk, //dataMem使能、時鐘input wire [11:0] addr, //12位指令地址input wire [15:0] data_in, //16位輸入數據output wire [15:0] data_out //16位輸出數據
);reg [15:0] dataMem[4096:0]; //2^12個存儲單元,每個存儲單元16位assign data_out = dataMem[addr];initial begindataMem[0] = 16'b0000000000000001; //初始化1dataMem[1] = 16'b0000000000000010; //初始化2endalways@(negedge clk) beginif(dataMem_wr == 1)dataMem[addr] = data_in;endendmodule
2. CPU例化實現
調用以上各個模塊
module cpu(input wire clk, rst
);wire stop, ct, uct, acc_wr, dataMem_wr;wire [11:0] pc_addr;wire [3:0] alu_op;wire [15:0] ins, in1, in2, Z;//pc實例化pc pc(.clk(clk), .rst(rst), .stop(stop), .ct(ct), .uct(uct),.offset(ins[11:0]),.pc(pc_addr));//指令存儲器實例化insMem insMem(.addr(pc_addr),.Ins(ins));//acc實例化acc acc(.clk(clk), .acc_wr(acc_wr),.data_in(Z), .data_out(in1));//數據存儲器實例化dataMem dataMem(.dataMem_wr(dataMem_wr), .clk(clk),.addr(ins[11:0]),.data_in(Z),.data_out(in2));//cu實例化cu cu(.operate(ins[15:12]),.stop(stop), .uct(uct), .acc_wr(acc_wr), .dataMem_wr(dataMem_wr),.alu_op(alu_op));//alu實例化alu alu(.in1(in1), .in2(in2),.alu_op(alu_op),.ct(ct),.Z(Z));endmodule
3. 編寫測試文件
module cpu_test;reg clk, rst;initial begin clk = 1;rst = 1;#5 rst = 0;#80 $stop;endalways #5 clk = ~clk;cpu cpu(.clk(clk), .rst(rst));endmodule
4. 仿真結果及分析
根據以下原理圖及實驗結果波形圖進行分析
1. 清除累加器指令CL
0~5ns時:rst=1,pc中指令地址pc_addr=000000000000,到insMem中取出指令ins=0000000000000000,其中操作碼operation=0000傳給CU
4'b0000: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100000;
CU發出以上各種控制信號
-
alu_op=0000,然后alu執行清除累加器指令CLA,結果Z=0//清除累加器指令CLA 4'b0000: Z = 0; -
dataMem_wr=0,不能對dataMem進行寫操作; -
acc_wr=1,可以對acc進行寫操作
初始化時acc=1、dataMem[0]=0000000000000001;因此ACC的data_out端口輸出1,傳給ALU的in1口,in1=0000000000000001;dataMem[0]的數據輸出給ACC的in2,因此in2=0000000000000001
5~10ns時:5ns時rst置0,時鐘下降沿;ALU將Z=0寫入ACC中,同時ACC輸出數據到in1,使得in1=000000000000;in2不變
2. 累加器取反指令COM
10ns~15ns時:10ns時鐘上升沿,pc_addr加1得pc_addr=000000000001,到insMem中取出指令ins=0001000000000000,其中的操作碼operation=0001傳給CU
4'b0001: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100001;
CU發出以上各種控制信號
-
alu_op=0001:alu執行清除累加器指令CLA,結果Z=~in1=111111111111//累加器取反指令COM 4'b0001: Z = ~in1; -
dataMem_wr=0,不能對dataMem進行寫操作 -
acc_wr=1,可以對acc進行寫操作
此時in1、in2均不變
15~20ns時:15ns時鐘下降沿,ALU將Z=111111111111寫入ACC中,同時ACC輸出數據到in1,使得in1=111111111111;
3. 算術右移一位指令SHR
20ns~25ns時:20ns時鐘上升沿,pc_addr加1得pc_addr=000000000010,到insMem中取出指令ins=0010000000000000,其中的操作碼operation=0010傳給CU
4'b0010: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100010;
CU發出以上各種控制信號
-
alu_op=0010,然后alu執行算術右移一位指令SHR,結果Z=111111111111//算術右移一位指令SHR 4'b0010: Z = in1[15] == 1 ? {1'b1, in1[15:1]} : {1'b0, in1[15:1]}; -
dataMem_wr=0,不能對dataMem進行寫操作;acc_wr=1,可以對acc進行寫操作
in2不變
25~30ns時:25ns時鐘下降沿,ALU將Z=111111111111寫入ACC中,同時ACC輸出數據,使得in1=111111111111;in2不變
4. 循環左移一位指令CSL
30ns~35ns時:30ns時鐘上升沿,pc_addr加1得pc_addr=00000011,到insMem中取出指令ins=0011000000000000,其中的操作碼operation=0011傳給CU
4'b0011: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100011;
CU發出以上各種控制信號
-
alu_op=0011,alu執行循環左移一位指令CSL,結果Z=111111111111//循環左移一位指令 CSL4'b0011: Z = {in1[14:0], in1[15]}; -
dataMem_wr=0,不能對dataMem進行寫操作;acc_wr=1,可以對acc進行寫操作
in2不變
35~40ns時:35ns時鐘下降沿,ALU將Z=111111111111寫入ACC中,同時ACC輸出數據,使得in1=111111111111;in2不變
5. 加法指令ADD
40ns~45ns時:40ns時鐘上升沿,pc_addr加1得pc_addr=00000100,到insMem中取出指令ins=0100000000000001,其中的操作碼operation=0100傳給CU
4'b0100: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100100;
CU發出以上各種控制信號
-
alu_op=0100,然后alu執行加法指令ADD,in2從dataMem[1]讀入數據,與ACC的數據相加得結果Z=1111111111111111+b0000000000000010=0000000000000001//加法指令ADD 4'b0100: Z = in1 + in2; -
dataMem_wr=0,不能對dataMem進行寫操作; -
acc_wr=1,可以對acc進行寫操作
45~50ns時:45ns時鐘下降沿,ALU將Z=0000000000000001寫入ACC中,同時ACC輸出數據,使得in1=0000000000000001;in2不變;Z=in1+in2=0000000000000011
6. 存數指令STA
50ns~55ns時:50ns時鐘上升沿,pc_addr加1得pc_addr=000000000101,到insMem中取出指令ins=0101000000000000,其中的操作碼operation=0101傳給CU
4'b0101: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00010101;
CU發出以上各種控制信號
-
alu_op=0101,然后alu執行存數指令STA,結果Z=in1=0000000000000001//存數指令STA 4'b0101: Z = in1; -
dataMem_wr=1,可以對dataMem進行寫操作 -
acc_wr=0,不能對acc進行寫操作
55~60ns時:55ns時鐘下降沿,ALU將Z=0000000000000001寫入dataMem[000000000101]中,輸出數據,使得in2=0000000000000001;in1不變
7. 取數指令LDA
60ns~65ns時:60ns時鐘上升沿,pc_addr加1得pc_addr=00000110,到insMem中取出指令ins=0110000000000000,其中的操作碼operation=0110傳給CU
4'b0110: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00100110;
CU發出以上各種控制信號
-
alu_op=0110,然后alu執行取數指令LDA,結果Z=in2=0000000000000001 -
dataMem_wr=0,不能對dataMem進行寫操作;acc_wr=1,可以對acc進行寫操作
65~70ns時:65ns時鐘下降沿,ALU將Z=0000000000000001寫入ACC中,同時輸出數據,使得in1=0000000000000001;in2不變
8. 無條件轉移指令JMP
70ns~75ns時:70ns時鐘上升沿,pc_addr加1得pc_addr=000000000111,到insMem中取出指令ins=0111000000001001,其中的操作碼operation=0111傳給CU
4'b0111: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00000111;
CU發出以上各種控制信號
alu_op=0111,然后alu執行無條件轉移指令JMPdataMem_wr=0,不能對dataMem進行寫操作;acc_wr=0,不能對acc進行寫操作uct=1,進行無條件轉移
75~80ns時:75ns時鐘下降沿,pc被修改,轉移偏移量為9,pc_addr=000000001001-1=000000001000;
9. 有條件轉移指令BAN
80ns~85ns時:80ns時鐘上升沿,pc_addr加1得pc_addr=00001001,到insMem中取出指令ins=1000000000001001,其中的操作碼operation=1000傳給CU
4'b1000: {stop,uct,acc_wr,dataMem_wr,alu_op} = 8'b00001000;
CU發出以上各種控制信號
-
alu_op=1001,然后alu執行有條件轉移指令BAN,結果ct=0//有條件轉移BAN 4'b1000: ct = in1[15]==1?1:0; -
dataMem_wr=0,不能對dataMem進行寫操作; -
acc_wr=0,不能對acc進行寫操作
85~90ns時:75ns時鐘下降沿,由于ct,所以pc不被修改,保持不變
10. 停機指令STP
90ns后:90ns時鐘上升沿,pc_addr加1得pc_addr=00001001,到insMem中取出指令ins=100100000000000,其中的操作碼operation=1001傳給CU
4'b1001: {stop,uct,ct,acc_wr,dataMem_wr,alu_op} = 8'b100000000;
CU使stop=1,發出停機控制信號,執行停機指令
//停機指令STP
4'b1001: ;
從此pc不再增加,保持不變
總結
以上是生活随笔為你收集整理的单周期十条指令CPU设计与verilog实现(Modelsim)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VS Code搭建C/C++开发环境超详
- 下一篇: Docker暴露端口服务器公网IP无法访