Debug C/C++ embedded code in RTL simulation
SPV enable Pre-Silicon Software Validation, in RTL simulation process.
How it is work ?
Assume you have your own C code, as a big function that called main.
In the real life, main called at the beginning of the simulation/chip life, until main finish (forever usually).
The target of the SW, is to Manage the peripheral of the component. the SW influence the peripheral by Read/Write registers, DMA commands and more.
Debug embedded by SPV concept is to perform the same influence on the peripheral, by perform the same Read/Write register, DMA commands and other, without using the processor net-list.
Main steps:
Changes in SW:
encapsulate any Read/Write/DMA command with define like:
-
var = READ(add)
-
WRITE(add,value)
-
include "spv.h" (supplied by SPV) that direct READ/WRITE/DMA to external stub function that implement the READ/WRITE/DMA.
-
switch to real processor, done by not include "spv.h".
-
That's all you need, switch to the real processor at the moment
Changes in verification environment:
call to SW main from stub of the verification environment. this make SW as a thread of the verification environment. the SW run in time zero until READ/WRITE/DMA commands called, in this case the SW stuck until the command done, this will take 2-3 clock cycle, depend on real processor protocol (example bellow).
Changes in compilation command:
Compile SW as a .lib (.a) Win/Linux.
link .{lib,a} to your verification DLL.
Changes in RTL:
do not include the processor Net-List.
You ready to run/Debug the SW.
Performance:
Start debug your c code from the first day you have c code/Verilog.
-
don't need waiting to real processor.
-
don't need to simulate small design with big processor.
-
Don't need processor Compiler, Linker and other tools to start.
-
Don't need to write registers from verification code.
-
Verification is pure, embedded is pure. both independent.
-
Debug your C, as a visual studio C application.
-
easy for the Verification environment, easy for designer, easy for SW engineer.
Running time 5-10 X faster than with processor (Total Runtime ).
Code example:
SW code:
Stub code:
APB Read (SPV stub code) APB Write (SPV stub code)
if ( sps1_scr_cmd_type == LOAD_PRBS) {
SPV_WR_HW(reg_holder->modem_scr_seg_len,0);//Load with len=0
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
//roll with actual length
SPV_WR_HW(reg_holder->modem_scr_seg_type,JUST_ROLL_PRBS);
SPV_WR_HW(reg_holder->modem_scr_seg_len,tranSPVer_size);
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0)//wr_pulse
} else {
while (SPV_WR_HW(reg_holder->modem_scr_ready)!= 1) {
SPV_WR_HW(reg_holder->modem_scr_seg_type,sps1_scr_cmd_type); // [3:0]
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
}
}
if ( sps1_scr_cmd_type == LOAD_PRBS) {
SPV_WR_HW(reg_holder->modem_scr_seg_len,0);//Load with len=0
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
//roll with actual length
SPV_WR_HW(reg_holder->modem_scr_seg_type,JUST_ROLL_PRBS);
SPV_WR_HW(reg_holder->modem_scr_seg_len,tranSPVer_size);
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0)//wr_pulse
} else {
while (SPV_WR_HW(reg_holder->modem_scr_ready)!= 1) {
SPV_WR_HW(reg_holder->modem_scr_seg_type,sps1_scr_cmd_type); // [3:0]
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
}
}
if ( sps1_scr_cmd_type == LOAD_PRBS) {
SPV_WR_HW(reg_holder->modem_scr_seg_len,0);//Load with len=0
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
//roll with actual length
SPV_WR_HW(reg_holder->modem_scr_seg_type,JUST_ROLL_PRBS);
SPV_WR_HW(reg_holder->modem_scr_seg_len,tranSPVer_size);
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0)//wr_pulse
} else {
while (SPV_WR_HW(reg_holder->modem_scr_ready)!= 1) {
SPV_WR_HW(reg_holder->modem_scr_seg_type,sps1_scr_cmd_type); // [3:0]
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
}
}
if ( sps1_scr_cmd_type == LOAD_PRBS) {
SPV_WR_HW(reg_holder->modem_scr_seg_len,0);//Load with len=0
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
//roll with actual length
SPV_WR_HW(reg_holder->modem_scr_seg_type,JUST_ROLL_PRBS);
SPV_WR_HW(reg_holder->modem_scr_seg_len,tranSPVer_size);
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0)//wr_pulse
} else {
while (SPV_WR_HW(reg_holder->modem_scr_ready)!= 1) {
SPV_WR_HW(reg_holder->modem_scr_seg_type,sps1_scr_cmd_type); // [3:0]
SPV_WR_HW(reg_holder->modem_scr_seg_sps1,0);//wr_pulse
}
}
unsigned ApbInst::Read(unsigned addr)
{
LockSem();
m_Sig_apb_paddr = addr;
m_Sig_apb_pwrite = 0;
m_Sig_apb_psel = 1;
Wait(m_ClkPos);
m_Sig_apb_penable = 1;
while (m_Sig_apb_pready.Uint() != 1)
Wait(m_ClkPos);
}
m_Sig_apb_penable = 0;
m_Sig_apb_psel = 0;
UnlockSem();
return m_Sig_apb_prdata.Uint();
}
unsigned ApbInst::Write(unsigned addr,unsigned val)
{
LockSem();
m_Sig_apb_paddr = addr;
m_Sig_apb_pwrite = 1;
m_Sig_apb_psel = 1;
m_Sig_apb_pwdata = val;
Wait(m_ClkPos);
m_Sig_apb_penable = 1;
while (m_Sig_apb_pready.Uint() != 1)
Wait(m_ClkPos);
}
m_Sig_apb_penable = 0;
m_Sig_apb_psel = 0;
UnlockSem();
}