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