Search code examples
system-verilogsystem-verilog-dpiverilator

import constant dpi-c function in systemverilog


I have an opentitan like processor which can be simulated with verilator.

For this, there is a top_verilator function like this:

module top_verilator(input logic clk_i, rst_ni);
...
system #(
    .SRAMInitFile("/home/user/location/to/vmem")
) u_system (
    .clk_i,
    .rst_ni
);
endmodule

what i want to do is read the vmem location out of a enviornment variable as multiple people work on the project.

what i tried to do is import getenv like this import "DPI-C" function string getenv(input string env_name); as shown here How do I read an environment variable in Verilog/System Verilog?. However, this does not function with recent systemverilog versions, as this gives the error Constant function may not be DPI import (IEEE 1800-2023 13.4.3) as described here https://github.com/verilator/verilator/issues/3103. Is there another way to do this?


Solution

  • Parameters need to be determined by the elaboration stage of the compile. DPI's are executed during simulation. So it makes sense a parameter cannot be assigned by a DPI.

    If SRAMInitFile needs to be a parameters, then a workaround would be to assign it with a macro during compile. Depending on the simulator, either -define VMEM_PATH=${VMEM_PATH} or +define+VMEM_PATH=${VMEM_PATH} or -DVMEM_PATH=${VMEM_PATH} should work as a option during compile (check your simulator manual).

    Then your code would look like:

    `ifndef VMEM_PATH
      // Default path if macro is not defined from compile command line
      `define VMEM_PATH /home/user/location/to/vmem
    `endif
    // Macro to convert input to string
    `define STR(S) `"S`"
    module top_verilator(input logic clk_i, rst_ni);
    ...
    system #(
        .SRAMInitFile(`STR(`VMEM_PATH))
    ) u_system (
        .clk_i,
        .rst_ni
    );
    endmodule
    

    Alternatively, if you can have your testbench backdoor load the values to the memory, then you could to use the getenv() DPI (assuming you don't need a synthesizable test-bench). If this is an option, then code like this may help:

    import "DPI-C" function string getenv(input string env_name);
    ...
    function void load_mem();
      string vmem_path = getenv("VMEM_PATH");
      $readmemh(vmem_path , tb.dut.top_verilator.system.mem );
    endfunction