165 lines
7.8 KiB
Systemverilog
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
|