ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

单周期CPU

2021-07-05 23:05:59  阅读:205  来源: 互联网

标签:begin 周期 31 output input CPU d0 d1


一、设计思路

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、支持指令

列出支持指令并将其分类:

strldcal_rcal_iluib_typejjrjaljalrshamt
swlwadduoribeqsll
subusltisra
sltaddiusrl
sllv
srav
srlv

2、功能模块

先按照lw指令列出所需功能模块(lw经过模块最多),再依次检查现有模块是否支持其余指令,若不能支持,则添加相应模块。

moduleinputoutput功能描述
PCD(端口名,下同)Q指令计数器
ADD4PCPC4加4运算
IMIAIR指令存储器
RFA1RD1寄存器堆的读出部分
A2RD2
EXTI16EXTD选择输出SIMM,LIMM,UIMM
EXTOP
CMPD1RES比较两个数据的大小,以决定是否分支
D2
NPCPC4NEXTPC计算BPC,JPC
I26
NPCOP
ALUAAO执行不同计算
B
SHAMT
ALUOP
DMDARD数据存储器,支持写入字和读出字
WD
WM
RM
RFA3寄存器堆的写入部分
WD3
WR

注:上表的SIMM表示将16位立即数作符号扩展成32位;UIMM则是无符号扩展;LIMM则是专门为lui指令设计的将低16位移至高16位,并扩展至32位。BPC则是将指令地址(PC)按照分支指令地址变换方式计算分支地址,JPC则是将指令地址(PC)按照跳转指令地址变换方式计算跳转地址。

3、数据通路

在上一步列出的所有功能模块基础上,考虑如何连接这些模块。

需要分别列出所有指令的数据通路(即在功能模块之间连线),并将其整合起来,得到最终的数据通路(完成功能模块的连接)。

moduleinputLDSTRCAL_RCAL_ILUIB_TYPEJJRJALJALRSHAMT
PC
ADD4PCQQQQQQQQQQQ
IMIAQQQQQQQQQQQ
PCDPC4PC4PC4PC4PC4PC4PC4PC4PC4PC4PC4
RFA1IR[RS]IR[RS]IR[RS]IR[RS]IR[RS]IR[RS]IR[RS]
A2IR[RT]IR[RT]IR[RT]
EXTI16IR[I16]IR[I16]IR[I16]IR[I16]
CMPD1RD1
D2RD2
NPCPC4PC4PC4PC4
I26IR[I16]IR[I26]IR[I26]
PCDNEXTPCNEXTPCRD1NEXTPCRD1
ALUARD1RD1RD1RD1
BEXTDEXTDRD2EXTDRD2
SHAMTIR[SH]
DMDAAOAO
WDRD2
RFA3IR[RT]IR[RD]IR[RD]IR[RT]$31IR[RD]IR[RD]
WD3RDAOAOEXTDPC4PC4AO

注:IR[RS]是说,IR端口数据(指令)的RS字段。

4、控制器设计

INPUTINPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUTOUTPUT
INSTRUCTIONOPFUNCTPCSELEXTOPNPCOPALUCTRLALUOPBSELWMRMA3SELWD3SELWR
LW100011X00X00(+)00(不写)1(读字)001
SW101011X00X00(+)01(写字)0XX0
ADD0000001000000XX15FUNCT100111
ADDU0000001000010XX15FUNCT100111
SUB0000001000100XX15FUNCT100111
SUBU0000001000110XX15FUNCT100111
SHAMT000000FUNCT0XX15FUNCT100111
ORI001101X02X22000011
SLTI001010X00X33000011
ADDIU001001X00X00000011
LUI001111X01XXXX00021
BEQ000100XRESX0XXX00XX0
J000010X1X1XXX00XX0
JR0000000010002XXXXX00XX0
JAL000011X1X1XXX00231
JALR0000000010012XXXXX00131
NOP0000000000000XXXXX00XX0
  • 控制信号说明

    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的编程很重要。

标签:begin,周期,31,output,input,CPU,d0,d1
来源: https://blog.csdn.net/de_pool/article/details/118500669

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有