RISC_V_LAB hinzugefügt

This commit is contained in:
muellerlu
2026-06-09 08:33:18 +02:00
commit 3c0ec38544
233 changed files with 90271 additions and 0 deletions
@@ -0,0 +1,328 @@
// *********************************************************************************************
// Description : Verilator tb
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Aug.2025 by Marcus Bednara
// Last Modified : 15.Oct.2025 by Hussein Elzomor [commit d0452cd]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Renamed modules from *soc* to *cpu*
// 15.Oct.2025 H.Elzomor Added evalText function
// *********************************************************************************************
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <verilated.h>
#include <verilated_fst_c.h>
#include "Vcpu_harness.h"
#include "Vcpu_harness__Dpi.h"
// only required for accessing model internal memory ressources via the rootp pointer.
// Bad style, better use systemverilog harness with tasks and functions to do that.
// #include "Vcpu_harness___024root.h"
// #include "svdpi.h"
#define SOC_CLK_PERIOD 40
//--------------------------------------------------------------
/// @brief Simulation environment class for the cpu model.
/// Contains a set of high level methods for controlling the model from test environment.
class cpu
{
private:
Vcpu_harness *dut;
VerilatedFstC *mTrace;
vluint64_t T;
uint32_t cpuClkState;
bool running;
string program;
public:
//--------------------------------------------------------------
/// @brief Constructor
cpu (int argc, char** argv)
{
// setup verilator stuff
T = 0;
dut = new Vcpu_harness();
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(true);
mTrace = new VerilatedFstC;
dut->trace(mTrace, 5);
mTrace->open("wavedump.fst");
cout << "Registered DPI-C functions:\n";
Verilated::scopesDump();
const svScope scope = svGetScopeFromName("TOP.cpu_harness");
assert(scope); // Check for nullptr if scope not found
svSetScope(scope);
running = false;
// initialize all input signals
initSignals();
} // swirl()
//--------------------------------------------------------------
/// @brief simulation tick, advances the simulation time and calls the eval() function of the model on every active clock edge
void tick ()
{
int do_eval;
if (T%SOC_CLK_PERIOD==0) {
dut->setClk(cpuClkState);
cpuClkState = 1-cpuClkState;
do_eval = 1;
}
// Other clock domains must be generated the same way
// if (T%OTHER_CLK_PERIOD==0) {
// dut->setOtherClk(otherClkState);
// otherClkState = 1-otherClkState;
// do_eval = 1;
// }
if (do_eval) {
dut->eval();
// evaluate the LED status in each clock cycle if the CPU is running (i.e., after reset)
if (running && program == "unknown") evalLed();
// evaluate the Fibonacci Series location in stack (starting at 2027) and print value if it has changed
if (running && program == "fibonacci") evalFibonacci();
// evaluate the 'hello world!' location in the DataMem in each clock cycle if the CPU is running (i.e., after reset)
if (running && program == "helloWorld") evalHelloWorld();
// evaluate the Prime Factors location in RegFile (x17) and print value if it has changed
if (running && program == "primeFactors") evalPrimeFactors();
mTrace->dump(T);
do_eval = 0;
}
T++;
} // tick()
//--------------------------------------------------------------
/// @brief Initialize all input signals of the hardware model to a defined value
void initSignals()
{
dut->setInitial();
} // initSignals()
//--------------------------------------------------------------
/// @brief Wait for a number of active edges of clk signal
/// @param numEdges number of rising edges
/// @param active active 1=rising 0=falling edge
void waitClocks (int numEdges=1, int activeEdge=1)
{
int clk_d;
for (int j=0; j<numEdges; ++j) {
while (1) {
clk_d = cpuClkState;
tick();
if (clk_d==1-activeEdge && cpuClkState==activeEdge) break;
}
} // for
} // waitClocks()
//--------------------------------------------------------------
/// @brief Toggle the reset signal active (low)
/// @param numEdges number of clock cyles keeping the reset active
void reset (int numEdges=1)
{
dut->setReset(0); // reset is active low
waitClocks (numEdges);
dut->setReset(1);
} // reset();
//--------------------------------------------------------------
/// @brief load the cpu memory from vmem formatted file
void loadRAM (char* vmemFile)
{
dut->loadRAM(vmemFile);
} // loadRAM()
/// @brief check the LED status and print value if it has change
void evalLed ()
{
static uint8_t oldLedStatus=0xff;
uint8_t currentLedStatus;
currentLedStatus=dut->getLed();
if (currentLedStatus!=oldLedStatus) {
cout << "T=" << T << ": LED=" << std::bitset<8>(currentLedStatus) << endl;
oldLedStatus = currentLedStatus;
}
} // evalLed()
/// @brief check Fibonacci Series location in stack (starting at 2027) and print value if it has changed
void evalFibonacci()
{
int memStartLoc = 2027;
const int memLengthInBytes = 40;
const int memLengthInWords = ceil(memLengthInBytes / 4.0);
static uint32_t oldValue[memLengthInWords];
uint32_t vlaue[memLengthInWords];
bool update = 0;
for (int i = 0; i < memLengthInWords; i++)
{
vlaue[i] = dut->getMem(memStartLoc + i);
if (oldValue[i] != vlaue[i])
update = 1;
}
if (update)
{
cout << endl
<< "T=" << T << ": \t Hex \t Dec" << endl;
for (int i = 0; i < memLengthInWords; i++)
{
dut->printMem(memStartLoc + i, "fibonacci");
oldValue[i] = vlaue[i];
}
cout << endl;
}
} // evalFibonacci()
/// @brief check 'hello world' location in DataMem (starting at 1024) and print value if it has changed
void evalHelloWorld()
{
int memStartLoc = 1024;
const int memLengthInBytes = 13;
const int memLengthInWords = ceil(memLengthInBytes / 4.0);
static uint32_t oldValue[memLengthInWords];
uint32_t vlaue[memLengthInWords];
bool update = 0;
for (int i = 0; i < memLengthInWords; i++)
{
vlaue[i] = dut->getMem(memStartLoc + i);
if (oldValue[i] != vlaue[i])
update = 1;
}
if (update)
{
cout << endl
<< "T=" << T << ": \t Hex \t ASCII" << endl;
for (int i = 0; i < memLengthInWords; i++)
{
dut->printMem(memStartLoc + i, "helloWorld");
oldValue[i] = vlaue[i];
}
cout << endl;
}
} // evalHelloWorld()
/// @brief check Prime Factors location in RegFile (x17) and print value if it has changed
void evalPrimeFactors()
{
// Number to be factorised
int regLoc_Number = 16;
static uint32_t oldValue_Number;
uint32_t value_Number;
value_Number = dut->getReg(regLoc_Number);
if (oldValue_Number != value_Number & value_Number > 1) dut->printReg(regLoc_Number, "primeNumber");
oldValue_Number = value_Number;
// Prime Factors
int regLoc_PrimeFactor = 17;
static uint32_t oldValue_PrimeFactor;
uint32_t value_PrimeFactor;
value_PrimeFactor = dut->getReg(regLoc_PrimeFactor);
if (oldValue_PrimeFactor != value_PrimeFactor & value_PrimeFactor > 1) dut->printReg(regLoc_PrimeFactor, "primeFactors");
oldValue_PrimeFactor = value_PrimeFactor;
} // evalPrimeFactors()
//--------------------------------------------------------------
/// @brief start the DUT
void start()
{
running = true;
dut->enable(1);
} // start()
//--------------------------------------------------------------
/// @brief close the trace file and delete the Verilator object
void stop()
{
dut->enable(0);
mTrace->close();
delete dut;
} // stop()
//--------------------------------------------------------------
/// @brief Set the program name
void setProgram(string prog)
{
if (prog.find("fibonacci") != string::npos) program = "fibonacci";
else if (prog.find("helloWorld") != string::npos) program = "helloWorld";
else if (prog.find("primeFactors") != string::npos) program = "primeFactors";
else program = "unknown";
cout << "program set to " << program << endl;
} // setProgram()
//--------------------------------------------------------------
/// @brief Get the program name
string getProgram()
{
return program;
} // getProgram()
}; // class cpu
int main (int argc, char** argv)
{
uint32_t nCycles;
char* program_path = new char[strlen(argv[2])]();
// Get number of simulation cycles
nCycles = atoi(argv[1]);
// Get the program
program_path = argv[2];
string program_path_str = program_path;
cout << "\nCreating model...\n";
cpu *m = new cpu(argc, argv);
m->loadRAM(program_path);
m->setProgram(program_path_str);
cout << "\nStarting model...\n";
cout << "\nResetting...\n";
m->reset(10);
cout << "Starting CPU...\n" << std::flush;
m->start();
cout << "Running for " << nCycles << " clock cycles...\n\n" << std::flush;
cout << "Printing evaluation for " << m->getProgram() << " program!\n" << std::flush;
m->waitClocks(nCycles);
cout << "\nDone, closing simulation.\n\n\n" << std::flush;
m->stop();
delete m;
exit(EXIT_SUCCESS);
}
@@ -0,0 +1,185 @@
// *********************************************************************************************
// Description : Verilator tb
// 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 : 15.Oct.2025 by Hussein Elzomor
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <verilated.h>
#include <verilated_fst_c.h>
#include "Vdecoder_harness.h"
#include "Vdecoder_harness__Dpi.h"
// only required for accessing model internal memory ressources via the rootp pointer.
// Bad style, better use systemverilog harness with tasks and functions to do that.
// #include "Vdecoder_harness___024root.h"
// #include "svdpi.h"
#define DECODER_CLK_PERIOD 40
//--------------------------------------------------------------
/// @brief Simulation environment class for the decoder model.
/// Contains a set of high level methods for controlling the model from test environment.
class decoder
{
private:
Vdecoder_harness *dut;
VerilatedFstC *mTrace;
vluint64_t T;
uint32_t decoderClkState;
bool running;
public:
//--------------------------------------------------------------
/// @brief Constructor
decoder (int argc, char** argv)
{
// setup verilator stuff
T = 0;
dut = new Vdecoder_harness();
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(true);
mTrace = new VerilatedFstC;
dut->trace(mTrace, 5);
mTrace->open("wavedump.fst");
cout << "Registered DPI-C functions:\n";
Verilated::scopesDump();
const svScope scope = svGetScopeFromName("TOP.decoder_harness");
assert(scope); // Check for nullptr if scope not found
svSetScope(scope);
running = false;
// initialize all input signals
initSignals();
} // swirl()
//--------------------------------------------------------------
/// @brief simulation tick, advances the simulation time and calls the eval() function of the model on every active clock edge
void tick ()
{
int do_eval;
if (T%DECODER_CLK_PERIOD==0) {
dut->setClk(decoderClkState);
decoderClkState = 1-decoderClkState;
do_eval = 1;
}
if (do_eval) {
dut->eval();
mTrace->dump(T);
do_eval = 0;
}
T++;
} // tick()
//--------------------------------------------------------------
/// @brief Initialize all input signals of the hardware model to a defined value
void initSignals()
{
dut->setInitial();
} // initSignals()
//--------------------------------------------------------------
/// @brief Wait for a number of active edges of clk signal
/// @param numEdges number of rising edges
/// @param active active 1=rising 0=falling edge
void waitClocks (int numEdges=1, int activeEdge=1)
{
int clk_d;
for (int j=0; j<numEdges; ++j) {
while (1) {
clk_d = decoderClkState;
tick();
if (clk_d==1-activeEdge && decoderClkState==activeEdge) break;
}
} // for
} // waitClocks()
//--------------------------------------------------------------
/// @brief load the decoder memory from vmem formatted file
void loadRAM(char *vmemFile)
{
dut->loadRAM(vmemFile);
} // loadRAM()
//--------------------------------------------------------------
/// @brief start the DUT
void start()
{
running = true;
dut->enable(1);
} // start()
//--------------------------------------------------------------
/// @brief close the trace file and delete the Verilator object
void stop()
{
dut->enable(0);
mTrace->close();
delete dut;
} // stop()
//--------------------------------------------------------------
/// @brief print signal info
void printInfo()
{
dut->printInfo();
}
}; // class decoder
int main (int argc, char** argv)
{
uint32_t nCycles;
int r;
// Get number of simulation cycles
nCycles = atoi(argv[1]);
cout << "\nCreating model...\n";
decoder *m = new decoder(argc, argv);
m->loadRAM(argv[2]);
cout << "Starting DECODER simulation...\n" << std::flush;
m->start();
cout << "Running for " << nCycles << " clock cycles...\n" << std::flush;
m->waitClocks(nCycles);
m->printInfo();
cout << "\nDone, closing simulation.\n\n\n" << std::flush;
m->stop();
delete m;
exit(EXIT_SUCCESS);
}