Site Title

MATLAB Runtime integration
It is really good idea to import all MATLAB capabilities to the verification environment.
MATLAB supplies a very strong capabilities in mathematical area and more.
MATLAB could supply a great help in areas like:
Image processing and algorithm in wireless communication, Filters, bits correction (like: LDPC, BCH.), Scrambling , vector and matrix manipulation are only part of the great capabilities that MATLAB supplies.
More than that, the most of the algorithm engineers are familiar with MATLAB, and many times they develop the design by MATLAB to perform feasibility studies.
Import MATLAB projects to the verification environment could save us 90% percent of the verification environment writing process.
it is because the MATLAB project could contain:
-
Generation.
-
Data to drive
-
Test point.
-
information on how to configure design.
-
Golden model is also inside.
So, we need just build the peripheral, which call MATLAB with test parameters, while MATLAB will generate data, performs simulation and supplies information on how to configure design, a vector of complex or any other information to drive the design, and expected result on each test point.
in the most of the time each test point have the same behavioral, they include clock data and valid. So code that for-each clock, compare between MATLAB results against design result, could be created automatically for each test point.
That's what SPV of SimPlus provides.
DPF - Digital process framework
DPF - is a C++ software framework, built from two parts.
-
C++ library upon SPV, for testing simulated HDL designs against a bit accurate (or clock accurate) software model. These kinds of models are often used in DSP applications, (hence the name), usually using MATLAB. DPF provides a structure for creating test benches with a high degree of automation, and the necessary interface infrastructure to communicate with MATLAB based reference models during Runtime.
-
C++ library that enable dealing in a freestanding with mat lab Data Structure, mat lab function (m files) and *.mat files.
DPF - MATLAB interface classes
These classes wrap Mat-lab entities such as structures, cells, numeric arrays and matrix's, that old numbers, complex, strings (double, float, integer unsigned [8,16,32,64]and provide a simple, intuitive way to read and write the data contained therein. Passing this data structure to HDL or from HDL to MATLAB is very simple with DPF.
MATLAB wrapper classes - DPF, allow the user create MATLAB entities at Runtime, and use them for MATLAB input or output.
User could create structure, complex or any object and pass it to MATLAB as an input.
User could create empty object to be as output to MATLAB function. MATLAB will build the output object, by the output data which could be structure, vector, MATRIX or any supported MATLAB type.
DPF works in two modes:
Compiled MATLAB code (with mcc)
Launch MATLAB instance (eng_Open).
eng_Open:
in this interface we call in the beginning to MATLAB from the environment, the environment get a pointer to the eng_Open, and by a special code in DPF, the environment could pass command to MATLAB. Command could be calling m files, while the input output created in the environment. in Runtime there is option to open the MATLAB GUI, and search open or debug the MATLAB.
With MCC (MATLAB C Compiler):
working with MCC compiler of MATLAB, is more attractive for big projects, especially for big simulation, it enable call MATLAB thousands time in simulation with very good efficiency, minimum memory, and good performance.
Steps (and examples):
-
-
You could pass information from your own C/C++/HDL to MATLAB structure, and call again, now you have a feedback between HDL and MATLAB model.
-
call function, now you have the output parameter that hold the results of the simulation. results could be complex vector, numbers or any, In the most of the time it's big structure with all the simulation results. you could access to any place in the structure, and use the information as a free 'C/C++' structure.
-
use DPF classes to declare your parameter objects (MATLAB think they are mxArray), for input you should set data to DPF objects, for output just set your C++ object.
-
in header file choose the function that you want to call, each parameter there is mxArray of MATLAB.
You want to call function in your project.
-
-
In your project make include to the H file, and link to the .DLL(.SO for LINUX).
-
Compile your project (could be even > 100 m files) to 1 .DLL(.so)file and one H file
Example:
We have a modem project that do the following:
-
generate packet (bits)
-
translate bits to symbols (depend on table and bps (Bit per symbol)
-
make scrambling
-
Passes through channel (with special SNR)
-
DE-scrambling
-
LDCP (error correction)
-
BCH(error correction)
-
More ....
the project that do all these and more functionality exists in MATLAB project, with Dozens of files that exists in directory and sub directory like:
Using MCC compiler to compile all the project and get:
-
1 H file that include the header of each function in the MATLAB project.
-
1 DLL that contain the binary of all the MATLAB project.
-
The DLL (SO file) depended on MATLAB run-time library.
-
HDL:
Do the same as MATLAB project, or part of it.
Verification environment:
We want to use MATLAB MCC results to do the following:
-
Generated valid packet or frame, depend on configuration from verification environment.
-
Used to drive design.
-
-
Make simulation across all station (Test Point) in design.
-
Supply all Test points results (Symbol, scrambling, channel....).
-
Used in Monitor and checker.
-
-
we want to call MATLAB thousands of times. so we want that in the beginning we call MATLAB to prepare all the data structure that used many times in simulation like:
-
encapsulation table
-
scrambling configuration
-
All valid packet structures.
-
more..
-
The target of this request is to save time, memory and simulation time.
-
DPF of SPV look direct to MATLAB engine, so any object allocated in the beginning of simulation, still in alive along all the simulation.
-
This requirements explain the left side in slide bellow (One time), we prepare what ever we can in time 0, and use this information at any call. so for any call MATLAB do only small simulation, because he have all the infra structure.
More than that the information could be used to configure the software and the HDL in the beginning. config the scrambler initialization, the encapsulation table and other.
A little code:
Call once:
This function supplied by H file, with 3 outputs, while the other parameters are input configuration.
We declare 4 instance of class MlStructArray:
mlFrameTestCaseListOut, mlScramblingParamSetsListOut,
mlLutsStructOut, mlVlSnr
The output parameter pass as they born to the MAT function, MATLAB will build the output structure with all the information, the input should be initial by environment.
The first input mlFrameTestCaseListOut - it is a big structure that hold the data structure to all the valid packet. we need it at any call when we will ask (for example) simulation with packet no 9, the simulation could create immediattely a packet no '9' with new random data and make on it simulation.
Call multiple times:
That's it.
After call RunModem we got a complex vector (theComplex) with normalize from -1: 1 to 11 bit, which is the HDL interface size for each symbol. this is the expected results after 1 test point that translate bits to symbol. in object mlInterResultsStrctOut which is structure, we could found the frame bits list, these bit will use for the driver side.
We have another Test point, which is the symbole after scrambling, this information is also in struct mlInterResultsStrctOut .
So we have:
-
data to drive
-
Data to check at 2 Test point.
In the most of the time there are many test point, so we build automatic code that get information about 3 elements.
-
Matlab field name is struct.
-
Signal data out.
-
Signal data valid.
the monnitor code became to be very simple.
Another aspect in many verification environment is how we configure design by MATLAB information. This is also simple with DPF of SPV.
Small example in this code.
This register configuration could be done by SW that run against the processor or with SPV solution Pre-Silicon Software validation

mlfGen_DVBS2X_frame_defs(
3,
mlFrameTestCaseListOut,
mlScramblingParamSetsListOut,
mlLutsStructOut,
mlVlSnr
);
CppComplex& RunModem(unsigned frameInd)
{
mlTestCaseInd[0] = frameInd;
//Call matlab to make simulation, and return all Test Point
mlfRun_PL_framing_sim_on_DVBS2X(
3,mlFrameVecOut, mlInterResultsStrctOut,
mlFrameTestCaseListOut, mlTestCaseInd
);
isSuccess = true;
ComplexMl2Vec(theComplex,mlFrameVecOut,true,11);
return theComplex;
}
void Monitor::ChecktestPoint()
For each TP in TestPoint begin
if TP.Valid() begin
Check that TP.HdlData= TP.MatData;
end
end
void Config::SymConf(unsigned BaseAddr,unsigned Ind){
MlStructArray& config= m_MatInf->m_MlCfg;
ComplexList alpha =
MatHelp::GetElemMlDoubleList(Ind,"KL.A",config);
ComplexList beta =
MatHelp::GetElemMlDoubleList(Ind,"KL.B",config);
int size = alpha.Size();
for(int ind = 0; ind < size ; ind=ind+1){
m_ApbInst->Write((RegAB.Addr + BaseAddr + ind*4)
,beta.IList[ind]*2 + alpha.IList[ind]);
}
}
Big example of MATLAB testbench, relate to code at page Simulator - Faster (5x).
This MATLAB test bench project is similar to the SPV verification environment (C++). The only change is that in this project we don't have generators, and not golden model. MATLAB is the generator and golden model. in the most of the MATLAB project we deal with complex pkt, video processing or other, when we call MATLAB for 1 PKT that across many test points like shaper interpolator or other. so we call MATLAB once per 1 big transaction, MATLAB prepare for us vectors to any expected test points and the generation data. in this example the golden model is very simple, it is operator. so we call MATLAB to prepare 3 vectors for 10000-100000 or 1000000 iterations of shift right for example. 1 vector will include aval second vector will include bval and third is the results. and the same for other operators.
/* File drive.h
This file include the interface to HDL. Signals Events, clocks and some vectors that filled by MATLAB {generation, expected data}. it's includes also all the TCM (TASK - Time consuming method) that work always. They will call MATLAB any time vectors prepared derive all info, and expected data checked already.
there are 2 types of TCM. 1 is as thread that enable write Wait([event],[time), and other TCM which is much faster and called at any event N times.
#pragma once
#include "SpvHfile.h"
#include "MatCalcInf.h"
class Driver : public SpvBase
{
public:
Driver(MatCalcInf* MatInf);
MatCalcInf* m_MatCalcInf;
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_ClkDivPos , m_ClkDivNeg;//45
SpvEvent m_ClkShiftLPos , m_ClkShiftLNeg;//50
SpvEvent m_ClkShiftRPos , m_ClkShiftRNeg;//55
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 DriveCheckAlwaysDivTP();
void DriveCheckAlwaysAndTP();
void DriveCheckAlwaysModeTP();
void DriveCheckAlwaysXorTP();
void DriveCheckAlwaysShiftLTP();
void DriveCheckAlwaysShiftRTP();
void DriveCheckAlwaysOrFast();
void DriveCheckAlwaysAddFast();
void DriveCheckAlwaysSubFast();
void DriveCheckAlwaysMultFast();
void DriveCheckAlwaysDivFast();
void DriveCheckAlwaysAndFast();
void DriveCheckAlwaysModeFast();
void DriveCheckAlwaysXorFast();
void DriveCheckAlwaysShiftLFast();
void DriveCheckAlwaysShiftRFast();
unsigned m_VecSize;
vector<unsigned> m_AddAVec , m_AddBVec , m_AddResVec;
vector<unsigned> m_OrAVec , m_OrBVec , m_OrResVec;
vector<unsigned> m_SubAVec , m_SubBVec , m_SubResVec;
vector<unsigned> m_MultAVec , m_MultBVec, m_MultResVec;
vector<unsigned> m_AndAVec , m_AndBVec , m_AndResVec;
vector<unsigned> m_ModeAVec , m_ModeBVec, m_ModeResVec;
vector<unsigned> m_XorAVec , m_XorBVec , m_XorResVec;
vector<unsigned> m_DivAVec , m_DivBVec , m_DivResVec;
vector<unsigned> m_ShiftRAVec, m_ShiftRBVec, m_ShiftRResVec;
vector<unsigned> m_ShiftLAVec, m_ShiftLBVec, m_ShiftLResVec;
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_DivNumErr , m_DivNumOK;
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;
};
//File drive.cpp
#include "AllSig.h"
#include "Driver.h"
unsigned loopSize;
//Start and initial object
Driver::Driver(MatCalcInf* matCalcInf)
{
m_MatCalcInf = matCalcInf;
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_ClkDivNeg.Init(SH::m_Sigclk_div, AtNeg);//45
m_ClkShiftLNeg.Init(SH::m_Sigclk_shiftL, AtNeg);//50
m_ClkShiftRNeg.Init(SH::m_Sigclk_shiftR, 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_ClkDivPos.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_XorNumErr = 0;
m_OrNumErr = 0;
m_AndNumErr = 0;
m_MultNumErr = 0;
m_AddNumErr = 0;
m_SubNumErr = 0;
m_ShiftLNumErr = 0;
m_ShiftRNumErr = 0;
m_DivNumErr = 0;
m_XorNumOK = 0;
m_OrNumOK = 0;
m_AndNumOK = 0;
m_MultNumOK = 0;
m_AddNumOK = 0;
m_DivNumOK = 0;
m_SubNumOK = 0;
m_ShiftLNumOK = 0;
m_ShiftRNumOK = 0;
loopSize = SD::GetUint("LOOP_SIZE");
m_VecSize = 100000;
cout << "LoopSize ==" << loopSize << endl;
SH::m_Siguse_SpvTb = 1;
//m_AddAVec.resize(m_VecSize);
//m_AddBVec.resize(m_VecSize);
//m_AddResVec.resize(m_VecSize);
}
//lunch all TCM (Fast TCM or Thread)
void Driver::StartProcess()
{
if (SD::GetBool("DO_FAST_PROC")) {
StartAProc(m_ClkDivNeg, this, (SpvProcMethod)&Driver::DriveCheckAlwaysDivFast);
StartAProc(m_ClkOrNeg, this, (SpvProcMethod)&Driver::DriveCheckAlwaysOrFast);
StartAProc(m_ClkSubNeg, this, (SpvProcMethod)&Driver::DriveCheckAlwaysSubFast);
StartAProc(m_ClkMultNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysMultFast);
StartAProc(m_ClkModeNeg,this, (SpvProcMethod)&Driver::DriveCheckAlwaysModeFast);
StartAProc(m_ClkXorNeg, this, (SpvProcMethod)&Driver::DriveCheckAlwaysXorFast);
} else {
//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);
}
}
///////////// OR /////////
void Driver::DriveCheckAlwaysOrFast()
{
static unsigned cnt = 0, ind = 0;
//call MATLAB when start simulation
if (cnt == 0) m_MatCalcInf->PrepareOrVector(m_OrAVec, m_OrBVec, m_OrResVec, m_VecSize);
if (cnt++) {
if (m_OrResVec[ind] != SH::m_Sigor_res) {
cout<<cnt<<": Error ***: m_OrA=0x"<<hex<<m_OrAVec[ind]<<" m_OrB = 0x.."<<endl; m_OrNumErr++;
} else {
m_OrNumOK++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareOrVector(m_OrAVec, m_OrBVec, m_OrResVec, m_VecSize);
ind = 0;
}
}
//Set data and calculate expected for next negedge.
SH::m_Sigor_a = m_OrAVec[ind]; SH::m_Sigor_b = m_OrBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysOr NoErr=" <<m_OrNumErr<<" m_OrNumOK="<<m_OrNumOK<<endl;
}
}
/////////////////////////////////// ADD ///////////////////////
void Driver::DriveCheckAlwaysAddFast()
{
static unsigned cnt = 0, ind = 0;
if (cnt == 0) //call MATLAB when start simulation
if (!m_MatCalcInf->PrepareAddVector(m_AddAVec, m_AddBVec, m_AddResVec, m_VecSize)) {
cout << " PrepareAddVector fail DriveCheckAlwaysAddFast stop now." << endl;
CurrAProc()->Kill(); return;
}
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++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareAddVector(m_AddAVec, m_AddBVec, m_AddResVec, m_VecSize);
ind = 0;
}
}
//Set data Add calculate expected for next negedge.
SH::m_Sigadd_a = m_AddAVec[ind]; SH::m_Sigadd_b = m_AddBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysAdd NoErr="<<m_AddNumErr<<" m_AddNumOK="<<m_AddNumOK<<endl;
}
}
void Driver::DriveCheckAlwaysDivFast()
{
static unsigned cnt = 0, ind = 0;
//call MATLAB when start simulation
if (cnt==0) m_MatCalcInf->PrepareDivVector(m_DivAVec,m_DivBVec,m_DivResVec,m_VecSize);
if (cnt++) {
if (m_DivResVec[ind] != SH::m_Sigdiv_res) {
cout<<cnt<<": Error ***: m_DivA=0x"<<hex<<m_DivAVec[ind]<<" m_DivB=0x.."<<endl; m_DivNumErr++;
} else {
m_DivNumOK++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareDivVector(m_DivAVec, m_DivBVec, m_DivResVec, m_VecSize);
ind = 0;
}
}
//Set data Div calculate expected for next negedge.
SH::m_Sigdiv_a = m_DivAVec[ind]; SH::m_Sigdiv_b = m_DivBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysAdd NoErr=" << m_AddNumErr << " NoOK=" <<m_AddNumOK<<endl;
}
}
//////////////////////////// SUB /////////////////
void Driver::DriveCheckAlwaysSubFast()
{
static unsigned cnt = 0, ind = 0;
//call MATLAB when start simulation
if (cnt == 0) m_MatCalcInf->PrepareSubVector(m_SubAVec, m_SubBVec, m_SubResVec, m_VecSize);
if (cnt++) {
if (m_SubResVec[ind] != SH::m_Sigsub_res) {
cout<<cnt<<": Error ***: m_SubA=0x"<<hex<<m_SubAVec[ind]<<" m_SubB=0x.."<<endl; m_SubNumErr++;
} else {
m_SubNumOK++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareSubVector(m_SubAVec, m_SubBVec, m_SubResVec, m_VecSize);
ind = 0;
}
}
//Set data Sub calculate expected for next negedge.
SH::m_Sigsub_a = m_SubAVec[ind]; SH::m_Sigsub_b = m_SubBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysSubFast NoErr="<<m_SubNumErr<<" NoOK=" <<m_SubNumOK<< endl;
}
}
///////////////////// MULT /////////////
void Driver::DriveCheckAlwaysMultFast()
{
static unsigned cnt = 0, ind = 0;
if (cnt == 0)//call MATLAB when start simulation
if (!m_MatCalcInf->PrepareMultVector(m_MultAVec,m_MultBVec,m_MultResVec,m_VecSize)) {
cout << " PrepareMultVector fail DriveCheckAlwaysMultTP stop now." << endl;
CurrAProc()->Kill(); return;
}
if (cnt++) {
if (m_MultResVec[ind] != SH::m_Sigmult_res) {
cout<<cnt<<": Error ***: m_MultA=0x"<<hex<<m_MultAVec[ind]<<" m_MultB=0x."<<endl;
m_MultNumErr++;
} else {
m_MultNumOK++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareMultVector(m_MultAVec, m_MultBVec, m_MultResVec, m_VecSize);
ind = 0;
}
}
//Set data Mult calculate expected for next negedge.
SH::m_Sigmult_a = m_MultAVec[ind]; SH::m_Sigmult_b = m_MultBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysMultFast NoErr="<<m_MultNumErr<<" NoOK="<<m_MultNumOK<<endl;
}
}
////////////////////// AND /////////////////
void Driver::DriveCheckAlwaysAndFast()
{
static unsigned cnt = 0, ind = 0;
if (cnt == 0)//call MATLAB when start simulation
if (!m_MatCalcInf->PrepareAndVector(m_AndAVec, m_AndBVec, m_AndResVec, m_VecSize)) {
cout << " PrepareAndVector fail DriveCheckAlwaysAndTP stop now." << endl;
CurrAProc()->Kill(); return;
}
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++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareAndVector(m_AndAVec, m_AndBVec, m_AndResVec, m_VecSize);
ind = 0;
}
}
//Set data and calculate expected for next negedge.
SH::m_Sigand_a = m_AndAVec[ind]; SH::m_Sigand_b = m_AndBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout<<"DriveCheckAlwaysAndFast NoErr="<< m_AndNumErr << " NoOK="<<m_AndNumOK<<endl;
}
}
////////////////////// MODE ////////////////
void Driver::DriveCheckAlwaysModeFast()
{
static unsigned cnt = 0, ind = 0;
if (cnt == 0)//call MATLAB when start simulation
if (!m_MatCalcInf->PrepareModeVector(m_ModeAVec, m_ModeBVec, m_ModeResVec, m_VecSize)) {
cout << " PrepareModeVector fail DriveCheckAlwaysModeTP stop now." << endl;
CurrAProc()->Kill(); return;
}
if (cnt++) {
if (m_ModeResVec[ind] != SH::m_Sigmode_res) {
cout<<cnt<<": Error ***:m_ModeA=0x"<<hex<<m_ModeAVec[ind]<<" m_ModeB=0x."<< endl;
m_ModeNumErr++;
} else {
m_ModeNumOK++;
}
if (++ind == m_VecSize) {//call matlan any m_VecSize iteration
m_MatCalcInf->PrepareModeVector(m_ModeAVec, m_ModeBVec, m_ModeResVec, m_VecSize);
ind = 0;
}
}
//Set data and calculate expected for next negedge.
SH::m_Sigmode_a = m_ModeAVec[ind]; SH::m_Sigmode_b = m_ModeBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout << "DriveCheckAlwaysModeFast m_ModeNumErr=" << m_ModeNumErr << " m_ModeNumOK = " << m_ModeNumOK << endl;
}
}
////////////////////////////////////// XOR ////////////////////////////
void Driver::DriveCheckAlwaysXorFast()
{
static unsigned cnt = 0, ind = 0;
if (cnt == 0)
if (!m_MatCalcInf->PrepareXorVector(m_XorAVec, m_XorBVec, m_XorResVec, m_VecSize)) {
cout << " PrepareXorVector fail DriveCheckAlwaysXorTP stop now." << endl;
CurrAProc()->Kill(); return;
}
if (cnt++) {
if (m_XorResVec[ind] != SH::m_Sigxor_res) {
cout << cnt << ": Error ***: m_XorA = 0x" << hex << m_XorAVec[ind] << " m_XorB = 0x" << m_XorBVec[ind] << " SPV result = 0x" << m_XorResVec[ind] << " HDL m_Sigxor_res = " << SH::m_Sigxor_res(SpvHex) << dec << " T:" << SimTime() << endl;
m_XorNumErr++;
} else {
m_XorNumOK++;
}
if (++ind == m_VecSize) {
m_MatCalcInf->PrepareXorVector(m_XorAVec, m_XorBVec, m_XorResVec, m_VecSize);
ind = 0;
}
}
//Set data and calculate expected for next negedge.
SH::m_Sigxor_a = m_XorAVec[ind]; SH::m_Sigxor_b = m_XorBVec[ind];
if (cnt > loopSize) {
CurrAProc()->Kill();
cout << "DriveCheckAlwaysXorFast m_XorNumErr=" << m_XorNumErr << " m_XorNumOK = " << m_XorNumOK << endl;
StopSim();//this is the most long process.
}
}
/////////////////////////////////////////////////// SHIFTL //////////////////////////////
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<<"DriveAlwaysShiftLFast NoErr="<<m_ShiftLNumErr<<" NoOK="<<m_ShiftLNumOK<< endl;
}
}
/////////////////////////////////////////////////// SHIFTR ////////////////////////////
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.."<<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<<"DriveAlwaysShiftRFast NoErr="<<m_ShiftRNumErr<<" NoOK="<<m_ShiftRNumOK<<endl;
}
}
//This is the m file that i used for this project
function [CalcInfoOut] = PrepareList(CalcInfoIn)
CalcInfoOut.First(1) = 0;
CalcInfoOut.Second(1) = 0;
CalcInfoOut.Result(1) = 0;
if CalcInfoIn.Cmd == CalcEnum.Add
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = CalcInfoOut.First(c) + CalcInfoOut.Second(c);
end
elseif CalcInfoIn.Cmd == CalcEnum.Sub
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = CalcInfoOut.First(c) - CalcInfoOut.Second(c);
end
elseif CalcInfoIn.Cmd == CalcEnum.Dev
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = CalcInfoOut.First(c) / CalcInfoOut.Second(c);
end
elseif CalcInfoIn.Cmd == CalcEnum.Mode
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = mod(CalcInfoOut.First(c),CalcInfoOut.Second(c));
end
elseif CalcInfoIn.Cmd == CalcEnum.And
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = bitand(CalcInfoOut.First(c),CalcInfoOut.Second(c));
end
elseif CalcInfoIn.Cmd == CalcEnum.Xor
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = bitxor(CalcInfoOut.First(c),CalcInfoOut.Second(c));
end
elseif CalcInfoIn.Cmd == CalcEnum.Or
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,4000000000],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = bitor(CalcInfoOut.First(c),CalcInfoOut.Second(c));
end
elseif CalcInfoIn.Cmd == CalcEnum.ShiftL
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,31],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = bitshift(CalcInfoOut.First(c),CalcInfoOut.Second(c));
end
elseif CalcInfoIn.Cmd == CalcEnum.ShiftR
CalcInfoOut.First = randi([0,4000000000],1,CalcInfoIn.NumCmd);
CalcInfoOut.Second= randi([0,31],1,CalcInfoIn.NumCmd);
for c = 1: CalcInfoIn.NumCmd
CalcInfoOut.Result(c) = bitsra(CalcInfoOut.First(c),CalcInfoOut.Second(c));
end
end
//After compile m files by MATLAB C Compiler I got this H file and DLL.
//In this project I use only 1 function interface from MATLAB (in most of the time I use 1-2 function only), the other are internal function that I could use but not required.
/*
* MATLAB Compiler: 8.0 (R2020a)
* Date: Mon Jun 9 20:51:29 2025
* Arguments:
* "-B""macro_default""-K""-v""-W""lib:libSpvMatCalc""-T""link:lib""-I""./MFiles
* ""create_default_structs.m""PrepareListAdd.m""PrepareListSub.m""PrepareListDi
* v.m""PrepareListMode.m""PrepareListMult.m""PrepareListXor.m""PrepareListOr.m"
* "PrepareListAnd.m"
*/
#ifndef libSpvMatCalc_h
#define libSpvMatCalc_h 1
#if defined(__cplusplus) && !defined(mclmcrrt_h) && defined(__linux__)
# pragma implementation "mclmcrrt.h"
#endif
#include "mclmcrrt.h"
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif
/* This symbol is defined in shared libraries. Define it here
* (to nothing) in case this isn't a shared library.
*/
#ifndef LIB_libSpvMatCalc_C_API
#define LIB_libSpvMatCalc_C_API /* No special import/export declaration */
#endif
/* GENERAL LIBRARY FUNCTIONS -- START */
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV libSpvMatCalcInitializeWithHandlers(
mclOutputHandlerFcn error_handler,
mclOutputHandlerFcn print_handler);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV libSpvMatCalcInitialize(void);
extern LIB_libSpvMatCalc_C_API
void MW_CALL_CONV libSpvMatCalcTerminate(void);
extern LIB_libSpvMatCalc_C_API
void MW_CALL_CONV libSpvMatCalcPrintStackTrace(void);
/* GENERAL LIBRARY FUNCTIONS -- END */
/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxCreate_default_structs(int nlhs, mxArray *plhs[], int nrhs, mxArray
*prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListAdd(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListSub(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListDiv(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListMode(int nlhs, mxArray *plhs[], int nrhs, mxArray
*prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListMult(int nlhs, mxArray *plhs[], int nrhs, mxArray
*prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListXor(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListOr(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
extern LIB_libSpvMatCalc_C_API
bool MW_CALL_CONV mlxPrepareListAnd(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */
/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfCreate_default_structs(int nargout, mxArray** CalcInfoIn);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListAdd(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListSub(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListDiv(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListMode(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListMult(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListXor(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListOr(int nargout, mxArray** CalcInfoOut, mxArray* num);
extern LIB_libSpvMatCalc_C_API bool MW_CALL_CONV mlfPrepareListAnd(int nargout, mxArray** CalcInfoOut, mxArray* num);
#ifdef __cplusplus
}
#endif
/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */
#endif
//This file is the interface to MATLAB MatCalcInf.h
#pragma once
/*
* MatCalcInf.h
*
* Created on: MAY 12, 2025
* Author: shmuel
*/
#ifndef MAT_CALC_INF
#define MAT_CALC_INF
#include "SpvHfile.h"
#include "MlStructWalker.h"
#include "MlStructVisitor.h"
#include <DpfMl.h>
#include "SpvMlGuiCall.h"
class MatCalcInf //: public SpvBase
{
public:
MatCalcInf();
bool StartMat();
void PrepareMatObj();
void CallMat(vector<int> dataA, vector<int> dataB, vector<int> Result);
void Copy2Vec(vector<int> dataB, vector<int> Result);
bool PrepareAddVector(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results, unsigned numObj);
bool PrepareDivVector(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareOrVector( vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareSubVector(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareMultVector(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareModeVector(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareAndVector( vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareXorVector( vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
bool PrepareData( vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj);
////Output
//MlStructArray m_MlHighLevelStruct;
//Input
MlDoubleArray m_MlNumObj;
MlStructArray m_MlResults;
string m_Names[3];
};
#endif /* MCCGETHIGHLEVELSTRUCT_H_ */
//This file is the implementation interface to MATLAB MatCalcInf.cpp
#include "MatCalcInf.h"
#include "libSpvMatCalc.h"
#include "math.h"
#include "AllSig.h"
ofstream MatError("MatError.txt");
static int myPrintHandler(const char* s)
{
cout << "MATLAB:" << s << endl;
return 5;
}
static int MyErrorHandler(const char* s)
{
MatError << s << endl;
MatError.flush();
cout << "MatErr :" << s << endl;
return 5;
}
bool StartTryApp()
{
bool isSuccess = mclmcrInitialize();
if (!mclInitializeApplication(NULL, 0)) {
std::cerr << "could not initialize the application properly" << std::endl;
return false;
}
isSuccess = libSpvMatCalcInitialize();
if (isSuccess == false) {
cout << "libTryStructInitialize fail stopSim " << endl;
StopSim();
}
else {
cout << "libTryStructInitialize success " << endl;
}
isSuccess = isSuccess && libSpvMatCalcInitializeWithHandlers((mclOutputHandlerFcn)MyErrorHandler, (mclOutputHandlerFcn)myPrintHandler);
if (isSuccess == false) {
cout << "libTryStructInitializeWithHandlers fail " << endl;
}
return isSuccess;
}
MatCalcInf::MatCalcInf()
{
m_Names[0] = "First";
m_Names[1] = "Second";
m_Names[2] = "Result";
}
bool MatCalcInf::StartMat()
{
if (StartTryApp()) {
PrepareMatObj();
return true;
}
return false;
}
void MatCalcInf::PrepareMatObj()
{
m_MlNumObj.Resize(1);
}
bool MatCalcInf::PrepareAddVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListAdd(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareDivVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListDiv(1, m_MlResults,m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareOrVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListOr(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareSubVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListSub(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareModeVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListMode(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareMultVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListMult(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
//Don't know why but MATLAB neglect the precision of last 8 bit
PrepareData(a, b, results, numObj);
for (unsigned i = 0; i < numObj; i++) {
results[i] = a[i] * b[i];
}
return true;
}
bool MatCalcInf::PrepareAndVector(vector<unsigned>& a, vector<unsigned>& b, vector<unsigned>& results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListAnd(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareXorVector(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results, unsigned numObj)
{
m_MlNumObj[0] = numObj;
m_MlResults.Destroy();
bool isOk = mlfPrepareListXor(1, m_MlResults, m_MlNumObj);
if (!isOk) return false;
return PrepareData(a, b, results, numObj);
}
bool MatCalcInf::PrepareData(vector<unsigned>&a,vector<unsigned>&b,vector<unsigned>&results,unsigned numObj)
{
double* dataPtr[3];
unsigned size = 0;
if (m_MlResults.GetNumFields() == 3) {
for (unsigned ind = 0; ind < 3; ind++) {
MlStructField& currField = m_MlResults.GetField(m_Names[ind].c_str());
size = currField.Size();
dataPtr[ind] = currField.GetDoublePtr();
}
}
a.resize(size); b.resize(size); results.resize(size);
for (unsigned i = 0; i < size; i++) {
a[i] = (unsigned)dataPtr[0][i];
b[i] = (unsigned)dataPtr[1][i];
results[i] = (unsigned)dataPtr[2][i];
}
return true;
}
void MatCalcInf::CallMat(vector<int> dataA, vector<int> dataB, vector<int> Result)
{
Copy2Vec(dataA, dataB);
}
void MatCalcInf::Copy2Vec(vector<int>dataB,vector<int> Result)
{
}