數位電路設計之五級流水線設計(CPU)
這個流水線應該是我大二上的時候的最高水平了,現在看起來確實很簡單,程式碼風格也不是很好,沒有模組化,而且這些指令也不是嚴格的mips的所有指令,是自己定義的一些。但是放在部落格裡也算是對自己過去的一個總結吧!
現在再看這個程式碼,我覺得寫得太噁心了,沒有註釋,沒有說清楚關鍵的地方。我自己都忘了為什麼這麼寫~~
後來發現有非常坑爹的Bug!!!!祝好!!!我沒有改過來了~~~
• 實驗步驟
1.先寫好CPU的指令集。
2.根據指令集先把一些基本的指令實現,比如LOAD,STORE等,把大概的流水線先畫出框圖。畫出框圖後,把基本指令實現。除錯,模擬。
3.在2的基礎上加入別的指令,考慮好hazard的問題
4.優化程式碼程式碼,除錯,simulation。
• 實驗原理
流水線是數字系統中一種提高系統穩定性和工作速度的方法,廣泛應用於高檔CPU的架構中。根據MIPS處理器的特點,將整體的處理過程分為取指令(IF)、指令譯碼(ID)、執行(EX)、儲存器訪問(MEM)和暫存器會寫(WB)五級,對應多週期的五個處理階段。一個指令的執行需要5個時鐘週期,每個時鐘週期的上升沿來臨時,此指令所代表的一系列資料和控制資訊將轉移到下一級處理。
流水線暫存器負責將流水線的各部分分開,共有IF/ID、ID/EX、EX/MEM、MEM/WB四組。根據前面的介紹可知,四組流水線暫存器要求不完全相同,因此設計也有不同考慮。
(1)EX/MEM、MEM/WB兩組流水線暫存器只是普通暫存器。
(2)當流水線發生資料跳轉時,需清空ID/EX流水線暫存器而插入一個氣泡,因此ID/EX流水線暫存器是一個帶同步清零功能的暫存器。
需要注意的是,由於模擬對初始值的要求,上述暫存器都應考慮有reset訊號的接入,以提供模擬時各暫存器的初值。
流水線:
取址:處理器從指令儲存器中讀取指令
譯碼:處理器從暫存器檔案中讀取源運算元並對指令譯碼產生控制訊號
執行:處理器使用ALU執行計算
儲存器訪問:處理器從資料儲存器中讀取或者寫入資料
寫回:若是LOAD指令,將結果寫回暫存器檔案。
>>加、減電路的設計考慮
減法、比較及部分分支指令(BN、BNE等)均可用加法器和必要的輔助電路來實現。對ALU來說,它的兩個運算元輸入時都已經是補碼形式,當要完成兩個運算元的減法時,即A補-B補,可將減法轉換為加法,利用加法器來實現:
›A補-B補= A補+(-B補)= A補+(B補)補= A補+(B補)反+1
加法器完成的功能為:
sum=A+~B+1。即可完成加減運算。
由於32位加法器的運算速度影響著CPU頻率的高低,因此設計一個高速加法器尤為重要,本實驗採用的是超前進位加法器,不過弄出來的速度比不過描述級語言寫出的加法,所以後來加法就改成直接加了。
比較電路的設計考慮
對於比較運算,如果最高為不同,即A[31]≠B[31],則根據A[31]、B[31]決定比較結果,但應注意有符號數和無符號數比較運算的區別。
①在有符號數比較SLT運算中,判斷A<B的方法為:
若A為負數、B為0或正數:A[15]&&(~B[15])
若A、B符號相同,A-B為負:(A[15]~^B[15]) && sum[15]
則SLTResult=(A[15]&&(~B[15])) ||( (A[15]~^B[15]) && sum[15])
②在無符號數比較SLT運算中,判斷A<B的方法為:
若A最高位為0、B最高位為1:(~A[15] )&&B[15]
若A、B最高位相同,A-B為負:(A[15]~^B[15]) && sum[15]
則SLTResult=((~A[15] )&&B[15]) ||( (A[15]~^B[15]) && sum[15])
算術右移運算電路的設計考慮:
Verilog HDL的算術右移的運算子為“<<<”。要實現算術右移應注意,被移位的物件必須定義為reg型別,但是在SRA指令,被移位的物件運算元B為輸入訊號,不能定義為reg型別,因此必須引入reg型別中間變數B_reg,相應的Verilog HDL語句為:
reg signed [31:0] B_reg;
always @(B) begin
B_reg = B; end
引入reg型別的中間變數B_reg後,就可對B_reg進行算術右移操作。
邏輯運算:
與、或、或非、異或、邏輯移位等運算較為簡單,只是要注意一點,AND、XOR、OR三條指令的立即數為16位無符號數,應“0擴充套件”為32位無符號數,在運算的同時完成“0擴充套件”。
CPU的verilog程式碼:
`timescale 1ns / 1ps
// state macro define
`define idle 1'b0
`define exec 1'b1
// instruction macro define
`define NOP 5'b00000
`define HALT 5'b00001
`define LOAD 5'b00010
`define STORE 5'b00011
`define SLL 5'b00100
`define SLA 5'b00101
`define SRL 5'b00110
`define SRA 5'b00111
`define ADD 5'b01000
`define ADDI 5'b01001
`define SUB 5'b01010
`define SUBI 5'b01011
`define CMP 5'b01100
`define AND 5'b01101
`define OR 5'b01110
`define XOR 5'b01111
`define LDIH 5'b10000
`define ADDC 5'b10001
`define SUBC 5'b10010
`define JUMP 5'b11000
`define JMPR 5'b11001
`define BZ 5'b11010
`define BNZ 5'b11011
`define BN 5'b11100
`define BNN 5'b11101
`define BC 5'b11110
`define BNC 5'b11111
// general register
`define gr0 3'b000
`define gr1 3'b001
`define gr2 3'b010
`define gr3 3'b011
`define gr4 3'b100
`define gr5 3'b101
`define gr6 3'b110
`define gr7 3'b111
module CPU(input wire reset,
input wire enable, //make the
input wire start, //start CPU
input wire clock, //clock
input wire [15:0]i_datain, //instruction
input wire [15:0]d_datain, //data from memory
output reg d_we, //write enable
output wire [7:0]i_addr, //pc
output reg [7:0]d_addr, //output adder for data memory
output reg [15:0]d_dataout //output data to data memory
);
reg [15:0]gr[7:0]; //register file
reg state,next_state; //to control the CPU
assign i_addr = pc;
//************* CPU control *************//
always @(posedge clock)
begin
if (!reset)
state <= `idle;
else
state <= next_state;
end
[email protected](*)
begin
case (state)
`idle :
if ((enable == 1'b1) && (start == 1'b1))
next_state <= `exec;
else
next_state <= `idle;
`exec :
if ((enable == 1'b0) || (wb_ir[15:11] == `HALT))
next_state <= `idle;
else
next_state <= `exec;
endcase
end
//_______________________________________________
reg [15:0]id_ir;
reg [7:0]pc;
//************* IF *************//
[email protected](posedge clock or negedge reset)
begin
if (!reset)
begin
id_ir <= 16'b0000_0000_0000_0000;
pc <= 8'b0000_0000;
end
else if (state ==`exec)
begin
if(((ex_ir[15:11] == `BZ) && (zf == 1'b1)) || ((ex_ir[15:11] == `BN) && (nf == 1'b1))||
((ex_ir[15:11] == `BNZ) && (zf == 1'b0)) || ((ex_ir[15:11] == `BNN) && (nf == 1'b0))||
((ex_ir[15:11] == `BC) && (cf == 1'b1)) || ((ex_ir[15:11] == `BNC) && (cf == 1'b0))||
ex_ir[15:11] == `JMPR)
begin
pc <= ALUo[7:0];
id_ir <= i_datain;
end
else if(id_ir[15:11] == `JUMP)//如果判斷出指令是JUMP,直接跳轉,就可以減少功耗,不必冒險
begin
pc <= id_ir[7:0];
id_ir <= i_datain;
end
//------------------------------------------------對於LOAD的處理--------------------------------------
else if((id_ir[15:11] == `LOAD)&&(i_datain[15:11]!=`JUMP)&&(i_datain[15:11]!=`NOP)&&(i_datain[15:11]!=`HALT)
&&(i_datain[15:11]!=`LOAD))
begin
if((id_ir[10:8]==i_datain[2:0])&&((i_datain[15:11]==`ADD)||(i_datain[15:11]==`ADDC)||(i_datain[15:11]==`SUB)
||(i_datain[15:11]==`SUBC)||(i_datain[15:11]==`CMP)||(i_datain[15:11]==`AND)||(i_datain[15:11]==`OR)
||(i_datain[15:11]==`XOR)))
begin
pc <= pc;
id_ir <= 16'bx;
end
else if((id_ir[10:8]==i_datain[6:4])&&((i_datain[15:11]==`STORE)||(i_datain[15:11]==`ADD)||(i_datain[15:11]==`ADDC)
||(i_datain[15:11]==`SUB)||(i_datain[15:11]==`SUBC)||(i_datain[15:11]==`AND)||(i_datain[15:11]==`OR)
||(i_datain[15:11]==`XOR)||(i_datain[15:11]==`CMP)||(i_datain[15:11]==`SLL)||(i_datain[15:11]==`SRL)
||(i_datain[15:11]==`SLA)||(i_datain[15:11]==`SRA)
))
begin
pc <= pc;
id_ir <= 16'bx;
end
else if((id_ir[10:8]==i_datain[10:8])&&((i_datain[15:11]==`STORE)||(i_datain[15:11]==`LDIH)||(i_datain[15:11]==`SUBI)
||(i_datain[15:11]==`JMPR)||(i_datain[15:11]==`BZ)||(i_datain[15:11]==`BNZ)||(i_datain[15:11]==`BN)
||(i_datain[15:11]==`BNN)||(i_datain[15:11]==`BNC)))
begin
pc <= pc;
id_ir <= 16'bx;
end
end
else
begin
pc <= pc + 1;
id_ir <= i_datain;
end
end
else if (state ==`idle)
pc <= pc;
else;
end
//----------------------------------------------------------------------------------------------------------------------------------------------------
reg [15:0]ex_ir,reg_A,reg_B,smdr;
//************* ID *************//
[email protected](posedge clock or negedge reset)
begin
if(!reset)
begin
ex_ir <= 16'b0000_0000_0000_0000;
reg_A <= 16'b0000_0000_0000_0000;
reg_B <= 16'b0000_0000_0000_0000;
smdr <= 16'b0000_0000_0000_0000;
end
else if (state == `exec)
begin
ex_ir <= id_ir;
//------------------根據不同的操作,reg_A的賦值以處理hazard-------------------------------
if ((id_ir[15:11] == `BZ) || (id_ir[15:11] == `BN) || (id_ir[15:11] == `BNZ) || (id_ir[15:11] == `BNN) || (id_ir[15:11] == `JMPR)
|| (id_ir[15:11] == `LDIH)||(id_ir[15:11] == `ADDI) || (id_ir[15:11] == `SUBI) || (id_ir[15:11] == `BC) || (id_ir[15:11] == `BNC))
begin //處理ADD等hazard
if((id_ir[10:8]==ex_ir[10:8])&&(ex_ir!=`NOP)&&(ex_ir!=`CMP)&&(ex_ir!=`JUMP)&&(ex_ir!=`LOAD)&&(ex_ir!=`HALT))//這些指令沒有目的暫存器,LOAD指令是所需的內容還沒有出來存
reg_A <= ALUo; //後一條指令要用到前一條指令的結果
else if((id_ir[10:8]==mem_ir[10:8])&&(mem_ir!=`NOP)&&(mem_ir!=`CMP)&&(mem_ir!=`JUMP)&&(mem_ir!=`HALT))
//----------------------------------------------------------------------
begin
if(mem_ir==`LOAD)
reg_A <= d_datain;
else
reg_A <= reg_C; //看看LOAD指令在這裡會不會已經出結果了
end
//----------------------------------------------------------------------
else if((id_ir[10:8]== wb_ir[10:8])&&(wb_ir!=`NOP)&&(wb_ir!=`CMP)&&(wb_ir!=`JUMP)&&(wb_ir!=`HALT))
reg_A <= reg_C1;
else
//reg_A <= gr[id_ir[10:8]];
begin
if(id_ir[10:8] == 0)
reg_A <= gr[0];
else if(id_ir[10:8] == 1)
reg_A <= gr[1];
else if(id_ir[10:8] == 2)
reg_A <= gr[2];
else if(id_ir[10:8] == 3)
reg_A <= gr[3];
else if(id_ir[10:8] == 4)
reg_A <= gr[4];
else if(id_ir[10:8] == 5)
reg_A <= gr[5];
else if(id_ir[10:8] == 6)
reg_A <= gr[6];
else if(id_ir[10:8] == 7)
reg_A <= gr[7];
end
end
else if((id_ir[15:11] == `ADD)||(id_ir[15:11] == `LOAD)||(id_ir[15:11] == `STORE)||(id_ir[15:11] == `ADDC)||(id_ir[15:11] == `SUB)
||(id_ir[15:11] == `SUBC)||(id_ir[15:11] == `CMP) ||(id_ir[15:11] == `AND) ||(id_ir[15:11] == `OR) ||(id_ir[15:11] == `XOR)
||(id_ir[15:11] == `SLL) ||(id_ir[15:11] == `SRL) ||(id_ir[15:11] == `SLA) ||(id_ir[15:11] == `SRA))
//LAOD,STORE,CMP,ADD,ADDC,SUB,SUBC,AND,OR,XOR,SLL,SRL,SLA,SRA
begin //處理ADD等hazard
if((id_ir[6:4]==ex_ir[10:8])&&(ex_ir!=`NOP)&&(ex_ir!=`CMP)&&(ex_ir!=`JUMP)&&(ex_ir!=`LOAD)&&(ex_ir!=`HALT))//這些指令沒有目的暫存器,LOAD指令是所需的內容還沒有出來存
reg_A <= ALUo; //後一條指令要用到前一條指令的結果
else if((id_ir[6:4]==mem_ir[10:8])&&(mem_ir!=`NOP)&&(mem_ir!=`CMP)&&(mem_ir!=`JUMP)&&(mem_ir!=`HALT))
//----------------------------------------------------------------------
begin
if(mem_ir[15:11]==`LOAD)
reg_A <= d_datain;
else
reg_A <= reg_C;
end
//----------------------------------------------------------------------
else if((id_ir[6:4]== wb_ir[10:8])&&(wb_ir!=`NOP)&&(wb_ir!=`CMP)&&(wb_ir!=`JUMP)&&(wb_ir!=`HALT))
reg_A <= reg_C1;
else
begin
if(id_ir[6:4] == 0)
reg_A <= gr[0];
else if(id_ir[6:4] == 1)
reg_A <= gr[1];
else if(id_ir[6:4] == 2)
reg_A <= gr[2];
else if(id_ir[6:4] == 3)
reg_A <= gr[3];
else if(id_ir[6:4] == 4)
reg_A <= gr[4];
else if(id_ir[6:4] == 5)
reg_A <= gr[5];
else if(id_ir[6:4] == 6)
reg_A <= gr[6];
else if(id_ir[6:4] == 7)
reg_A <= gr[7];
end
end
else if((( mem_ir[15:11] == `BZ) && (zf == 1'b1)) || ((mem_ir[15:11] == `BN) && (nf == 1'b1)) ||
(( mem_ir[15:11] == `BNZ) && (zf == 1'b0))|| ((mem_ir[15:11] == `BNN) && (nf == 1'b0))||
((mem_ir[15:11] == `BC) && (cf == 1'b1)) || ((mem_ir[15:11] == `BNC) && (cf == 1'b0))||
mem_ir[15:11] == `JMPR)
reg_A <= 16'b0000_0000_0000_0000;
else;
//------------------根據不同的操作,reg_B的賦值以處理hazard-------------------------------
if (id_ir[15:11] == `LDIH)
reg_B <= {id_ir[7:0], 8'b0000_0000};
else if ((id_ir[15:11] == `LOAD) || (id_ir[15:11] == `STORE) || (id_ir[15:11] == `SLL)
|| (id_ir[15:11] == `SRL) || (id_ir[15:11] == `SLA) || (id_ir[15:11] == `SRA))
reg_B <= {12'b0000_0000_0000, id_ir[3:0]};
else if ((id_ir[15:11] == `BZ) || (id_ir[15:11] == `BN) || (id_ir[15:11] == `BNZ) || (id_ir[15:11] == `BNN)|| (id_ir[15:11] == `JMPR)
|| (id_ir[15:11] == `SUBI) || (id_ir[15:11] == `ADDI) || (id_ir[15:11] == `BC) || (id_ir[15:11] == `BNC) || (id_ir[15:11] == `JUMP))
reg_B <= {8'b0000_0000, id_ir[7:0]};
else if ((id_ir[15:11] == `ADD)||(id_ir[15:11] == `ADDC)||(id_ir[15:11] == `SUB)||(id_ir[15:11] == `SUBC)
||(id_ir[15:11] == `CMP)||(id_ir[15:11] == `AND) ||(id_ir[15:11] == `OR) ||(id_ir[15:11] == `XOR))
//ADD,ADDC,SUB,SUBC,AND,OR,XOR,CMP
begin //處理ADD等hazard
if((id_ir[2:0]==ex_ir[10:8])&&(ex_ir!=`NOP)&&(ex_ir!=`CMP)&&(ex_ir!=`JUMP)&&(ex_ir!=`LOAD)&&(ex_ir!=`HALT))//這些指令沒有目的暫存器,LOAD指令是所需的內容還沒有出來存
reg_B <= ALUo; //後一條指令要用到前一條指令的結果
else if((id_ir[2:0]==mem_ir[10:8])&&(mem_ir!=`NOP)&&(mem_ir!=`CMP)&&(mem_ir!=`JUMP)&&(mem_ir!=`HALT))
//----------------------------------------------------------------------
begin
if(mem_ir[15:11]==`LOAD)
reg_B <= d_datain;
else
reg_B <= reg_C; //看看LOAD指令在這裡會不會已經出結果了
end
//----------------------------------------------------------------------
else if((id_ir[2:0]== wb_ir[10:8])&&(wb_ir!=`NOP)&&(wb_ir!=`CMP)&&(wb_ir!=`JUMP)&&(wb_ir!=`HALT))
reg_B <= reg_C1;
else
//reg_B <= gr[id_ir[2:0]];
begin
if(id_ir[2:0] == 0)
reg_B <= gr[0];
else if(id_ir[2:0] == 1)
reg_B <= gr[1];
else if(id_ir[2:0] == 2)
reg_B <= gr[2];
else if(id_ir[2:0] == 3)
reg_B <= gr[3];
else if(id_ir[2:0] == 4)
reg_B <= gr[4];
else if(id_ir[2:0] == 5)
reg_B <= gr[5];
else if(id_ir[2:0] == 6)
reg_B <= gr[6];
else if(id_ir[2:0] == 7)
reg_B <= gr[7];
end
end
else if(((mem_ir[15:11] == `BZ) && (zf == 1'b1)) || ((mem_ir[15:11] == `BN) && (nf == 1'b1))||
((mem_ir[15:11] == `BNZ) && (zf == 1'b0)) || ((mem_ir[15:11] == `BNN) && (nf == 1'b0))||
((mem_ir[15:11] == `BC) && (cf == 1'b1)) || ((mem_ir[15:11] == `BNC) && (cf == 1'b0))||
mem_ir[15:11] == `JMPR)
reg_B <= 16'b0000_0000_0000_0000;
else;
//-----------------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------對smdr的賦值---------------------------------------------------
if(id_ir[15:11] == `STORE)
// smdr <= gr[id_ir[10:8]];
begin //處理ADD等hazard
if((id_ir[10:8]==ex_ir[10:8])&&(ex_ir!=`NOP)&&(ex_ir!=`CMP)&&(ex_ir!=`JUMP)&&(ex_ir!=`LOAD)&&(ex_ir!=`HALT))//這些指令沒有目的暫存器,LOAD指令是所需的內容還沒有出來存
smdr <= ALUo; //後一條指令要用到前一條指令的結果
else if((id_ir[10:8]==mem_ir[10:8])&&(mem_ir!=`NOP)&&(mem_ir!=`CMP)&&(mem_ir!=`JUMP)&&(mem_ir!=`HALT))
//----------------------------------------------------------------------
begin
if(mem_ir==`LOAD)
smdr <= d_datain;
else
smdr <= reg_C;
end
//----------------------------------------------------------------------
else if((id_ir[10:8]== wb_ir[10:8])&&(wb_ir!=`NOP)&&(wb_ir!=`CMP)&&(wb_ir!=`JUMP)&&(wb_ir!=`HALT))
smdr <= reg_C1;
else
smdr <= gr[id_ir[10:8]];
end
end
end
//wire flag_mem;
reg [15:0]mem_ir,smdr1;
reg [15:0]reg_C;
reg [15:0]ALUo;
reg zf,nf,cf,dw;
reg cin;
//************************* EX *****************************//
[email protected](posedge clock)
begin
if(!reset)
begin
mem_ir<= 16'b0000_0000_0000_0000;
smdr1 <= 16'b0000_0000_0000_0000;
reg_C <= 16'b0000_0000_0000_0000;
dw <= 1'b0;
zf <= 1'b0;
nf <= 1'b0;
end
else if (state == `exec)
begin
mem_ir <= ex_ir;
smdr1 <= smdr;
reg_C <= ALUo;
if ((ex_ir[15:11] == `ADDC) || (ex_ir[15:11] == `CMP) || (ex_ir[15:11] == `SUBC)
|| (ex_ir[15:11] == `SUB) || (ex_ir[15:11] == `ADDI)|| (ex_ir[15:11] == `SUBI)
|| (ex_ir[15:11] == `LDIH)|| (ex_ir[15:11] == `ADD) || (ex_ir[15:11] == `SLL)
|| (ex_ir[15:11] == `SRL) || (ex_ir[15:11] == `SLA) || (ex_ir[15:11] == `SRA)
|| (ex_ir[15:11] == `BZ) || (ex_ir[15:11] == `BNZ) || (ex_ir[15:11] == `BN)
|| (ex_ir[15:11] == `BNN) || (ex_ir[15:11] == `BC) || (ex_ir[15:11] == `BNC))
//ADD和CMP指令中,nf為1當最高位為1時,此時結果是一個負數。
begin //zf為1,當ALU輸出結果為0時。
if (ALUo == 16'b0000_0000_0000_0000)
zf <= 1'b1;
else
zf <= 1'b0;
if (ALUo[15] == 1'b1)
nf <= 1'b1;
else
nf <= 1'b0;
end
else
begin
zf <= zf;
nf <= nf;
end
if (ex_ir[15:11] == `STORE) //如果指令是STORE的話,那麼資料記憶體的寫入使能賦為1,否則為0
dw <= 1'b1;
else
dw <= 1'b0;
end
end
//--------------------------------ALU--------------------------------
always @(reg_A or reg_B or ex_ir[15:11])
case(ex_ir[15:11])
`ADD:
{cf,ALUo} <= reg_A + reg_B; //add
`ADDI:
{cf,ALUo} <= reg_A + reg_B; //addi
`ADDC:
{cf,ALUo} <= reg_A + reg_B + cin; //addc
`SUB:
{cf,ALUo} <= reg_A - reg_B; //sub
`SUBI:
{cf,ALUo} <= reg_A - reg_B; //subi
`SUBC:
{cf,ALUo} <= reg_A - reg_B - cin; //subc
`CMP:
{cf,ALUo} <= reg_A - reg_B; //cmp。計算a-b,根據結果得出flag的值
`LOAD:
{cf,ALUo} <= reg_A + reg_B; //load
`STORE:
{cf,ALUo} <= reg_A + reg_B; //store
`LDIH:
{cf,ALUo} <= reg_A + reg_B; //ldih
`AND:
ALUo <= (reg_A & reg_B); //and
`OR:
ALUo <= (reg_A | reg_B); //or
`XOR:
ALUo <= (reg_A ^ reg_B); //xor
`SLL:
ALUo <= (reg_A << reg_B[3:0]); //ex_ir[3:0]);
//sll,使用的是指令中傳過來的資料
`SLA:
ALUo <= (reg_A <<< reg_B[3:0]); //ex_ir[3:0]); //sla
`SRL:
ALUo <= (reg_A >> reg_B[3:0]); //ex_ir[3:0]); //srl
`SRA:
ALUo <= (reg_A >>> reg_B[3:0]); //ex_ir[3:0]); //sra
`BZ:
{cf,ALUo} <= reg_A + reg_B; //bz
`BNZ:
{cf,ALUo} <= reg_A + reg_B; //bnz
`BN:
{cf,ALUo} <= reg_A + reg_B; //bn
`BNN:
{cf,ALUo} <= reg_A + reg_B; //bnn
`BC:
{cf,ALUo} <= reg_A + reg_B; //bc
`BNC:
{cf,ALUo} <= reg_A + reg_B; //bnc
`JMPR:
{cf,ALUo} <= reg_A + reg_B; //jmpr
default:
begin
ALUo <= ALUo;
cf <= cf;
end
endcase
reg [15:0]wb_ir,reg_C1;
//**************************************** MEM ************************************//
[email protected](posedge clock)
begin
if(!reset)
begin
cin <= 1'b0;
wb_ir <= 16'b0000_0000_0000_0000;
reg_C1 <= 16'b0000_0000_0000_0000;
d_we <= 0;
d_addr <= 8'b0;
d_dataout<= 16'b0;
end
else if (state == `exec)
begin
cin <= cf;
wb_ir <= mem_ir;
begin
d_we <= dw;
d_addr <= reg_C[7:0];
d_dataout<= smdr1;
end
if (mem_ir[15:11] == `LOAD) //除了LOAD指令外,reg_C1均來自reg_C
reg_C1 <= d_datain;
else//ADD,ADDC,SUB,SUBC,ADDI,SUBI,AND,OR,XOR,SLL,SRL,SLA,SRA(CMP應該要特殊考慮)
reg_C1 <= reg_C;
end
end
//*********************************** WB *****************************************//
[email protected](posedge clock)
if(!reset)
begin
gr[7] <= 16'b0000_0000_0000_0000;
gr[6] <= 16'b0000_0000_0000_0000;
gr[5] <= 16'b0000_0000_0000_0000;
gr[4] <= 16'b0000_0000_0000_0000;
gr[3] <= 16'b0000_0000_0000_0000;
gr[2] <= 16'b0000_0000_0000_0000;
gr[1] <= 16'b0000_0000_0000_0000;
gr[0] <= 16'b0000_0000_0000_0000;
end
else if (state == `exec)
begin
if ((wb_ir[15:11] == `LOAD)|| (wb_ir[15:11] == `ADD) || (wb_ir[15:11] == `ADDC)
|| (wb_ir[15:11] == `SUB) || (wb_ir[15:11] == `SUBC)|| (wb_ir[15:11] == `LDIH)
|| (wb_ir[15:11] == `ADDI)|| (wb_ir[15:11] == `SUBI)|| (wb_ir[15:11] == `AND)
|| (wb_ir[15:11] == `OR) || (wb_ir[15:11] == `XOR) || (wb_ir[15:11] == `SLL)
|| (wb_ir[15:11] == `SLA) || (wb_ir[15:11] == `SRL) || (wb_ir[15:11] == `SRA) )
gr[wb_ir[10:8]] <= reg_C1;
else
gr[wb_ir[10:8]] <= gr[wb_ir[10:8]];
end
else;
endmodule
模擬檔案:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 20:53:17 10/25/2013
// Design Name: CPU
// Module Name: F:/Digital_Practice/Practice/CPU/stimulus2.v
// Project Name: CPU
// Revision 0.01 - File Created
////////////////////////////////////////////////////////////////////////////////
// state macro define
`define idle 1'b0
`define exec 1'b1
// instruction macro define
`define NOP 5'b00000
`define HALT 5'b00001
`define LOAD 5'b00010
`define STORE 5'b00011
`define SLL 5'b00100
`define SLA 5'b00101
`define SRL 5'b00110
`define SRA 5'b00111
`define ADD 5'b01000
`define ADDI 5'b01001
`define SUB 5'b01010
`define SUBI 5'b01011
`define CMP 5'b01100
`define AND 5'b01101
`define OR 5'b01110
`define XOR 5'b01111
`define LDIH 5'b10000
`define ADDC 5'b10001
`define SUBC 5'b10010
`define JUMP 5'b11000
`define JMPR 5'b11001
`define BZ 5'b11010
`define BNZ 5'b11011
`define BN 5'b11100
`define BNN 5'b11101
`define BC 5'b11110
`define BNC 5'b11111
// general register
`define gr0 3'b000
`define gr1 3'b001
`define gr2 3'b010
`define gr3 3'b011
`define gr4 3'b100
`define gr5 3'b101
`define gr6 3'b110
`define gr7 3'b111
module stimulus2;
// Inputs
reg reset;
reg enable;
reg start;
reg clock;
reg [15:0] i_datain;
reg [15:0] d_datain;
// Outputs
wire d_we;
wire [7:0] i_addr;
wire [7:0] d_addr;
wire [15:0] d_dataout;
// Instantiate the Unit Under Test (UUT)
CPU uut (
.reset(reset),
.enable(enable),
.start(start),
.clock(clock),
.i_datain(i_datain),
.d_datain(d_datain),
.d_we(d_we),
.i_addr(i_addr),
.d_addr(d_addr),
.d_dataout(d_dataout)
);
initial begin
$dumpfile("CPU.vcd");
$dumpvars(1,stimulus2.uut);
// Initialize Inputs
clock = 0;
reset = 0;
start = 0;
enable = 0;
d_datain = 0;
i_datain = 0;
// Wait 100 ns for global reset to finish
#10;
// Add stimulus here
//************* test pattern *************//
$display("LOAD,ADD,HALT,SUB,STORE");
$display("pc: id_ir :reg_A:reg_B:ALUo:reg_C:da:dd :w:reC1:gr1 :gr2 :gr3 :exir:mmir:wbir:smdr");
$monitor("%h:%b:%h :%h :%h :%h :%h:%h:%b:%h:%h:%h:%h:%h:%h:%h:%h:%b",
uut.pc, uut.id_ir, uut.reg_A, uut.reg_B, uut.ALUo,uut.reg_C,
d_addr, d_dataout, d_we, uut.reg_C1, uut.gr[1], uut.gr[2], uut.gr[3],uut.ex_ir,uut.mem_ir,uut.wb_ir,uut.smdr,uut.zf);
enable <= 1; start <= 0; i_datain <= 0; d_datain <= 0; /*select_y <= 0;*/
#10 reset <= 0;
#10 reset <= 1;
#10 enable <= 1;
#10 start <= 1;
#10 start <= 0;
i_datain <= {`LOAD, `gr1, 1'b0, `gr0, 4'b0000};
d_datain <= 16'hfC00; // 3 clk later from LOAD
#10 i_datain <= {`LOAD, `gr2, 1'b0, `gr0, 4'b0001};
#10;//阻塞相當於延遲一個週期取i_datain
#10 i_datain <= {`ADD, `gr3, 1'b0, `gr1, 1'b0, `gr2};
#10 i_datain <= {`ADD, `gr3, 1'b0, `gr1, 1'b0, `gr2};
d_datain <= 16'h10AB;
#10 i_datain <= {`ADDC, `gr3, 1'b0, `gr2, 1'b0, `gr1};
#10 i_datain <= {`SUB, `gr3, 1'b0, `gr2, 1'b0, `gr1};
#10 i_datain <= {`SUBC, `gr3, 1'b0, `gr2, 1'b0, `gr1};
#10 i_datain <= {`STORE, `gr3, 1'b0, `gr0, 4'b0010};
//#10 i_datain <= {`HALT, 11'b000_0000_0000};
//
#10 start <= 1;
#10 start <= 0;
$display("SLL,SRA,SLA,SRL");
$display("pc: id_ir :reg_A:reg_B:ALUo:reg_C:da:dd :w:reC1:gr1 :gr2 :gr3 :ddin:exir:mmir:wbir:smdr");
i_datain <= {`SLL, `gr3, 1'b0, `gr1, 4'b0010};
#10 i_datain <= {`SRA, `gr3, 1'b0, `gr3, 4'b0010};
#10 i_datain <= {`SLA, `gr3, 1'b0, `gr2, 4'b011};
#10 i_datain <= {`SRL, `gr3, 1'b0, `gr2, 4'b0001};
//#10 i_datain <= {`HALT, 11'b000_0000_0000};
//
#10 start <= 1;
#10 start <= 0;
$display("LDIH,SUBI,BZ,AND,OR,XOR");
$display("pc: id_ir :reg_A:reg_B:ALUo:reg_C:da:dd :w:reC1:gr1 :gr2 :gr3 :ddin:exir:mmir:wbir:smdr:zf");
i_datain <= {`LDIH, `gr1, 8'b0000_0100 };
#10 i_datain <= {`BZ, `gr3, 4'b0000, 4'b0001 };
#10 i_datain <= {`ADDI, `gr1, 4'b1111, 4'b1111 };
#10 i_datain <= {`AND, `gr3, 1'b0,`gr1, 1'b0,`gr2 };
#10 i_datain <= {`OR, `gr3,1'b0, `gr1,1'b0, `gr2 };
#10 i_datain <= {`XOR, `gr3, 1'b0,`gr1, 1'b0,`gr2 };
#10 i_datain <= {`HALT, 11'b000_0000_0000};
#10 i_datain <= {`BZ, `gr3, 4'b0000, 4'b0001 };
#10 i_datain <= {`ADDI, `gr1, 4'b1111, 4'b1111 };
#10 i_datain <= {`AND, `gr3, 1'b0,`gr1, 1'b0,`gr2 };
#10 i_datain <= {`OR, `gr3,1'b0, `gr1,1'b0, `gr2 };
#10 i_datain <= {`XOR, `gr3, 1'b0,`gr1, 1'b0,`gr2 };
#10 i_datain <= {`HALT, 11'b000_0000_0000};
#10 i_datain <= {`BZ, `gr3, 4'b0000, 4'b0001 };
#10 i_datain <= {`ADDI, `gr1, 4'b1111, 4'b1111 };
#10 i_datain <= {`AND, `gr3, 1'b0,`gr1, 1'b0,`gr2 };
#10 i_datain <= {`OR, `gr3,1'b0, `gr1,1'b0, `gr2 };
#10 i_datain <= {`XOR, `gr3, 1'b0,`gr1, 1'b0,`gr2 };
#10 i_datain <= {`HALT, 11'b000_0000_0000};
end
always #5 clock = ~clock;
endmodule
綜合結果:
模擬結果:
相關推薦
數位電路設計之五級流水線設計(CPU)
這個流水線應該是我大二上的時候的最高水平了,現在看起來確實很簡單,程式碼風格也不是很好,沒有模組化,而且這些指令也不是嚴格的mips的所有指令,是自己定義的一些。但是放在部落格裡也算是對自己過去的一個總結吧! 現在再看這個程式碼,我覺得寫得太噁心了,沒有註釋,沒有說清楚關鍵
JavaScript高級程序設計之引用類型(上)
5-0 歸並 高級 new es5 順序 回調函數 比較 並且 引用類型是比較復雜的一種類型。在面向對象的編程中,會經常用到引用類型,可以說它是編程語言的核心。在JS中內置了幾種引用類型,下邊會進行一一的介紹。 內置引用類型 Object類型 1、聲明方式:直接使用new操
原型設計之Axure實戰教程(一)
一、原型設計軟體介紹為什麼要進行原型設計?大約66%的軟體開發失敗或虧損的前三大原因為: — 缺乏使用者參與 — 需求或規格不完整 — 需求或規格變更是一種高效的以使用者為中心的技術,是個有效的簡化文件編制、吸引使用者參與、早期辨認需求遺漏、將
原型設計之Axure實戰教程(二)
一、Axure的工作環境一、選單和工具欄常用操作:檔案開啟、儲存、撤銷、重做、格式刷、輸出原型、輸出規格等操作二、頁面導航面板可調整需要展示頁面的層次和順序,以使用者註冊為例,如下圖 三、元件面板1、形狀類基本形狀為矩形,點選三角形可調整圓角,點選圓點可選擇其他形狀如心型、圓
設計模式之適配器模式(Adapter)
功能 系統 第三方 抽象 可能 對象 期待 技術分享 適配器 我想要是說適配器模式,提一下“電壓”、“耳機”、“充電器”和 "USB” 的例子應該是比較恰當的了。就說說自己的親身經歷,我原來的手機是NOKIA5730。後來也不知道有沒有國行,但是不推薦大家買這款手機,不適
設計模式之建造者模式(Builder)
人的 做出 字體 存在 分享 定義 固定 也不會 抽象方法 一個人活到70歲以上,都會經歷這樣的幾個階段:嬰兒,少年,青年,中年,老年。並且每個人在各個階段肯定是不一樣的呀,我覺得可以說世界上不存在兩個人在人生的這5個階段的生活完全一樣,但是活到70歲以上的人,都經歷了這幾
JAVA設計模式之單例模式(轉)
單例對象 日誌 locking anti 常見 基本上 title 加載 懶漢式 本文繼續介紹23種設計模式系列之單例模式。 概念: java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,這裏主要介紹三種:懶漢式單例、餓漢式單例、登記式單例。 單例模式有以下特
C#.Net 設計模式學習筆記之創建型 (一)
應用 種類 單件 src nag abstract 子類 指定 相關 1、抽象工廠(Abstract Factory)模式 常規的對象創建方法: //創建一個Road對象 Road road =new Road(); new 的問題: 實現依賴,不能應對“具
GOF23設計模式之建造者模式(builder)
gin 實例 情況 gof ace state 實現 oid sql 一、建造者模式概述 建造者模式的本質: 1.分離了對象子組件的單獨構造(由Builder負責)和裝配(由Director負責)。從而可以構造出復雜的對象。這個模式適用於:某個對象的過程復雜的情
GOF23設計模式之觀察者模式(observer)
hang 事件監聽器 rgs str arr public pda import lob 一、觀察者模式概述 觀察者模式主要用於 1 :N 的通知。當一個對象(目標對象 Subject 或 Observable)的狀態變化時,它需要通知一系列對象(觀察者對象 Obser
設計模式之模板方法模式(TemplateMethod)
pla AR 應用 blog public ood 操作 () eal 模板方法模式使用繼承來實現模式的功能,在基類使用一個方法來定義算法的各個步驟,這些步驟(方法)的具體實現會放到子類中,通過這樣來實現不同算法對象的算法拼合,完成該對象整體算法的實現。 作用 模板方法
DotNet菜鳥入門之無限極分類(一)設計篇
對數 tar null 擴展 creat nvarchar 鏈表 文章 數據庫設計 寫這個教程的原因,是因為,無限極分類,在許多項目中,都用得到。而對於新手來說,不是很好理解,同時,操作上也有一些誤區或者不當之處。所以我就鬥膽,拋磚引玉一下,已一個常見的後臺左側頻道樹為例子
JavaScript高級程序設計學習(四)之引用類型(續)
dso 也有 特殊字符 src sin define 訪問 ast 編碼 一、Date類型 其實引用類型和相關的操作方法,遠遠不止昨天的所說的那些,還有一部分今天繼續補充。 在java中日期Date,它所屬的包有sql包,也有util包。我個人比較喜歡用util包的。理由,
Java學習--設計模式之結構型模式(二)
and 它的 null spa bubuko imp AD mco flyweight 一、裝飾器模式(Decorator Pattern) 1、概念 裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類
python設計模式之單例模式(二)
__new__ 有意 {} 開發人員 sta 字典 spa 出現 創建 上次我們簡單了解了一下什麽是單例模式,今天我們繼續探究。上次的內容點這 python設計模式之單例模式(一) 上次們討論的是GoF的單例設計模式,該模式是指:一個類有且只有一個對象。通常我們需
設計模式之適配器模式(七)
一起 添加 lec pan ati ide 需要 display 沒有 設計模式之適配器模式 適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設計模式屬於結構型模式,它結合了兩個獨立接口的功能。 這種模式涉及到一個單一的類,該類負責加
設計模式---對象創建模式之構建器模式(Builder)
out ++ 生成 構造器 build 創建過程 隱藏 spa col 一:概念 Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23種設計模式中的一種。Builder模式是一種對象創建型模式之一,用來隱藏復合對象的創建過程,它把復合對象的創建過程加以
設計模式---對象性能模式之享元模式(Flyweight)
ret 大量 根據 利用 問題 字母 只讀 時代 帶來 一:概念 通過與其他類似對象共享數據來減少內存占用 如果一個應用程序使用了太多的對象, 就會造成很大的存儲開銷。 特別是對於大量輕量級 (細粒度)的對象,比如在文檔編輯器的設計過程中,我們如果為每個字母
設計模式---接口隔離模式之中介者模式(Mediator)
單向 com clas 分享 分享圖片 獨立 mage 分解 pan 一:概念 在Mediator模式中,類之間的交互行為被統一放在Mediator的對象中,對象通過Mediator對象同其他對象交互。Mediator對象起到控制器的作用 二:動機 在軟件
設計模式---狀態變化模式之state狀態模式(State)
情況 ... 概念 擴展 pen com 耦合 new 發現 前提:狀態變化模式 在組建構建過程中,某些對象的狀態經常面臨變化,如何對這些變化進行有效的管理?同時又維持高層模塊的穩定?“狀態變化”模式為這一個問題提供了一種解決方案。 典型