blob: 3cc323c67d22eda8ece26877737083aa38b4248b [file] [log] [blame]
`include "utils.vh"
// set default value for the following parameters, if not defined from command-line
// memory depth
`ifndef WMASK
`define WMASK 4
`endif
`ifndef MEMD
`define MEMD 256
`endif
// data width
`ifndef DATAW
`define DATAW 32
`endif
// number of reading ports
`ifndef nWPORTS
`define nWPORTS 1
`endif
// number of writing ports
`ifndef nRPORTS
`define nRPORTS 2
`endif
// Simulation cycles count
`ifndef CYCC
`define CYCC 1000
`endif
`ifndef Basic_Model
`define Basic_Model 256
`endif
`ifndef ADDRW
`define ADDRW 8
`endif
// WDW (Write-During-Write) protection
`ifndef WDW
`define WDW 0
`endif
// WAW (Write-After-Write) protection
`ifndef WAW
`define WAW 1
`endif
// RDW (Read-During-Write) protection
`ifndef RDW
`define RDW 1
`endif
// RAW (Read-After-Write) protection
`ifndef RAW
`define RAW 1
`endif
module ram_generic_nr1w_tb;
localparam MEMD = `MEMD ; // memory depth
localparam DATAW = `DATAW ; // data width
localparam nRPORTS = `nRPORTS ; // number of reading ports
localparam nWPORTS = `nWPORTS ; // number of writing ports
localparam CYCC = `CYCC ; // simulation cycles count
localparam ADDRW = `ADDRW; // address size
localparam VERBOSE = 0 ; // verbose logging (1:yes; 0:no)
localparam CYCT = 10 ; // cycle time
localparam RSTT = 5.2*CYCT ; // reset time
localparam TERFAIL = 0 ; // terminate if fail?
localparam TIMEOUT = 2*CYCT*CYCC ; // simulation time
localparam BASIC_MODEL = `Basic_Model;
reg clk = 1'b0 ; // global clock
reg rst = 1'b1 ; // global reset
reg [nWPORTS-1:0 ] WEnb ; // write enable for each writing port
reg [ADDRW*nWPORTS-1:0] WAddr_pck ; // write addresses - packed from nWPORTS write ports
reg [ADDRW-1:0 ] WAddr_upk [nWPORTS-1:0]; // write addresses - unpacked 2D array
reg [ADDRW*nRPORTS-1:0] RAddr_pck ; // read addresses - packed from nRPORTS read ports
reg [ADDRW-1:0 ] RAddr_upk [nRPORTS-1:0]; // read addresses - unpacked 2D array
reg [DATAW*nWPORTS-1:0] WData_pck ; // write data - packed from nWPORTS read ports
reg [DATAW-1:0 ] WData_upk [nWPORTS-1:0]; // write data - unpacked 2D array
wire [DATAW*nRPORTS-1:0] RData_pck_sram ; // read data - packed from nRPORTS read ports
reg [DATAW-1:0 ] RData_upk_sram [nRPORTS-1:0]; // read data - unpacked 2D array
reg [DATAW*nRPORTS-1:0] RData_pck_golden ; // read data - packed from nRPORTS read ports
reg [DATAW-1:0 ] RData_upk_golden [nRPORTS-1:0]; // read data - unpacked 2D array
reg [`WMASK*nWPORTS-1:0] wmask_pck ; // wmask packed
reg [`WMASK-1:0 ] wmask_upk [nWPORTS-1:0]; // wmask unpacked
integer i,j; // general indeces
// generates random ram hex/mif initializing files
task genInitFiles;
input [31 :0] DEPTH ; // memory depth
input [31 :0] WIDTH ; // memoty width
input [255 :0] INITVAL; // initial vlaue (if not random)
input RAND ; // random value?
input [1:8*20] FILEN ; // memory initializing file name
reg [255 :0] ramdata;
integer addr,hex_fd,mif_fd;
begin
// open hex/mif file descriptors
hex_fd = $fopen({FILEN,".hex"},"w");
mif_fd = $fopen({FILEN,".mif"},"w");
// write mif header
$fwrite(mif_fd,"WIDTH = %0d;\n",WIDTH);
$fwrite(mif_fd,"DEPTH = %0d;\n",DEPTH);
$fwrite(mif_fd,"ADDRESS_RADIX = HEX;\n" );
$fwrite(mif_fd,"DATA_RADIX = HEX;\n\n" );
$fwrite(mif_fd,"CONTENT BEGIN\n" );
// write random memory lines
for(addr=0;addr<DEPTH;addr=addr+1) begin
if (RAND) begin
`GETRAND(ramdata,WIDTH);
end else ramdata = INITVAL;
$fwrite(hex_fd,"%0h\n",ramdata);
$fwrite(mif_fd," %0h : %0h;\n",addr,ramdata);
end
// write mif tail
$fwrite(mif_fd,"END;\n");
// close hex/mif file descriptors
$fclose(hex_fd);
$fclose(mif_fd);
end
endtask
initial begin
$dumpfile("srimulation.vcd");
$dumpvars(0,ram_generic_nr1w_tb);
end
integer rep_fd, ferr;
initial begin
// write header
//rep_fd = $fopen("sim.txt","r"); // try to open report file for read
//$ferror(rep_fd,ferr); // detect error
//$fclose(rep_fd);
rep_fd = $fopen("sim.txt","w"); // open report file for append
if (1) begin // if file is new (can't open for read); write header
$fwrite(rep_fd,"===============================Simulation Results======================================\n");
$fwrite(rep_fd,"=======================================================================================\n");
$fwrite(rep_fd,"Golden Golden Golden Actual Actual Actual Result \n");
$fwrite(rep_fd,"Read Model Model Read Model Model \n");
$fwrite(rep_fd,"Port RAddr RData Port RAddr RData \n");
$fwrite(rep_fd,"=======================================================================================\n");
$fclose(rep_fd);
end
$write("Simulating RAM:\n");
$write("Write ports : %0d\n" ,nWPORTS );
$write("Read ports : %0d\n" ,nRPORTS );
$write("Data width : %0d\n" ,DATAW );
$write("RAM depth : %0d\n" ,MEMD );
$write("Address width: %0d\n",ADDRW );
$write("Memory Size : %0d KB \n\n", (MEMD*DATAW)/8000);
// generate random ram hex/mif initializing file
genInitFiles(MEMD,DATAW ,0,1,"init_ram");
// finish simulation
#(TIMEOUT) begin
$write("*** Simulation terminated due to timeout\n");
$finish;
end
end
// generate clock and reset
always #(CYCT/2) clk = ~clk; // toggle clock
initial #(RSTT ) rst = 1'b0; // lower reset
// pack/unpack data and addresses
`ARRINIT;
always @* begin
`ARR2D1D(nRPORTS,ADDRW,RAddr_upk ,RAddr_pck );
`ARR2D1D(nWPORTS,`WMASK,wmask_upk ,wmask_pck );
`ARR2D1D(nWPORTS,ADDRW,WAddr_upk ,WAddr_pck );
`ARR1D2D(nWPORTS,DATAW,WData_pck ,WData_upk );
`ARR1D2D(nRPORTS,DATAW,RData_pck_sram ,RData_upk_sram );
`ARR2D1D(nRPORTS,DATAW,RData_upk_golden ,RData_pck_golden );
end
// register write addresses
reg [ADDRW-1:0 ] WAddr_r_upk [nWPORTS-1:0]; // previous (registerd) write addresses - unpacked 2D array
always @(negedge clk)
//WAddr_r_pck <= WAddr_pck;
for (i=0;i<nWPORTS;i=i+1) WAddr_r_upk[i] <= WAddr_upk[i];
// generate random write data and random write/read addresses; on falling edge
reg wdw_addr; // indicates same write addresses on same cycle (Write-During-Write)
reg waw_addr; // indicates same write addresses on next cycle (Write-After-Write)
reg rdw_addr; // indicates same read/write addresses on same cycle (Read-During-Write)
reg raw_addr; // indicates same read address on next cycle (Read-After-Write)
always @(negedge clk) begin
// generate random write addresses; different that current and previous write addresses
for (i=0;i<nWPORTS;i=i+1) begin
wdw_addr = 1; waw_addr = 1;
while (wdw_addr || waw_addr) begin
`GETRAND(WAddr_upk[i],ADDRW);
wdw_addr = 0; waw_addr = 0;
if (!`WDW) for (j=0;j<i ;j=j+1) wdw_addr = wdw_addr || (WAddr_upk[i] == WAddr_upk[j] );
if (!`WAW) for (j=0;j<nWPORTS;j=j+1) waw_addr = waw_addr || (WAddr_upk[i] == WAddr_r_upk[j]);
end
end
// generate random read addresses; different that current and previous write addresses
for (i=0;i<nRPORTS;i=i+1) begin
rdw_addr = 1; raw_addr = 1;
while (rdw_addr || raw_addr) begin
`GETRAND(RAddr_upk[i],ADDRW);
`GETRAND(wmask_upk[i], `WMASK);
rdw_addr = 0; raw_addr = 0;
if (!`RDW) for (j=0;j<nWPORTS;j=j+1) rdw_addr = rdw_addr || (RAddr_upk[i] == WAddr_upk[j] );
if (!`RAW) for (j=0;j<nWPORTS;j=j+1) raw_addr = raw_addr || (RAddr_upk[i] == WAddr_r_upk[j]);
end
end
// generate random write data and write enables
`GETRAND(WData_pck,DATAW*nWPORTS);
`GETRAND(WEnb , nWPORTS);
if (rst) WEnb=1'b0; //else WEnb={nWPORTS{1'b1}};
end
integer cycc=1; // cycles count
integer pass;
integer p;
always @(negedge clk) begin
if (!rst) begin
#(CYCT/10) // a little after falling edge
#(CYCT/2) // a little after rising edge
//if (cycc==CYCC) begin
for(p=0; p<nRPORTS; p=p+1) begin
pass = (RData_upk_golden[p]===RData_upk_sram[p]);
rep_fd = $fopen("sim.txt","a+");
$fwrite(rep_fd,"%-10d %-10d %-15h %-10d %-10d %-15h %-10s \n",p,RAddr_upk[p],RData_upk_golden[p],p,RAddr_upk[p],RData_upk_sram[p],pass?"pass":"fail");
$fclose(rep_fd);
end
if (cycc==CYCC) begin
$finish;
end
cycc=cycc+1;
end
end
// Golden model of SRAM
integer q,r,s;
reg [DATAW-1:0] mem [0:MEMD-1];
initial begin
// $readmemh("init_ram.hex", mem);
for(r=0; r<MEMD; r=r+1) mem[r] = {DATAW{1'b0}};
end
always @(posedge clk)
begin
if(WEnb) begin
for(s=0; s<`WMASK; s=s+1) begin
if(wmask_pck[s])
mem[WAddr_pck][8*s +: 8] = WData_pck[8*s +: 8];
end
end
else begin
for(q=0; q<nRPORTS; q=q+1) begin
RData_upk_golden[q] <= #(10) mem[RAddr_upk[q]];
end
end
end
ram_generic_nr1w #( .NUM_WMASKS (`WMASK),
.MEMD(MEMD),
.DATA_WIDTH(DATAW), // data width
.nRPORTS(nRPORTS), // number of reading ports
.nWPORTS(nWPORTS), // number of write ports
.IZERO (1), // binary / Initial RAM with zeros (has priority over IFILE)
.IFILE (""), // initialization mif file (don't pass extension), optional
.BASIC_MODEL (BASIC_MODEL),
.ADDR_WIDTH(ADDRW),
.DELAY (3))
ram_nr1w ( `ifdef USE_POWER_PINS
.vccd1(vccd1),
.vssd1(vssd1),
`endif
.clk(clk), // clock
.csb(1'b0), // active low chip select
.web(~WEnb), // active low write control
.wmask(wmask_pck), // write mask
.addr((WEnb==1'b1)? {nRPORTS{WAddr_pck}}:RAddr_pck),
.din(WData_pck),
.dout(RData_pck_sram),
.clk1(clk),
.csb1(1'b1),
.addr1({ADDRW*nRPORTS{1'b0}}),
.dout1());
endmodule