Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

verilog - Parameterizing a SystemVerilog interface for optional array of a port element

I would like to fill in the correct signal declarations and the modport declarations so that my interface and desire code example use case compiles in Vivado. I am working in SystemVerilog with .sv file extensions. The reason that I would like to "if statement" different signal declarations is so that the instantiating and using of my interface is way more elegant. I don't want the user to have to type many [0] to specify a single element in a single element array of 1st dimension with of 1 and 2nd dimension width of 1.

Bear with me on the purpose, I had to remove all elements of this code's application in my work. I have tailored it to be a very simple example.

I do not want someone to need to select the 0th and 0th element if the 1st dimension or the array is 1 and the second dimension of the array is 1.

For example I want the user to be able to do the following, but it doesn't compile. This is my base QUESTION. How do I achieve being able to have code as elegant as the following snippet?:

MyInterface # ( .DATA_WIDTH( 8 ), .ADDR_WIDTH( 8 ), .A1D( 1 ), .A2D( 1 ) ) my_signal () ;

assign my_signal.bus.data = 8'h20 ;

The error is:

[Synth 8-6038] cannot resolve hierarchical name for the item 'data' [".../File.sv":21]

Instead I find the user will have to do this for a specific signal that is 1 element total (there is no error with the following):

MyInterface # ( .DATA_WIDTH( 8 ), .ADDR_WIDTH( 8 ), .A1D( 1 ), .A2D( 1 ) ) my_signal () ;

assign my_signal.bus[0][0].data = 8'h20 ;

I felt that something like this should make this achievable with the following code:

interface MyInterface #(int DATA_W, ADDR_W, A1D, A2D) () ;

  typedef struct packed
    { logic                valid
    ; logic [ADDR_W-1:0]   addr
    ; logic [DATA_W-1:0]   data
    ; } SimpleStruct;

  if ( A1D == 1 ) begin
    SimpleStruct bus;
    logic ready;
  end
  else begin
    if ( A2D == 1 ) begin
      SimpleStruct [A1D-1:0] bus;
      logic        [A1D-1:0] ready;
    end
    else begin
      SimpleStruct [A1D-1:0][A2D-1:0] bus;
      logic        [A1D-1:0][A2D-1:0] ready;
    end
  end
  
  modport SNK (input  bus, output ready);
  modport SRC (output bus, input  ready);

endinterface

This didn't compile because bus and ready were "not declared" ... so I changed to a less elegant (i tried surrounding in generate just guessing, but that didn't help):

interface MyInterface #(int DATA_W, ADDR_W, A1D, A2D) () ;

  typedef struct packed
    { logic                valid
    ; logic [ADDR_W-1:0]   addr
    ; logic [DATA_W-1:0]   data
    ; } SimpleStruct;

  if ( A1D == 1 ) begin
    SimpleStruct bus;
    logic ready;

    modport SNK (input  bus, output ready);
    modport SRC (output bus, input  ready);
  end
  else begin
    if ( A2D == 1 ) begin
      SimpleStruct [A1D-1:0] bus;
      logic        [A1D-1:0] ready;
  
      modport SNK (input  bus, output ready);
      modport SRC (output bus, input  ready);
    end
    else begin
      SimpleStruct [A1D-1:0][A2D-1:0] bus;
      logic        [A1D-1:0][A2D-1:0] ready;
  
      modport SNK (input  bus, output ready);
      modport SRC (output bus, input  ready);
    end
  end

endinterface

The same desire goes for the case where the user wants to use a single dimensioned array where length > 1. For example: imho desirable:

MyInterface # ( .DATA_WIDTH( 8 ), .ADDR_WIDTH( 8 ), .A1D( 3 ), .A2D( 1 ) ) my_signal () ;

assign my_signal.bus.data[0] = 8'h20 ;
assign my_signal.bus.data[1] = 8'h21 ;
assign my_signal.bus.data[2] = 8'h22 ;

I think the code above looks better than the code below. And the whole point of me experimenting or choosing to use interfaces is code reusability and elegance. I don't want the user to constantly be fighting with "I want a single element, but will get partially ambiguous error that is tough to figure out the solution to":
imho Not desirable:

MyInterface # ( .DATA_WIDTH( 8 ), .ADDR_WIDTH( 8 ), .A1D( 3 ), .A2D( 1 ) ) my_signal () ;

assign my_signal.bus.data[0][0] = 8'h20 ;
assign my_signal.bus.data[1][0] = 8'h21 ;
assign my_signal.bus.data[2][0] = 8'h22 ;

My desire is to have the user write the code they need to accomplish the complexity of elements that they want. There are most uses for a single element, some uses for a 1D array of elements, and few uses for 2D array of the elements. Since I will want to have one interface defined, I will have to allow for all the uses. I don't want in-elegant code needed just because I want the interface to support 2D and a user only needs a single element for their particular instantiation and code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I guess the best way to do something like you describe is to use a type parameter and to define types outside of the interface. Here is an example.

interface MyInterface #(type SimpleStruct = logic) () ;  
  SimpleStruct  bus;
  logic         ready;
   
  modport SNK (input  bus, output ready);
  modport SRC (output bus, input  ready);

endinterface

module mymod #(int DATA_W = 1, int ADDR_W = 1) ();

  typedef struct packed
    { logic                valid
    ; logic [ADDR_W-1:0]   addr
    ; logic [DATA_W-1:0]   data
    ; } SimpleStruct;
  
  MyInterface #(SimpleStruct) if1();
  
  typedef SimpleStruct[2] SimpleStruct2;
  MyInterface #(SimpleStruct2) if2();

  typedef SimpleStruct[2][2] SimpleStruct3;
  MyInterface #(SimpleStruct3) if3();

endmodule
  

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...