HDL Explorer
SPV supplies an HDL explorer for: Verilog, VHDL and SystemC.
The explorer, explores by default all design from top to the last leaf.
This is a strong tool, because it could make many automation process. part of them are inside the SPV library. The header that supply some methods for automation process are in SpvConfig.h.
Examples of the main use of HDL explorer:
when we build a new verification environment, in the most of the time we deal with the signals in top level, but sometimes we want access to deep signals like cpu (Write/Read register), or other.
Instead of declare signals interface by hand, and making mistakes in the signal HDL PATH, we use HDL explorer to build us the interface in a moment.
We recommend to add this code with flag false, in function SpvMain, which is first entry point to SPV environment.
when simulator loads design, he calls SpvMain (Part of the integration processes between SPV and simulator).
if the design changed in the top or in branch that we deal with, or it is the first step of building verification environment, we change the flag to be 'true'.
As a result, when we run the simulation, the HDL explorer will prepare the HDL interface to the verification environment.
The preparation results are 4 files.
AllSig.{cpp,h}:
These files, declares class 'SH', who all his variables are static.
include such file in project, enables verification designer to access any signal in design immediately, without need to mark his PATH, or to declare the object. because class 'SH" declares all the signals, in the path that you chooses in function 'SpvMain'.
In the H file, user could find an important information about each signal. such his full name, Register/Wire , Size in bits.
An example of such file (part of it to understand the concept).
spv.v:
This Verilog file, contains register for each wire in top. this register enable verification environment to assign values to wire.
Assign 'wire_x' = reg_x, when reg_x initial to 'z'. If we want to change 'wire_x', we change the register 'reg_x'.
Access to registers is more simple, and don't require this method. in verification code user could relate to wire and register directly.
So spv.v used, to makes connection between design and SPV code.
AllSigParam.xml:
This xml file used for GUI matters.
SpvGui supplies dialogs that enable create generators, numbers, strings and more. AllSigParam.xml includes information about the signals that we deal with. and SpvGui supplies dialogs that deal with signals like:
-
making clocks.
-
perform reset.
-
perform signals initialization.
-
Create TCM process in GUI
-
process with loops.
-
In loop they Write/Read signals.
-
Even checkers can be added in GUI
-
-
Example of using HDL explorer results.
Using class SH that hold all the signal interface.
In this example, we init all signal at once, and use them by prefix SH::'SigName', all the signal objects are with the source name in design + prefix m_Sig.
In SpvGui page you could find many example how we use the information in file AllSigParam.xml .
class SH //SpvHdl connection
{
public:
SH();
~SH();
static void InitStaticSignal();// Call this static method to init signals
static SpvSig m_Sigclk; //wire Wifi.clk PORT_IN:
static SpvSig m_Sigrst_n; //wire Wifi.rst_n PORT_IN:
static SpvSig m_Sigmpi_addr; //wire [17:0] Wifi.mpi_addr PORT_IN:
static SpvSig m_Sigmpi_enab; //wire Wifi.mpi_enab PORT_IN:
static SpvSig m_Sigmpi_wr_enab; //wire Wifi.mpi_wr_enab PORT_IN:
static SpvSig m_Sigmpi_wr_data; //wire [63:0] Wifi.mpi_wr_data PORT_IN:
static SpvSig m_Sigsymb_valid; //wire Wifi.symb_valid PORT_IN:
static SpvSig m_Sigsymb_i_0; //wire [11:0] Wifi.symb_i_0 PORT_IN:
static SpvSig m_Sigsymb_q_0; //wire [11:0] Wifi.symb_q_0 PORT_IN:
static SpvSig m_Sigsymb_i_1; //wire [11:0] Wifi.symb_i_1 PORT_IN:
static SpvSig m_Sigsymb_q_1; //wire [11:0] Wifi.symb_q_1 PORT_IN:
static SpvSig m_Sigcfg_pls_value; //wire [7:0] Wifi.cfg_pls_val PORT_IN:
}
void SpvMain(int argc,char **argv)
{
if (true) {
vector<string> pathList;
pathList.push_back("design_top");
pathList.push_back("design_top.core.cpull");
pathList.push_back("design_top.bfll_left");
pathList.push_back("design_top.bfll_right");
SpvConfig::CreateSpvHdlInf(pathList,"./Runtime");
cout<<" HDL interface for pfb created, Please compile again spv.v"<<endl;
StopSim();
SpvSig::Finish();
return;
}
// ..... Other initial code
....
}
// code for: wire Wifi.clk"
reg Wifi_clk;
initial Wifi_clk= 1'bz;
assign Wifi.clk = Wifi_clk;
// code for: wire Wifi.rst_n"
reg Wifi_rst_n;
initial Wifi_rst_n= 1'bz;
assign Wifi.rst_n = Wifi_rst_n;
// code for: wire [17:0] Wifi.mpi_addr"
reg [17:0] Wifi_mpi_addr;
initial Wifi_mpi_addr= 18'bz;
assign Wifi.mpi_addr = Wifi_mpi_addr;
// code for: wire Wifi.mpi_enab"
reg Wifi_mpi_enab;
initial Wifi_mpi_enab= 1'bz;
assign Wifi.mpi_enab = Wifi_mpi_enab;
//In the beginning of the project (In SpvMain()) we initial all signal
SH::InitStaticSignal();
//In code at BootStrap.cpp code (In H we declare the objects):
m_ClkPos(SH::m_SigClk,AtPos);//Create SPV event
void BootStrap::InitWorld()
{
Wait(m_ClkPos);
SH::m_Sigrst_n = 0;
Wait(m_ClkPos,10);//Wait 10 clock in reset
SH::m_Sigrst_n = 1;//exit reset
//Now we could start
m_Driver = new TestDriver();
m_Monitor = new TestMonitor();
m_ScoreBoard = new TestScoreBoard();
m_Coverage = new TestCoverage();
//Start working, any class implement his target.
m_Driver->StartProcess(m_ScoreBoard);//pass info to score board
m_Monitor->StartProcess(m_ScoreBoard);//pass info to score board
m_ScoreBoard->StartProcess();