DfT/riscv_rtl/hw/dv/rtl/main_mem_tb.sv
2026-05-29 10:19:13 +02:00

239 lines
9.2 KiB
Systemverilog

// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 20.Oct.2025 by Aliakbar Merchant
// Last Modified : 24.Oct.2025 by Aliakbar Merchant [commit 89a5087]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
`timescale 1ns/1ns
module main_mem_tb ();
// local Parameters
localparam string MEM_INIT_FILE = "main_mem.hex";
// Helpers for addressing width
localparam logic[1:0] _byte = 2'b00; // byte: 8 bits
localparam logic[1:0] _half = 2'b01; // half: 16 bits
localparam logic[1:0] _word = 2'b10; // word: 32 bits
// Local Signals
// clk and reset
logic clk;
logic reset;
// Memory
logic[31:0] DAddr;
logic[31:0] IAddr;
logic[31:0] DWData;
logic[31:0] DRData;
logic[31:0] IRData;
logic DWE;
logic[1:0] DWidth;
// Helpers for display results purpose
logic[31:0] value_at_0;
logic[31:0] value_at_1;
logic[31:0] value_at_2;
logic[31:0] value_at_3;
logic[31:0] value_at_1024;
logic[31:0] value_at_1025;
logic[31:0] value_at_1026;
logic[31:0] value_at_1027;
// Toplevel instance (DUT)
main_mem u_main_mem (
.clk (clk ),
.reset (reset ),
.DAddr (DAddr ),
.IAddr (IAddr ),
.DWData (DWData ),
.DRData (DRData ),
.IRData (IRData ),
.DWE (DWE ),
.DWidth (DWidth )
);
// Clock generation
always #1 clk = ~clk;
// Initialize and run simulation
initial begin
loadMem(MEM_INIT_FILE);
value_at_0 = main_mem_tb.u_main_mem.RAM[0];
value_at_1 = main_mem_tb.u_main_mem.RAM[1];
value_at_2 = main_mem_tb.u_main_mem.RAM[2];
value_at_3 = main_mem_tb.u_main_mem.RAM[3];
value_at_1024 = main_mem_tb.u_main_mem.RAM[1024];
value_at_1025 = main_mem_tb.u_main_mem.RAM[1025];
value_at_1026 = main_mem_tb.u_main_mem.RAM[1026];
value_at_1027 = main_mem_tb.u_main_mem.RAM[1027];
clk = 0;
DAddr = 32'd4096;
IAddr = 0;
DWData = 0;
DWidth = 0;
reset = 1; DWE=1; #7;
DWE = 0;
reset = 0; #2;
test_scenario1(); #30;
$finish;
end
// Test scenario 1
task test_scenario1();
fork
read_inst_mem(15);
display_inst_read_results();
write_data_mem(4096);
join
display_write_results();
fork
display_read_results();
read_data_mem(4096);
join
endtask: test_scenario1
// Intruction memory read transactions and results display
task read_inst_mem(int unsigned n = 1);
repeat(n) begin
cycles_pe(1);
IAddr = IAddr+4;
end
endtask:read_inst_mem
task display_inst_read_results();
$display("\n----------------------------------------------------------------------------------" );
$display("Instruction MEMORY READ RESULTS" );
$display("15 instruction are read by testbench starting at adrress 0x0000 i.e at (RAM[0]) but only 4 displyed for simplicity" );
$display("----------------------------------------------------------------------------------" );
cycles_pe(2);
$display("Time = %0dns \t : IAddr = 0x0000(RAM[0]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_0, IRData );
cycles_pe(1);
$display("Time = %0dns \t : IAddr = 0x0004(RAM[1]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_1, IRData );
cycles_pe(1);
$display("Time = %0dns \t : IAddr = 0x0008(RAM[2]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_2, IRData );
cycles_pe(1);
$display("Time = %0dns \t : IAddr = 0x000c(RAM[3]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_3, IRData );
endtask:display_inst_read_results
// Data memory write transaction and results display
task write_data_mem(logic [31:0] daddr_init=32'd4096);
cycles_pe(1);
DWE = 1;
DWidth = 0;
DAddr = daddr_init+0;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 1;
DWidth = 1;
DAddr = daddr_init+4;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 1;
DWidth = 2;
DAddr = daddr_init+8;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 1;
DWidth = 3;
DAddr = daddr_init+12;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 0;
endtask:write_data_mem
task display_write_results();
$display("\n----------------------------------------------------------------------------------" );
$display("DATA MEMORY WRITE RESULTS" );
$display("4 Write transaction are being done by testbench starting at adrress 0x1000 i.e at (RAM[1024]) with all 4 combination of DWidth" );
$display("Data written is always 0xDEADBEEF i.e DWData = DEADBEEF" );
$display("----------------------------------------------------------------------------------" );
$display("Time = %0dns \t : DWidth = 0 DAddr = 0x1000(RAM[1024]): Start value at RAM[1024] = 0x%h Expected value at RAM[1024]= 0xef%h Actual Value at RAM[1024]: 0x%h" , $time, value_at_1024,value_at_1024[23:0], getMem(1024) );
$display("Time = %0dns \t : DWidth = 1 DAddr = 0x1004(RAM[1025]): Start value at RAM[1025] = 0x%h Expected value at RAM[1025]= 0xbeef%h Actual Value at RAM[1025]: 0x%h" , $time, value_at_1025,value_at_1025[15:0], getMem(1025) );
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1008(RAM[1026]): Start value at RAM[1026] = 0x%h Expected value at RAM[1026]= 0xdeadbeef Actual Value at RAM[1026]: 0x%h" , $time, value_at_1026, getMem(1026) );
$display("Time = %0dns \t : DWidth = 3 DAddr = 0x100c(RAM[1027]): Start value at RAM[1027] = 0x%h Expected value at RAM[1027]= 0x%h Actual Value at RAM[1027]: 0x%h" , $time, value_at_1027,value_at_1027, getMem(1027) );
endtask:display_write_results
// Data Memory read transaction and results display
task read_data_mem(logic [31:0] daddr_init=32'd4096);
cycles_pe(1);
DWidth = 0;
DAddr = daddr_init+0;
cycles_pe(1);
DWidth = 1;
DAddr = daddr_init+4;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+8;
cycles_pe(1);
DWidth = 3;
DAddr = daddr_init+12;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+0;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+4;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+8;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+12;
endtask:read_data_mem
task display_read_results();
$display("\n----------------------------------------------------------------------------------" );
$display("DATA MEMORY READ RESULTS" );
$display("8 Read transaction are being done by testbench starting at adrress 0x1000 i.e at (RAM[1024])" );
$display("----------------------------------------------------------------------------------" );
cycles_pe(2);
$display("Time = %0dns \t : DWidth = 0 DAddr = 0x1000(RAM[1024]): Expected value = 0x000000ef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 1 DAddr = 0x1004(RAM[1025]): Expected value = 0x0000beef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1008(RAM[1026]): Expected value = 0xdeadbeef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 3 DAddr = 0x100c(RAM[1027]): Expected value = 0xdeadbeef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1000(RAM[1024]): Expected value = 0xef%h Actual Value at DRData: 0x%h" , $time, value_at_1024[23:0], DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1004(RAM[1025]): Expected value = 0xbeef%h Actual Value at DRData: 0x%h" , $time, value_at_1025[15:0], DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1008(RAM[1026]): Expected value = 0xdeadbeef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x100c(RAM[1027]): Expected value = 0x%h Actual Value at DRData: 0x%h" , $time, value_at_1027, DRData );
endtask:display_read_results
// Helper tasks
// Memory
function int getMem(int location);
getMem = u_main_mem.RAM[location];
endfunction: getMem
task cycles_pe(int unsigned N = 1);
repeat(N) @(posedge clk);
endtask: cycles_pe
task cycles_ne(int unsigned N = 1);
repeat(N) @(negedge clk);
endtask: cycles_ne
// Load hex file into memory
task loadMem (string fileName);
$display("\nTime = %0dns \t : Loading '%s' into Memory", $time, fileName);
$readmemh(fileName, main_mem_tb.u_main_mem.RAM);
endtask: loadMem
endmodule