user9906612
user9906612

Reputation: 77

Passing by reference into System Verilog module or Interface

I would like to create a reusable interface or module where the hierarchy of a memory element outside it can be passed to it by reference. I know passing by reference cannot be done to a module or an interface as per LRM but is there a way to achieve it without using defines. Please see the testcase below where the line that is commented out shows good results will give the right value in memory but I will need to pass the hierachy into an interface that is specific to this example and cant make the interface more reusable. I would like to make the badd results call work but not sure how to do this:

----------------------------Verilog----------------------------------

module t1_tb();

   reg clk;
   reg write;
   reg [4:0] address;
   reg [31:0] data_in;
   wire [31:0] data_out;

   mem_model mem_model (clk, write, address, data_in, data_out);

   mem_intf mem_intf(clk, address, mem_model.memory);

   initial 
     begin
       clk = 0;
       write = 0;
       address = 0;
       for (int i = 0; i < 32; i++)
           mem_model.memory[i] = 32'haaaaaaaa;

       forever clk = #5 ~clk;

     end

   initial 
     begin
       #200;
       $display ("memory locations are %h and %h \n", mem_model.memory[0], mem_model.memory[1]);
       $finish;
     end

endmodule

module mem_model(input clk, input write, input [4:0] address, input [31:0] data_in, output [31:0] data_out);

reg [31:0] memory [0:31];

assign data_out = memory[address];

always @(posedge clk)
  if (write)
     memory[address] <= data_in;

endmodule

interface mem_intf (input clk, input [4:0] add, input  logic [31:0] mem [0:31]);

   import "DPI-C" context send_int  = function void send_int_c  ();
   export "DPI-C" clks_delay        = task clks_delay; 

task clks_delay(input int unsigned usecs);

     for (int i = 0; i < (int'(usecs/3.33) * 1000); ++i)
         @(posedge clk);

endtask

task automatic mem_acc( input [4:0] add, ref reg  [31:0] memory1 [0:31] );
     #10;
     memory1[add] = '1;
     #10;
     $display ("memory locations are %h and %h and add is %h\n", memory1[0], memory1[1], add);

endtask

task monitor_interrupts (input [6:0] interrupts);
   send_int_c();
endtask

    initial 
      begin
       #100;
       mem_acc(0, mem);  //bad results
       //mem_acc(0, t1_tb.mem_model.memory); // good results
      end

endinterface

-------------------C Functions-----------------

void send_int(void)
{
    printf("From C Sending Interrupt..\n");

}
extern void clks_delay(int seconds);

void clks_delay(int seconds)
{
        printk("From C clocks_delay: %uld\n", seconds);
}

Upvotes: 0

Views: 3289

Answers (1)

dave_59
dave_59

Reputation: 42673

But you can pass any variable by reference to a port.

interface mem_intf (input clk, input [4:0] add, ref logic [31:0] mem [0:31]);

See section 23.3.3 Port connection rules in the IEEE 1800-2017 LRM


Update

Another option is using the bind construct to instantiate the interface, and upwards reference the memory. The name of the memory would have to be the same for all instances.

interface mem_intf (input clk, input [4:0] add);
...

    initial 
      begin
       #100;
       mem_acc(0, memory);  //upward reference

      end

endinterface
module t1_tb();


   mem_model mem_model1 (clk, write, address, data_in, data_out);

   bind mem_model: mem_model1 mem_intf mem_intf(clk, address);

Upvotes: 1

Related Questions