SPV Test-bench Studio, represents a further step forward in verification technology. It is a software environment, integrated with RTL hardware simulation environment.SPV integrates with VHDL/Verilog/Mix for Linux/Windows, designed for writing verification test suites.
SPV is a verification environment, which takes the advantages of the strongest tools and languages, imports them, in order to help building rich and faster verification environment.
SPV enable write mix languages, C++, C, Python and MATLAB for writing verification code.
Tools:
-
Verification frame work for editing, compiling, linking and debugging.
-
Visual studio for windows.
-
Eclipse for Linux
-
MATLAB become to be C interface by using MCC compiler, and DPF os SimPlus.
-
-
Advantages:
-
The most powerful and flexible editing tools, that enable the same environment to compile link and debug the code.
-
GUI environment for testing process:
-
Change test parametrs, Generators, clocks, Boolean, numbers (float, double, Uint, Int, Long vectoor), and even creating processes that drive and check the design by mouse click only.
-
-
C ++ is a language that is supported and developed by millions of engineers worldwide, providing detailed documentation, examples and explanations of what a user might think. These engineers have developed the language to be the most rich, providing a solution to every problem. Many libraries for almost any purpose, and an open and rich language that allows the final developer to do whatever he likes, using the best tools for developing, running and debugging.
-
Standard - C ++ is the most stable and standard language. Old C code (30 years ago), works excelent, with the newest methods available today, platforms and environment
-
the most of the abilities no cost.
-

File SpvMain.cpp:
1. Special function that should be exists, called from SPV kernel at time 0, when simulation loaded, and create the testbench tree.
2. option - explore design and prepare interface (For C++ and python) in true condition.
3. GUI - Read GUI data base, generators, Boolean, signals, strings and more
4. make new 2 Boot-Strap that hold the testbench tree.
#include "SpvHfile.h"
#include "BootStrap.h"
#include "AllSig.h"
void SpvMain(int argc, char** argv)//SpvMain called first from kernel simulator
{
cout << "Run SPV Version 7 dll" << endl;
if (false) {
vector<string> pathList;
pathList.push_back("TopCalc");
SpvConfig::CreateSpvHdlInf(pathList, "./Runtime", ExpAllType);
cout << " HDL interface for SimDesignTop1 created, Please compile again spv.v" << endl;
StopSim();
return;
}
//Load GUI data base
SD::LoadRunTime("./Runtime");
if (SD::IsExists("USE_ASSERT", BoolType))
SpvConfig::SetAssert(SD::GetBool("USE_ASSERT"));
else
SpvConfig::SetAssert(false);
SpvConfig::SetInternalErrorType((SpvInternalError)(SD::GetUint("STOP_SIMULATION")));
SpvConfig::UseSeed((SpvSeedType)(SD::GetUint("RAND_SEED")), SD::GetUint("SEED"));
SpvConfig::SetCoutImmediat(true);
//Start the test bench
PrepareGSpvCharAttr();
SH::InitStaticSignal();
BootStrap* test = new BootStrap;
}
File BootStrap.{h,cpp}:
1. Create the testbench tree - and start run after 10 NS.
//BootStrap.h
#pragma once
#include "Driver.h"
class BootStrap : public SpvBase
{
public:
BootStrap();
void StartProcess();
Driver* m_Driver;
};
//BootStrap.cpp
#include "BootStrap.h"
#include "AllSig.h"
SpvSig m_Rst;
BootStrap::BootStrap()
{
m_Driver = NULL;
StartTProc(this, (SpvProcMethod)&BootStrap::StartProcess);
SH::m_Siguse_SpvTb = 1;
}
void BootStrap::StartProcess()
{
Wait(10);
m_Driver = new Driver();
m_Driver->StartProcess();
}
File Driver.{h,cpp}:
1. In this file we declare events, Pos/Neg for each clock.
2 we declare TCM (Time consuming method) function of 2 types:
a. Thread function (with wait in the middle of function) - easy use but little slowly.
b. Atomic process - called each simulator event - Very fast code, but sometimes not convinces.
3. we declare variable to hold the expected results for each Verilog module.
//Driver.h
#pragma once
#include "SpvHfile.h"
#include "ParseHelper.h"
class Driver : public SpvBase
{
public:
Driver();
SpvEvent m_ClkOrPos , m_ClkOrNeg;//15
SpvEvent m_ClkAddPos , m_ClkAddNeg;//20
SpvEvent m_ClkSubPos , m_ClkSubNeg;//25
SpvEvent m_ClkMultPos , m_ClkMultNeg;//30
SpvEvent m_ClkAndPos , m_ClkAndNeg;//35
SpvEvent m_ClkModePos , m_ClkModeNeg;//40
SpvEvent m_ClkXorPos , m_ClkXorNeg;//45
SpvEvent m_ClkShiftLPos , m_ClkShiftLNeg;//50
SpvEvent m_ClkShiftRPos , m_ClkShiftRNeg;//55
SpvEvent m_ClkCurledPos , m_ClkCurledNeg;//500
void StartProcess();
//Calculator process
void DoAlwaysOr();
void DoAlwaysAdd();
void DoAlwaysSub();
void DoAlwaysMult();
void DoAlwaysAnd();
void DoAlwaysMode();
void DoAlwaysXor();
void DoAlwaysShiftL();
void DoAlwaysShiftR();
void DriveCheckAlwaysOrTP();
void DriveCheckAlwaysAddTP();
void DriveCheckAlwaysSubTP();
void DriveCheckAlwaysMultTP();
void DriveCheckAlwaysAndTP();
void DriveCheckAlwaysModeTP();
void DriveCheckAlwaysXorTP();
void DriveCheckAlwaysShiftLTP();
void DriveCheckAlwaysShiftRTP();
void DriveCruledAlwaysTP();
void DriveCheckAlwaysOrFast();
void DriveCheckAlwaysAddFast();
void DriveCheckAlwaysSubFast();
void DriveCheckAlwaysMultFast();
void DriveCheckAlwaysAndFast();
void DriveCheckAlwaysModeFast();
void DriveCheckAlwaysXorFast();
void DriveCheckAlwaysShiftLFast();
void DriveCheckAlwaysShiftRFast();
void DriveCruledAlwaysFast();
unsigned m_OrA , m_OrB , m_OrRes;
unsigned m_AddA , m_AddB , m_AddRes;
unsigned m_SubA , m_SubB , m_SubRes;
unsigned m_MultA , m_MultB , m_MultRes;
unsigned m_AndA , m_AndB , m_AndRes;
unsigned m_ModeA , m_ModeB , m_ModeRes;
unsigned m_XorA , m_XorB , m_XorRes;
unsigned m_ShiftLA, m_ShiftLB , m_ShiftLRes;
unsigned m_ShiftRA, m_ShiftRB , m_ShiftRRes;
unsigned m_OrNumErr , m_OrNumOK;
unsigned m_AddNumErr , m_AddNumOK;
unsigned m_SubNumErr , m_SubNumOK;
unsigned m_MultNumErr , m_MultNumOK;
unsigned m_AndNumErr , m_AndNumOK;
unsigned m_ModeNumErr , m_ModeNumOK;
unsigned m_XorNumErr , m_XorNumOK;
unsigned m_ShiftLNumErr , m_ShiftLNumOK;
unsigned m_ShiftRNumErr , m_ShiftRNumOK;
unsigned m_CruledNumErr , m_CruledNumOK;
//Curled
SpvBitVec m_RegAVec, m_RegBVec, m_RegCVec, m_RegDVec;
Literal m_Literal8Bit;
unsigned m_ConstCurled;
SpvBitVec m_CurledA, m_CurledB, m_ExpWireA, m_ExpWireB, m_ExpWireC;
};
Driver.cpp
#include "AllSig.h"
#include "Driver.h"
unsigned loopSize;
Driver::Driver()
{
//Init signals and event
m_ClkOrNeg.Init(SH::m_Sigclk_or, AtNeg);//15
m_ClkAddNeg.Init(SH::m_Sigclk_add, AtNeg);//20
m_ClkSubNeg.Init(SH::m_Sigclk_sub, AtNeg);//25
m_ClkMultNeg.Init(SH::m_Sigclk_mult, AtNeg);//30
m_ClkAndNeg.Init(SH::m_Sigclk_and, AtNeg);//35
m_ClkModeNeg.Init(SH::m_Sigclk_mode, AtNeg);//40
m_ClkXorNeg.Init(SH::m_Sigclk_xor, AtNeg);//45
m_ClkShiftLNeg.Init(SH::m_Sigclk_shiftL, AtNeg);//50
m_ClkShiftRNeg.Init(SH::m_Sigclk_shiftR, AtNeg);//55
m_ClkCurledNeg.Init(SH::m_Sigcurled_clk, AtNeg);//55
m_ClkOrPos.Init(SH::m_Sigclk_or, AtNeg);//20
m_ClkAddPos.Init(SH::m_Sigclk_add, AtPos);//20
m_ClkSubPos.Init(SH::m_Sigclk_sub, AtPos);//25
m_ClkMultPos.Init(SH::m_Sigclk_mult, AtPos);//30
m_ClkAndPos.Init(SH::m_Sigclk_and, AtPos);//35
m_ClkModePos.Init(SH::m_Sigclk_mode, AtPos);//40
m_ClkXorPos.Init(SH::m_Sigclk_xor, AtPos);//45
m_ClkShiftLPos.Init(SH::m_Sigclk_shiftL, AtPos);//50
m_ClkShiftRPos.Init(SH::m_Sigclk_shiftR, AtPos);//55
m_ClkCurledPos.Init(SH::m_Sigcurled_clk, AtPos);//55
//Init num error and num OK to be 0
m_XorNumErr = 0;
m_OrNumErr = 0;
m_AndNumErr = 0;
m_MultNumErr = 0;
m_AddNumErr = 0;
m_SubNumErr = 0;
m_ShiftLNumErr = 0;
m_ShiftRNumErr = 0;
m_CruledNumErr = 0;
m_XorNumOK = 0;
m_OrNumOK = 0;
m_AndNumOK = 0;
m_MultNumOK = 0;
m_AddNumOK = 0;
m_SubNumOK = 0;
m_ShiftLNumOK = 0;
m_ShiftRNumOK = 0;
m_CruledNumOK = 0;
loopSize = SD::GetUint("LOOP_SIZE");
cout << "LoopSize ==" << loopSize << endl;
//Init SpvBitVec size to be as signals size
m_ExpWireA.Resize(SH::m_SigwireA.Size());
m_ExpWireB.Resize(SH::m_SigwireB.Size());
m_ExpWireC.Resize(SH::m_SigwireC.Size());
m_RegAVec.Resize(SH::m_SigregA.Size());
m_RegBVec.Resize(SH::m_SigregB.Size());
m_RegCVec.Resize(SH::m_SigregC.Size());
m_RegDVec.Resize(SH::m_SigregD.Size());
//Init const literal value by string
m_Literal8Bit.Init("8'b1100XxZz");
//init cruly variable size
m_ConstCurled = 0xAbCdEf01;
m_CurledA.Resize(64);
m_CurledB.Resize(64);
//Set literal value in correct bit as a slice.
unsigned firstLiteralCurledBit = SH::m_SigregD.Size() + SH::m_SigregC.Size() + SH::m_SigregB.Size();
unsigned secondLiteralCurledBit=firstLiteralCurledBit+m_Literal8Bit.m_Avec.Size()-1;
m_CurledA(firstLiteralCurledBit,secondLiteralCurledBit) = m_Literal8Bit.m_Avec;
m_CurledB(firstLiteralCurledBit, secondLiteralCurledBit) = m_Literal8Bit.m_Bvec;
m_CurledA(secondLiteralCurledBit + 1, secondLiteralCurledBit + 32) = m_ConstCurled;
m_CurledB(secondLiteralCurledBit + 1, secondLiteralCurledBit + 32) = 0;
//assign{ wireA,wireB,wireC } = { regA,0xAbCdEf01,8'b1100XxZz,regB,regC,regD[0:2],regD[3]};
}
void Driver::StartProcess()
{
if (SD::GetBool("DO_FAST_PROC")) {//Start all fast process if DO_FAST_PROC == true
//4M actions time performance: Debug: 8 second. Release: 2.5 second.
cout << " DO_FAST_PROC=TRUE Mode loopSize = " << loopSize << endl;
StartAProc(m_ClkOrNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysOrFast);
StartAProc(m_ClkAddNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysAddFast);
StartAProc(m_ClkSubNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysSubFast);
StartAProc(m_ClkMultNeg,this,(SpvProcMethod)&Driver::DriveCheckAlwaysMultFast);
StartAProc(m_ClkAndNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysAndFast);
StartAProc(m_ClkModeNeg,this,(SpvProcMethod)&Driver::DriveCheckAlwaysModeFast);
StartAProc(m_ClkXorNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysXorFast);
StartAProc(m_ClkShiftLNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysShiftLFast);
StartAProc(m_ClkShiftRNeg, this, (SpvProcMethod)&Driver::DriveCheckAlwaysShiftRFast);
StartAProc(m_ClkCurledNeg, this, (SpvProcMethod)&Driver::DriveCruledAlwaysFast);
} else {//Start all thread process if DO_FAST_PROC == false
//0.4M actions time performance: Debug: 37 second. Release: 29 second.
cout << " DO_FAST_PROC=FALSE Mode loopSize = " << loopSize << endl;
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysOrTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysAddTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysSubTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysMultTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysAndTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysModeTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysXorTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysShiftLTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCheckAlwaysShiftRTP);
StartTProc(this, (SpvProcMethod)&Driver::DriveCruledAlwaysTP);
}
}
/////////////////////////////////////////////////// OR /////////////////////
void Driver::DriveCheckAlwaysOrTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkOrNeg);
if (m_OrRes != SH::m_Sigor_res) {
cout <<i<<": Error ***: m_OrA = 0x" <<hex<<m_OrA << " m_OrB = 0x .."<<endl;
m_OrNumErr++;
} else {
m_OrNumOK++;
}
}
m_OrA = GenUnsigned(); m_OrB = GenUnsigned(); m_OrRes = m_OrA | m_OrB;
SH::m_Sigor_a = m_OrA; SH::m_Sigor_b = m_OrB;
}
cout <<"DriveCheckAlwaysOrTP m_OrNumErr="<<m_OrNumErr<<" m_OrNumOK="<<m_OrNumOK<< endl;
}
void Driver::DriveCheckAlwaysOrFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_OrRes != SH::m_Sigor_res) {
cout <<cnt<<": Error ***: m_OrA=0x"<<hex<<m_OrA<<" m_OrB = 0x"<<endl;
m_OrNumErr++;
} else {
m_OrNumOK++;
}
}
//Set data and calculate expected for next negedge.
m_OrA = GenUnsigned(); m_OrB = GenUnsigned(); m_OrRes = m_OrA | m_OrB;
SH::m_Sigor_a = m_OrA; SH::m_Sigor_b = m_OrB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout << "DriveCheckAlwaysOr m_OrNumErr=" << m_OrNumErr << " m_OrNumOK = ";
cout << m_OrNumOK << endl;
}
}
/////////////////////////////////////////////////// ADD //////////////////////
void Driver::DriveCheckAlwaysAddTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkAddNeg);
if (m_AddRes != SH::m_Sigadd_res) {
cout<<i<<": Error ***: m_AddA = 0x"<<hex <<m_AddA<<" m_AddB = 0x.."<<endl;
m_AddNumErr++;
} else {
m_AddNumOK++;
}
}
m_AddA = GenUnsigned(); m_AddB = GenUnsigned(); m_AddRes = m_AddA + m_AddB;
SH::m_Sigadd_a = m_AddA; SH::m_Sigadd_b = m_AddB;
}
cout<<"DriveCheckAlwaysAddTP m_AddNoErr="<<m_AddNoErr<<" m_AddNoOK="<<m_AddNumOK<<endl;
}
void Driver::DriveCheckAlwaysAddFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_AddRes != SH::m_Sigadd_res) {
cout<<cnt<<": Error ***: m_AddA=0x"<<hex<<m_AddA<<" m_AddB=0x"<< m_AddB<<endl;
m_AddNumErr++;
} else {
m_AddNumOK++;
}
}
//Set data Add calculate expected for next negedge.
m_AddA = GenUnsigned(); m_AddB = GenUnsigned(); m_AddRes = m_AddA + m_AddB;
SH::m_Sigadd_a = m_AddA; SH::m_Sigadd_b = m_AddB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysAdd NoErr="<< m_AddNumErr<<" NoOK="<<m_AddNumOK <<endl;
}
}
/////////////////////////////////////////////////// SUB //////////////////
void Driver::DriveCheckAlwaysSubTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkSubNeg);
if (m_SubRes != SH::m_Sigsub_res) {
cout<<i<<": Error ***:m_SubA=0x"<<hex<<m_SubA<<" m_SubB=0x"<<m_SubB<<endl;
m_SubNumErr++;
} else {
m_SubNumOK++;
}
}
m_SubA = GenUnsigned(); m_SubB = GenUnsigned(); m_SubRes = m_SubA - m_SubB;
SH::m_Sigsub_a = m_SubA; SH::m_Sigsub_b = m_SubB;
}
cout<<"DriveCheckAlwaysSubTP NoErr="<<m_SubNumErr<<" NoOK = "<<m_SubNumOK << endl;
}
void Driver::DriveCheckAlwaysSubFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_SubRes != SH::m_Sigsub_res) {
cout<<cnt<<": Error ***: m_SubA=0x"<<hex<<m_SubA<<" m_SubB=0x"<<m_SubB<<endl;
m_SubNumErr++;
} else {
m_SubNumOK++;
}
}
//Set data Sub calculate expected for next negedge.
m_SubA = GenUnsigned(); m_SubB = GenUnsigned(); m_SubRes = m_SubA - m_SubB;
SH::m_Sigsub_a = m_SubA; SH::m_Sigsub_b = m_SubB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysSubFast NoErr="<<m_SubNumErr <<" NoOK="<< m_SubNumOK << endl;
}
}
////////////////////////////////////////////// MULT /////////////////////////////
void Driver::DriveCheckAlwaysMultTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkMultNeg);
if (m_MultRes != SH::m_Sigmult_res) {
cout<<i<<": Error ***: m_MultA = 0x"<<hex<<m_MultA<<" m_MultB = 0x"<<endl;
m_MultNumErr++;
} else {
m_MultNumOK++;
}
}
m_MultA = GenUnsigned(); m_MultB = GenUnsigned(); m_MultRes = m_MultA * m_MultB;
SH::m_Sigmult_a = m_MultA; SH::m_Sigmult_b = m_MultB;
}
cout<<"DriveCheckAlwaysMultTP NoErr="<<m_MultNumErr<<" NoOK="<< m_MultNumOK<<endl;
}
void Driver::DriveCheckAlwaysMultFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_MultRes != SH::m_Sigmult_res) {
cout << cnt << ": Error ***: m_MultA = 0x" << hex << m_MultA << " m_MultB = 0x" << m_MultB << " SPV result = 0x" << m_MultRes << " HDL m_Sigmult_res = " << SH::m_Sigmult_res(SpvHex) << dec << " T:" << SimTime() << endl;
m_MultNumErr++;
}
else {
m_MultNumOK++;
}
}
//Set data Mult calculate expected for next negedge.
m_MultA = GenUnsigned(); m_MultB = GenUnsigned(); m_MultRes = m_MultA * m_MultB;
SH::m_Sigmult_a = m_MultA; SH::m_Sigmult_b = m_MultB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout << "DriveCheckAlwaysMultFast m_MultNumErr=" << m_MultNumErr << " m_MultNumOK = " << m_MultNumOK << endl;
}
}
///////////////////////////// AND ///////////////////
void Driver::DriveCheckAlwaysAndTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkAndNeg);
if (m_AndRes != SH::m_Sigand_res) {
cout<<i<<": Error ***: m_AndA=0x"<<hex<<m_AndA<<" m_AndB=0x"<<m_AndB<<endl;
m_AndNumErr++;
} else {
m_AndNumOK++;
}
}
m_AndA = GenUnsigned(); m_AndB = GenUnsigned(); m_AndRes = m_AndA & m_AndB;
SH::m_Sigand_a = m_AndA; SH::m_Sigand_b = m_AndB;
}
cout<<"DriveCheckAlwaysAndTP NoErr=" << m_AndNumErr << " NoOK = " << m_AndNumOK << endl;
}
void Driver::DriveCheckAlwaysAndFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_AndRes != SH::m_Sigand_res) {
cout<<cnt<<": Error ***: m_AndA=0x"<<hex<<m_AndA<<" m_AndB=0x"<<m_AndB<<endl;
m_AndNumErr++;
} else {
m_AndNumOK++;
}
}
//Set data and calculate expected for next negedge.
m_AndA = GenUnsigned(); m_AndB = GenUnsigned(); m_AndRes = m_AndA & m_AndB;
SH::m_Sigand_a = m_AndA; SH::m_Sigand_b = m_AndB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysAndFast NoErr="<<m_AndNumErr <<" NoOK="<< m_AndNumOK<<endl;
}
}
/////////////////////////////////////////////////// MODE //////////////////////////
void Driver::DriveCheckAlwaysModeTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkModeNeg);
if (m_ModeRes != SH::m_Sigmode_res) {
cout<<i<<": Error ***: m_ModeA = 0x"<<hex<<m_ModeA<< " m_ModeB = 0x"<<endl;
m_ModeNumErr++;
} else {
m_ModeNumOK++;
}
}
m_ModeA = GenUnsigned(0, 0x7FFFFFFF); m_ModeB = GenUnsigned(0, 0x7FFFFFFF); m_ModeRes = m_ModeA % m_ModeB;
SH::m_Sigmode_a = m_ModeA; SH::m_Sigmode_b = m_ModeB;
}
cout<<"DriveCheckAlwaysModeTP NoErr="<< m_ModeNumErr << " NoOK="<<m_ModeNumOK<<endl;
}
void Driver::DriveCheckAlwaysModeFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_ModeRes != SH::m_Sigmode_res) {
cout<<cnt<<": Error ***:m_ModeA=0x"<<hex<<m_ModeA<<" m_ModeB=0x"<<m_ModeB<<endl;
m_ModeNumErr++;
} else {
m_ModeNumOK++;
}
}
//Set data and calculate expected for next negedge.
m_ModeA = GenUnsigned(0, 0x7FFFFFFF); m_ModeB = GenUnsigned(0, 0x7FFFFFFF); m_ModeRes = m_ModeA % m_ModeB;
SH::m_Sigmode_a = m_ModeA; SH::m_Sigmode_b = m_ModeB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysModeFast NoErr="<<m_ModeNumErr<<" NoOK="<<m_ModeNumOK <<endl;
}
}
/////////////////////////////////////////////////// XOR ///////////////////////
void Driver::DriveCheckAlwaysXorTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkXorNeg);
if (m_XorRes != SH::m_Sigxor_res) {
cout<<i<<": Error ***: m_XorA=0x"<<hex<<m_XorA<<" m_XorB=0x"<<m_XorB<<endl;
m_XorNumErr++;
} else {
m_XorNumOK++;
}
}
//drive data for next checking
m_XorA = GenUnsigned(); m_XorB = GenUnsigned(); m_XorRes = m_XorA ^ m_XorB;
SH::m_Sigxor_a = m_XorA; SH::m_Sigxor_b = m_XorB;
}
cout<<"DriveCheckAlwaysXorTP NoErr="<<m_XorNumErr<<" NoOK=" << m_XorNumOK << endl;
}
void Driver::DriveCheckAlwaysXorFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_XorRes != SH::m_Sigxor_res) {
cout<<cnt<<": Error ***: m_XorA=0x"<<hex<<m_XorA<<" m_XorB=0x"<<m_XorB<<endl;
m_XorNumErr++;
} else {
m_XorNumOK++;
}
}
//Set data and calculate expected for next negedge.
m_XorA = GenUnsigned(); m_XorB = GenUnsigned(); m_XorRes = m_XorA ^ m_XorB;
SH::m_Sigxor_a = m_XorA; SH::m_Sigxor_b = m_XorB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysXorFast NoErr="<< m_XorNumErr<< " NoOK="<<m_XorNumOK<<endl;
}
}
/////////////////////////////////////////////////// SHIFTL //////////////////////////
void Driver::DriveCheckAlwaysShiftLTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkShiftLNeg);
if (m_ShiftLRes != SH::m_SigshiftL_res) {
cout<<i<<": Error ***: m_ShiftLA=0x"<<hex<<m_ShiftLA<<" m_ShiftLB=0x"<<endl;
m_ShiftLNumErr++;
} else {
m_ShiftLNumOK++;
}
}
m_ShiftLA=GenUnsigned();m_ShiftLB=GenUnsigned(0,31);
m_ShiftLRes=m_ShiftLA<< m_ShiftLB;
SH::m_SigshiftL_a = m_ShiftLA; SH::m_SigshiftL_b = m_ShiftLB;
}
cout<<"Drive..AlwaysShiftLTP NoErr=" <<m_ShiftLNumErr<<" NoOK="<<m_ShiftLNumOK<< endl;
}
void Driver::DriveCheckAlwaysShiftLFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_ShiftLRes != SH::m_SigshiftL_res) {
cout << cnt << ": Error ***: m_ShiftLA = 0x" << hex << m_ShiftLA << " m_ShiftLB = 0x" << m_ShiftLB << " SPV result = 0x" << m_ShiftLRes << " HDL m_SigshiftL_res = " << SH::m_SigshiftL_res(SpvHex) << dec << " T:" << SimTime() << endl;
m_ShiftLNumErr++;
}
else {
m_ShiftLNumOK++;
}
}
//Set data ShiftL calculate expected for next negedge.
m_ShiftLA = GenUnsigned(); m_ShiftLB = GenUnsigned(0, 31); m_ShiftLRes = m_ShiftLA << m_ShiftLB;
SH::m_SigshiftL_a = m_ShiftLA; SH::m_SigshiftL_b = m_ShiftLB;
if (cnt > loopSize) {
CurrAProc()->Kill();
cout << "DriveCheckAlwaysShiftLFast m_ShiftLNumErr=" << m_ShiftLNumErr << " m_ShiftLNumOK = " << m_ShiftLNumOK << endl;
}
}
/////////////////////////////////////////////////// SHIFTR ////////////////////////////////////////////////////////////
void Driver::DriveCheckAlwaysShiftRTP()
{
for (unsigned i = 0; i < loopSize; i++) {
if (i) {
Wait(m_ClkShiftRNeg);
if (m_ShiftRRes != SH::m_SigshiftR_res) {
//cout << i << ": Error ***: m_ShiftRA = " << m_ShiftRA(SpvHex) << " m_ShiftRB = " << m_ShiftRB(SpvHex) << " SPV result = " << m_ShiftRRes(SpvHex) << " HDL m_SigregShiftRC = " << SH::m_SigregShiftRC(SpvHex) << " T:" << SimTime() << endl;
cout << i << ": Error ***: m_ShiftRA = 0x" << hex << m_ShiftRA << " m_ShiftRB = 0x" << m_ShiftRB << " SPV result = 0x" << m_ShiftRRes << " HDL m_SigshiftR_res = " << SH::m_SigshiftR_res(SpvHex) << dec << " T:" << SimTime() << endl;
m_ShiftRNumErr++;
}
else {
m_ShiftRNumOK++;
}
}
m_ShiftRA = GenUnsigned(0, 0x7FFFFFFF); m_ShiftRB = GenUnsigned(0, 31); m_ShiftRRes = m_ShiftRA >> m_ShiftRB;
SH::m_SigshiftR_a = m_ShiftRA; SH::m_SigshiftR_b = m_ShiftRB;
}
cout << "DriveCheckAlwaysShiftRTP m_ShiftRNumErr=" << m_ShiftRNumErr << " m_ShiftRNumOK = " << m_ShiftRNumOK << endl;
cout << " Num of iteration " << loopSize << " in all method T:" << SimTime() << endl;
StopSim();//this is the most long process.
}
void Driver::DriveCheckAlwaysShiftRFast()
{
static unsigned cnt = 0;
if (cnt++) {
if (m_ShiftRRes != SH::m_SigshiftR_res) {
cout << cnt << ": Error ***: m_ShiftRA = 0x" << hex << m_ShiftRA << " m_ShiftRB = 0x" << m_ShiftRB << " SPV result = 0x" << m_ShiftRRes << " HDL m_SigshiftR_res = " << SH::m_SigshiftR_res(SpvHex) << dec << " T:" << SimTime() << endl;
m_ShiftRNumErr++;
}
else {
m_ShiftRNumOK++;
}
}
//Set data ShiftR calculate expected for next negedge.
m_ShiftRA = GenUnsigned(0, 0x7FFFFFFF); m_ShiftRB = GenUnsigned(0, 31); m_ShiftRRes = m_ShiftRA >> m_ShiftRB;
SH::m_SigshiftR_a = m_ShiftRA; SH::m_SigshiftR_b = m_ShiftRB;
if (cnt > loopSize) {
//StopSim();//this is the most long process.
CurrAProc()->Kill();
cout << "DriveCheckAlwaysShiftRFast m_ShiftRNumErr=" << m_ShiftRNumErr << " m_ShiftRNumOK = " << m_ShiftRNumOK << endl;
}
}
////////////////////////////////// CURLED //////////////////////
void Driver::DriveCruledAlwaysTP()
{
}
void Driver::DriveCruledAlwaysFast()
{
static unsigned cnt = 0;
if (cnt++) {
bool isErr = false;
if (m_CurledA(0, 9).Uint() != SH::m_SigwireC.Uint()) {
cout<<cnt<<": Error***: m_CurledA(0,9)=0x"<<hex<<m_CurledA(0,9).Uint();
cout<<" !=wireC=0x"<<wireC.Uint()<<dec<<" T:"<<SimTime()<< endl;
isErr = true;
}
SPV_UINT64 last34 = m_CurledA.Uint64() >> 30, sig34 = SH::m_SigwireA.Uint64();
if (last34 != sig34) {
cout<<cnt<<":Error***: m_CurledA(63,63-34+1)=0x"<<m_CurledA(63,63-34+ 1).Uint() ; cout<<"!=wireA=0x"<<SH::m_SigwireA.Uint()<<dec<<" T:"<<SimTime()<<endl;
isErr = true;
}
//Need to check also SH::m_SigwireB.Uint() -- it is mix with Z|X
m_CruledNumErr = (isErr) ? (m_CruledNumErr + 1) : m_CruledNumErr ;
m_CruledNumOK = (isErr) ? m_CruledNumOK : (m_CruledNumOK + 1);
}
//Set value, so hdl will make curled process
SH::m_SigregA = m_RegAVec.Gen();
SH::m_SigregB = m_RegBVec.Gen();
SH::m_SigregC = m_RegCVec.Gen();
SH::m_SigregD = m_RegDVec.Gen();
m_CurledA[0] = m_RegDVec[3];
m_CurledA(1, 3) = m_RegDVec(0,2).Uint();
m_CurledA(4, 10)= m_RegCVec;
m_CurledA(11,14)= m_RegBVec;
//Literal & m_ConstCurled are const so they are there.
m_CurledA(64-9,63)= m_RegAVec;
//m_CurledB is const always
if (cnt > loopSize) {
cout<<"DriveCruledFast NoErr="<<m_CruledNumErr<<" NoOK = "<<m_CruledNumOK<< endl;
CurrAProc()->Kill();
StopSim();//this is the most long process.
}
}
SPV Basic environment content::
The basic SPV library enable build your simple verification environment and it includes the following general classes.
-
-
Create values-dependent constraints.
-
Creation of structures, dependent on constraints and connections between different fields (package).
-
-
-
Coverage declaration:
-
Cross and single coverage.
-
Coverage items declaration.
-
Coverage deriving verification, enable achieve 100% coverage and 100% efficiency.
-
-
-
Bits Manipulation:
-
class SpvBitVec :
-
behave like integer {unlimited size).
-
All mathematical operation.
-
A data structure similar to the 'PLI' interface {Used for quick information transfer between the environment and the simulator }
-
Used for generating random numbers and values, creating packages for communication protocols, and any manipulation of bits.
-
-
-
-
enable call any 'm' file with 'ENG' open mode (MATLAB with GUI).
-
Enable call any MATLAB function by using MCC compiler.
-
SPV supply classes to deal with any MATLAB data structure like:
-
Struct.
-
Elements (List)
-
DoubleArray (Complex and not complex).
-
Cell.
-
strings.
-
MatFile.
-
Struct walker.
-
other
-
-
SPV loads one DLL per project, all the objects created are in the same running process.
-
Using DPF to deal with MATLAB make it.
-
Faster (Performance 10X VS files).
-
Easy of use.
-
enable connect any information from MATLAB to HDL, from HDL to MATLAB.
-
-
-
SPV Scheduler and simulator interface.
-
Read/Write access to any element in VHDL/Verilog.
-
Event driven:
-
SPV enable wait to any HDL event like:
-
Posedge, Negedge, Change, =<>!= value of any signal in design.
-
-
Wait time.
-
-
Read/Write slice, 'X', 'Z' , bin and mix.
-
Deal with any signal size.
-
TCM that behave like thread, with Wait events in loop or not.
-
Example:
-
-
More topics.
-
-
Create Tests.
-
Run tests.
-
Create regression.
-
Create generators,clock,checkers more...
-
Explore design.
-
More...
-
-
SPV's Key Advantages:
-
Performance - High speed (5X compared to other verification tools)
-
Standard C++ language –
-
Modular and reusable code.
-
Wide range of tools and libraries available.
-
Low cost and fast development for new features
-
A lot of professional engineers in C ++
-
Platform - LINUX, UNIX & WINDOWS
-
The Only complete solution for functional verification in Windows.
-
Excellent verification frame work for editing, compiling, linking and debugging.
-
Full Integration with HDL Simulators.
-
Especially Suitable for FPGA Development.
-
Plug & play – Low cost introduction and assimilation.
-
Support for Mixed VHDL / Verilog Verification.
-
More ...
-