top of page

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();

  }

Wave in APB interface (Done by  the embedded SW without  processor)

bottom of page