單周期CPU設計總結


單周期CPU

一、設計思路

1、CPU的意義

CPU是計算機的核心,因為它是計算機指令的處理單元。

計算機體系結構包含兩個方面,一個方面是指令集,一個方面是硬件實現。指令集是計算機被定義擁有的執行指令,計算機通過支持指令集的運行,來完成計算工作並為程序員編程服務。硬件實現則是具體的硬件去實現指令集,這個硬件實現的核心就是CPU的設計。

這里寫的CPU的設計是32位機器的CPU,指令和數據均為32位。支持指令為簡化mips指令集。

2、CPU的設計

CPU的設計包含數據通路的設計和控制器的設計。數據通路是執行指令必須的硬件(ALU、IM、DM、GRF等),控制器則是根據指令產生相應控制信號,來控制相應硬件以支持多條指令。

  • 數據通路設計

    CPU的功能是支持指令集,因此硬件設計是為了執行指令。

    設計CPU的結構的方法:先選擇一條需要經過最多硬件的指令,來為它構建數據通路。再依據其他指令在已有數據通路上添加硬件或線路,直到數據通路支持所有指令。

  • 控制器設計

    在已有的數據通路基礎上,針對每一條指令,列出其所需要的控制信號,每一組控制信號對應一種指令的全部執行。將指令相應字段和部分計算結果作為控制器的輸入,控制信號作為輸出,依據上述映射關系(真值表)設計控制器。

二、實際操作

0、設計說明

CPU架構的設計是沒有很多約束的,基本要求就是能夠支持指令集,基於不同的考量可以有不同的設計。舉例來說:對於beq指令是否跳轉的判斷,可以借用ALU的減法計算,也可以直接增設CMP比較器得出,兩種方式都可以,因為功能正確。為了提高吞吐量,或者為了節省成本,會選擇一些特別的設計,這一點在流水線CPU 的設計上可以明顯地看出。

CPU具體設計的方法是我下面進行的幾步:列出所需指令,寫出功能模塊,連接模塊,構造控制器,全部連接起來。這些表格對最終代碼實現十分重要,因為代碼量較大,先從表格檢查起,再依據表格寫碼可以減少bug。

1、支持指令

列出支持指令並將其分類:

str ld cal_r cal_i lui b_type j jr jal jalr shamt
sw lw addu ori   beq         sll
    subu slti             sra
    slt addiu             srl
    sllv                
    srav                
    srlv                

2、功能模塊

先按照lw指令列出所需功能模塊(lw經過模塊最多),再依次檢查現有模塊是否支持其余指令,若不能支持,則添加相應模塊。

module input output 功能描述
PC D(端口名,下同) Q 指令計數器
ADD4 PC PC4 加4運算
IM IA IR 指令存儲器
RF A1 RD1 寄存器堆的讀出部分
  A2 RD2  
EXT I16 EXTD 選擇輸出SIMM,LIMM,UIMM
  EXTOP    
CMP D1 RES 比較兩個數據的大小,以決定是否分支
  D2    
NPC PC4 NEXTPC 計算BPC,JPC
  I26    
  NPCOP    
ALU A AO 執行不同計算
  B    
  SHAMT    
  ALUOP    
DM DA RD 數據存儲器,支持寫入字和讀出字
  WD    
  WM    
  RM    
RF A3   寄存器堆的寫入部分
  WD3    
  WR    

注:上表的SIMM表示將16位立即數作符號擴展成32位;UIMM則是無符號擴展;LIMM則是專門為lui指令設計的將低16位移至高16位,並擴展至32位。BPC則是將指令地址(PC)按照分支指令地址變換方式計算分支地址,JPC則是將指令地址(PC)按照跳轉指令地址變換方式計算跳轉地址。

3、數據通路

在上一步列出的所有功能模塊基礎上,考慮如何連接這些模塊。

需要分別列出所有指令的數據通路(即在功能模塊之間連線),並將其整合起來,得到最終的數據通路(完成功能模塊的連接)。

module input LD STR CAL_R CAL_I LUI B_TYPE J JR JAL JALR SHAMT
PC                        
ADD4 PC Q Q Q Q Q Q Q Q Q Q Q
IM IA Q Q Q Q Q Q Q Q Q Q Q
                         
PC D PC4 PC4 PC4 PC4 PC4 PC4 PC4 PC4 PC4 PC4 PC4
RF A1 IR[RS] IR[RS] IR[RS] IR[RS]   IR[RS]   IR[RS]   IR[RS]  
  A2     IR[RT]     IR[RT]         IR[RT]
EXT I16 IR[I16] IR[I16]   IR[I16] IR[I16]            
CMP D1           RD1          
  D2           RD2          
NPC PC4           PC4 PC4   PC4    
  I26           IR[I16] IR[I26]   IR[I26]    
                         
PC D           NEXTPC NEXTPC RD1 NEXTPC RD1  
ALU A RD1 RD1 RD1 RD1              
  B EXTD EXTD RD2 EXTD             RD2
  SHAMT                     IR[SH]
                         
DM DA AO AO                  
  WD   RD2                  
                         
RF A3 IR[RT]   IR[RD] IR[RD] IR[RT]       $31 IR[RD] IR[RD]
  WD3 RD   AO AO EXTD       PC4 PC4 AO

注:IR[RS]是說,IR端口數據(指令)的RS字段。

4、控制器設計

  INPUT INPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT
INSTRUCTION OP FUNCT PCSEL EXTOP NPCOP ALUCTRL ALUOP BSEL WM RM A3SEL WD3SEL WR
LW 100011 X 0 0 X 0 0(+) 0 0(不寫) 1(讀字) 0 0 1
SW 101011 X 0 0 X 0 0(+) 0 1(寫字) 0 X X 0
ADD 000000 100000 0 X X 15 FUNCT 1 0 0 1 1 1
ADDU 000000 100001 0 X X 15 FUNCT 1 0 0 1 1 1
SUB 000000 100010 0 X X 15 FUNCT 1 0 0 1 1 1
SUBU 000000 100011 0 X X 15 FUNCT 1 0 0 1 1 1
SHAMT 000000 FUNCT 0 X X 15 FUNCT 1 0 0 1 1 1
ORI 001101 X 0 2 X 2 2 0 0 0 0 1 1
SLTI 001010 X 0 0 X 3 3 0 0 0 0 1 1
ADDIU 001001 X 0 0 X 0 0 0 0 0 0 1 1
LUI 001111 X 0 1 X X X X 0 0 0 2 1
BEQ 000100 X RES X 0 X X X 0 0 X X 0
J 000010 X 1 X 1 X X X 0 0 X X 0
JR 000000 001000 2 X X X X X 0 0 X X 0
JAL 000011 X 1 X 1 X X X 0 0 2 3 1
JALR 000000 001001 2 X X X X X 0 0 1 3 1
NOP 000000 000000 0 X X X X X 0 0 X X 0
  • 控制信號說明

    PCSEL:用於選擇下一個指令的地址是PC4,還是NPC,或者是[RS]寄存器里的地址。NPC是分支地址(BPC)或者跳轉地址(JPC),簡單來說就是非PC4的下一條指令可能地址。

    EXTOP:EXT模塊內部有多個輸出,選擇適當擴展立即數作為最終輸出的信號。

    NPCOP:選擇是BPC還是JPC。(其實這里可以把PC4一起作為NPC模塊的輸入,直接選出下一條指令地址)

    ALUCTRL&ALUOP:這里ALU 的控制信號是二次譯碼,ALUCTRL用來區分是否是R型計算指令,若是,則通過FUNCT字段進行二次譯碼決定ALU的輸出結果(之所以二次譯碼只因為R型指令的OP字段全為0);若不是,則可通過指令的OP字段決定ALU的輸出結果。

    BSEL:ALU的第二個操作數的選擇信號,對於addu指令,B端口輸入是寄存器堆的RT輸出,對於addi指令,B端口輸入是立即數的符號擴展結果,B端口的輸入來源不同,因此需要信號選擇。

    WM:數據存儲器的寫入控制信號。

    RM:數據存儲器的讀出控制信號。

    A3SEL:寄存器堆的寫入寄存器編號的選擇信號,因為addu指令的寫入寄存器的編號由指令RD字段給出,lw指令和jalr指令的寫入寄存器編號由指令RT字段給出,而jr指令的寫入寄存器固定是$ra(31號寄存器),該端口數據的來源不同,需要信號來選擇。

    WD3SEL:寄存器堆寫入數據的選擇信號,因為寫入的數據可以是DM中讀出的數據(lw),也可以是ALU計算得到的數據(addu),也可以是經移位擴展得到的數據(lui),還可以是指令的返回地址(jal,jalr),需要信號來選擇。

    WR:寄存器堆的寫入控制信號。

  • 再次說明

    控制信號的設計的基本要求是能滿足所有指令在同一CPU 上正確執行,因此十分依靠CPU的硬件結構,不同的結構就有其特別的控制信號設計。控制信號的設計還需要盡可能的簡潔,否則控制電路會更加復雜,上面ALU的控制信號所采用的二次譯碼就是簡化的控制信號的電路設計。

三、代碼實現

Verilog語言編寫的單周期CPU

module MFPC( //PC的多選器
   input [31:0] pc4,
   input [31:0] nextpc,
   input [31:0] rd1,
   input [1:0] pcsel,
   output [31:0] d
   );
assign d = (pcsel == 2'd0)? pc4:
(pcsel == 2'd1)? nextpc:
(pcsel == 2'd2)? rd1:
32'h00003000;

endmodule
module PC( //PC
   input clk,
   input reset,
   input enable,
   input [31:0] d,
   output [31:0] q
   );
reg [31:0] pc;
initial begin
pc = 32'h00003000;
end
always@(posedge clk) begin
if(enable) begin
if(reset) begin
pc <= 32'h00003000;
end
else begin
pc <= d;
end
end
end
assign q = pc;

endmodule
module ADD4( //自增4模塊
   input [31:0] pc,
   output [31:0] pc4
   );
assign pc4 = pc + 4;

endmodule
module IM( //指令存儲器模塊
   input [31:0] ia,
input reset,
input clk,
   output [31:0] ir
   );
parameter [31:0] num_instr = 1024;
reg [31:0] im [num_instr-1:0];
integer i;
initial begin
$readmemh("code.txt",im);
end
assign ir = im[ia[11:2]];
endmodule
module MFA3(  //A3端口數據選擇器
   input [4:0] ir_rt,
   input [4:0] ir_rd,
   input [1:0] a3sel,
   output [4:0] a3
   );
assign a3 = (a3sel == 0)? ir_rt:
(a3sel == 1)? ir_rd:
(a3sel == 2)? 5'd31:
5'd0;


endmodule
module MFWD3( //WD3端口數據選擇器
   input [31:0] rd,
   input [31:0] ao,
   input [31:0] extd,
   input [31:0] pc4,
   input [2:0] wd3sel,
   output [31:0] wd3
   );
assign wd3 = (wd3sel == 0)? rd:
 (wd3sel == 1)? ao:
 (wd3sel == 2)? extd:
 (wd3sel == 3)? pc4:
 0;

endmodule
module EXT( //擴展模塊
   input [15:0] i16,
   input [1:0] extop,
   output [31:0] extd
   );
assign extd = (extop == 0)? {{16{i16[15]}},i16}:
(extop == 1)? {i16,16'b0}:
(extop == 2)? {16'b0,i16}:
0;
endmodule
module CMP( //比較器
   input [31:0] d1,
   input [31:0] d2,
   output res
   );
assign res = (d1 == d2);

endmodule
module NPC( //下一條指令生成模塊
    input [31:0] pc4,
    input [25:0] i26,
    input npcop,
    output [31:0] nextpc
    );
	 assign nextpc = (npcop == 0)? $signed(pc4) + $signed({{14{i26[15]}},i26[15:0],2'b0}): {pc4[31:28],i26,2'b0};

endmodule
module ALU( //ALU模塊
    input [31:0] a,
    input [31:0] b,
    input [4:0] shamt,
    input [3:0] aluop,
    output [31:0] ao
    );
	 assign ao = (aluop == 0)? $signed(a) + $signed(b):
					 (aluop == 1)? $signed(a) - $signed(b):
					 (aluop == 2)? a | b:
					 (aluop == 3)? ($signed(a) < $signed(b)):
					 (aluop == 4)? (b << a[4:0]):
					 (aluop == 5)? $signed($signed(b) >>> a[4:0]):
					 (aluop == 6)? (b >> a[4:0]):
					 (aluop == 7)? (b << shamt):
					 (aluop == 8)? $signed($signed(b) >>> shamt):
					 (aluop == 9)? (b >> shamt):
					 32'b0;
	 
	

endmodule
module MFB( //B端口選擇器
    input [31:0] extd,
    input [31:0] rd2,
    input bsel,
    output [31:0] b
    );
	 assign b = (bsel == 0)? extd:
					rd2;


endmodule
module RF( //寄存器堆模塊
    input [4:0] a1,
    input [4:0] a2,
    input [4:0] a3,
    input [31:0] wd3,
    output [31:0] rd1,
    output [31:0] rd2,
    input reset,
    input clk,
    input wr
    );
	 reg [31:0] rf [31:1];
	 integer i;
	 initial begin
		 for(i = 1 ;i < 32; i = i + 1) begin
			 rf[i] = 32'b0;
		 end
	 end
	 always@(posedge clk) begin
		 if(reset) begin
			 for(i = 1;i < 32;i = i + 1) begin
				 rf[i] = 32'b0;
			 end
		 end
		 else if(wr && a3 != 5'b0) begin
			 rf[a3] <= wd3;
		 end
	 end
	 assign rd1 = (a1 == 5'd0)? 32'b0: 
					  rf[a1];
	 assign rd2 = (a2 == 5'd0)? 32'b0:
					  rf[a2];
	
endmodule
module DM( //數據存儲器模塊
    input [31:0] da,
    input [31:0] wd,
    input [1:0] wm,
    input [2:0] rm,
	 input clk,
	 input reset,
    output [31:0] rd
    );
	 parameter [31:0] num_data = 4096; // 1024words
	 reg [7:0] dm [num_data-1:0];
	 integer i;
	 wire [7:0] temp3,temp2,temp1,temp0;
	 initial begin
		 for(i = 0; i < num_data; i = i + 1)
		 dm[i] = 8'b0;
	 end
	 
	 always@(posedge clk) begin
		 if(reset) begin
			 for(i = 0; i < num_data; i = i + 1)
			 dm[i] = 8'b0;
		 end
		 else if(wm != 0) begin
			 case(wm)
				 1: begin //sw
					 dm[da[11:0]] <= wd[7:0];
					 dm[da[11:0] + 12'd1] <= wd[15:8];
					 dm[da[11:0] + 12'd2] <= wd[23:16];
					 dm[da[11:0] + 12'd3] <= wd[31:24];
				 end
				 2: begin //sh
					 dm[da[11:0]] <= wd[7:0];
					 dm[da[11:0] + 12'd1] <= wd[15:8];
				 end
				 3: begin //sb
					 dm[da[11:0]] <= wd[7:0];
				 end
			 endcase
		 end
	 end
	 assign temp3 = dm[da[11:0] + 12'd3];
	 assign temp2 = dm[da[11:0] + 12'd2];
	 assign temp1 = dm[da[11:0] + 12'd1];
	 assign temp0 = dm[da[11:0]];
	 
	 assign rd = (rm == 1)? {temp3,temp2,temp1,temp0}: //lw
					 (rm == 2)? {16'b0,temp1,temp0}: //lhu
					 (rm == 3)? {{16{temp1[7]}},temp1,temp0}: //lh
					 (rm == 4)? {24'b0,temp0}: //lbu
					 (rm == 5)? {{24{temp0[7]}},temp0}: //lb
					 0;
					 
					 

endmodule
module MAINDECODER( //主譯碼器模塊
    input [5:0] op,
	 input [5:0] funct,
	 input [4:0] ir_rd,
	 input res,
    output reg [1:0] pcsel,
    output reg [1:0] extop,
    output reg npcop,
    output reg [3:0] aluctrl,
    output reg bsel,
    output reg [1:0] wm,
    output reg [2:0] rm,
    output reg [1:0] a3sel,
    output reg [2:0] wd3sel,
    output reg wr
    );
	 
	 always@(*) begin
		 case(op)
			 6'b0: begin
				 if(funct == 6'b001000) begin //jr
					 pcsel = 2'd2;
					 wm = 2'd0;
					 rm = 3'd0;
					 wr = 1'd0;
				 end
				 else if(funct == 6'b001001) begin //jalr
					 pcsel = 2'd2;
					 wm = 2'd0;
					 rm = 3'd0;
					 a3sel = 2'd1;
					 wd3sel = 3'd3;
					 wr = 1'd1;
				 end
				 else if(funct == 6'b0 && ir_rd == 5'b0) begin //nop
					 pcsel = 2'd0;
					 wm = 2'd0;
					 rm = 3'd0;
					 wr = 1'd0;
				 end
				 else begin //cal_r,shamt
					 pcsel = 2'd0;
					 aluctrl = 4'd15;
					 bsel = 1'd1;
					 wm = 2'd0;
					 rm = 3'd0;
					 a3sel = 2'd1;
					 wd3sel = 3'd1;
					 wr = 1'd1;
				 end
			 end
			 6'b100011: begin //lw
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd1;
				 a3sel = 2'd0;
				 wd3sel = 3'd0;
				 wr = 1'd1;
			 end
			 6'b100101: begin //lhu
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd2;
				 a3sel = 2'd0;
				 wd3sel = 3'd0;
				 wr = 1'd1;
			 end
			 6'b100001: begin //lh
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd3;
				 a3sel = 2'd0;
				 wd3sel = 3'd0;
				 wr = 1'd1;
			 end
			 6'b100100: begin //lbu
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd4;
				 a3sel = 2'd0;
				 wd3sel = 3'd0;
				 wr = 1'd1;
			 end
			 6'b100000: begin //lb
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd5;
				 a3sel = 2'd0;
				 wd3sel = 3'd0;
				 wr = 1'd1;
			 end
			 6'b101011: begin //sw
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd1;
				 rm = 3'd0;
				 wr = 1'd0;
			 end
			 6'b101001: begin //sh
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd2;
				 rm = 3'd0;
				 wr = 1'd0;
			 end
			 6'b101000: begin //sb
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd3;
				 rm = 3'd0;
				 wr = 1'd0;
			 end
			 6'b001111: begin //lui
				 pcsel = 2'd0;
				 extop = 2'd1;
				 wm = 2'd0;
				 rm = 3'd0;
				 a3sel = 2'd0;
				 wd3sel = 3'd2;
				 wr = 1'd1;
			 end
			 6'b000100: begin //beq
				 pcsel = (res == 0)? 2'd0: 2'd1;
				 npcop = 1'd0;
				 wm = 2'd0;
				 rm = 3'd0;
				 wr = 1'd0;
			 end
			 6'b000010: begin //j
				 pcsel = 2'd1;
				 npcop = 1'd1;
				 wm = 2'd0;
				 rm = 3'd0;
				 wr = 1'd0;
			 end
			 6'b000011: begin //jal
				 pcsel = 2'd1;
				 npcop = 1'd1;
				 wm = 2'd0;
				 rm = 3'd0;
				 a3sel = 2'd2;
				 wd3sel = 3'd3;
				 wr = 1'd1;
			 end
			 6'b001101: begin //ori
				 pcsel = 2'd0;
				 extop = 2'd2;
				 aluctrl = 4'd2;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd0;
				 a3sel = 2'd0;
				 wd3sel = 3'd1;
				 wr = 1'd1;
			 end
			 6'b001010: begin //slti
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd3;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd0;
				 a3sel = 2'd0;
				 wd3sel = 3'd1;
				 wr = 1'd1;
			 end
			 6'b001001: begin //addiu
				 pcsel = 2'd0;
				 extop = 2'd0;
				 aluctrl = 4'd0;
				 bsel = 1'd0;
				 wm = 2'd0;
				 rm = 3'd0;
				 a3sel = 2'd0;
				 wd3sel = 3'd1;
				 wr = 1'd1;
			 end
		 endcase
	 end


endmodule
module ALUDECODER( //ALU譯碼器模塊
    input [3:0] aluctrl,
    input [5:0] funct,
    output reg [3:0] aluop
    );
	 
	 initial aluop = 0;
	 always@(*) begin
		  if(aluctrl != 4'd15) begin
			  aluop = aluctrl;
		  end
		  else begin
			 case(funct)
				 6'b100001: aluop = 0;//addu
				 6'b100011: aluop = 1;//subu
				 6'b101010: aluop = 3;//slt
				 6'b000100: aluop = 4;//sllv
				 6'b000111: aluop = 5;//srav
				 6'b000110: aluop = 6;//srlv
				 6'b000000: aluop = 7;//sll
				 6'b000011: aluop = 8;//sra
				 6'b000010: aluop = 9;//srl
			 endcase
		 end
	 end
	 

endmodule
module DECODER( //譯碼器模塊
    input [5:0] op,
    input [5:0] funct,
	 input [4:0] ir_rd,
    input res,
    output [1:0] pcsel,
    output [1:0] extop,
    output npcop,
    output [3:0] aluop,
    output bsel,
    output [1:0] wm,
    output [2:0] rm,
    output [1:0] a3sel,
    output [2:0] wd3sel,
    output wr
    );
	 wire [3:0] aluctrl;
	 
	 MAINDECODER maindecoder (
    .op(op), 
    .funct(funct), 
    .res(res), 
	 .ir_rd(ir_rd),
    .pcsel(pcsel), 
    .extop(extop), 
    .npcop(npcop), 
    .aluctrl(aluctrl), 
    .bsel(bsel), 
    .wm(wm), 
    .rm(rm), 
    .a3sel(a3sel), 
    .wd3sel(wd3sel), 
    .wr(wr)
    );
	 
	 ALUDECODER aludecoder (
    .aluctrl(aluctrl), 
    .funct(funct), 
    .aluop(aluop)
    );
	 

endmodule
`define rs 25:21
`define rt 20:16
`define rd 15:11
`define op 31:26
`define i16 15:0
`define sh 10:6
`define i26 25:0
`define funct 5:0

module mips( //CPU模塊
    input clk,
    input reset
    );
	 parameter enable = 1'd1;
	 wire [31:0] d,q,pc4,ir,wd3,rd1,rd2,extd,nextpc,ao,b,rd;
	 wire [4:0] a3;
	 wire res;
	 wire [1:0] pcsel;
    wire [1:0] extop;
    wire npcop;
    wire [3:0] aluop;
    wire bsel;
    wire [1:0] wm;
    wire [2:0] rm;
    wire [1:0] a3sel;
    wire [2:0] wd3sel;
    wire wr;
	 
	 MFPC mfpc (
    .pc4(pc4), 
    .nextpc(nextpc), 
    .rd1(rd1), 
    .pcsel(pcsel), 
    .d(d)
    );
	 
	 PC pc (
    .clk(clk), 
    .reset(reset), 
    .enable(enable), 
    .d(d), 
    .q(q)
    );
	 
	 ADD4 add4 (
    .pc(q), 
    .pc4(pc4)
    );
	 
	 IM im (
    .ia(q), 
    .reset(reset), 
    .clk(clk), 
    .ir(ir)
    );
	 
	 MFA3 mfa3 (
    .ir_rt(ir[`rt]), 
    .ir_rd(ir[`rd]), 
    .a3sel(a3sel), 
    .a3(a3)
    );
	 
	 MFWD3 mfwd3 (
    .rd(rd), 
    .ao(ao), 
    .extd(extd), 
    .pc4(pc4), 
    .wd3sel(wd3sel), 
    .wd3(wd3)
    );
	 
	 EXT ext (
    .i16(ir[`i16]), 
    .extop(extop), 
    .extd(extd)
    );
	 
	 CMP cmp (
    .d1(rd1), 
    .d2(rd2), 
    .res(res)
    );
	 
	 NPC npc (
    .pc4(pc4), 
    .i26(ir[`i26]), 
    .npcop(npcop), 
    .nextpc(nextpc)
    );
	 
	 ALU alu (
    .a(rd1), 
    .b(b), 
    .shamt(ir[`sh]), 
    .aluop(aluop), 
    .ao(ao)
    );
	 
	 MFB mfb (
    .extd(extd), 
    .rd2(rd2), 
    .bsel(bsel), 
    .b(b)
    );
	 
	 RF rf (
    .a1(ir[`rs]), 
    .a2(ir[`rt]), 
    .a3(a3), 
    .wd3(wd3), 
    .rd1(rd1), 
    .rd2(rd2), 
    .reset(reset), 
    .clk(clk), 
    .wr(wr)
    );
	 
	 DM dm (
    .da(ao), 
    .wd(rd2), 
    .wm(wm), 
    .rm(rm),
    .clk(clk), 
    .reset(reset), 
    .rd(rd)
    );
	 
	 DECODER decoder (
    .op(ir[`op]), 
    .funct(ir[`funct]), 
	 .ir_rd(ir[`rd]),
    .res(res), 
    .pcsel(pcsel), 
    .extop(extop), 
    .npcop(npcop), 
    .aluop(aluop), 
    .bsel(bsel), 
    .wm(wm),
	 .rm(rm),
    .a3sel(a3sel), 
    .wd3sel(wd3sel), 
    .wr(wr)
    );

	 always@(posedge clk) begin
		 if(reset == 0) begin
		    if(wr == 1'd1)
			 $display("@%h: $%d <= %h", q, a3, wd3);
		    if(wm != 2'd0)
			 $display("@%h: *%h <= %h", q, ao, rd2);
		 end
		 
	 end


endmodule

注:此代碼僅供參考,僅支持所聲明指令。

四、筆者感受

CPU實現算是大學第一次遇到的有一定代碼量的編程,它給我帶來的更多的是面對復雜編程的經驗:越復雜,越要先抽象再具體。后面的流水線CPU會更加體現這一點,表格(設計)的重要性對CPU的編程很重要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM