verilog實現的五級流水簡易CPU(帶板極驗證)

 實現一個簡易的五級流水的CPU,解決Hazard,並實現板極驗證。app

    1 設計總覽框架


2 實現原理ide

根據Top view 將整個CPU分爲3個模塊:測試

   1 PCPU 主要模塊:用從指令內存獲得的指令進行運算處理,並從數據內存中寫入或讀取數據。這是最核心的部分,其餘模塊都很好設計。優化

   2 Instruction_Mem 指令模塊: PCPU模塊提供指令,使得PCPU中經過指令寄存器中的值,找到指令的內存地址,從而讀取指令。lua

   3 Data_Mem  數據模塊: PCPU從中讀取數據或寫入數據spa

板極驗證:設計

   4個開關表示選擇哪個數據顯示,用47段數碼管顯示數字code


3 整個PCPU的工做流程:ip

 五級流水:

註釋:       

IF 從指令模塊中,經過指令寄存器PC尋址,得到指令。

ID 解碼指令,根據操做碼提取要用到的數據輸入通用寄存器。

EX ALU運算單元在指令的調度下,使用以前通用寄存器中的數據根據不一樣指令完成不一樣運算。運算後將結果輸出到reg_C中,並設置各個標記位的值。

MEM:這裏主要是針對LOADSTORE這類的讀寫指令要用到的。對於其餘指令沒有特別要求。

WB:回寫把計算結果寫入指令的左值中,這裏除了跳轉指令和loadstore指令,都是寫回第一個操做數(寄存器)


4 須要實現的彙編指令


分階段實現優化過程

階段一 實現最基本的cpu(沒有指令存儲器,數據存儲器,沒有解決hazard,沒有板極驗證,什麼也沒有

   完成步驟:

步驟1:理解流水線工做原理

 上課時流水線是聽懂了,寄存器賦值,取數這些基本原理大概弄懂了。不過實際操做仍是有不少要注意的。

步驟2:開始逐級編寫基本代碼

 有了老師給的樣例代碼,整個框架基本構建好了。因此要作的就是弄清楚每一個指令在每一級流水中須要作些什麼,而後在每一級流水中再總結這些操做的共同點,不一樣點,須要特別注意的地方。

1)指令操做碼的設計:

 優化:這裏考慮了一下控制指令的特殊性,由於控制指令在流水每一級操做中有很大類似性,因此爲了簡化電路,還有判斷時代碼的簡化,把全部控制指令的前兩位設爲「11」,而其餘指令前兩位都不是「11」。這樣編寫代碼的時候更容易理清邏輯,綜合的時候電路也簡單一些。

2)指令各級流水的設計:

 這裏思考了不少,設計每一條指令都須要特別當心,最重要的是在IDEX還有ALUo中。

    總結一下,主要就是整個16 bits的指令在流水線的每一步中起到「指揮」做用,而後每一級流水的工做就是在上一級完成後,利用

 

A  ID中的寄存器賦值:

    reg_A reg_B中存儲的是在指令右邊將要送入ALU參與運算的值。

   因爲指令的右邊一般聲明的是寄存器的編號(由於用戶只能對通用寄存器進行操做,沒法直接訪問內存)或者當即數,因此要經過編號找到肯定的寄存器,再將該通用寄存器裏的值賦給reg_A 或者 reg_B

優化: 這裏爲了減小reg_A reg_B的翻轉,考慮了一些優化。好比把要用到當即數的指令的當即數不寫入寄存器,而是在下一級流水中之間從指令中取數。

  B   exALUo的計算                                                       

主要就是用verilog自己的運算直接操做。運算後賦值個ALUo寄存器和cf標誌位。

優化:好比一些用當即數的操做,以前沒有存入reg_A reg_B直接從ex_ir中取數計算。

C   mem中的讀寫

  主要要和data模塊進行數據傳輸,指令就是loadstore 

 D  wb中寫回運算結果

    因爲算數指令和邏輯運算指令基本都是要寫回到寄存器。因此這裏判斷爲:非跳轉指令,非storeload指令,則寫回第一個操做數(寄存器)。


6 源代碼

   1).v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    14:15:05 12/18/2014 
// Design Name: 
// Module Name:    CPU 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
// data transfer & Arithmetic
`define NOP 5'b00000
`define HALT 5'b00001
`define LOAD 5'b00010
`define STORE 5'b00011
`define LDIH 5'b10000
`define ADD 5'b01000
`define ADDI 5'b01001
`define ADDC 5'b10001
`define SUB 5'b01011
`define SUBI 5'b10011
`define SUBC 5'b10111
`define CMP 5'b01100
// control
`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
// logic / shift
`define AND 5'b01101
`define OR 5'b01111
`define XOR 5'b01110
`define SLL 5'b00100
`define SRL 5'b00110
`define SLA 5'b00101
`define SRA 5'b00111
// 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
// FSM
`define idle 1'b0
`define exec 1'b1

/******* the whole module CPU is made of  Instuction_Mem module, PCPU module and Data_Mem module ********/
module CPU(
    input wire clk, clock, enable, reset, start,
	 input wire[3:0] select_y,
	 output [7:0] select_segment,   
	 output [3:0] select_bit
    );
	 
wire[15:0] d_datain;
wire[15:0] i_datain;
wire[7:0] d_addr;
wire[7:0] i_addr;
wire[15:0] d_dataout;
wire d_we;
wire[15:0] y;	

reg [20:0] count = 21'b0;	 


	Instruction_Mem instruction(clock,reset,i_addr,i_datain);	
	PCPU pcpu(clock, enable, reset, start, d_datain, i_datain, 
	 select_y, i_addr, d_addr, d_dataout, d_we, y);	
	 
     	 
	Data_memory data(clock, reset, d_addr, d_dataout, d_we, d_datain);
    
   Board_eval eval(clk, y, select_segment, select_bit);
endmodule

/************************ Instruction memeory module   *****************************/
module Instruction_Mem ( 
    input wire clock, reset,
    input wire[7:0] i_addr,
	output [15:0] i_datain
	 );
reg[15:0] i_data[255:0]; // 8 bits pc address to get instructions
reg[15:0] temp;

always@(negedge clock) 
begin
	if(!reset) 
	    begin
	       i_data[0] <= {`LOAD, `gr1, 1'b0, `gr0, 4'b0000};
		    i_data[1] <= {`LOAD, `gr2, 1'b0, `gr0, 4'b0001};
		    i_data[2] <= {`ADD, `gr3, 1'b0, `gr1, 1'b0, `gr2};
		    i_data[3] <= {`SUB, `gr3, 1'b0, `gr1, 1'b0, `gr2};
		    i_data[4] <= {`CMP, `gr3, 1'b0, `gr2, 1'b0, `gr1};
		    i_data[5] <= {`ADDC, `gr3, 1'b0, `gr1, 1'b0, `gr2};
		    i_data[6] <= {`SUBC, `gr3, 1'b0, `gr1, 1'b0, `gr2};
		    i_data[7] <= {`SLL, `gr2, 1'b0, `gr3, 1'b0, 3'b001};
		    i_data[8] <= {`SRL, `gr3, 1'b0, `gr1, 1'b0, 3'b001};
		    i_data[9] <= {`SLA, `gr4, 1'b0, `gr1, 1'b0, 3'b001};
		    i_data[10] <= {`SRA, `gr5, 1'b0, `gr1, 1'b0, 3'b001};
		    i_data[11] <= {`STORE, `gr3, 1'b0, `gr0, 4'b0010};
		    i_data[12] <= {`HALT, 11'b000_0000_0000};
	    end
	 else 
	    begin
	        temp = i_data[i_addr[7:0]];
	    end
	 end
	 assign i_datain = temp; 


endmodule

/**************************** PCPU module ***************************/
module PCPU(
 input wire clock, enable, reset, start,
 input wire [15:0] d_datain,  // output from Data_Mem module
 input wire [15:0] i_datain,  // output from Instruction_Mem module
 input wire [3:0] select_y,   // for the board evaluation 
 output  [7:0] i_addr,
 output  [7:0] d_addr,
 output  [15:0] d_dataout,
 output  d_we,
 output  [15:0] y
    );

reg [15:0] gr [7:0];
reg nf, zf, cf;
reg state, next_state;
reg dw;
reg [7:0] pc;
reg[15:0] y_forboard;
reg [15:0] id_ir;
reg [15:0] wb_ir;
reg [15:0] ex_ir;
reg [15:0] mem_ir;
reg [15:0] smdr = 0;
reg [15:0] smdr1 = 0;
reg signed [15:0] reg_C1; //有符號
reg signed [15:0] reg_A;
reg signed [15:0] reg_B;
reg signed [15:0] reg_C;
reg signed [15:0] ALUo;
 

//************* 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
	

assign i_addr = pc; // 準備下一條指令的地址	
	
//************* IF *************//
always @(posedge clock or negedge reset)
	begin
		if (!reset)
			begin
            id_ir <= 16'b0;
            pc <= 8'b0;
			end
			
		else if (state ==`exec)
		// Stall happens in IF stage, always compare id_ir with i_datain to decide pc and id_ir 
		begin
		    // 立即將被執行的指令要用到以前load寫入的值時, stall two stages , id and ex.
			
            /* 
			 指令中後第2、三個操做數均爲寄存器時,須要判斷LOAD的第一個操做數是否與這些指令的後兩個寄存器有衝突	
			 爲一部分算數運算指令和邏輯運算指令
            */			
			if((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) 
			  &&( (id_ir[15:11] == `LOAD && (id_ir[10:8]  == i_datain[6:4] || id_ir[10:8]  == i_datain[2:0])) 
			    ||(ex_ir[15:11] == `LOAD && (ex_ir[10:8]  == i_datain[6:4] || ex_ir[10:8]  == i_datain[2:0]))
				)
			  ) // end if
			    begin
				   id_ir <= 16'bx; 
				   pc <= pc;  // hold pc		
			    end		  			
            /* 
     	     指令中第二個操做數爲寄存器變量並參與運算時,須要判斷LOAD的第一個操做數是否與這些指令的第二個操做數的寄存器有衝突		   
			 爲移位指令和STORE指令
			*/
  			else if (( i_datain[15:11] == `SLL
			         ||i_datain[15:11] == `SRL
					 ||i_datain[15:11] == `SLA
					 ||i_datain[15:11] == `SRA
					 ||i_datain[15:11] == `STORE)
                    &&((id_ir[15:11] == `LOAD &&(id_ir[10:8]  == i_datain[6:4])) 
					  ||(ex_ir[15:11] == `LOAD &&(ex_ir[10:8]  == i_datain[6:4]))
					  )
					)
					begin
					   id_ir <= 16'bx;
					   pc <= pc;  // hold pc
					end 
			/* 
			   跳轉指令系列,id和ex階段都須要stall,mem階段跳轉
            */	
			else if(id_ir[15:14] == 2'b11 || ex_ir[15:14] == 2'b11)
			        begin
				       id_ir <= 16'bx;
					   pc <= pc;  // hold pc
					end 
					
			/* mem階段跳轉 */
			else
			  begin
			// BZ & BNZ
				if(((mem_ir[15:11] == `BZ)
					&& (zf == 1'b1)) 
				|| ((mem_ir[15:11] == `BNZ)
					&& (zf == 1'b0)))
				begin
					id_ir <= 16'bx;
					pc <= reg_C[7:0];
				end
				// BN & BNN	
				else if(((mem_ir[15:11] == `BN)
					&& (nf == 1'b1)) 
				|| ((mem_ir[15:11] == `BNN)
					&& (nf == 1'b0)))
				begin
					id_ir <= 16'bx;
					pc <= reg_C[7:0];
				end
				// BC & BNC	
				else if(((mem_ir[15:11] == `BC)
					&& (cf == 1'b1)) 
				|| ((mem_ir[15:11] == `BNC)
					&& (cf == 1'b0)))
				begin
					id_ir <= 16'bx;
					pc <= reg_C[7:0];
				end
				// JUMP 
				else if((mem_ir[15:11] == `JUMP)			
				|| (mem_ir[15:11] == `JMPR))
				begin
					id_ir <= 16'bx;
					pc <= reg_C[7:0];
				end
				// 非跳轉指令且沒有檢測到衝突
				else
				begin
				    id_ir <= i_datain;
					pc <= pc + 1;
				end
			  end  // end else
		end // else reset
	end // end always
	
	
//************* ID *************//
always @(posedge clock or negedge reset) 
    begin
	    if (!reset)
			begin
				ex_ir <= 16'b0;
				reg_A <= 16'b0;
				reg_B <= 16'b0;
				smdr <= 16'b0;
			end
			
		else if (state == `exec)
		//Data forwarding happens in ID stage, always check id_ir to decide reg_A/B
			begin
				ex_ir <= id_ir;
			    // ********************reg_A 賦值******************* //
				
				
				/*  其餘無衝突的狀況 */	  
				// reg_A <= r1: 要用到 r1 參與運算的指令,即除 "JUMP" 外的控制指令和一些運算指令,將寄存器r1中的值賦給reg_A
				 if ((id_ir[15:14] == 2'b11 && id_ir[15:11] != `JUMP) 
				|| (id_ir[15:11] == `LDIH)
				|| (id_ir[15:11] == `ADDI)
				|| (id_ir[15:11] == `SUBI))
					reg_A <= gr[id_ir[10:8]];
				
				else if (id_ir[15:11] == `LOAD) 
					reg_A <= gr[id_ir[6:4]];
					  
				// case for data forwarding, 當前指令第2個操做數用到以前指令第1個操做數的結果
				 else if(id_ir[6:4] == ex_ir[10:8])
				      reg_A <= ALUo;
			    else if(id_ir[6:4] == wb_ir[10:8]) 
				      reg_A <= reg_C1;
			    else if(id_ir[6:4] == mem_ir[10:8]) 
				      reg_A <= reg_C;
					  
				//reg_A <= r2: 若是運算中不用到 r1,要用到 r2, 則將 gr[r2]
				else 
					reg_A <= gr[id_ir[6:4]];
					
				//************************* reg_B賦值************************//
				
			  if (id_ir[15:11] == `STORE)
					begin
						reg_B <= {12'b0000_0000_0000, id_ir[3:0]}; //value3
						smdr <= gr[id_ir[10:8]]; // r1
			      end
				// case for data forwarding, 當前指令第3個操做數用到以前指令第1個操做數的結果
				else if(id_ir[2:0] == ex_ir[10:8])
				      reg_B <= ALUo;
			    else if(id_ir[2:0] == wb_ir[10:8]) 
				      reg_B <= reg_C1;
			    else if(id_ir[2:0] == mem_ir[10:8]) 
				      reg_B <= reg_C;
							
				  
				/*  其餘無衝突的狀況 */	  
				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))
					
					reg_B <= gr[id_ir[2:0]];
				
			end
	end		

//************* ALUo *************//	

always @ (*) 
    begin
	    // {val2, val3}
		if  (ex_ir[15:11] == `JUMP)
			ALUo <= {8'b0, ex_ir[7:0]};
		// 跳轉指令 r1 + {val2, val3}
		else if  (ex_ir[15:14] == 2'b11)
		    ALUo <= reg_A + {8'b0, ex_ir[7:0]};
	    //算數運算,邏輯運算,計算結果到ALUo, 並計算cf標誌位
		else 
		begin
			case(ex_ir[15:11])
			`LOAD: ALUo <= reg_A + {12'b0000_0000_0000, ex_ir[3:0]};
			`STORE: ALUo <= reg_A + reg_B;
			`LDIH: {cf, ALUo} <= reg_A + { ex_ir[7:0], 8'b0 };
			`ADD: {cf, ALUo} <= reg_A + reg_B;
			`ADDI:{cf, ALUo} <= reg_A + { 8'b0, ex_ir[7:0] };
			`ADDC: {cf, ALUo} <= reg_A + reg_B + cf;
			`SUB: {cf, ALUo} <= {{1'b0, reg_A} - reg_B};
			`SUBI: {cf, ALUo} <= {1'b0, reg_A }- { 8'b0, ex_ir[7:0] };
			`SUBC:{cf, ALUo} <= {{1'b0, reg_A} - reg_B - cf};
			`CMP: {cf, ALUo} <= {{1'b0, reg_A} - reg_B};
			`AND: {cf, ALUo} <= {1'b0, reg_A & reg_B};
			`OR: {cf, ALUo} <= {1'b0, reg_A | reg_B};
			`XOR: {cf, ALUo} <= {1'b0, reg_A ^ reg_B};
			`SLL: {cf, ALUo} <= {reg_A[4'b1111 - ex_ir[3:0]], reg_A << ex_ir[3:0]};
			`SRL: {cf, ALUo} <= {reg_A[ex_ir[3:0] - 4'b0001], reg_A >> ex_ir[3:0]};
			`SLA: {cf, ALUo} <= {reg_A[ex_ir[3:0] - 4'b0001], reg_A <<< ex_ir[3:0]};
			`SRA: {cf, ALUo} <= {reg_A[4'b1111 - ex_ir[3:0]], reg_A >>> ex_ir[3:0]};
			default: begin
			        
					 end
        endcase								
		end
 end

//************* EX *************//	
always @(posedge clock or negedge reset) 
    begin
	    if (!reset)
			begin
				mem_ir <= 16'b0;
				reg_C <= 16'b0;
				dw <= 0;
				nf <= 0;
				zf <= 0;
				smdr1 <= 16'b0;
			end
			
		else if (state == `exec)
			begin
				mem_ir <= ex_ir;
				reg_C <= ALUo;
				if (ex_ir[15:11] == `STORE)
					begin
						dw <= 1'b1;
						smdr1 <= smdr;
					end
				
				// 設置標誌位zf, nf, 算數和邏輯運算
				else if(ex_ir[15:14] != 2'b11 && ex_ir[15:11] != `LOAD)
				     begin
				       zf <= (ALUo == 0)? 1:0;
					   nf <= (ALUo[15] == 1'b1)? 1:0;
						dw <= 1'b0;
				     end	
            else		
                 dw <= 1'b0;				
			end		
    end

// PCPU module 的輸出
assign d_dataout = smdr1;
assign d_we = dw;
assign d_addr = reg_C[7:0];

//************* MEM *************//
always @(posedge clock or negedge reset) 
    begin
	    if (!reset)
			begin
				wb_ir <= 16'b0;
				reg_C1 <= 16'b0;
			end
			
		else if (state == `exec)
			begin
				wb_ir <= mem_ir;			
				if (mem_ir[15:11] == `LOAD)
					reg_C1 <= d_datain;
				else if(mem_ir[15:14] != 2'b11)
					reg_C1 <= reg_C;				
			end			
	end
//************* WB *************//
always @(posedge clock or negedge reset) 
    begin
	    if (!reset)
			begin
			   gr[0] <= 16'b0;
				gr[1] <= 16'b0;
				gr[2] <= 16'b0;
				gr[3] <= 16'b0;
				gr[4] <= 16'b0;
				gr[5] <= 16'b0;
				gr[6] <= 16'b0;
				gr[7] <= 16'b0;
			end			
			
		else if (state == `exec)
			begin
			    // 回寫到 r1
				if ((wb_ir[15:14] != 2'b11) 
				   &&(wb_ir[15:11] != `STORE)		  
				   &&(wb_ir[15:11] != `CMP)
				)
					gr[wb_ir[10:8]] <= reg_C1;
			end	
   end
   
// 板極驗證
assign y = y_forboard; // 板極驗證須要的輸出
always @(select_y) 
  begin
   case(select_y)
	  4'b0000: y_forboard <= {8'B0,pc};
	  4'b0001: y_forboard <= id_ir;
	  4'b0010: y_forboard <= reg_A;
	  4'b0011: y_forboard <= reg_B;
	  4'b0100: y_forboard <= smdr;
	  4'b0101: y_forboard <= ALUo;
	  4'b0110: y_forboard <= {15'b0, cf};
	  4'b0111: y_forboard <= {15'b0, nf};
	  4'b1000: y_forboard <= reg_C;
	  4'b1001: y_forboard <= reg_C1;
	  4'b1010: y_forboard <= gr[0];
	  4'b1011: y_forboard <= gr[1];
	  4'b1100: y_forboard <= gr[2];
	  4'b1101: y_forboard<= gr[3];
	  4'b1110: y_forboard <= gr[4];
	  4'b1111: y_forboard <= gr[5];
	endcase
 end
 
endmodule

/**************************** Data memory module ******************************/
module 	Data_memory (
input wire clock, reset, 
input wire [7:0] d_addr,
input wire [15:0] d_dataout, 
input wire  d_we, 
output  [15:0] d_datain
);
 reg[15:0] temp;
	 reg[15:0] d_data[255:0];
	 always@(negedge clock) begin
	    if(!reset) begin
	      d_data[0] <= 16'hFc00;
		   d_data[1] <= 16'h00AB;
		 end else if(d_we) begin
		   d_data[d_addr] <= d_dataout;
		 end else begin
		   temp = d_data[d_addr];
		 end
	 end
	 assign d_datain = temp;
endmodule

/**************************** Board evaluation module ******************************/
module Board_eval  ( 
    input wire clock,
    input wire [15:0] y,
	output reg [7:0] select_segment, 
	output reg [3:0] select_bit
	 );
parameter  SEG_NUM0 = 8'b00000011,  
           SEG_NUM1 = 8'b10011111,
			  SEG_NUM2 = 8'b00100101,
			  SEG_NUM3 = 8'b00001101,
			  SEG_NUM4 = 8'b10011001,
			  SEG_NUM5 = 8'b01001001,
			  SEG_NUM6 = 8'b01000001,
			  SEG_NUM7 = 8'b00011111,
			  SEG_NUM8 = 8'b00000001,
			  SEG_NUM9 = 8'b00001001,
			  SEG_A = 8'b00010001,
			  SEG_B = 8'b11000001,
			  SEG_C = 8'b01100011,
			  SEG_D = 8'b10000101,
			  SEG_E = 8'b01100001,
			  SEG_F = 8'b01110001;
// 位選		  
parameter  BIT_3 = 4'b0111,			  
			  BIT_2 = 4'b1011,
			  BIT_1 = 4'b1101,
			  BIT_0 = 4'b1110;	 

reg [20:0] count = 0;

always @ (posedge clock) begin
   count <= count + 1'b1;	
end			  

always @ (posedge clock) begin
  case(count[19:18])
  2'b00: begin
          select_bit <= BIT_3;
			 case(y[15:12])
			 4'b0000: select_segment <= SEG_NUM0;
			 4'b0001: select_segment <= SEG_NUM1;
			 4'b0010: select_segment <= SEG_NUM2;
			 4'b0011: select_segment <= SEG_NUM3;
			 4'b0100: select_segment <= SEG_NUM4;
			 4'b0101: select_segment <= SEG_NUM5;
			 4'b0110: select_segment <= SEG_NUM6;
			 4'b0111: select_segment <= SEG_NUM7;
			 4'b1000: select_segment <= SEG_NUM8;
			 4'b1001: select_segment <= SEG_NUM9;
			 4'b1010: select_segment <= SEG_A;
			 4'b1011: select_segment <= SEG_B;
			 4'b1100: select_segment <= SEG_C;
			 4'b1101: select_segment <= SEG_D;
			 4'b1110: select_segment <= SEG_E;
			 4'b1111: select_segment <= SEG_F;
			 endcase
			end
	
  2'b01: begin
          select_bit <= BIT_2;
			 case(y[11:8])
			 4'b0000: select_segment <= SEG_NUM0;
			 4'b0001: select_segment <= SEG_NUM1;
			 4'b0010: select_segment <= SEG_NUM2;
			 4'b0011: select_segment <= SEG_NUM3;
			 4'b0100: select_segment <= SEG_NUM4;
			 4'b0101: select_segment <= SEG_NUM5;
			 4'b0110: select_segment <= SEG_NUM6;
			 4'b0111: select_segment <= SEG_NUM7;
			 4'b1000: select_segment <= SEG_NUM8;
			 4'b1001: select_segment <= SEG_NUM9;
			 4'b1010: select_segment <= SEG_A;
			 4'b1011: select_segment <= SEG_B;
			 4'b1100: select_segment <= SEG_C;
			 4'b1101: select_segment <= SEG_D;
			 4'b1110: select_segment <= SEG_E;
			 4'b1111: select_segment <= SEG_F;
			 endcase
			end
  2'b10: begin
          select_bit <= BIT_1;
			 case(y[7:4])
			 4'b0000: select_segment <= SEG_NUM0;
			 4'b0001: select_segment <= SEG_NUM1;
			 4'b0010: select_segment <= SEG_NUM2;
			 4'b0011: select_segment <= SEG_NUM3;
			 4'b0100: select_segment <= SEG_NUM4;
			 4'b0101: select_segment <= SEG_NUM5;
			 4'b0110: select_segment <= SEG_NUM6;
			 4'b0111: select_segment <= SEG_NUM7;
			 4'b1000: select_segment <= SEG_NUM8;
			 4'b1001: select_segment <= SEG_NUM9;
			 4'b1010: select_segment <= SEG_A;
			 4'b1011: select_segment <= SEG_B;
			 4'b1100: select_segment <= SEG_C;
			 4'b1101: select_segment <= SEG_D;
			 4'b1110: select_segment <= SEG_E;
			 4'b1111: select_segment <= SEG_F;
			 endcase
			end
  2'b11: begin
         select_bit <= BIT_0;
			 case(y[3:0])
			 4'b0000: select_segment <= SEG_NUM0;
			 4'b0001: select_segment <= SEG_NUM1;
			 4'b0010: select_segment <= SEG_NUM2;
			 4'b0011: select_segment <= SEG_NUM3;
			 4'b0100: select_segment <= SEG_NUM4;
			 4'b0101: select_segment <= SEG_NUM5;
			 4'b0110: select_segment <= SEG_NUM6;
			 4'b0111: select_segment <= SEG_NUM7;
			 4'b1000: select_segment <= SEG_NUM8;
			 4'b1001: select_segment <= SEG_NUM9;
			 4'b1010: select_segment <= SEG_A;
			 4'b1011: select_segment <= SEG_B;
			 4'b1100: select_segment <= SEG_C;
			 4'b1101: select_segment <= SEG_D;
			 4'b1110: select_segment <= SEG_E;
			 4'b1111: select_segment <= SEG_F;
			 endcase
			end
  endcase

end 
endmodule


 2).test

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   21:22:32 12/29/2014
// Design Name:   CPU
// Module Name:   C:/Users/liang/Desktop/embed/CPU/CPU/CPUTest.v
// Project Name:  CPU
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: CPU
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module CPU_test;

	// Inputs
	reg clock;
	reg enable;
	reg reset;
	reg [3:0] select_y;
	reg start;

	// Outputs
	wire [15:0] y;

	// Instantiate the Unit Under Test (UUT)
	CPU cpu (
		.clock(clock), 
		.enable(enable), 
		.reset(reset),		
		.start(start), 	
      .select_y(select_y)		
		
	);

	initial begin
		// Initialize Inputs
		clock = 0;
		enable = 0;
		reset = 0;
		select_y = 0;
		start = 0;

		// Wait 100 ns for global reset to finish
		#100;
     forever begin
	    #5
		  clock <= ~clock;
	  end  
		// Add stimulus here
	end
initial begin

		// Wait 100 ns for global reset to finish
		#100;
$display("pc:     id_ir      :                  ex_ir              :reg_A:     reg_B:   reg_C:     cf: nf: zf:      regC1:      gr1:     gr2:   gr3:   gr4:    gr5:");
$monitor("%h:  %b:           %b:         %h:     %h:     %h:     %h: %h: %h:         %h:      %h:    %h:   %h:   %h:  %h", 
	cpu.pcpu.pc, cpu.pcpu.id_ir, cpu.pcpu.ex_ir, cpu.pcpu.reg_A, cpu.pcpu.reg_B, cpu.pcpu.reg_C,
	cpu.pcpu.cf, cpu.pcpu.nf, cpu.pcpu.zf, cpu.pcpu.reg_C1, cpu.pcpu.gr[1], cpu.pcpu.gr[2], cpu.pcpu.gr[3], cpu.pcpu.gr[4], cpu.pcpu.gr[5]);
	
   enable <= 1; start <= 0; select_y <= 0;

#10 reset <= 0;
#10 reset <= 1;
#10 enable <= 1;
#10 start <=1;
#10 start <= 0;
	end
      
endmodule


3).ucf

NET "select_segment[7]" LOC = "T17";
NET "select_segment[6]" LOC = "T18";
NET "select_segment[5]" LOC = "U17";
NET "select_segment[4]" LOC = "U18";
NET "select_segment[3]" LOC = "M14";
NET "select_segment[2]" LOC = "N14";
NET "select_segment[1]" LOC = "L14";
NET "select_segment[0]" LOC = "M13";

NET "select_bit[0]" LOC = "N16";
NET "select_bit[1]" LOC = "N15";
NET "select_bit[2]" LOC = "P18";
NET "select_bit[3]" LOC = "P17";

NET "clk" LOC = "V10";

NET "clock" LOC = "B8";
NET "clock" CLOCK_DEDICATED_ROUTE = FALSE;
NET "reset" LOC = "T10";
NET "enable" LOC = "T9";
NET "start" LOC = "V9";
NET "select_y[3]" LOC = "T5";
NET "select_y[2]" LOC = "V8";
NET "select_y[1]" LOC = "U8";
NET "select_y[0]" LOC = "N8";


7  測試用的指令:

         i_data[0] <= {`LOAD, `gr1, 1'b0, `gr0, 4'b0000};

                  i_data[1] <= {`LOAD, `gr2, 1'b0, `gr0, 4'b0001};

                  i_data[2] <= {`ADD, `gr3, 1'b0, `gr1, 1'b0, `gr2};

                  i_data[3] <= {`SUB, `gr3, 1'b0, `gr1, 1'b0, `gr2};

                  i_data[4] <= {`CMP, `gr3, 1'b0, `gr2, 1'b0, `gr1};

                  i_data[5] <= {`ADDC, `gr3, 1'b0, `gr1, 1'b0, `gr2};

                  i_data[6] <= {`SUBC, `gr3, 1'b0, `gr1, 1'b0, `gr2};

                  i_data[7] <= {`SLL, `gr2, 1'b0, `gr3, 1'b0, 3'b001};

                  i_data[8] <= {`SRL, `gr3, 1'b0, `gr1, 1'b0, 3'b001};

                  i_data[9] <= {`SLA, `gr4, 1'b0, `gr1, 1'b0, 3'b001};

                  i_data[10] <= {`SRA, `gr5, 1'b0, `gr1, 1'b0, 3'b001};

                  i_data[11] <= {`STORE, `gr3, 1'b0, `gr0, 4'b0010};

                  i_data[12] <= {`HALT, 11'b000_0000_0000};

pc: id_ir :            ex_ir :          reg_A reg_B reg_C cf nf zf regC1: gr1: gr2:  gr3:  gr4: gr5:

00: 0000000000000000: 0000000000000000: 0000: 0000: 0000: x: 0: 0: 0000: 0000: 0000: 0000: 0000: 0000

//如下兩個指令是LOAD,將Data Memory中 第一個和第二個數取出,存儲在gr1和gr2中

01: 0001000100000000: 0000000000000000: xxxx: xxxx: xxxx: x: x: x: 0000: 0000: 0000: 0000: 0000: 0000

02: 0001001000000001: 0001000100000000: 0000: xxxx: xxxx: x: x: x: xxxx: 0000: 0000: 0000: 0000: 0000

// Stall

02: xxxxxxxxxxxxxxxx: 0001001000000001: 0000: 0000: 0000: x: x: x: xxxx: 0000: 0000: 0000: 0000: 0000

02: xxxxxxxxxxxxxxxx: xxxxxxxxxxxxxxxx: xxxx: 0000: 0001: x: x: x: fc00: 0000: 0000: 0000: 0000: 0000

//開始ADD指令,gr3 <= gr1 + gr2

 03: 0100001100010010: xxxxxxxxxxxxxxxx: xxxx: 0000: 0001: x: x: x: 00ab: fc00: 0000: 0000: 0000: 0000

//開始SUB指令

04: 0101101100010010: 0100001100010010: fc00: 00ab: 0001: 1: x: x: 00ab: fc00: 00ab: 0000: 0000: 0000、

//開始CMP指令 通過兩級流水,此時ADD指令已經把加法運算結果寫入到了reg_C  ( gr1(fc00) – gr2(00ab))

05: 0110001100100001: 0101101100010010: fc00: 00ab: fcab: 0: 1: 0: 00ab: fc00: 00ab: 0000: 0000: 0000

//開始ADDC指令 通過兩級流水,此時SUB指令已經把減法運算結果寫入到了reg_C ( gr1(fc00 )- gr2(00ab)),有了借位,cf標誌位爲1

06: 1000101100010010: 0110001100100001: 00ab: fc00: fb55: 1: 1: 0: fcab: fc00: 00ab: 0000: 0000: 0000

//開始SUBC指令 通過兩級流水,此時CMP指令已經把減法運算結果寫入到了reg_C (gr2(00ab) – gr1(fc00)),00ab < fc00,cf標誌位爲0

07: 1011101100010010: 1000101100010010: fc00: 00ab: 04ab: 0: 0: 0: fb55: fc00: 00ab: fcab: 0000: 0000

//開始SLL指令 通過兩級流水,此時ADDC指令已經把加法運算結果寫入到了reg_C (gr1(fc00) + gr2(00ab) + CF(0))

08: 0010001000110001: 1011101100010010: fc00: 00ab: fcab: 0: 1: 0: 04ab: fc00: 00ab: fb55: 0000: 0000

//開始SRL指令 通過兩級流水,此時SUBC指令已經把減法運算結果寫入到了reg_C (gr1(fc00) - gr2(00ab) - CF(0))

09: 0011001100010001: 0010001000110001: fb55: 00ab: fb55: 1: 1: 0: fcab: fc00: 00ab: fb55: 0000: 0000

//開始SLA指令 通過兩級流水,此時SLL指令已經把移位運算結果寫入到了reg_C (gr3(fb55) 左移 1位)

0a: 0010110000010001: 0011001100010001: fc00: 00ab: f6aa: 0: 1: 0: fb55: fc00: 00ab: fcab: 0000: 0000

//開始SRA指令 通過兩級流水,此時SRL指令已經把移位運算結果寫入到了reg_C (gr1(fc00) 右移 1位)

0b: 0011110100010001: 0010110000010001: fc00: 00ab: 7e00: 0: 0: 0: f6aa: fc00: 00ab: fb55: 0000: 0000

//開始STORE指令 通過兩級流水,此時SLA指令已經把移位運算結果寫入到了reg_C (gr1(fc00) 算術左移 1位)

0c: 0001101100000010: 0011110100010001: fc00: 00ab: f800: 1: 1: 0: 7e00: fc00: f6aa: fb55: 0000: 0000

//開始HALT指令 通過兩級流水,此時SRA指令已經把移位運算結果寫入到了reg_C (gr1(fc00) 算術右移 1位)

0d: 0000100000000000: 0001101100000010: xxxx: 0002: fe00: 1: 1: 0: f800: fc00: f6aa: 7e00: 0000: 0000

0e: xxxxxxxxxxxxxxxx: 0000100000000000: xxxx: 0002: xxxx: 1: 1: 0: fe00: fc00: f6aa: 7e00: f800: 0000

0f: xxxxxxxxxxxxxxxx: xxxxxxxxxxxxxxxx: xxxx: 0002: xxxx: 1: x: x: xxxx: fc00: f6aa: 7e00: f800: fe00

10: xxxxxxxxxxxxxxxx: xxxxxxxxxxxxxxxx: xxxx: 0002: xxxx: 1: x: x: xxxx: fc00: f6aa: 7e00: f800: fe00

11: xxxxxxxxxxxxxxxx: xxxxxxxxxxxxxxxx: xxxx: 0002: xxxx: 1: x: x: xxxx: fc00: f6aa: 7e00: f800: fe00


以上以reg_C舉例說明驗證,其餘寄存器驗證相應的前移或後移一級流水線便可。

相關文章
相關標籤/搜索