239 lines
9.2 KiB
Systemverilog
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
|