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

165 lines
7.8 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 : 15.Oct.2025 by Hussein Elzomor
// Last Modified : 23.Oct.2025 by Hussein Elzomor [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Renamed file and module from soc_tb to cpu_tb
// *********************************************************************************************
// `define fibonacci
// `define helloWorld
// `define primeFactors
`timescale 1ns/1ns
module cpu_tb ();
// local signals
logic[7:0] led;
logic[6:0] btn;
logic reset;
logic clk;
// Toplevel instance (DUT)
cpu u_cpu (
.led(led),
.btn(btn),
.clk_25mhz(clk)
);
// Tie reset signal to the reset button
assign btn[0] = reset;
// Clock generation
always #20 clk = ~clk;
// Initialize and run simulation
initial begin
dumpWave("wave.vcd");
`ifdef fibonacci
loadMem("fibonacci.hex");
`elsif helloWorld
loadMem("helloWorld.hex");
`elsif primeFactors
loadMem("primeFactors.hex");
`endif
clk = 0;
$display("\nTime = %0dns \t : Resetting the CPU", $time);
reset = 0; #100;
$display("\nTime = %0dns \t : Reset released", $time);
reset = 1; #500000;
$finish;
end
// Fibonacci Program Monitor
`ifdef fibonacci
localparam int fibonacciStartLoc = 2027;
localparam int fibonacciLengthInWords = 10;
always_comb begin: Monitor_Fibonacci_Series_Calculation
$display("\nTime =%5dns\t\t\t Hex \t Dec", $time);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+0, u_cpu.theMem.RAM[fibonacciStartLoc+0], u_cpu.theMem.RAM[fibonacciStartLoc+0]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+1, u_cpu.theMem.RAM[fibonacciStartLoc+1], u_cpu.theMem.RAM[fibonacciStartLoc+1]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+2, u_cpu.theMem.RAM[fibonacciStartLoc+2], u_cpu.theMem.RAM[fibonacciStartLoc+2]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+3, u_cpu.theMem.RAM[fibonacciStartLoc+3], u_cpu.theMem.RAM[fibonacciStartLoc+3]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+4, u_cpu.theMem.RAM[fibonacciStartLoc+4], u_cpu.theMem.RAM[fibonacciStartLoc+4]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+5, u_cpu.theMem.RAM[fibonacciStartLoc+5], u_cpu.theMem.RAM[fibonacciStartLoc+5]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+6, u_cpu.theMem.RAM[fibonacciStartLoc+6], u_cpu.theMem.RAM[fibonacciStartLoc+6]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+7, u_cpu.theMem.RAM[fibonacciStartLoc+7], u_cpu.theMem.RAM[fibonacciStartLoc+7]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+8, u_cpu.theMem.RAM[fibonacciStartLoc+8], u_cpu.theMem.RAM[fibonacciStartLoc+8]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+9, u_cpu.theMem.RAM[fibonacciStartLoc+9], u_cpu.theMem.RAM[fibonacciStartLoc+9]);
$display("");
end
// Hello World Program Monitor
`elsif helloWorld
localparam int helloWorldStartLoc = 1024;
localparam int helloWorldLengthInWords = 4;
always_comb begin: Monitor_Hello_World_Printing
$display("\nTime =%5dns\t\t Hex \t\t ASCII", $time);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+0, u_cpu.theMem.RAM[helloWorldStartLoc+0], u_cpu.theMem.RAM[helloWorldStartLoc+0]);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+1, u_cpu.theMem.RAM[helloWorldStartLoc+1], u_cpu.theMem.RAM[helloWorldStartLoc+1]);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+2, u_cpu.theMem.RAM[helloWorldStartLoc+2], u_cpu.theMem.RAM[helloWorldStartLoc+2]);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+3, u_cpu.theMem.RAM[helloWorldStartLoc+3], u_cpu.theMem.RAM[helloWorldStartLoc+3]);
$display("");
end
// Prime Factors Program Monitor
`elsif primeFactors
localparam int primeNumberReg = 16;
always_comb begin: Monitor_Factorization_Number
if(u_cpu.theRegisters.registers[primeNumberReg] > 1)
$display("\nTime =%5dns \t : Register [%0d] updated - Finding the prime factors of %0d", $time,primeNumberReg, u_cpu.theRegisters.registers[primeNumberReg]);
end
localparam int primeFactorsReg = 17;
always_comb begin: Monitor_Prime_Number
if(u_cpu.theRegisters.registers[primeFactorsReg] > 1)
$display("Time =%5dns \t : Register [%0d] updated - %0d is a prime factor", $time,primeFactorsReg, u_cpu.theRegisters.registers[primeFactorsReg]);
end
`endif
// Wave Dump Helper Task
int i;
task dumpWave(string fileName);
// Open wave file and dump all signals (2D arrays not included)
$display("\nTime = %0dns \t : Opening wave file '%s'", $time, fileName);
$dumpfile(fileName);
$display("Time = %0dns \t : Dumping all %s signals in wave file (2D arrays not included)", $time, "cpu_tb");
$dumpvars(0, cpu_tb);
// Dump Memory in wave file
$display("\nTime = %0dns \t : Dumping Memory in wave file", $time);
for (i = 0; i < 100; i++) begin $dumpvars(0, cpu_tb.u_cpu.theMem.RAM[i]); end // A part of the Instruction Memory
for (i = 1024; i < 1124; i++) begin $dumpvars(0, cpu_tb.u_cpu.theMem.RAM[i]); end // A part of the Data Memory
for (i = 1968; i < 2048; i++) begin $dumpvars(0, cpu_tb.u_cpu.theMem.RAM[i]); end // A part of the Stack
// Dump registers in wave file
$display("\nTime = %0dns \t : Dumping Registers in wave file", $time);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[1]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[2]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[3]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[4]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[5]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[6]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[7]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[8]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[9]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[10]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[11]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[12]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[13]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[14]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[15]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[16]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[17]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[18]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[19]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[20]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[21]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[22]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[23]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[24]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[25]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[26]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[27]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[28]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[29]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[30]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[31]);
endtask: dumpWave
// Load hex file into memory
task loadMem (string fileName);
$display("\nTime = %0dns \t : Loading '%s' into Memory", $time, fileName);
$readmemh(fileName, cpu_tb.u_cpu.theMem.RAM);
endtask: loadMem
endmodule