天天看點

數字電路設計之五級流水線設計(CPU)

這個流水線應該是我大二上的時候的最高水準了,現在看起來确實很簡單,代碼風格也不是很好,沒有子產品化,而且這些指令也不是嚴格的mips的所有指令,是自己定義的一些。但是放在部落格裡也算是對自己過去的一個總結吧!

現在再看這個代碼,我覺得寫得太惡心了,沒有注釋,沒有說清楚關鍵的地方。我自己都忘了為什麼這麼寫~~

後來發現有非常坑爹的Bug!!!!祝好!!!我沒有改過來了~~~

• 實驗步驟

1.先寫好CPU的指令集。

數字電路設計之五級流水線設計(CPU)
數字電路設計之五級流水線設計(CPU)
數字電路設計之五級流水線設計(CPU)

2.根據指令集先把一些基本的指令實作,比如LOAD,STORE等,把大概的流水線先畫出框圖。畫出框圖後,把基本指令實作。調試,仿真。

數字電路設計之五級流水線設計(CPU)

3.在2的基礎上加入别的指令,考慮好hazard的問題

數字電路設計之五級流水線設計(CPU)

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
	
always@(*)
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 *************//
always@(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 *************//
always@(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 *****************************//	
always@(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 ************************************//
always@(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 *****************************************//
always@(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)

仿真結果:

數字電路設計之五級流水線設計(CPU)