添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a highly hierarchical design in SystemVerilog (synthesized using Xilinx Vivado). I use parametrized interfaces and modules. Some data types inside the interfaces are calculated using (interface internal) functions, based on their parameters. I want to be able to access information(specifically, bit width) of those types inside the modules that are using those interfaces. It seems that I can instantiate the type from the interfaces inside a module, but can not use the bit width as a constant .

That is, given the following:

interface iface #(PARAM=1);
    const int i = PARAM; //Gives a warning about simultaneous procedural and continuous assignment
    typedef logic [PARAM-1:0] t;
endinterface
module test(iface i);
    i.t s; //Works
    const int size1 = $bits(i.s); //Works
    const int size2 = $bits(s); //Works
    localparam int p = $bits(i.s); //Fails: Heirarchial name access not allowed
    wire [size1-1:0] s1; //Fails: "size1" is not constant
    wire [size2-1:0] s2; //Fails: "size2" is not constant
    wire [i.i-1:0] s3; //Fails: "i" is not constant
    wire [p-1:0] s3; //Would have worked, is "p" was defined
    localparam int p2 = i.i; //Fails: "i" is not constant
    localparam int p3 = i.PARAM; //Fails: Heirarchial name access not allowed
    //Any of the above two lines would solve all my problems
endmodule

I tried several solutions, including using packages. But in that case there seems to be no way to initialize the package parameters from the top-level parameters.

I read the SystemVerilog LRM regarding both interfaces and packages and could not find any solution in there.

Any solution (short of calculating the derived parameters outside the interface and passing them down the heirarchy) or a pointer in the right direction would be highly appreciated.

If you can declare variable s to type i.t, why not just use s or $bits(s) when you need the length (ie, i.t s; logic [$bits(s)-1:0] x;)? – Unn Dec 31, 2019 at 21:59

There is a confusing part in System Verilog. const int and others are not constants in the verilog sense. They are just const variables. Const keyword is just a contract with the run-time system not to modify them at run time.

"Real" constants are parameters and localparams. Those are compile time (elaboration time) constants. Only they could be used in width declarations. So a bunch of issues in your case are expected.

The second point is that only instances of variables and functions are supposed to be accessible by cross-module references. The typedef is not a such thing, so you cannot reference it this way. Potentially you are supposed to be able to access parameters as well and define your typdef inside the module:

module test(iface i);
 typedef logic [i.PARAM - 1: 0] t;

The above has only one problem: it does not work with all compilers. It works with vcs but does not with nc.

If you want to be generic, I suggest that you paremeterize the module and the interface with the same value.

module test#(PARAM = 1) (iface i);
  typedef logic [PARAM - 1: 0] t;
  const int size1 = $bits(i.s); //Works
  const int size2 = $bits(s); //Works
  localparam int p = $bits(i.s); //Fails: Heirarchial name access not allowed
  wire [p-1:0] s4; //Would have worked, is "p" was defined
  localparam int p3 = PARAM; 
endmodule
module top;
  localparam P8 = 8; // could be from a package
  iface #(.PARAM(P8)) i8();
  test #(.PARAM(P8)) test(i8);
endmodule 

Now, this is alwo a cadence issue localparam int p = $bits(i.s); It works with synopsys. So, just do not use it. you can still say local int p = PARAM; instead,

This is exactly what I wanted to avoid - passing parameters down the chain to both the interface and module instantiations. But it seems there is (at least in Vivado) no other way to do it. – Equilibrius Jan 2, 2020 at 12:47

Your difficulties may be related more to bugs in Vivado than any issues with your code. Passing parameters via interfaces is one of the many buggy aspects of Vivado. Each version of Vivado has different bugs that occur randomly, ranging from nonsensical error messages, to incorrect elaboration, to crashes. On top of all that, synthesis and simulation both have different bugs and code that works in one will probably not work in the other.

If you're willing to deal with all that, here's an example that should work in recent versions of Vivado synthesis. I tested this with version 2019.1.

interface iface #(PARAM=1);
    logic [PARAM-1:0] t = 0;
endinterface
module test(iface i);
    wire [i.PARAM-1:0] var1;
    initial if ($bits(var1) != 42) $error("err1");
    localparam int PARAM2 = i.PARAM + 1;
    wire [PARAM2-1:0] var2;
    initial if ($bits(var2) != 43) $error("err2");
endmodule
module tb;
    iface #(42) my_iface ();
    test my_test (my_iface);
endmodule

Note that this will probably not work in the Vivado simulator. And watch out, because some bugs only appear once you've passed an interface down multiple levels of hierarchy.

Thanks for the info! For now I just brute forced it by propagating the params down the heirarchy. And I've encountered all the problems you mention while trying to find a solution. As I already completed all my RTL design I won't change it, but I'll keep this solution in mind when I start a new project. – Equilibrius Jan 15, 2020 at 15:02

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.