`timescale 1 ns / 1 ns
module regfile_tb();
parameter Td2 = 5; // the half of the period
parameter Nd = 16; // the data size
parameter Na = 3; // the address size
parameter Nreg = (1 << Na); // the number of registers
reg clk, rst_n, we;
wire [Nd-1:0] rda, rdb; // read data
reg [Nd-1:0] d; // write data
reg [Na-1:0] wa, ra, rb; // addresses
reg [Nd-1:0] regm [0:Nreg-1]; // shadow memory for the regs
integer i; // loop index
regfile dut(.clk(clk), .rst_n(rst_n), .we(we), .din(d), .waddr(wa),
.raddra(ra), .raddrb(rb), .rdata(rda), .rdatb(rdb));
defparam dut.Nd = Nd; // map the parameters
defparam dut.Na = Na;
always # Td2 clk = ~clk; // generate the clock
initial begin
$dumpfile("regfile.vcd");
$dumpvars(1, regfile_tb.dut);
end
initial
$monitor("Zeit: %t, write enable changed to: %b", $time, we);
initial
begin
clk = 1'b0; // initial value of the clock
rst_n = 0; // power up reset
repeat (2) @(negedge clk);
rst_n = 1; // deactivate the reset
for (i = 0; i < Nreg; i = i + 1) // write some pattern
write_reg(i, i | (i+1) << 8);
for (i = 0; i < Nreg; i = i + 1) // read back
read_reg(0, i, regm[i]); // using port A
for (i = 0; i < Nreg; i = i + 1)
read_reg(1, i, regm[i]); // and port B
rst_n = 0; // reset
@(negedge clk);
rst_n = 1;
for (i = 0; i < Nreg; i = i + 1) // read and expect 0
read_reg(0, i, 0);
for (i = 0; i < Nreg; i = i + 1) // from both ports
read_reg(1, i, 0);
end
task write_reg;
input [Na-1:0] rega;
input [Nd-1:0] regd;
begin
we = 1;
d = regd;
wa = rega;
@ (negedge clk);
regm[rega] = regd;
we = 0;
end
endtask
task read_reg;
input prt; // 0 or 1
input [Na-1:0] rega;
input [Nd-1:0] regd;
begin
we = 0;
if (prt==0) ra = rega;
else rb = rega;
@ (negedge clk);
if ((prt==0) && (rda != regd))
$display("%t : expected 0x%04x, readA 0x%04x, reg# %d", $time, regd, rda, rega);
if ((prt==1) && (rdb != regd))
$display("%t : expected 0x%04x, readB 0x%04x, reg# %d", $time, regd, rdb, rega);
end
endtask
endmodule