Interface issue

Hi,
I’m trying to implement a RAM model as below…
10 address decodes 4 RAMs(8x8)and each RAM enabled/disabled.
I’m getting interface issue…
someone help me on this…

mem_if

interface mem_if ();
//  typedef enum {WRITE,READ} rw_t;
  logic reset;
  logic clock;
  logic enable;
  logic [7:0] addr;
  logic [7:0] data;
  //rw_t rwn;
  logic rwn;
endinterface

RAM

module RAM (mem_if MemBus);
  logic [7:0] mem[0:255];

  always @ (negedge MemBus.reset or posedge MemBus.clock or MemBus.enable) 
  begin
    if (MemBus.enable)begin
        if (~MemBus.reset) 
            MemBus.data = 8'bz;
        else begin
        if (MemBus.rwn)
            MemBus.data = mem[MemBus.addr];
        else
            mem[MemBus.addr] = MemBus.data;
        end
    end
  end
endmodule

mem_cntrl_if

interface mem_ctrl_if ();
 // typedef enum {WRITE,READ} rw_t;
  logic Reset;
  logic Clock;
  logic [9:0] Addr;
  logic [7:0] Data;
  // rw_t RWn;
  logic RWn;
  // modport mem_if (input Reset,Clock,Enable,RWn, input logic [7:0] Addr,inout logic [7:0] Data);
endinterface

mem_ctrl

module mem_ctrl (mem_ctrl_if ctrl_if);
	
	logic [3:0] Enable;
	
	//instantiate interfaces
	mem_if mem0if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[0]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));
	mem_if mem1if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[1]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));
	mem_if mem2if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[2]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));
	mem_if mem3if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[3]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));
	
	//Enable Memory based on [9:8] bits at Addr
	assign Enable[0] = (ctrl_if.Addr[9:8] == 2'b00) ? 1'b1 : 1'b0;
	assign Enable[1] = (ctrl_if.Addr[9:8] == 2'b01) ? 1'b1 : 1'b0;
	assign Enable[2] = (ctrl_if.Addr[9:8] == 2'b10) ? 1'b1 : 1'b0;
	assign Enable[3] = (ctrl_if.Addr[9:8] == 2'b11) ? 1'b1 : 1'b0;
	
	//instantiate RAMs
	RAM ram0 (.MemBus (mem0if));
	RAM ram1 (.MemBus (mem1if));
	RAM ram2 (.MemBus (mem2if));
	RAM ram3 (.MemBus (mem3if));
endmodule

Getting Error as below…
Caching library ‘worklib’ … Done
Elaborating the design hierarchy:
mem_if mem0if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[0]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));
|
ncelab: *E,CUVPOM (./mem_ctrl.sv,7|20): Port name ‘reset’ is invalid or has multiple connections.
mem_if mem0if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[0]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));
|
ncelab: *E,CUVPOM (./mem_ctrl.sv,7|44): Port name ‘clock’ is invalid or has multiple connections.
mem_if mem0if(.reset (ctrl_if.Reset), .clock (ctrl_if.Clock), .enable (Enable[0]), .addr (ctrl_if.Addr[7:0]),.data (ctrl_if.Data),.rwn (ctrl_if.RWn));

Here there are two problems. First, Signals defined in mem_if does not have the direction. You need to use assign statement to connect. Second, data signal is bidirectional.

Example:


mem_if mem0if();
    assign mem0if.reset = Reset;
    assign mem0if.clock = Clock;
    assign mem0if.enable = Enable[0];
    assign mem0if.addr = Addr[7:0];
    //assign mem0if.data = Data;  //  This has to be taken care with more combo logic.
    assign mem0if.rwn = RWn;

In reply to vybhava:

vybhava,

Thanks for your reply. I know that we can do it assigning individually, but the key is why we could not connect the port from the interface?

See here other example…

interface cpu_if ();
 typedef enum {WRITE,READ} rw_t;
 typedef enum logic[3:0] {AND,NAND,OR,NOR,XOR,XNOR,NOT,LSFT,RSFT,ADD,SUB,MUL,DIV,MOD,FADD} opcode;
   
  logic reset;
  logic clock;
  
  //RAM
  logic [7:0] ram_addr;
  logic [7:0] ram_data;
  rw_t rwn;
  //logic rwn;
  
  //ROM
  logic [3:0] rom_addr;
  logic [7:0] rom_data;
 
 //ALU
  logic [7:0] alu_a;
  logic [7:0] alu_b;
  opcode alu_op;
  logic [7:0] alu_out;
     
  modport ram_if(input reset,clock,ram_addr,rwn,inout ram_data);
  modport rom_if(input reset,clock,rom_addr,output rom_data);
  modport alu_if (input reset,clock,alu_a,alu_b,alu_op,output alu_out);

endinterface

At cpu_top,

module cpu_top;
...
	// The CPU interface
   cpu_if cpuif();
   
   cpuif.ram_if ramif();
   cpuif.rom_if romif();
   cpuif.alu_if aluif();
			
    // DUT instantiation
   CPU dut (cpuif);

initial
..

here I’m getting error as below…

ncvlog: *W,TSNSPK (/home/samy_j/myuvm/Mem_Ex/cpu_uvc_pkg.sv,9|18): `timescale is not specified for the package. The default timescale of 1ns/1ns will be assumed for this package.
file: /home/samy_j/myuvm/Mem_Ex/cpu_top.sv
cpuif.ram_if ramif();
|
ncvlog: *E,EXPSMC (/home/samy_j/myuvm/Mem_Ex/cpu_top.sv,26|21): expecting a semicolon (‘;’) [12.3.2(IEEE)].
cpuif.rom_if romif();
|
ncvlog: *E,EXPSMC (/home/samy_j/myuvm/Mem_Ex/cpu_top.sv,27|21): expecting a semicolon (‘;’) [12.3.2(IEEE)].
cpuif.alu_if aluif();
|
ncvlog: *E,EXPSMC (/home/samy_j/myuvm/Mem_Ex/cpu_top.sv,28|21): expecting a semicolon (‘;’) [12.3.2(IEEE)].
module worklib.cpu_top:sv
errors: 3, warnings: 0
irun: *E,VLGERR: An error occurred during parsing. Review the log file for errors with the code *E and fix those identified problems to proceed. Exiting with code (status 1).

I’m not sure, what is wrong here?? May be I’m missing a key…

John

In reply to John Verif:

John,

I have modified the ram controller code and made it working. I came to following conclusion on interface and modport usage.

  1. In interface declaration if direction(input, output and inout) is not defined only way to connect is using assign statement. If direction is declared we can connect during instantiation.

  2. If interface has modport we can not use modport instance to connect the signals wia port. We have to use assign statement to connect interface signals then modport of same interface should be passed to respective modules. Please refer to below code. Modport is passed to all the modules.

Please note → Still I need to figure out how to handle the inout data.

I used the VCS simlator.


mem_ctrl_if.sv


interface mem_ctrl_if ();
logic Reset;
logic Clock;
logic [9:0] Addr;
logic [7:0] Data;
logic RWn;
modport mem_ctrl_md (input Reset,Clock,Addr,RWn,inout Data);
endinterface


mem_if.sv


interface mem_if();
logic reset;
logic clock;
logic enable;
logic [7:0] addr;
logic [7:0] data;
logic rwn;
modport mem_md(input reset, clock, enable, addr, rwn, inout data);
endinterface


ram.sv


module RAM (mem_if.mem_md MemBus);
logic [7:0] mem[0:255];

always @ (negedge MemBus.reset or posedge MemBus.clock or MemBus.enable)
begin
if (MemBus.enable)begin
if (~MemBus.reset)
//MemBus.data = 8’bz;
$display(“Need to add the code\n”);
else begin
if (MemBus.rwn)
//MemBus.data = mem[MemBus.addr];
$display(“Need to add the code\n”);
else
mem[MemBus.addr] = MemBus.data;
end
end
end
endmodule


mem_ctrl.sv


module mem_ctrl(mem_ctrl_if.mem_ctrl_md ctrl_if);

    logic [3:0] Enable;

    //instantiate interfaces
    mem_if mem0if();
    assign mem0if.reset = ctrl_if.Reset;
    assign mem0if.clock = ctrl_if.Clock;
    assign mem0if.enable = Enable[0];
    assign mem0if.addr = ctrl_if.Addr[7:0];
    assign mem0if.data = ctrl_if.RWn ? 8'bz : ctrl_if.Data;
    assign mem0if.rwn  = ctrl_if.RWn;

    mem_if mem1if();
    assign mem1if.reset = ctrl_if.Reset;
    assign mem1if.clock = ctrl_if.Clock;
    assign mem1if.enable = Enable[1];
    assign mem1if.addr = ctrl_if.Addr[7:0];
    assign mem1if.data = ctrl_if.RWn ? 8'bz : ctrl_if.Data;
    assign mem1if.rwn  = ctrl_if.RWn;

    mem_if mem2if();
    assign mem2if.reset = ctrl_if.Reset;
    assign mem2if.clock = ctrl_if.Clock;
    assign mem2if.enable = Enable[2];
    assign mem2if.addr = ctrl_if.Addr[7:0];
    assign mem2if.data = ctrl_if.RWn ? 8'bz : ctrl_if.Data;
    assign mem2if.rwn  = ctrl_if.RWn;


    mem_if mem3if();
    assign mem3if.reset = ctrl_if.Reset;
    assign mem3if.clock = ctrl_if.Clock;
    assign mem3if.enable = Enable[3];
    assign mem3if.addr = ctrl_if.Addr[7:0];
    assign mem3if.data = ctrl_if.RWn ? 8'bz : ctrl_if.Data;
    assign mem3if.rwn  = ctrl_if.RWn;

    //Enable Memory based on [9:8] bits at Addr
    assign Enable[0] = (ctrl_if.Addr[9:8] == 2'b00) ? 1'b1 : 1'b0;
    assign Enable[1] = (ctrl_if.Addr[9:8] == 2'b01) ? 1'b1 : 1'b0;
    assign Enable[2] = (ctrl_if.Addr[9:8] == 2'b10) ? 1'b1 : 1'b0;
    assign Enable[3] = (ctrl_if.Addr[9:8] == 2'b11) ? 1'b1 : 1'b0;
    //instantiate RAMs
    RAM ram0 (.MemBus (mem0if.mem_md));
    RAM ram1 (.MemBus (mem1if.mem_md));
    RAM ram2 (.MemBus (mem2if.mem_md));
    RAM ram3 (.MemBus (mem3if.mem_md));

endmodule


tb.sv


module tb;
mem_ctrl_if CTRL_IF();
mem_ctrl U_mem_ctrl(CTRL_IF.mem_ctrl_md);
endmodule


In cpu code there is problem, Following usage is wrong.


cpu_if cpuif(); // This instance already has ram_if, rom_if and alu_if. You can use this as cpuif.rom_if, cpuif.alu_if and cpuif.rom_if

cpuif.ram_if ramif(); // Wrong
cpu_if.ram_if ramif(): // Correct usage
cpuif.rom_if romif(); // Wrong
cpuif.alu_if aluif(); // Wrong


Please past the complete code of CPU.

Lets continue the discussion if concepts are not clear.
Thanks
Vybhava S

In reply to vybhava:

If you want to share signals in one interface with another interface, make them ports of the interface. You need to use wires if you want to have bidirectional signals.

interface mem_ctrl_if (
    input logic Reset,  // shared signals
    input logic Clock
  );
  logic [9:0] Addr; // per interface instance signals
  wire [7:0] Data;
  logic RWn;
endinterface

interface mem_if(
    input logic reset,
    input logic clock
  );
  logic enable;
  logic [7:0] addr;
  wire [7:0] data;
  logic rwn;
endinterface

Then when you instantiate them

mem_if mem0if(ctrl_if.Reset,ctrl_if.Clock);

In reply to dave_59:

Dave,

I tried as below…

interface mem_ctrl_if (input logic Reset,input logic Clock);
  logic [9:0] Addr;
  wire [7:0] Data;
  //rw_t RWn;
  logic RWn;
 endinterface

mem_ctrl module

module mem_ctrl (mem_ctrl_if mcif);
   logic [3:0] Enable;
	//Enable Memory based on [9:8] bits at Addr
	assign Enable[0] = (mcif.Addr[9:8] == 2'b00) ? 1'b1 : 1'b0;
	assign Enable[1] = (mcif.Addr[9:8] == 2'b01) ? 1'b1 : 1'b0;
	assign Enable[2] = (mcif.Addr[9:8] == 2'b10) ? 1'b1 : 1'b0;
	assign Enable[3] = (mcif.Addr[9:8] == 2'b11) ? 1'b1 : 1'b0;
  genvar i;
  generate
    for (i=0; i<4; i++) begin : ram
        RAM ram_i (.reset (mcif.Reset),.clock (mcif.Clock),.enable (Enable[i]),.rwn (mcif.RWn),.addr (mcif.Addr),.data (mcif.Data));
    end
  endgenerate

RAM module…

module RAM (input logic reset,clock,enable,rwn,[7:0] addr,inout wire [7:0] data);
  logic [7:0] mem[0:255];
  always @ (posedge clock or enable) 
  begin
   if (enable) 
   begin 
    if (~rwn)
      mem[addr] = data;
   end
  end
  assign data = (~reset) ? 8'b0 : ((rwn && enable) ? mem[addr] : 8'bz);
endmodule

at mem_top…

module mem_top;
...
	// Clock and reset signals
	reg clock;
	reg reset;
	
	// The Memory interface
	mem_ctrl_if mcif(.Reset (reset),.Clock (clock));
			
        // DUT instantiation
	mem_ctrl dut(mcif);

	initial begin
            #1000 $finish;
	end

	// Generate clock
	always
		#5 clock=~clock;

	// Generate reset
	initial begin
		reset <= 1;
		clock <=1;
		#10 reset <= 0;
		#100 reset <= 1;
		#10000 reset <= 0;
	end
	
	//Initialize Memory
	initial
	fill_mem ();

	task fill_mem ();
            for(int k=0; k<4; k++)begin
		for (int i=0;i<256;i++)begin
			dut.ram[k].ram_i.mem[i] = 255-i;
		end
            end
	endtask : fill_mem
...
endmodule

I’m getting error as below…

dut.ram[k].ram_i.mem[i] = 255-i;
|
ncelab: *E,NOTPAR (./mem_top.sv,62|11): Illegal operand for constant expression [4(IEEE)].
irun: *E,ELBERR: Error during elaboration (status 1), exiting.

Correct me if any issue in my code.

John

In reply to John Verif:

When you use generate to create multiple instances of a module, it is not an array that you can dynamically index; you must use a constant, and you can use another generate block to do that.

genvar k;
for(k=0;k<4;k++) begin
   initial
	fill_mem ();
   task fill_mem ();
		for (int i=0;i<256;i++)begin
			dut.ram[k].ram_i.mem[i] = 255-i;
		end
	endtask : fill_mem
end

In reply to dave_59:

Thanks Dave, it works!!

John

Is there any way to connect the simple interfaces to the array of interfaces in System Verilog.

The example snippet is follows.

// -------- INTERFACE --------
interface my_if;
    logic   d;
endinterface

// -------- INTERMEDIATE MODULE --------
module intermediate(
    my_if   i1,
    my_if   i2
    );

    sub mySub(
        .a   ('{i1,i2})// With this type of connection getting the syntax error on '{i1,i2} .
        .w1  (1'b1)
    );
endmodule

// -------- SUB MODULE --------
module sub(
    my_if         a[2],
    input wire    w1
    );

    assign a[0].d = w1;
    assign a[1].d = ~w1;
endmodule

In reply to Kuma:
Unfortunately, there is no way in SystemVerilog to compose an interface from a group of other interfaces. What looks like an array of instances is actually just a shortcut for declaring a set of individual instances.

In reply to dave_59:

Hi Dave,

Is there any work around to connect this simple interface to this array of interfaces?

Thanks

In reply to Bhaskar chary:
You would need to show more of what you are trying to do. What is preventing you form declaring an array of interface instances in module intermediate?