單周期CPU設計
終於有點時間了,恰好多周期的設計也已經完成,其實只想寫寫多周期的,無奈單周期補上才好,哈哈哈~
—————+—————黃金分割線—————+—————
首先要理解什麽叫單周期CPU(與後面多周期CPU對比)單周期CPU指的是一條指令的執行在一個時鐘周期內完成,然後開始下一條指令的執行,即一條指令用一個時鐘周期完成。
單周期CPU的功能:能夠實現一些指令功能操作。需設計的指令與格式如下:
==>算術運算指令
(1)add rd , rs, rt (說明:以助記符表示,是匯編指令;以代碼表示,是機器指令)
000000 |
rs(5位) |
rt(5位) |
rd(5位) |
reserved |
功能:rd←rs + rt。reserved為預留部分,即未用,一般填“0”。
(2)addi rt , rs ,immediate
000001 |
rs(5位) |
rt(5位) |
immediate(16位) |
功能:rt←rs + (sign-extend)immediate;immediate符號擴展再參加“加”運算。
(3)sub rd , rs , rt
000010 |
rs(5位) |
rt(5位) |
rd(5位) |
reserved |
完成功能:rd←rs - rt
==> 邏輯運算指令
(4)ori rt , rs ,immediate
010000 |
rs(5位) |
rt(5位) |
immediate(16位) |
功能:rt←rs | (zero-extend)immediate;immediate做“0”擴展再參加“或”運算。
(5)and rd , rs , rt
010001 |
rs(5位) |
rt(5位) |
rd(5位) |
reserved |
功能:rd←rs & rt;邏輯與運算。
(6)or rd , rs , rt
010010 |
rs(5位) |
rt(5位) |
rd(5位) |
reserved |
功能:rd←rs | rt;邏輯或運算。
==> 傳送指令
(7)move rd , rs
100000 |
rs(5位) |
00000 |
rd(5位) |
reserved |
功能:rd←rs + $0 ;$0=$zero=0。
==> 存儲器讀/寫指令
(8)sw rt ,immediate(rs) 寫存儲器
100110 |
rs(5位) |
rt(5位) |
immediate(16位) |
功能:memory[rs+ (sign-extend)immediate]←rt;immediate符號擴展再相加。
(9) lw rt , immediate(rs)讀存儲器
100111 |
rs(5位) |
rt(5位) |
immediate(16位) |
功能:rt ← memory[rs + (sign-extend)immediate];immediate符號擴展再相加。
==> 分支指令
(10)beq rs,rt,immediate
110000 |
rs(5位) |
rt(5位) |
immediate(位移量,16位) |
功能:if(rs=rt) pc←pc +4 + (sign-extend)immediate <<2;
特別說明:immediate是從PC+4地址開始和轉移到的指令之間指令條數。immediate符號擴展之後左移2位再相加。為什麽要左移2位?由於跳轉到的指令地址肯定是4的倍數(每條指令占4個字節),最低兩位是“00”,因此將immediate放進指令碼中的時候,是右移了2位的,也就是以上說的“指令之間指令條數”。
==>停機指令
(11)halt
111111 |
00000000000000000000000000(26位) |
功能:停機;不改變PC的值,PC保持不變。
設計原理
CPU在處理指令時,一般需要經過以下幾個步驟:
(1) 取指令(IF):根據程序計數器PC中的指令地址,從存儲器中取出一條指令,同時,PC根據指令字長度自動遞增產生下一條指令所需要的指令地址,但遇到“地址轉移”指令時,則控制器把“轉移地址”送入PC,當然得到的“地址”需要做些變換才送入PC。
(2) 指令譯碼(ID):對取指令操作中得到的指令進行分析並譯碼,確定這條指令需要完成的操作,從而產生相應的操作控制信號,用於驅動執行狀態中的各種操作。
(3) 指令執行(EXE):根據指令譯碼得到的操作控制信號,具體地執行指令動作,然後轉移到結果寫回狀態。
(4) 存儲器訪問(MEM):所有需要訪問存儲器的操作都將在這個步驟中執行,該步驟給出存儲器的數據地址,把數據寫入到存儲器中數據地址所指定的存儲單元或者從存儲器中得到數據地址單元中的數據。
(5) 結果寫回(WB):指令執行的結果或者訪問存儲器中得到的數據寫回相應的目的寄存器中。
單周期CPU,是在一個時鐘周期內完成這五個階段的處理。
MIPS32的指令的三種格式:
R類型:
31 26 25 21 20 16 15 11 10 6 5 0
op |
rs |
rt |
rd |
sa |
func |
6位 5位 5位 5位 5位 6位
I類型:
31 26 25 21 20 16 15 0
op |
rs |
rt |
immediate |
6位 5位 5位 16位
J類型:
31 26 25 0
op |
address |
6位 26位
其中,
op:為操作碼;
rs:為第1個源操作數寄存器,寄存器地址(編號)是00000~11111,00~1F;
rt:為第2個源操作數寄存器,或目的操作數寄存器,寄存器地址(同上);
rd:為目的操作數寄存器,寄存器地址(同上);
sa:為位移量(shift amt),移位指令用於指定移多少位;
func:為功能碼,在寄存器類型指令中(R類型)用來指定指令的功能;
immediate:為16位立即數,用作無符號的邏輯操作數、有符號的算術操作數、數據加載(Laod)/數據保存(Store)指令的數據地址字節偏移量和分支指令中相對程序計數器(PC)的有符號偏移量;
address:為地址。
圖2是一個簡單的基本上能夠在單周期上完成所要求設計的指令功能的數據通路和必要的控制線路圖。其中指令和數據各存儲在不同存儲器中,即有指令存儲器和數據存儲器。訪問存儲器時,先給出地址,然後由讀/寫信號控制(1-寫,0-讀。當然,也可以由時鐘信號控制,但必須在圖上標出)。對於寄存器組,讀操作時,先給出地址,輸出端就直接輸出相應數據;而在寫操作時,在 WE使能信號為1時,在時鐘邊沿觸發寫入。圖中控制信號作用如表1所示,表2是ALU運算功能表。
表1 控制信號的作用
控制信號名 |
狀態“0” |
狀態“1” |
PCWre |
PC不更改,相關指令:halt |
PC更改,相關指令:除指令halt外 |
ALUSrcB |
來自寄存器堆data2輸出,相關指令:add、sub、or、and、move、beq |
來自sign或zero擴展的立即數,相關指令:addi、ori、sw、lw |
ALUM2Reg |
來自ALU運算結果的輸出,相關指令:add、addi、sub、ori、or、and、move |
來自數據存儲器(Data MEM)的輸出,相關指令:lw |
RegWre |
無寫寄存器組寄存器,相關指令: sw、halt |
寄存器組寫使能,相關指令:add、addi、sub、ori、or、and、move、lw |
InsMemRW |
讀指令存儲器(Ins. Data),初始化為0 |
寫指令存儲器 |
DataMemRW |
讀數據存儲器,相關指令:lw |
寫數據存儲器,相關指令:sw |
ExtSel |
相關指令:ori,(zero-extend)immediate(0擴展) |
相關指令:addi、sw、lw、beq, (sign-extend)immediate(符號擴展) |
PCSrc |
PC←PC+4,相關指令:add、sub、ori、or、and、move、sw、lw、beq(zero=0) |
PC←PC+4+(sign-extend)immediate,同時zero=1,相關指令:beq |
RegOut |
寫寄存器組寄存器的地址,來自rt字段,相關指令:addi、ori、lw |
寫寄存器組寄存器的地址,來自rd字段,相關指令:add、sub、and、or、move |
ALUOp[2..0] |
ALU 8種運算功能選擇(000-111),看功能表 |
相關部件及引腳說明:
InstructionMemory:指令存儲器,
Iaddr,指令存儲器地址輸入端口
IDataIn,指令存儲器數據輸入端口(指令代碼輸入端口)
IDataOut,指令存儲器數據輸出端口(指令代碼輸出端口)
RW,指令存儲器讀寫控制信號,為1寫,為0讀
DataMemory:數據存儲器,
Daddr,數據存儲器地址輸入端口
DataIn,數據存儲器數據輸入端口
DataOut,數據存儲器數據輸出端口
RW,數據存儲器讀寫控制信號,為1寫,為0讀
RegisterFile:(寄存器組)
Read Reg1,rs寄存器地址輸入端口
Read Reg2,rt寄存器地址輸入端口
Write Reg,將數據寫入的寄存器端口,其地址來源rt或rd字段
Write Data,寫入寄存器的數據輸入端口
Read Data1,rs寄存器數據輸出端口
Read Data2,rt寄存器數據輸出端口
WE,寫使能信號,為1時,在時鐘上升沿寫入
ALU:
result,ALU運算結果
zero,運算結果標誌,結果為0輸出1,否則輸出0
表2 ALU運算功能表
ALUOp[2..0] |
功能 |
描述 |
000 |
A + B |
加 |
001 |
A – B |
減 |
010 |
B – A |
減 |
011 |
A ∨ B |
或 |
100 |
A ∧ B |
與 |
101 |
/A ∧ B |
A非與B |
110 |
A ? B |
異或 |
111 |
A ⊙ B |
同或 |
需要說明的是根據要實現的指令功能要求畫出以上數據通路圖,和確定ALU的運算功能(當然,以上指令沒有完全用到提供的ALU所有功能,但至少必須能實現以上指令功能操作)。從數據通路圖上可以看出控制單元部分需要產生各種控制信號,當然,也有些信號必須要傳送給控制單元。從指令功能要求和數據通路圖的關系得出以上表1,這樣,從表1可以看出各控制信號與相應指令之間的相互關系,根據這種關系就可以得出控制信號與指令之間的關系表(如下),再根據關系表可以寫出各控制信號的邏輯表達式,這樣控制單元部分就可實現了。
表3 控制信號與指令的關系表
|
控制信號 |
||||||||||
指令 |
z |
PCWre |
ALUSrcB |
ALUM2Reg |
RegWre |
InsMemRW |
DataMemRW |
ExtSel |
PCSrc |
RegOut |
ALUOp[2..0] |
add |
x |
1 |
0 |
0 |
1 |
0 |
x |
x |
0 |
1 |
000 |
addi |
x |
1 |
1 |
0 |
1 |
0 |
x |
1 |
0 |
0 |
000 |
sub |
x |
1 |
0 |
0 |
1 |
0 |
x |
x |
0 |
1 |
001 |
ori |
x |
1 |
1 |
0 |
1 |
0 |
x |
0 |
0 |
0 |
011 |
and |
x |
1 |
0 |
0 |
1 |
0 |
x |
x |
0 |
1 |
100 |
or |
x |
1 |
0 |
0 |
1 |
0 |
x |
x |
0 |
1 |
011 |
move |
x |
1 |
0 |
0 |
1 |
0 |
x |
x |
0 |
1 |
000 |
sw |
x |
1 |
1 |
x |
0 |
0 |
1 |
1 |
0 |
x |
000 |
lw |
x |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
0 |
000 |
beq |
0 |
1 |
0 |
x |
0 |
0 |
x |
1 |
0 |
x |
001 |
1 |
1 |
0 |
x |
0 |
0 |
x |
1 |
1 |
x |
001 |
|
halt |
x |
0 |
x |
x |
x |
0 |
x |
x |
x |
x |
xxx |
分析與設計
根據實驗原理中的單周期CPU數據通路和控制線路圖,我們可以清楚的知道單周期CPU的設計應包括controlUnit,RegisterFile, ALU, DataMemory, instructionMemory, PC, signZeroExtend這幾個模塊,其中為了運行整個CPU還需要加入一個頂層模塊(singleCycleCPU)來調用這七個模塊,所以自然地,這七個模塊為頂層模塊的子模塊。設計流程邏輯圖如下:
1、控制單元(controlUnit.v)
根據數據通路圖可以知道,控制單元的功能是接收一個6位的操作碼(opCode)和一個標誌符(zero)作為輸入,輸出PCWre、ALUSrcB等控制信號,各控制信號的作用見實驗原理的控制信號作用表(表1),從而達到控制各指令的目的。其中模塊內部實現則根據實驗原理中控制信號與指令的關系表(表3)列出各信號的邏輯表達式從而實現各信號的輸出。比如:
ALUOp的表達式為:ALUOp[2]=i_and
ALUOp[1]=i_ori | i_or
ALUOp[0]=i_sub | i_ori | i_or | i_beq
所以其實現為:assignALUOp[2] = (opCode == 6‘b010001)? 1 : 0;
assignALUOp[1] = (opCode == 6‘b010000 || opCode == 6‘b010010)? 1 : 0;
assign ALUOp[0] = (opCode == 6‘b000010 || opCode == 6‘b010000|| opCode == 6‘b010010 || opCode == 6‘b110000)? 1 : 0;
整個模塊設計如下:
[plain] view plain copy- </pre><pre name="code" class="plain">`timescale 1ns / 1ps
- module controlUnit(opCode, zero, PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut, ALUOp);
- input [5:0] opCode;
- input zero;
- output PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut;
- output[2:0] ALUOp;
- assign PCWre = (opCode == 6‘b111111)? 0 : 1;
- assign ALUSrcB = (opCode == 6‘b000001 || opCode == 6‘b010000 || opCode == 6‘b100110 || opCode == 6‘b100111)? 1 : 0;
- assign ALUM2Reg = (opCode == 6‘b100111)? 1 : 0;
- assign RegWre = (opCode == 6‘b100110 || opCode == 6‘b111111)? 0 : 1;
- assign InsMemRW = 0;
- assign DataMemRW = (opCode == 6‘b100111)? 0 : 1;
- assign ExtSel = (opCode == 6‘b010000)? 0 : 1;
- assign PCSrc = (opCode == 6‘b110000 && zero == 1)? 1 : 0;
- assign RegOut = (opCode == 6‘b000001 || opCode == 6‘b010000 || opCode == 6‘b100111)? 0 : 1;
- assign ALUOp[2] = (opCode == 6‘b010001)? 1 : 0;
- assign ALUOp[1] = (opCode == 6‘b010000 || opCode == 6‘b010010)? 1 : 0;
- assign ALUOp[0] = (opCode == 6‘b000010 || opCode == 6‘b010000 || opCode == 6‘b010010 || opCode == 6‘b110000)? 1 : 0;
- endmodule
[html] view plain copy
- `timescale 1ns / 1ps
- module ALU(ReadData1, ReadData2, inExt, ALUSrcB, ALUOp, zero, result);
- input [31:0] ReadData1, ReadData2, inExt;
- input ALUSrcB;
- input [2:0] ALUOp;
- output zero;
- output [31:0] result;
- reg zero;
- reg [31:0] result;
- wire [31:0] B;
- assign B = ALUSrcB? inExt : ReadData2;
- always @(ReadData1 or ReadData2 or inExt or ALUSrcB or ALUOp or B)
- begin
- case(ALUOp)
- // A + B
- 3‘b000: begin
- result = ReadData1 + B;
- zero = (result == 0)? 1 : 0;
- end
- // A - B
- 3‘b001: begin
- result = ReadData1 - B;
- zero = (result == 0)? 1 : 0;
- end
- // B - A
- 3‘b010: begin
- result = B - ReadData1;
- zero = (result == 0)? 1 : 0;
- end
- // A ∨ B
- 3‘b011: begin
- result = ReadData1 | B;
- zero = (result == 0)? 1 : 0;
- end
- // A ∧ B
- 3‘b100: begin
- result = ReadData1 & B;
- zero = (result == 0)? 1 : 0;
- end
- // /A ∧ B
- 3‘b101: begin
- result = (~ReadData1) & B;
- zero = (result == 0)? 1 : 0;
- end
- // A ⊕ B
- 3‘b110: begin
- result = ReadData1 ^ B;
- zero = (result == 0)? 1 : 0;
- end
- // A ⊙ B
- 3‘b111: begin
- result = ReadData1 ^~ B;
- zero = (result == 0)? 1 : 0;
- end
- endcase
- end
- endmodule
3、PC單元(PC.v)
PC單元以時鐘信號clk、重置標誌Reset、立即數以及PCWreck和PCSrc兩個信號控制為輸入,輸出當前PC地址,具體設計如下:
[html] view plain copy
- `timescale 1ns / 1ps
- module PC(clk, Reset, PCWre, PCSrc, immediate, Address);
- input clk, Reset, PCWre, PCSrc;
- input [31:0] immediate;
- output [31:0] Address;
- reg [31:0] Address;
- /*initial begin
- Address = 0;
- end*/
- always @(posedge clk or negedge Reset)
- begin
- if (Reset == 0) begin
- Address = 0;
- end
- else if (PCWre) begin
- if (PCSrc) Address = Address + 4 + immediate*4;
- else Address = Address + 4;
- end
- end
- endmodule
4、 擴展單元(signZeroExtend.v)
擴展單元的設計比較簡單,其功能就是將一個16位的立即數擴展到32位,具體模塊設計如下:
[html] view plain copy
- `timescale 1ns / 1ps
- module signZeroExtend(immediate, ExtSel, out);
- input [15:0] immediate;
- input ExtSel;
- output [31:0] out;
- assign out[15:0] = immediate;
- assign out[31:16] = ExtSel? (immediate[15]? 16‘hffff : 16‘h0000) : 16‘h0000;
- endmodule
5、數據存儲單元(DataMemory.v)
數據存儲單元的功能是讀取數據,根據數據通路圖可以有如下模塊設計:
[html] view plain copy
- `timescale 1ns / 1ps
- module dataMemory(DAddr, DataIn, DataMemRW, DataOut);
- input [31:0] DAddr, DataIn;
- input DataMemRW;
- output reg [31:0] DataOut;
- reg [31:0] memory[0:31];
- // read data
- always @(DataMemRW) begin
- if (DataMemRW == 0) assign DataOut = memory[DAddr];
- end
- // write data
- integer i;
- initial begin
- for (i = 0; i < 32; i = i+1) memory[i] <= 0;
- end
- always @(DataMemRW or DAddr or DataIn)
- begin
- if (DataMemRW) memory[DAddr] = DataIn;
- end
- endmodule
6、指令存儲單元(instructionMemory.v)
根據當前的PC地址得到對應的op,rs,rt,rd以及immediate.
內部實現:
將需要測試的匯編指令程序轉化為指令代碼,當然,每個人都可以有自己的測試指令,能正確轉化為指令代碼就好。為了書寫的簡便,我們可以將32位的二進制指令代碼轉化為16進制。具體測試表設計如下:
地址 |
匯編程序 |
指令代碼 |
|||||
op(6) |
rs(5) |
rt(5) |
rd(5)/immediate (16) |
16進制數代碼 |
|||
0x00000004 |
addi $1,$0,8 |
000001 |
00000 |
00001 |
0000 0000 0000 1000 |
= |
04010008 |
0x00000008 |
ori $2,$0,12 |
010000 |
00000 |
00010 |
0000 0000 0000 1100 |
= |
4002000C |
0x0000000C |
add $3,$1,$2 |
000000 |
00001 |
00010 |
00011 00000000000 |
= |
00221800 |
0x00000010 |
sub $4,$2,$1 |
000010 |
00010 |
00001 |
00100 00000000000 |
= |
08412000 |
0x00000014 |
and $5,$1,$2 |
010001 |
00001 |
00010 |
00101 00000000000 |
= |
44222800 |
0x00000018 |
or $6,$1,$2 |
010010 |
00001 |
00010 |
00110 00000000000 |
= |
48223000 |
0x0000001C |
beq $1,$2,4 (轉030) |
110000 |
00001 |
00010 |
0000 0000 0000 0100 |
= |
C0220004 |
0x00000020 |
move $7,$1 |
100000 |
00001 |
00000 |
00111 00000000000 |
= |
80203800 |
0x00000024 |
sw $1,1($7) |
100110 |
00111 |
00001 |
0000 0000 0000 0001 |
= |
98E10001 |
0x00000028 |
lw $2,0($1) |
100111 |
00001 |
00010 |
0000 0000 0000 0000 |
= |
9C220000 |
0x0000002C |
beq $2,$7,-5 (轉01C) |
110000 |
00010 |
00111 |
1111 1111 1111 1011 |
= |
C047FFFB |
0x00000030 |
halt |
111111 |
00000 |
00000 |
0000000000000000 |
= |
FC000000 |
其次,為了存儲這些指令代碼,可以申請一個32位的二進制數組來存儲它們,最後根據PC地址得到對應的op,rs,rt,immediate等,具體模塊設計如下:
[html] view plain copy
- `timescale 1ns / 1ps
- module instructionMemory(
- input [31:0] pc,
- input InsMemRW,
- output [5:0] op,
- output [4:0] rs, rt, rd,
- output [15:0] immediate);
- wire [31:0] mem[0:15];
- assign mem[0] = 32‘h00000000;
- // addi $1,$0,8
- assign mem[1] = 32‘h04010008;
- // ori $2,$0,12
- assign mem[2] = 32‘h4002000C;
- // add $3,$1,$2
- assign mem[3] = 32‘h00221800;
- // sub $4,$2,$1
- assign mem[4] = 32‘h08412000;
- // and $5,$1,$2
- assign mem[5] = 32‘h44222800;
- // or $6,$1,$2
- assign mem[6] = 32‘h48223000;
- // beq $1,$2,4 (轉030)
- assign mem[7] = 32‘hC0220004;
- // move $7,$1
- assign mem[8] = 32‘h80203800;
- // sw $1,1($7)
- assign mem[9] = 32‘h98E10001;
- // lw $2,0($1)
- assign mem[10] = 32‘h9C220000;
- // beq $2,$7,-5 (轉01C)
- assign mem[11] = 32‘hC047FFFB;
- // halt
- assign mem[12] = 32‘hFC000000;
- assign mem[13] = 32‘h00000000;
- assign mem[14] = 32‘h00000000;
- assign mem[15] = 32‘h00000000;
- // output
- assign op = mem[pc[5:2]][31:26];
- assign rs = mem[pc[5:2]][25:21];
- assign rt = mem[pc[5:2]][20:16];
- assign rd = mem[pc[5:2]][15:11];
- assign immediate = mem[pc[5:2]][15:0];
- endmodule
7、寄存器文件單元(registerFile.v)
寄存器文件單元的功能是接收instructionMemory中的rs,rt,rd作為輸入,輸出對應寄存器的數據,從而達到取寄存器裏的數據的目的。需要註意的是,在其內部實現的過程中,為了防止0號寄存器寫入數據需要在writeReg的時候多加入一個判斷條件,即writeReg不等於0時寫入數據。具體設計如下:
[html] view plain copy
- `timescale 1ns / 1ps
- module registerFile(clk, RegWre, RegOut, rs, rt, rd, ALUM2Reg, dataFromALU, dataFromRW, Data1, Data2);
- input clk, RegOut, RegWre, ALUM2Reg;
- input [4:0] rs, rt, rd;
- input [31:0] dataFromALU, dataFromRW;
- output [31:0] Data1, Data2;
- wire [4:0] writeReg;
- wire [31:0] writeData;
- assign writeReg = RegOut? rd : rt;
- assign writeData = ALUM2Reg? dataFromRW : dataFromALU;
- reg [31:0] register[0:31];
- integer i;
- initial begin
- for (i = 0; i < 32; i = i+1) register[i] <= 0;
- end
- // output
- assign Data1 = register[rs];
- assign Data2 = register[rt];
- // Write Reg
- always @(posedge clk or RegOut or RegWre or ALUM2Reg or writeReg or writeData) begin
- if (RegWre && writeReg) register[writeReg] = writeData; // 防止數據寫入0號寄存器
- end
- endmodule
8、頂層模塊(singleStyleCPU)
頂層模塊(singleStyleCPU)是整個CPU的控制模塊,通過連接各個子模塊來達到運行CPU的目的,整個模塊設計可以如下:
[html] view plain copy- `include "controlUnit.v"
- `include "dataMemory.v"
- `include "ALU.v"
- `include "instructionMemory.v"
- `include "registerFile.v"
- `include "signZeroExtend.v"
- `include "PC.v"
- `timescale 1ns / 1ps
- module SingleCycleCPU(
- input clk, Reset,
- output wire [5:0] opCode,
- output wire [31:0] Out1, Out2, curPC, Result);
- wire [2:0] ALUOp;
- wire [31:0] ExtOut, DMOut;
- wire [15:0] immediate;
- wire [4:0] rs, rt, rd;
- wire zero, PCWre, PCSrc, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, RegOut;
- // module ALU(ReadData1, ReadData2, inExt, ALUSrcB, ALUOp, zero, result);
- ALU alu(Out1, Out2, ExtOut, ALUSrcB, ALUOp, zero, Result);
- // module PC(clk, Reset, PCWre, PCSrc, immediate, Address);
- PC pc(clk, Reset, PCWre, PCSrc, ExtOut, curPC);
- // module controlUnit(opCode, zero, PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut, ALUOp);
- controlUnit control(opCode, zero, PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut, ALUOp);
- // module dataMemory(DAddr, DataIn, DataMemRW, DataOut);
- dataMemory datamemory(Result, Out2, DataMemRW, DMOut);
- /* module instructionMemory(
- input [31:0] pc,
- input InsMemRW,
- input [5:0] op,
- input [4:0] rs, rt, rd,
- output [15:0] immediate);*/
- instructionMemory ins(curPC, InsMemRW, opCode, rs, rt, rd, immediate);
- // module registerFile(clk, RegWre, RegOut, rs, rt, rd, ALUM2Reg, dataFromALU, dataFromRW, Data1, Data2);
- registerFile registerfile(clk, RegWre, RegOut, rs, rt, rd, ALUM2Reg, Result, DMOut, Out1, Out2);
- // module signZeroExtend(immediate, ExtSel, out);
- signZeroExtend ext(immediate, ExtSel, ExtOut);
- endmodule
[html] view plain copy
從頂層模塊中可以看出整個CPU的輸入只有時鐘信號clk和重置信號Reset,所以測試程序代碼比較簡單。(說明:下面是在測試文件中額外加的,因為其他初始化數據ISE已經自動生成,點贊)
Reset = 1; //初始化PC地址,為0
forever #100 clk = ~clk;
一個簡單的單周期就設計完成了,重點是要學會其中涉及到的模塊化思想,這中模塊化的分解思想應用極其廣泛,所以,最好學會熟練使用。
表臉粘一下仿真結果好了:
單周期CPU卒,見多周期CPU,2333~
原文:http://blog.csdn.net/zhaokx3/article/details/51493842
單周期CPU設計