// ********************************************************************************************* // 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