Systemverilog DPI-C

Is possible to use this idea in a non-Uvm based test bench? I have the DSP C-code which I have integrated into a test bench successfully but now need to handle an interrupt.

In reply to Guy S:

UVM is just SystemVerilog code that someone else wrote for you. I don’t see how that relates to your question.

A C reference module usually makes trade-offs between pin-level accuracy and performance. Without knowing how the interrupt affects the C reference model, it is difficult to know how to help you further.

In reply to dave_59:
Hi Dave, I am a relative new comer to System Verilog hence the question. The system I have is a test board which uses a DSP and FPGA to test, configure and set coefficients in an ASIC. The ASIC has a continuous interrupt back to the FPGA that starts an SPI transmission, which when completed sends an interrupt to the DSP. I have modelled the DSP interface as per one of your previous examples, DPIExport, and using the DSP C code to pre-integrate the DSP and FPGA in a test bench. The test bench is used to call the required functions within the C source code, all works well so far, thank you for the example. I now have to implement the ISR for the interrupt and came across this example of yours; is it easier to modify this accordingly and keep it UVM or can I add the relevant calls and modules to the DPIExport example and modify this?

The following hopefully shows the main calls, the C functions are started by the test_en and the test_no which are passed in from the main test bench.


module adsp (system_clk, system_reset, test_id, test_en, test_done, dsp_addr, dsp_data, dsp_read, dsp_write, dsp_ack, interrupt);

    input system_clk;
    input system_reset;
    input test_en;
    input [7:0] test_id;
    output test_done;
    output [31:0] dsp_addr;
    inout [31:0] dsp_data;
    output dsp_read;
    output dsp_write;
    input dsp_ack;
    input interrupt;

    import "DPI-C" context task c_adsp (input int);
    import "DPI-C" context task interrupt_handler(int int_set);
    export "DPI-C" task adsp_v_read;
    export "DPI-C" task adsp_v_write;
    export "DPI-C" task sv_clk_posedge;
    export "DPI-C" task sv_delay;
    export "DPI-C" function sv_init_mem;
    export "DPI-C" function sv_debug;
    
    int test_no;

    reg dsp_read_reg;
    reg dsp_write_reg;
    reg halt;
    reg [31:0]   ad_reg;
    reg [31:0]   data_reg;
    reg [15:0]  mem[0:15];

    assign zap_id = zap_otp;
    assign dsp_addr = ad_reg;
    assign dsp_data = data_reg;
    assign dsp_read = dsp_read_reg;
    assign dsp_write = dsp_write_reg;
    assign test_no = test_id;
    assign test_done = halt;

    always @(posedge test_en)
    begin : cpu_run
        halt = 0;
        c_adsp(test_no);
        halt = 1;
        #25;
        halt = 0;
    end

    task sv_clk_posedge;
        @(posedge system_clk);
    endtask : sv_clk_posedge

    task adsp_v_read;
        input  address;
        output data;
        int    address;
        int    data;
    begin
        ad_reg <= address;
        #TDARL
        dsp_read_reg <= 0;
        @(posedge dsp_ack);
        #TRW;
        data = dsp_data;
        dsp_read_reg <= 1;
        #TRWR;
    end
    endtask : adsp_v_read

    task adsp_v_write;
        input address;
        input data;
        int   address;
        int   data;
    begin
        ad_reg <= address;
        data_reg <= data;
        #TDAWL;
        dsp_write_reg <= 0;
        @(posedge dsp_ack);
        #TWW;
        dsp_write_reg <= 1;
        #TDWHD;
        data_reg = 32'bz;
        #TRWR;
    end
    endtask : adsp_v_write

    function void sv_init_mem;
        input     index;
        output    data;
        int   index;
        int   data;
        data = mem[index];
    endfunction : sv_init_mem

    task sv_delay (input int t);
      $display("sv_delay: %d ", t);
      #t;
    endtask

    function void sv_debug(string msg, int addr, int data);
        $display("sv_wr_debug: %s %H %H", msg, addr, data);
    endfunction

    initial
    begin
        halt = 0;
        int_done = 0;
        ad_reg = 32'bz;
        data_reg = 32'bz;
        dsp_write_reg <= 1;
        dsp_read_reg <= 1;
        $readmemh("zap_bytes.dat", mem);
    end // initial begin

endmodule : adsp


In reply to Guy S:

Thanks for the additional information but I still do not understand how this relates to UVM. Are you trying to integrate this into an existing UVM testbench, or trying to develop a new one? It is fairly straightforward to get the adsp_v_read/write tasks to emit UVM sequences/transactions.

Regardless of whether you are using UVM or not, we need to understand how the interrupt service routine affects the DSP transactions in flight. Is the ISR a separate process? Are the transactions suspended during the ISR, or do they need to be restarted? Or can the interrupt only be serviced in between transactions?

There are different ways to handle each of these situations, and as I mentioned above, sometimes you have to make tradeoffs to model what is actually required in verification. I’m not sure if you are able to get into enough detail in this forum, so you may want to seek out local advice from your tool vendor.

In reply to dave_59:
I am creating a new test bench which doesn’t need to be UVM. The interrupt is just a very simple mechanism whereby it pauses the current execution services the interrupt and then resumes. As always trying to convey by text any technical ideas is always difficult.