《计算机组成原理》单周期CPU处理器的Verilog设计

《计算机组成原理》单周期CPU处理器的设计

  • 一、实验原理
    • 1. 单周期CPU
    • 2. 单周期CPU指令模块
    • 3. MIPS指令格式
    • 4. 指令处理流程
    • 5. 单周期CPU数据通路
  • 二、单周期CPU的设计
    • 1.pcadd4
    • 2. PC
    • 3.INSTMEM
    • 4. DATAMEM
    • 5. SHIFTER32_L2
    • 6. SHIFTER_COMBINATION
    • 7. MUX4X32
    • 8. MUX2X5
    • 9. EXT16T32
    • 10. MUX2X32
    • 11.CONUNIT
    • 12.REGFILE
    • 13. ALU
    • 14.CPU
    • 15.Test测试代码
    • 16.其他模块的代码
  • 三、设计运行结果


一、实验原理

1. 单周期CPU

单周期CPU可以看成由数据通路和和控制部件两大部分组成。数据通路是指在指令执行过程中,数据所经过的路径和路径上所涉及的功能部件。而控制部件则根据每条指令的不同功能,生成对不同数据通路的不同控制信号,正确地控制指令的执行流程。
因此,要设计处理器,首先需要确定处理器的指令集和指令编码,然后确定每条指令的数据通路,最后确定数据通路的控制信号。

2. 单周期CPU指令模块

单周期(Single Cycle)CPU是指CPU从取出1条指令到执行完该指令只需1个时钟周期。一条指令的执行过程包括:取指令→分析指令→执行指令→保存结果(如果有的话)。对于单周期CPU来说,这些执行步骤均在一个时钟周期内完成。
《计算机组成原理》单周期CPU处理器的Verilog设计_第1张图片

3. MIPS指令格式

MIPS指令系统结构有MIPS-32和MIPS-64两种。本实验的MIPS指令选用MIPS-32。以下所说的MIPS指令均指MIPS-32。MIPS的指令格式为32位。下图给出了MIPS指令的3种格式。
《计算机组成原理》单周期CPU处理器的Verilog设计_第2张图片

4. 指令处理流程

在这里插入图片描述

5. 单周期CPU数据通路

CPU的电路包括数据路径(Data path)和控制部件(Control Unit)两大部分,下面给出了单周期CPU的总体设计图。
《计算机组成原理》单周期CPU处理器的Verilog设计_第3张图片
一个简单的基本上能够在单周期上完成所要求设计的指令功能的数据通路和必要的控制线路图。其中指令储存在指令储存器,数据储存在数据存储器。访问存储器时,先给出地址,然后由读/写信号控制。对于寄存器组,读操作时,先给出地址,输出端直接输出相应数据;而在写操作时,在 We使能信号为1时,在时钟边沿触发写入。

二、单周期CPU的设计

1.pcadd4

《计算机组成原理》单周期CPU处理器的Verilog设计_第4张图片
pcadd4用来作为PC寄存器的更新信号。
由于每条指令32位,所以增加一个32位加法器,固定与32位的立即数4进行相加,且得到的结果在当前时钟信号的上升沿更新进PC寄存器。
其中,In为输入端口,输入当前指令地址;Out为下一条指令地址,为输出端口。

① PCADD4

module PCadd4(PC_o,PCadd4);
    input [31:0] PC_o;//偏移量
    output [31:0] PCadd4;//新指令地址
    CLA_32 cla32(PC_o,4,0, PCadd4, Cout);
endmodule

② CLA_32

module CLA_32(X,Y,Cin,S,Cout);
    input[31:0]X,Y;
    input Cin;
    output[31:0]S;
    output Cout;
    wire Cout0,Cout1,Cout2,Cout3,Cout4,Cout5,Cout6;
    CLA_4 add0(X[3:0],Y[3:0],Cin,S[3:0],Cout0);
    CLA_4 add1(X[7:4],Y[7:4],Cout0,S[7:4],Cout1);
    CLA_4 add2(X[11:8],Y[11:8],Cout1,S[11:8],Cout2);
    CLA_4 add3(X[15:12],Y[15:12],Cout2,S[15:12],Cout3);
    CLA_4 add4(X[19:16],Y[19:16],Cout3,S[19:16],Cout4);
    CLA_4 add5(X[23:20],Y[23:20],Cout4,S[23:20],Cout5);
    CLA_4 add6(X[27:24],Y[27:24],Cout5,S[27:24],Cout6);
    CLA_4 add7(X[31:28],Y[31:28],Cout6,S[31:28],Cout);
endmodule

③ CLA_4

module CLA_4(X,Y,Cin,S,Cout);
    input [3:0]X,Y;
    output Cout;
    input Cin;
    output [3:0]S;
    and i0(Y_3,X[3],Y[3]);
    or i1(X_3,X[3],Y[3]);
    and i2(Y_2,X[2],Y[2]);
    or i3(X_2,X[2],Y[2]);
    and i4(Y_1,X[1],Y[1]);
    or i5(X_1,X[1],Y[1]);
    and i6(Y_0,X[0],Y[0]);
    or i7(X_0,X[0],Y[0]);
    not i01(Y_31,Y_3);
    nand i02(Y_32,X_3,Y_2);
    nand i03(Y_33,X_3,X_2,Y_1);
    nand i04(Y_34,X_3,X_2,X_1,Y_0);
    nand i05(Y_35,X_3,X_2,X_1,X_0,Cin);
    nand i00(Cout,Y_31,Y_32,Y_33,Y_34,Y_35);//Cout的输出门级电路实现
    not i_2(Y__3,Y_3);
    and i21(Y_21,Y__3,X_3);
    not i22(Y_22,Y_2);
    nand i23(Y_23,X_2,Y_1);
    nand i24(Y_24,X_2,X_1,Y_0);
    nand i25(Y_25,X_2,X_1,X_0,Cin);
    nand i26(Y_26,Y_22,Y_23,Y_24,Y_25);
    xor i20(S[3],Y_21,Y_26);//S3的输出门级电路实现
    not i_1(Y__2,Y_2);
    and i11(Y_11,Y__2,X_2);
    not i12(Y_12,Y_1);
    nand i13(Y_13,X_1,Y_0);
    nand i14(Y_14,X_1,X_0,Cin);
    nand i15(Y_15,Y_12,Y_13,Y_14);
    xor i10(S[2],Y_11,Y_15);//S2的输出门级电路实现
    not i_0(Y__1,Y_1);
    and i51(Y_51,Y__1,X_1);
    not i52(Y_52,Y_0);
    nand i53(Y_53,X_0,Cin);
    nand i54(Y_54,Y_52,Y_53);
    xor i50(S[1],Y_51,Y_54);//S1的输出门级电路
    not i41(Y__0,Y_0);
    and i42(Y_4,Y__0,X_0);
    xor i40(S[0],Y_4,Cin);//S0的输出门级电路
endmodule

2. PC

《计算机组成原理》单周期CPU处理器的Verilog设计_第5张图片

PC寄存器用来给出指令在指令储存器中的地址。
为实现稳定输出,在时钟信号的上升沿更新,而且需要一个控制信号,在控制信号为0的时候初始化PC寄存器,即全部置零。
其中,Clk为输入信号,时钟周期;Reset为输入信号,输入控制信号;Result为输入信号,输入目标地址,可能是跳转地址或者是下一条指令的地址;Address为输出信号,输出指令地址。

代码如下:

module PC(Clk,Reset,Result,Address);  
    input Clk;//时钟
    input Reset;//是否重置地址。0-初始化PC,否则接受新地址       
    input[31:0] Result;
    output reg[31:0] Address;
    initial begin
        Address  <= 0;
    end
    always @(posedge Clk or negedge Reset)  
    begin  
        if (Reset==0) //如果为0则初始化PC,否则接受新地址
            begin  
                Address <= 0;  
            end  
        else   
            begin
                Address =  Result;  
        end  
    end  
endmodule

3.INSTMEM

《计算机组成原理》单周期CPU处理器的Verilog设计_第6张图片
依据当前pc,读取指令寄存器中相对应地址Addr[6:2]的指令。
将pc的输入作为敏感变量,当pc发生改变的时候,则进行指令的读取,根据相关的地址,输出指令寄存器中相对应的指令,且在设计指令的时候,要用到12条给出的指令且尽量合理。
Addr为输入信号,输入指令地址;Inst为输出信号,输出指令编码。

代码如下:

module INSTMEM(Addr,Inst);//指令存储器
    input[31:0]Addr;
    //状态为'0',写指令寄存器,否则为读指令寄存器
    output[31:0]Inst;
    wire[31:0]Rom[31:0];
    assign Rom[5'h00]=32'h20010008;//addi $1,$0,8 $1=8
    assign Rom[5'h01]=32'h3402000C;//ori $2,$0,12 $2=12
    assign Rom[5'h02]=32'h00221820;//add $3,$1,$2 $3=20
    assign Rom[5'h03]=32'h00412022;//sub $4,$2,$1 $4=4
    assign Rom[5'h04]=32'h00222824;//and $5,$1,$2 $5=8
    assign Rom[5'h05]=32'h00223025;//or $6,$1,$2 $6=12
    assign Rom[5'h06]=32'h14220002;//bne $1,$2,2
    assign Rom[5'h07]=32'hXXXXXXXX;
    assign Rom[5'h08]=32'hXXXXXXXX;
    assign Rom[5'h09]=32'h10220002;// beq $1,$2,2
    assign Rom[5'h0A]=32'h0800000D;// J 0D 
    assign Rom[5'h0B]=32'hXXXXXXXX;
    assign Rom[5'h0C]=32'hXXXXXXXX;
    assign Rom[5'h0D]=32'hAD02000A;// sw $2 10($8) memory[$8+10]=10
    assign Rom[5'h0E]=32'h8D04000A;//lw $4 10($8) $4=12
    assign Rom[5'h0F]=32'h00221826;//xor $3,$1,$2
    assign Rom[5'h10]=32'h00021900;//sll $3,$2,4
    assign Rom[5'h11]=32'h00021902;//srl $3,$2,4
    assign Rom[5'h12]=32'h00021903;//sra $3,$2,4
    assign Rom[5'h13]=32'h30470009;//andi $7,$2,9
    assign Rom[5'h14]=32'h382300EF;//xori $3,$1,0xef
    assign Rom[5'h15]=32'h3C011234;//lui $1,0x1234
    assign Rom[5'h16]=32'h0C00001A;//Jal 1A
    assign Rom[5'h17]=32'h0800001A;// J 1A
    assign Rom[5'h18]=32'hXXXXXXXX;
    assign Rom[5'h19]=32'hXXXXXXXX;
    assign Rom[5'h1A]=32'h03E00008;//Jr 16
    assign Rom[5'h1B]=32'hXXXXXXXX;
    assign Rom[5'h1C]=32'hXXXXXXXX;
    assign Rom[5'h1D]=32'hXXXXXXXX;
    assign Rom[5'h1E]=32'hXXXXXXXX;
    assign Rom[5'h1F]=32'hXXXXXXXX;
    assign Inst=Rom[Addr[6:2]];
endmodule

4. DATAMEM

《计算机组成原理》单周期CPU处理器的Verilog设计_第7张图片
数据存储器,通过控制信号,对数据寄存器进行读或者写操作,并且此处模块额外合并了输出DB的数据选择器,此模块同时输出写回寄存器组的数据DB。
由于需要支持取数/存数指令,所以要在指令储存器的基础上增加写入数据的数据写入端口,写使能信号。又因为写操作在时钟信号的上升沿,所以要增加时钟信号。
《计算机组成原理》单周期CPU处理器的Verilog设计_第8张图片
代码如下:

module DATAMEM(Addr,Din,Clk,We,Dout);
    input [31:0]Addr,Din;
    input Clk,We;
    output [31:0]Dout;
	reg [31:0]ram[0:31];
	integer i;
	initial begin
        for ( i = 0 ; i <= 31 ; i = i + 1) 
            ram [i] = i;
    end
	always @ (posedge Clk) begin
        if (We) ram[Addr[6:2]] <= Din;
	end
	assign Dout = ram[Addr[6:2]];
endmodule

5. SHIFTER32_L2

一个固定左移两位的移位器。
使用32位移位器SHIFTER32,固定左移两位即可。
X:指令中的偏移量,输入信号;
Sh:偏移左移后的结果,输出信号

代码如下:

module SHIFTER32_L2(X,Sh);
    input [31:0] X;
    output [31:0] Sh;
    parameter z=2'b00;
    assign Sh={X[29:0],z};
endmodule

6. SHIFTER_COMBINATION

《计算机组成原理》单周期CPU处理器的Verilog设计_第9张图片
J指令中用以产生跳转的目标地址。
跳转的目标地址采用拼接的方式形成,最高4位为PC+4的最高4位,中间26位为J型指令的26位立即数字段,最低两位为0。
X:指令编码的低26位字段,输入信号。
PCADD4:PC+4的32位字段,输入信号。
Y:32位转移目标地址,输出信号。

代码如下:

module SHIFTER_COMBINATION(X,PCADD4,Sh);
    input [25:0] X;
    input [31:0] PCADD4;
    output [31:0] Sh;
    parameter z=2'b00;
    assign Sh={PCADD4[31:28],X[25:0],z};
endmodule

7. MUX4X32

《计算机组成原理》单周期CPU处理器的Verilog设计_第10张图片
实现目标地址的选择。
目标地址可能是PC+4,也可能是beq和bne的跳转地址或是J型跳转地址,所以采用一个32位四选一多路选择器。
A0:PC+4的地址,输入信号
A1:空位,输入信号
A2:beq和bne指令的跳转地址,输入信号
A3:J指令的跳转地址,输入信号
S:对地址进行选择的控制信号,输入信号
Y:目标地址,输出信号

代码如下:

module MUX4X32(A0, A1, A2, A3, S, Y);
    input [31:0] A0, A1, A2, A3;
    input [1:0] S;
    output [31:0] Y;
    function [31:0] select;
        input [31:0] A0, A1, A2, A3;
        input [1:0] S;
            case(S)
                2'b00: select = A0;
                2'b01: select = A1;
                2'b10: select = A2;
                2'b11: select = A3;
            endcase
    endfunction
    assign Y = select (A0, A1, A2, A3, S);
endmodule

8. MUX2X5

《计算机组成原理》单周期CPU处理器的Verilog设计_第11张图片
R型指令和I行指令的Wr信号不同,所以需要一个5位二选一选择器进行选择。
R型指令Wr选择rd信号,I型指令Wr选择rt信号。
A0:R型指令的rd信号,输入信号
A1:I型指令的rt信号,输入信号
S:选择指令的控制信号,输入信号
Y:Wr信号,输出信号

代码如下:

module MUX2X5(A0,A1,S,Y);
    input [4:0]A0,A1;
    input S;
    output [4:0] Y;
    function [4:0] select;
        input [4:0] A0,A1;
        input S;
            case(S)
                1'b0:select=A0;
                1'b1:select=A1;
        endcase
    endfunction
    assign Y=select(A0,A1,S);
endmodule

9. EXT16T32

《计算机组成原理》单周期CPU处理器的Verilog设计_第12张图片
I指令的addi需要对立即数进行符号拓展,andi和ori需要对立即数进行零扩展,所以需要一个扩展模块。
采用一个16位扩展成32位的扩展模块EXT16T32,实现零扩展和符号扩展。
X:I型指令的立即数字段,输入信号。
Se:选择零扩展或是符号扩展的控制模块,输入信号。
Y:扩展后的立即数,输出信号。

代码如下:

module EXT16T32(X,Se,Y);
    input [15:0]X;
    input Se;
    output [31:0]Y;
    wire [31:0]E0,E1;
    wire [15:0]e={16{X[15]}};
    parameter z=16'b0;
    assign E0={z,X};
    assign E1={e,X};
    MUX2X32 i(E0,E1,Se,Y);
endmodule

10. MUX2X32

《计算机组成原理》单周期CPU处理器的Verilog设计_第13张图片
模块1的功能
ALU的Y端输入信号种类根据指令的不同而不同。
在执行R型指令时,ALU的Y端输入信号可能来自Qb,在执行I型指令的addi,andi和ori指令时时,ALU的Y端输入信号来自EXT16T32,所以需要一个二选一选择器。
A0:来自EXT16T32的信号,输入信号。
A1:来自REGFLE中Qb端口的信号,输入信号。
S:控制信号。
Y:输入ALU进行后续计算的信号,输出信号。

模块2的功能
在lw指令中,需要将DATAMEM中选中储存器的值保存到REGFILE的寄存器中,而其他会更新REGFILE的指令的更新信号来自于ALU的R输出端。所以需要一个二选一选择器进行选择。
A0: DATAMEM的输出值,输入信号
A1:ALU的输出值,输入信号
S:控制信号
Y::写入R寄存器堆D端的信号,输出信号

代码如下:

module MUX2X32(A0,A1,S,Y);
    input [31:0]A0,A1;
    input S;
    output [31:0]Y;
    function [31:0]select;
        input [31:0]A0,A1;
        input S;
        case(S)
            1'b0:select=A0;
            1'b1:select=A1;
        endcase
    endfunction
    assign Y = select(A0,A1,S);
endmodule

11.CONUNIT

《计算机组成原理》单周期CPU处理器的Verilog设计_第14张图片
控制器是作为CPU控制信号产生的器件,通过通过解析op得到该指令的各种控制信号,使其他器件有效或无效。
Func:Op,输入信号。
Op:Func,输入信号。
Z:零标志信号,对Pcsrc有影响,输入信号。
Wreg:控制寄存器端的写使能信号,输出信号。
Aluc:控制ALU的计算种类,输出信号。
Aluqb:控制ALU的Y端口的输入值,输出信号。
Pcsrc:控制目标指令地址,输出信号。
Regrt:控制输入寄存器的Wr端口,输出信号。
Reg2reg:控制REHFILE更新值的来源。
Se:控制扩展模块,输出信号。
Wmem:控制数据存储器的写使能信号,输出信号。

控制信号
《计算机组成原理》单周期CPU处理器的Verilog设计_第15张图片
代码如下:

module CONUNIT(
	input [5:0]Op,
	input [5:0]Func,
	input Z,
	output Regrt,
	output Se,
	output Wreg,
	output Aluqb,
	output [3:0]Aluc,
	output Wmem,
	output [1:0]Pcsrc,
	output Reg2reg,
	output shift,
	output j	
    );
    wire i_add = (Op == 6'b000000 & Func == 6'b100000)?1:0;
    wire i_sub = (Op == 6'b000000 & Func == 6'b100010)?1:0;
    wire i_and = (Op == 6'b000000 & Func == 6'b100100)?1:0;
    wire i_or  = (Op == 6'b000000 & Func == 6'b100101)?1:0;
    wire i_xor = (Op == 6'b000000 & Func == 6'b100110)?1:0;
    wire i_sll = (Op == 6'b000000 & Func == 6'b000000)?1:0;
    wire i_srl = (Op == 6'b000000 & Func == 6'b000010)?1:0;
    wire i_sra = (Op == 6'b000000 & Func == 6'b000011)?1:0;
    wire i_jr  = (Op == 6'b000000 & Func == 6'b001000)?1:0;
    //R
    wire i_addi = (Op == 6'b001000)?1:0;
    wire i_andi = (Op == 6'b001100)?1:0; 
    wire i_ori  = (Op == 6'b001101)?1:0;
    wire i_xori = (Op == 6'b001110)?1:0;
    wire i_lw   = (Op == 6'b100011)?1:0;
    wire i_sw   = (Op == 6'b101011)?1:0;
    wire i_beq  = (Op == 6'b000100)?1:0;
    wire i_bne  = (Op == 6'b000101)?1:0;
    wire i_lui  = (Op == 6'b001111)?1:0;
    //I
    wire i_j    = (Op == 6'b000010)?1:0;
    wire i_jal  = (Op == 6'b000011)?1:0;
    assign Wreg = i_add|i_sub|i_and|i_or|i_xor|i_sll|i_srl|i_sra|i_addi|i_andi|i_ori|i_or|i_xori|i_lw|i_lui|i_jal;
    assign Regrt = i_addi|i_andi|i_ori|i_xori|i_lw|i_sw|i_lui|i_beq|i_bne|i_j|i_jal;
    assign Reg2reg  = i_add|i_sub|i_and|i_or|i_xor|i_sll|i_srl|i_sra|i_addi|i_andi|i_ori|i_xori|i_sw|i_beq|i_bne|i_j|i_jal;
    assign Aluqb = i_add | i_sub | i_and | i_or | i_xor | i_sll | i_srl | i_sra | i_beq | i_bne |i_j;
    assign Se   = i_addi | i_lw | i_sw | i_beq | i_bne;
    assign Aluc[3] = i_sra;
    assign Aluc[2] = i_xor |i_lui | i_sll | i_srl | i_sra |i_xori;
    assign Aluc[1] = i_and | i_or | i_lui | i_srl | i_sra | i_andi | i_ori;
    assign Aluc[0] = i_sub | i_ori | i_or | i_sll | i_srl |i_sra| i_beq | i_bne;
    assign Wmem = i_sw;
    assign Pcsrc[0] = (i_beq&Z) | (i_bne&~Z) | i_jal | i_j;
    assign Pcsrc[1] = i_j | i_jr | i_jal;
    assign shift=i_sll | i_srl | i_sra;
    assign j=i_jal | i_jr;
endmodule

12.REGFILE

《计算机组成原理》单周期CPU处理器的Verilog设计_第16张图片
给出要读取的两个寄存器编号和要写入的寄存器编号,然后由Qa和Qb端口更新Ra和Rb端口的输入编号分别输入其值。
由32个寄存器组成,增加两个端口用于接收要读取的两个寄存器编号,另一个端口用于接收要写入的寄存器的编号。且在时钟上升沿将D写入。
Clk:时钟周期,输入信号。
21
Clrn:清零信号,输入信号。
D:寄存器更新值,输入信号。
Ra:读取寄存器编号1,输入信号。
Rb:读取寄存器编号2或立即数,输入信号。
We:写入寄存器编号3,输入信号。
Wr:写使能信号,为0的时候不能写入,D值不更新,为1的时候能写入,D值更新,输入信号。
Qa:输出寄存器1的值,输入信号。
Qb:输出寄存器2的值,输入信号。

代码如下:

module REGFILE(Ra,Rb,D,Wr,We,Clk,Clrn,Qa,Qb);
    input [4:0]Ra,Rb,Wr;
    input [31:0]D;
    input We,Clk,Clrn;
    output [31:0]Qa,Qb;
    wire [31:0]Y;
    wire [31:0]Q31,Q30,Q29,Q28,Q27,Q26,Q25,Q24,Q23,Q22,Q21,Q20,Q19,Q18,Q17,Q16,Q15,Q14,Q13,Q12,Q11,Q10,Q9,Q8,Q7,Q6,Q5,Q4,Q3,Q2,Q1,Q0;
    DEC5T32E dec(Wr,We,Y);
    REG32 reg32(D,Y,Clk,Clrn,Q31,Q30,Q29,Q28,Q27,Q26,Q25,Q24,Q23,Q22,Q21,Q20,Q19,Q18,Q17,Q16,Q15,Q14,Q13,Q12,Q11,Q10,Q9,Q8,Q7,Q6,Q5,Q4,Q3,Q2,Q1,Q0);
    MUX32X32 select1(Q31,Q30,Q29,Q28,Q27,Q26,Q25,Q24,Q23,Q22,Q21,Q20,Q19,Q18,Q17,Q16,Q15,Q14,Q13,Q12,Q11,Q10,Q9,Q8,Q7,Q6,Q5,Q4,Q3,Q2,Q1,Q0,Ra,Qa);
    MUX32X32 select2(Q31,Q30,Q29,Q28,Q27,Q26,Q25,Q24,Q23,Q22,Q21,Q20,Q19,Q18,Q17,Q16,Q15,Q14,Q13,Q12,Q11,Q10,Q9,Q8,Q7,Q6,Q5,Q4,Q3,Q2,Q1,Q0,Rb,Qb);
endmodule

13. ALU

《计算机组成原理》单周期CPU处理器的Verilog设计_第17张图片
算数逻辑部件,需要实现加,减,按位与,按位或。
需要2位控制信号控制运算类型,核心部件是32位加法器ADDSUB_32。
Aluc:控制信号。
X:寄存器1的值。
Y:寄存器2的值或立即数。
R:输入寄存器端口D的计算结果,输出信号。
Z:当值为1时代表两个输入信号值相等,当值为0时代表两个输入信号不等,输出信号。

代码如下:

module ALU(X,Y,Aluc,R,Z);
    input[31:0]X,Y;
    input[3:0]Aluc;
    output[31:0]R;
    output Z;
    wire[31:0]d_as,d_and,d_or,d_xor,d_lui,d_sh,d;
    ADDSUB_32 as32(X,Y,Aluc[0],d_as);
    assign d_and=X&Y;
    assign d_or=X|Y;
    assign d_xor=X^Y;
    assign d_lui={Y[15:0],16'h0};
    SHIFTER shift(Y,X[10:6],Aluc[3],Aluc[1],d_sh);
    MUX6X32 select(d_and,d_or,d_xor,d_lui,d_sh,d_as,Aluc[3:0],R);
    assign Z=~|R;
endmodule

14.CPU

《计算机组成原理》单周期CPU处理器的Verilog设计_第18张图片
实现CPU的封装,设计输出信号使得在方正时便于观察其波形图。
调用各个下层模块并将他们的输入和输出连接到一起。
CLk:时钟周期,外部输入信号。
Reset:清零信号,外部输入信号。

代码如下:

module CPU(Clk,Reset,Addr,Inst,Qa,Qb,ALU_R,NEXTADDR,D);
    input Clk,Reset;
    output [31:0] Inst,NEXTADDR,ALU_R,Qb,Qa,Addr,D;
    
    wire [31:0]Result,PCadd4,EXTIMM,InstL2,EXTIMML2,D1,X,Y,Dout,mux4x32_2,R;
    wire Z,Regrt,Se,Wreg,Aluqb,Reg2reg,Cout,Wmem,shift,j;
    wire [3:0]Aluc;
    wire [1:0]Pcsrc;
    wire [4:0]Wr,Wr1;
    
    PC pc(Clk,Reset,Result,Addr);
    PCadd4 pcadd4(Addr,PCadd4);
    INSTMEM instmem(Addr,Inst);
    
    CONUNIT conunit(Inst[31:26],Inst[5:0],Z,Regrt,Se,Wreg,Aluqb,Aluc,Wmem,Pcsrc,Reg2reg,shift,j);
    MUX2X5 mux2x5_1(Inst[15:11],Inst[20:16],Regrt,Wr1);
    MUX2X5 mux2x5_2(Wr1,31,j,Wr);
    EXT16T32 ext16t32(Inst[15:0],Se,EXTIMM);
    SHIFTER_COMBINATION shifter1(Inst[25:0],PCadd4,InstL2);
    SHIFTER shifter2(EXTIMM,2,0,0,EXTIMML2);
    REGFILE regfile(Inst[25:21],Inst[20:16],D,Wr,Wreg,Clk,Reset,Qa,Qb);
    MUX2X32 mux2x32_1(EXTIMM,Qb,Aluqb,Y);
    MUX2X32 mux2x32_2(Qa,Inst,shift,X);
    ALU alu(X,Y,Aluc,R,Z);
    DATAMEM datamem(R,Qb,Clk,Wmem,Dout); 
    MUX2X32 mux2x32_3(Dout,R,Reg2reg,D1);
    MUX2X32 mux2x32_4(D1,PCadd4,j,D);
    CLA_32 cla_32(PCadd4,EXTIMML2,0,mux4x32_2,Cout);
    MUX4X32 mux4x32(PCadd4,mux4x32_2,Qa,InstL2,Pcsrc,Result);
    assign NEXTADDR=Result;
    assign ALU_R=R;
endmodule

15.Test测试代码

module test();
reg Clk,Reset;
wire [31:0] Inst,NEXTADDR,ALU_R,Qb,Qa,Addr,D;
wire [31:0]Result,PCadd4,EXTIMM,InstL2,EXTIMML2,X,Y,Dout,mux4x32_2,R,D1;
wire Z,Regrt,Se,Wreg,Aluqb,Reg2reg,Cout,Wmem,shift,j;

wire [3:0]Aluc;
wire [1:0]Pcsrc;
wire [4:0]Wr,Wr1;
initial begin
Clk=0;
Reset=0;
#5
Reset<=1;
end
always #5 Clk=~Clk;

PC pc(Clk,Reset,Result,Addr);
PCadd4 pcadd4(Addr,PCadd4);
INSTMEM instmem(Addr,Inst);

CONUNIT conunit(Inst[31:26],Inst[5:0],Z,Regrt,Se,Wreg,Aluqb,Aluc,Wmem,Pcsrc,Reg2reg,shift,j);
MUX2X5 mux2x5_1(Inst[15:11],Inst[20:16],Regrt,Wr1);
MUX2X5 mux2x5_2(Wr1,31,j,Wr);
EXT16T32 ext16t32(Inst[15:0],Se,EXTIMM);
SHIFTER_COMBINATION shifter1(Inst[25:0],PCadd4,InstL2);
SHIFTER shifter2(EXTIMM,2,0,0,EXTIMML2);
REGFILE regfile(Inst[25:21],Inst[20:16],D,Wr,Wreg,Clk,Reset,Qa,Qb);
MUX2X32 mux2x32_1(EXTIMM,Qb,Aluqb,Y);
MUX2X32 mux2x32_2(Qa,Inst,shift,X);
ALU alu(X,Y,Aluc,R,Z);
DATAMEM datamem(R,Qb,Clk,Wmem,Dout);
MUX2X32 mux2x32_3(Dout,R,Reg2reg,D1);
MUX2X32 mux2x32_4(D1,PCadd4,j,D);
CLA_32 cla_32(PCadd4,EXTIMML2,0,mux4x32_2,Cout);
MUX4X32 mux4x32(PCadd4,mux4x32_2,Qa,InstL2,Pcsrc,Result);
assign NEXTADDR=Result;
assign ALU_R=R;
endmodule

16.其他模块的代码

由于篇幅有限,因此其模块代码上传至百度网盘,链接如下:
https://pan.baidu.com/s/1Ax3WyUybfBT8028JHug2RQ
提取码:jxlx


三、设计运行结果

具体“调制”过程省略。
《计算机组成原理》单周期CPU处理器的Verilog设计_第19张图片
《计算机组成原理》单周期CPU处理器的Verilog设计_第20张图片
《计算机组成原理》单周期CPU处理器的Verilog设计_第21张图片

你可能感兴趣的:(cpu,verilog,硬件)