I am trying to write a testbench in Verilog for computing dot product of two arrays. The base code for which the testbench has to be written is:
module pipe_MIPS32 (clk1, clk2);
input clk1, clk2; //Two-phase clock
reg[31:0] PC, IF_ID_IR, IF_ID_NPC;
reg[31:0] ID_EX_IR, ID_EX_NPC, ID_EX_A, ID_EX_B, ID_EX_Imm;
reg[2:0] ID_EX_type, EX_MEM_type, MEM_WB_type;
reg[31:0] EX_MEM_IR, EX_MEM_ALUout, EX_MEM_B;
reg EX_MEM_cond;
reg[31:0] MEM_WB_IR, MEM_WB_ALUout, MEM_WB_LMD;
reg[31:0] Reg[0:31]; //Register bank(32 x 32)
reg[31:0] Mem[0:1023]; //1024 x 32 memory
parameter ADD=6'b000000, SUB=6'b000001, AND=6'b000010, OR=6'b000011,
SLT=6'b000100, MUL=6'b000101, HLT=6'b111111, LW=6'b001000,
SW=6'b001001 , ADDI=6'b001010, SUBI=6'b001011, SLTI=6'b001100,
BNEQZ=6'b001101, BEQZ=6'b001110;
parameter RR_ALU=3'b000, RM_ALU=3'b001, LOAD=3'b010, STORE=3'b011, BRANCH=3'b100, HALT=3'B101;
reg HALTED; //Set after HLT instruction is completed(in WB stage)
reg TAKEN_BRANCH; //Required to disable instructions after branch
always @(posedge clk1) //IF stage
if(HALTED==0)
begin
if((( EX_MEM_IR[31:26] == BEQZ) && (EX_MEM_cond == 1)) || ((EX_MEM_IR[31:26] == BNEQZ) && (EX_MEM_cond == 0)))
begin
IF_ID_IR <= #2 Mem[EX_MEM_ALUout];
TAKEN_BRANCH <= #2 1'b1;
IF_ID_NPC <= #2 EX_MEM_ALUout + 1;
PC <= #2 EX_MEM_ALUout + 1;
end
else
begin
IF_ID_IR <= #2 Mem[PC];
IF_ID_NPC <= #2 PC + 1;
PC <= #2 PC+1;
end
end
always @(posedge clk2) //ID Stage
if (HALTED == 0)
begin
if(IF_ID_IR[25:21] == 5'b00000) ID_EX_A <= 0;
else ID_EX_A <= #2 Reg[IF_ID_IR[25:21]]; //"rs"
if(IF_ID_IR[20:16] == 5'b00000) ID_EX_B <= 0;
else ID_EX_B <= #2 Reg[IF_ID_IR[20:16]]; //"rt"
ID_EX_NPC <= #2 IF_ID_NPC;
ID_EX_IR <= #2 IF_ID_IR;
ID_EX_Imm <= #2 {{16{IF_ID_IR[15]}}, {IF_ID_IR[15:0]}};
case (IF_ID_IR[31:26])
ADD,SUB,AND,OR,SLT,MUL: ID_EX_type <= #2 RR_ALU;
ADDI,SUBI,SLTI: ID_EX_type <= #2 RM_ALU;
LW: ID_EX_type <= #2 LOAD;
SW: ID_EX_type <= #2 STORE;
BNEQZ, BEQZ: ID_EX_type <= #2 BRANCH;
HLT: ID_EX_type <= #2 HALT;
default: ID_EX_type <= #2 HALT; // Invalid opcode
endcase
end
always @(posedge clk1) //EX Stage
if(HALTED == 0)
begin
EX_MEM_type <= #2 ID_EX_type;
EX_MEM_IR <= #2 ID_EX_IR;
TAKEN_BRANCH <= #2 0;
case (ID_EX_type)
RR_ALU : begin
case(ID_EX_IR[31:26]) //"opcode"
ADD: EX_MEM_ALUout <= #2 ID_EX_A + ID_EX_B;
SUB: EX_MEM_ALUout <= #2 ID_EX_A - ID_EX_B;
AND: EX_MEM_ALUout <= #2 ID_EX_A & ID_EX_B;
OR : EX_MEM_ALUout <= #2 ID_EX_A | ID_EX_B;
SLT: EX_MEM_ALUout <= #2 ID_EX_A < ID_EX_B;
MUL: EX_MEM_ALUout <= #2 ID_EX_A * ID_EX_B;
default: EX_MEM_ALUout <= #2 32'hxxxxxxxx;
endcase
end
RM_ALU: begin
case (ID_EX_IR[31:26])
ADDI: EX_MEM_ALUout <= #2 ID_EX_A + ID_EX_Imm;
SUBI: EX_MEM_ALUout <= #2 ID_EX_A - ID_EX_Imm;
SLTI: EX_MEM_ALUout <= #2 ID_EX_A < ID_EX_Imm;
default: EX_MEM_ALUout <= #2 32'hxxxxxxxx;
endcase
end
LOAD, STORE:
begin
EX_MEM_ALUout <= #2 ID_EX_A + ID_EX_Imm;
EX_MEM_B <= #2 ID_EX_B;
end
BRANCH:
begin
EX_MEM_ALUout <= #2 ID_EX_NPC + ID_EX_Imm;
EX_MEM_cond <= #2 (ID_EX_A == 0);
end
endcase
end
always @(posedge clk2) //MEM stage
if(HALTED == 0)
begin
MEM_WB_type <= EX_MEM_type;
MEM_WB_IR <= #2 EX_MEM_IR;
case (EX_MEM_type)
RR_ALU, RM_ALU: MEM_WB_ALUout <= #2 EX_MEM_ALUout;
LOAD: MEM_WB_LMD <= #2 Mem[EX_MEM_ALUout];
STORE: if(TAKEN_BRANCH == 0) //Disable write
Mem[EX_MEM_ALUout] <= #2 EX_MEM_B;
endcase
end
always @(posedge clk1) //WB stage
begin
if(TAKEN_BRANCH==0) //disable write if branch taken
case (MEM_WB_type)
RR_ALU: Reg[MEM_WB_IR[15:11]] <= #2 MEM_WB_ALUout; //"rd"
RM_ALU: Reg[MEM_WB_IR[20:16]] <= #2 MEM_WB_ALUout; //"rt"
LOAD : Reg[MEM_WB_IR[20:16]] <= #2 MEM_WB_LMD; //"rt"
HALT : HALTED <= #2 1'b1;
endcase
end
endmodule
The testbench is to be implemented in Cadence software. So far all the results I obtained were either 0 or X. Can anyone suggest appropriate testbench for this?
1 Answer 1
Here is a very simple testbench:
module tb;
reg clk1;
reg clk2;
pipe_MIPS32 dut (
.clk1 (clk1),
.clk2 (clk2)
);
initial begin
clk1 = 0;
forever #5 clk1 = ~clk1;
end
initial begin
clk2 = 0;
forever #5 clk2 = ~clk2;
end
initial begin
$dumpvars;
#200 $finish;
end
endmodule
It drives the inputs with clock periods of 10. If you set your timescale to 1ns, then the signals run at 100MHz. You can adjust the frequencies as needed by changing the #5
delays.
Your code is a little unusual because it only has the 2 clock inputs and no outputs. This is fine if your goal is to have a simulation-only model, but if you want to synthesize the design, the module is required to have output ports.
Regarding the X results, the problem is that you are not initializing any of the logic. You properly declared signals using reg
, but the default value at time 0 for reg
types is x
(the unknown value). For simulation purposes, you could set signals to 0 inside the module. For example:
reg HALTED = 0;
This will make some of your signals known during simulation.
However, a better way to initialize signals is to add an input port to reset the logic. For example:
input reset;
always @(posedge clk1) begin
if (reset) begin
HALTED <= 0;
end else begin
// your logic here
end
end
Explore related questions
See similar questions with these tags.
Mem
? How are you initializingPC
to begin execution? \$\endgroup\$