Use interface signals as inout in systemverilog

What is the proper way to use same signals of an interface as input or output? I am aware that the way i am doing it, could end up with Xs since there are no restrictions in the use of the signals from the interface.

So what is the way to do this using the modports?

Code, Use signals as input or input or output of the same interface


interface tx_bfm();
  logic clk;
  logic ch;
  logic [7:0] data;
  
  modport tx_mst(output clk, ch, data);
  modport tx_slv(input clk, ch, output data);
  
  always @(posedge clk)
    if(ch)
      data = data + 1;
    else
      data = 0;

endinterface

interface rx_bfm();
  logic clk;
  logic ch;
  logic [7:0] data;
  bit [7:0] data_q [$];
  
  modport rx_mst(output clk, ch, input data);
  modport rx_slv(input clk, ch, data);
  
  always @(posedge clk)
    data_q.push_back(data);
endinterface

module tb;
  
  bit clk;
  
  /** Clk signal **/
  always #1 clk = ~clk;
  
  /** Instance for Interfaces **/
  tx_bfm tx_bfm0();
  rx_bfm rx_bfm0();
  
  /** Using tx_bfm as master without modport**/
  /*
  assign tx_bfm0.clk = clk; 
  assign rx_bfm0.clk = tx_bfm0.clk; 
  assign rx_bfm0.ch = tx_bfm0.ch;
  */
  
  /** Using rx_bfm as master without modport**/
  assign rx_bfm0.clk = clk; 
  assign tx_bfm0.clk = rx_bfm0.clk; 
  assign tx_bfm0.ch = rx_bfm0.ch;
  
  /** Trying to use modports for tx_bfm **/
  //tx_bfm.tx_mst tx_bfm_mst0();//
  
  initial begin
    $display("::-- Testing --::");
    
    /** Trying to use modports for tx_bfm **/
    //tx_bfm_mst0.clk = clk;
    //tx_bfm_mst0.ch = 1;
    
    #10 $finish;
  end
endmodule

In reply to leonelh:

Modports are a design construct and shouldn’t be used for verification.

You prevent X’s by connecting your signals in an appropriate manner.

In reply to cgales:
Alright. How can re-use a same BFM if signals from the BFM (interface) should be able to behave as input and output?

In reply to leonelh:

You can use a mode selection option to drive signals as required:


typedef enum {BFM_MASTER, BFM_SLAVE} mode_e;

// Interface that can be used for master or slave
interface my_bfm();
  logic clk;
  logic ch;
  logic [7:0] data;
  
  // Internal variables for Master mode  
  reg clk_r;
  reg ch_r;
  reg [7:0] data_r;
  
  mode_e mode = BFM_MASTER;
  
  // If BFM_MASTER, drive signals from internal variables
  // If BFM_SLAVE, tristate signals to enable external drivers
  assign clk  = (mode == BFM_MASTER) ? clk_r  : 'z;
  assign ch   = (mode == BFM_MASTER) ? ch_r   : 'z;
  assign data = (mode == BFM_MASTER) ? data_r : 'z;
  
  // Enable changing of mode - use during connect_phase() to configure
  // interface as master or slave
  function void set_mode(input mode_e mode_);
    mode = mode_;
  endfunction

  always @(posedge clk)
    if(ch)
      data_r = data_r + 1;
    else
      data_r = 0;
 
endinterface