模块源代码
module top( //顶层模块
input clk,
input rst_n,
);
wire ALUSrcASel;
wire [1:0] ALUSrcBSel;
wire [31:0] ALUSrcA;
wire [31:0] ALUSrcB;
wire [2:0] ALUControl;
wire [31:0] ALUResult;
wire [31:0] ALUResult_DFF; //加_DFF表示对应D触发器的输出,下同
wire Zero;
wire [31:0] SignExtented;
wire [5:0] RegRdaddr1;
wire [31:0] RegRdout1;
wire [31:0] RegRdout1_DFF;
wire [5:0] RegRdaddr2;
wire [31:0] RegRdout2;
wire [31:0] RegRdout2_DFF;
wire [5:0] RegWdaddr;
wire [31:0] RegWdin;
wire RegWrite;
wire RegDst;
wire [31:0] Memaddr_src; //这是计算出来的访存地址
wire [31:0] Memaddr; //这是计算出来的访存地址右移了两位,原因见下面
wire [31:0] Memout;
wire [31:0] Memin;
wire MemRead;
wire MemWrite;
wire MemtoReg;
wire [31:0] Instr;
wire [31:0] Data;
wire [31:0] PC;
wire [31:0] nextPC;
wire PCEn;
wire PCWrite;
wire LorD;
wire IRWrite;
wire [5:0] Funct;
wire [15:0] IMM16;
wire [4:0] Rd;
wire [4:0] Rt;
wire [4:0] Rs;
wire [5:0] Op;
wire [25:0] JumpIMM;
wire [1:0] PCSrc;
wire Branch;
//以上信号基本按数据通路图的命名,意义很明显,不多做注释了
//=======================PC========================
nextpclogic nextpclogic(PC,PCWrite,PCSrc,JumpIMM,Branch,Zero,ALUResult,ALUResult_DFF,nextPC,PCEn);
dff DFFPC(~clk,nextPC,PC,PCEn);
mux MUXPCALUout(LorD,PC,ALUResult_DFF,Memaddr_src);
//=======================Memory========================
assign Memaddr = Memaddr_src >> 2;//>>2是因为这里Mem是每个地址存储4字节,和实际上的(一地址一字节)不一样
Mem Mem(clk,MemWrite,Memaddr,Memin,Memout);
dff DFFInstr(~clk,Memout,Instr,IRWrite);
dff DFFData(~clk,Memout,Data,1'b1);
assign JumpIMM = Instr[25:0];
assign Funct = Instr[5:0];
assign IMM16 = Instr[15:0];
assign Rd = Instr[15:11];
assign Rt = Instr[20:16];
assign Rs = Instr[25:21];
assign Op = Instr[31:26];
assign Memin = RegRdout2_DFF;
//=======================Regfile========================
assign RegRdaddr1 = Rs;
assign RegRdaddr2 = Rt;
mux #(6) MUXRegWdaddr(RegDst,{1'b0,Rt},{1'b0,Rd},RegWdaddr);
mux MUXMemtoReg(MemtoReg,ALUResult_DFF,Data,RegWdin);
regfile regfile(clk,rst_n,RegRdaddr1,RegRdout1,RegRdaddr2,RegRdout2,RegWdaddr,RegWdin,RegWrite);
dff DFFRegRdout1(~clk,RegRdout1,RegRdout1_DFF,1'b1);
dff DFFRegRdout2(~clk,RegRdout2,RegRdout2_DFF,1'b1);
//=========================ALU==========================
assign SignExtented = {{16{IMM16[15]}},IMM16};
mux MUXALUSrcA(ALUSrcASel,PC,RegRdout1_DFF,ALUSrcA);
mux4 MUXALUSrcB(ALUSrcBSel,RegRdout2_DFF,4,SignExtented,SignExtented << 2,ALUSrcB);
alu alu(ALUSrcA,ALUSrcB,{2'b00,{ALUControl}},ALUResult,Zero,Sign);
dff DFFALUResult(~clk,ALUResult,ALUResult_DFF,1'b1);
//=======================Control========================
control control(clk,rst_n,Op,Funct,LorD,MemRead,MemWrite,IRWrite,RegDst,MemtoReg,RegWrite,ALUSrcASel,ALUSrcBSel,ALUControl,Branch,PCWrite,PCSrc,tcstate);
endmodule
parameter A_NOP =5'h00; //nop
parameter A_ADD =5'h01; //sign_add
parameter A_SUB =5'h02; //sign_sub
parameter A_AND =5'h03; //and
parameter A_OR =5'h04; //or
parameter A_XOR =5'h05; //xor
parameter A_NOR =5'h06; //nor
parameter A_SLT =5'h07; //slt
module alu(
input [31:0] alu_a,
input [31:0] alu_b,
input [4:0] alu_op,
output reg [31:0] alu_out,
output zero
);
assign zero = (alu_out == 32'b0)?1:0;
always@(*)
case (alu_op)
A_NOP: alu_out = 0;
A_ADD: alu_out = alu_a + alu_b;
A_SUB: alu_out = alu_a - alu_b;
A_AND: alu_out = alu_a & alu_b;
A_OR : alu_out = alu_a | alu_b;
A_XOR: alu_out = alu_a ^ alu_b;
A_NOR: alu_out = ~(alu_a | alu_b);
A_SLT: //if a<b(signed) return 1 else return 0;
begin
if(alu_a[31] == alu_b[31]) alu_out = (alu_a < alu_b) ? 32'b1 : 32'b0;
//同号情况,后面的小于是视为无符号的比较
else alu_out = (alu_a[31] < alu_b[31]) ? 32'b0 : 32'b1;
//有符号比较符号
end
default: ;
endcase
endmodule
module regfile( //寄存器文件
input clk,
input rst_n,
input [5:0] rAddr1,//读地址1
output [31:0] rDout1,//读数据1
input [5:0] rAddr2,//读地址2
output [31:0] rDout2,//读数据2
input [5:0] wAddr,//写地址
input [31:0] wDin,//写数据
input wEna//写使能
);
reg [31:0] data [0:63];
integer i;
assign rDout1=data[rAddr1];//读1
assign rDout2=data[rAddr2];//读2
always@(posedge clk or negedge rst_n)//写和复位
if(~rst_n)
begin
for(i=0; i<64; i=i+1) data[i]<=0;
end
else
begin
if(wEna)
data[wAddr]<=wDin;
end
endmodule
module nextpclogic( //生成下一个PC
input [31:0] PC,
input PCWrite,
input [1:0] PCSrc,
input [25:0] JumpIMM,
input Branch,
input Zero,
input [31:0] ALUResult,
input [31:0] ALUResult_DFF,
output [31:0] nextPC,
output PCEn
);
wire [31:0] ShiftLeft2;
wire [31:0] PCJump;
wire tmp;
assign ShiftLeft2 = JumpIMM << 2;
assign PCJump = {{PC[31:28]},{{2'b00,JumpIMM}<<2}};
mux4 MUXPC(PCSrc,ALUResult,ALUResult_DFF,PCJump,0,nextPC);
and(tmp,Branch,Zero);
or(PCEn,tmp,PCWrite);
endmodule
module dff #(parameter WIDTH = 32) ( //Data Flip-Flop
input clk,
input [WIDTH-1:0] datain,
output reg [WIDTH-1:0] dataout,
input en
);
always@(posedge clk)
begin
if(en)
dataout <= datain;
end
endmodule
module mux #(parameter WIDTH = 32)( //2路选择器
input sel,
input [WIDTH-1:0] d0,
input [WIDTH-1:0] d1,
output [WIDTH-1:0] out
);
assign out = (sel == 1'b1 ? d1 : d0);
endmodule
mux4.v
module mux4 #(parameter WIDTH = 32)( //4路选择器
input [1:0] sel,
input [WIDTH-1:0] d0,
input [WIDTH-1:0] d1,
input [WIDTH-1:0] d2,
input [WIDTH-1:0] d3,
output reg [WIDTH-1:0] out
);
always@(*)
case(sel)
2'b00: out=d0;
2'b01: out=d1;
2'b10: out=d2;
2'b11: out=d3;
default:;
endcase
endmodule
control.v
```verilog
module control( //控制模块,各信号的控制
input clk,rst_n,
input [5:0] Op, //instr[31:26]
input [5:0] Funct,//instr[5:0]
output reg LorD,
output reg MemRead,
output reg MemWrite,
output reg IRWrite,
output reg RegDst,
output reg MemtoReg,
output reg RegWrite,
output reg ALUSrcASel,
output reg [1:0] ALUSrcBSel,
output reg [2:0] ALUControl,
output reg Branch,
output reg PCWrite,
output reg [1:0] PCSrc,
output [3:0] tcstate
);
reg [3:0] cstate;
reg [3:0] nstate;
assign tcstate=cstate;
always @(posedge clk or negedge rst_n)//上升沿改变状态
if(~rst_n) cstate <= 4'd15;//reset状态
else cstate <= nstate;
always @(*)//计算次态
case(cstate)
4'd15://reset
nstate = 4'd0;
4'd0://fetch
nstate = 4'd1;
4'd1://decode
case(Op)
6'b000000: nstate = 4'd6;//R type
6'b100011: nstate = 4'd2;//lw
6'b101011: nstate = 4'd2;//sw
6'b000100: nstate = 4'd8;//beq
6'b000010: nstate = 4'd9;//jump
6'b001000: nstate = 4'd10;//addi
endcase
4'd2: //memaddr
case(Op)
6'b100011: nstate = 4'd3;//lw
6'b101011: nstate = 4'd5;//sw
endcase
4'd3: //memread
nstate = 4'd4;
4'd4: //memwriteback
nstate = 4'd0;
4'd5: //memwrite
nstate = 4'd0;
4'd6: //execute
nstate = 4'd7;
4'd7: //aluwriteback
nstate = 4'd0;
4'd8: //branch
nstate = 4'd0;
4'd9: //jump
nstate = 4'd0;
4'd10: //addi execute
nstate = 4'd11;
4'd11: //addi writeback
nstate = 4'd0;
endcase
//根据下一状态更改控制信号(有使用的信号将更改并做注释,不使用的选择信号置x,不使用的使能置0)
//这里虽然在下降沿更改,但信号将在下一周期(上升沿)起作用(也就是同在这个下降沿的操作读取到的信号是改变前的)
always @(negedge clk or negedge rst_n)//下降沿时,根据次态,更改信号
begin
if(~rst_n)
begin
LorD = 1'b0;
PCSrc = 2'b11; //nextPC=0; 利用4路选择器的剩余1路
PCWrite = 1'b1;
end
else
case(nstate)
4'd0://fetch
begin
LorD = 1'b0; //------Memaddr: PC
MemRead = 1'b1; //------enable Mem read
MemWrite = 1'b0;
IRWrite = 1'b1; //------enable save Instr
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'b0; //------srcA: PC
ALUSrcBSel = 2'b01; //------srcB: 4
ALUControl = 3'b001; //------ALU's func: add
Branch = 1'b0;
PCWrite = 1'b1; //------enable update PC
PCSrc = 2'b00; //------select nextPC=PC+4
end
4'd1://decode
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'b0; //------srcA: PC
ALUSrcBSel = 2'b11; //------srcB: SignExtended<<2
ALUControl = 3'b001; //------ALU's func: add
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd2: //memaddr
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'b1; //------srcA: RegRdout1_DFF
ALUSrcBSel = 2'b10; //------srcB: SignExtended
ALUControl = 3'b001; //------ALU's func: add
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd3: //memread
begin
LorD = 1'b1; //------Memaddr: ALUResult_DFF
MemRead = 1'b1; //------enable Mem read
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'bx;
ALUSrcBSel = 2'bxx;
ALUControl = 3'bxxx;
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd4: //memwriteback
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'b0; //------RegWdaddr: Rt
MemtoReg = 1'b1; //------RegWdin: Memout
RegWrite = 1'b1; //------enable Reg write
ALUSrcASel = 1'bx;
ALUSrcBSel = 2'bxx;
ALUControl = 3'bxxx;
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd5: //memwrite
begin
LorD = 1'b1; //------Memaddr: ALUResult_DFF
MemRead = 1'b0;
MemWrite = 1'b1; //------enable Mem write
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'bx;
ALUSrcBSel = 2'bxx;
ALUControl = 3'bxxx;
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd6: //R type execute
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'b1; //------srcA: RegRdout1_DFF
ALUSrcBSel = 2'b00; //------srcB: RegRdout2_DFF
case(Funct) //------ALU's func: decided by 'Funct'
6'b100000: ALUControl = 5'h01;//add
6'b100010: ALUControl = 5'h02;//sub
6'b100100: ALUControl = 5'h03;//and
6'b100101: ALUControl = 5'h04;//or
6'b100110: ALUControl = 5'h05;//xor
6'b100111: ALUControl = 5'h06;//nor
6'b101010: ALUControl = 5'h07;//slt
endcase
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd7: //aluwriteback
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'b1; //------RegWdaddr: Rd
MemtoReg = 1'b0; //------RegWdin: ALUResult_DFF
RegWrite = 1'b1; //------enable Reg write
ALUSrcASel = 1'bx;
ALUSrcBSel = 2'bxx;
ALUControl = 3'bxxx;
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd8: //branch
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'b1; //------srcA: RegRdout1_DFF
ALUSrcBSel = 2'b00; //------srcB: RegRdout2_DFF
ALUControl = 3'b010; //------ALU's func: sub
Branch = 1'b1; //------enable update PC if beq
PCWrite = 1'b0;
PCSrc = 2'b01; //------select nextPC = ALUResult_DFF(PCBeq)
end
4'd9: //jump
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'bx;
ALUSrcBSel = 2'bxx;
ALUControl = 3'bxxx;
Branch = 1'b0;
PCWrite = 1'b1; //------enable update PC
PCSrc = 2'b10; //------select nextPC = PCJump
end
4'd10: //addi execute
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'bx;
MemtoReg = 1'bx;
RegWrite = 1'b0;
ALUSrcASel = 1'b1; //------srcA: RegRdout1_DFF
ALUSrcBSel = 2'b10; //------srcB: SignExtended
ALUControl = 3'b001; //------ALU's func: add
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
4'd11: //addi regwriteback
begin
LorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
IRWrite = 1'b0;
RegDst = 1'b0; //------RegWdaddr: Rt
MemtoReg = 1'b0; //------RegWdin: ALUResult_DFF
RegWrite = 1'b1; //------enable Reg write
ALUSrcASel = 1'bx;
ALUSrcBSel = 2'bxx;
ALUControl = 3'bxxx;
Branch = 1'b0;
PCWrite = 1'b0;
PCSrc = 2'bxx;
end
endcase
end
endmodule
- test.v
```verilog
module test;
// Inputs
reg clk;
reg rst_n;
// Instantiate the Unit Under Test (UUT)
top uut (
.clk(clk),
.rst_n(rst_n),
);
initial begin
// Initialize Inputs
clk = 1;
//
rst_n = 1;
#100;
//
rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
forever begin
#10;
clk=~clk;
end
// Add stimulus here
end
endmodule