问题描述
也讨论于:
我无法在 SystemVerilog 中实现我的意图,试图使用最新的语言功能使我的代码更优雅、更简洁。用于合成**
我想完成以下任务:
- 能够在我想定义的打包结构中参数化字段的位宽......我尝试使用参数化接口构造来实现这一点
- 我希望具有该参数化接口的模块作为模块的 INPUT 能够推断接口内定义的打包结构内的字段的位宽
我在过去的实验中大部分都取得了成功,但我遇到了一个问题。
请看下面简单的接口定义:
interface MyInterface #(int DATA_W,ADDR_W) () ;
typedef struct packed
{ logic valid
; logic [ADDR_W-1:0] addr
; logic [DATA_W-1:0] data
; } SimpleStruct;
SimpleStruct bus;
logic ready;
modport SNK (input bus,output ready);
modport SRC (output bus,input ready);
endinterface
在此示例中,实例化一个接口并在我的 Top 模块中的一个简单模块的输入中使用它是很容易的:
module TopTest
( input wire Clock,input wire Reset,input wire [31:0] In,output wire dummyOut
) ;
MyInterface # ( 32,3 ) my_interface ();
assign my_interface.bus.data = In ;
assign my_interface.bus.addr = 3'h3 ;
InnerTest inst_mod_inner_test
( .Clock( Clock ),.Reset( Reset ),.Sink( my_interface )
) ;
assign dummyOut = my_interface.ready ;
endmodule
我遇到的问题是我不想用字段位宽参数化实际模块,因为我相信在编译时字段的位宽应该已经建立并且可以访问。情况似乎并非如此,我想知道是否有什么我可以做的事情来完成推断接口中打包结构的位宽(记住是这种情况,因为我希望它被参数化,我知道这很容易获取未在接口中定义而是在包或模块中定义的结构字段的 $bits)
module InnerTest
( input wire Clock,MyInterface.SNK Sink
) ;
localparam BIT_WIDTH_SINK_DATA = $bits( Sink.bus.data ) // this line errors out b/c sink is 'virtual'
RAM # ( .DATA_WIDTH( BIT_WIDTH_SINK_DATA ) ) ram ( ... // etc
... other code to drive output ready of interface ...
endmodule
设计师想要使模块“可参数化”的原因有很多,我过去曾采用这种方法,但我对不重复信息非常感兴趣。如果我采用简单的方法,我会简单地参数化我的内部测试模块,以便我为其提供 DATA_WIDTH,但是我将有两个数字要更新,以及许多我认为不需要的参数。我认为如果我能以某种方式简单地推断参数化结构的特征,那将是最优雅的。在我看来,我正在寻找的信息在编译时确实是已知的。我似乎无法访问它,或者这是 SystemVerilog 的另一个不足。
在模拟中跟进 Q Dave 提到的解决方法在使用 QuestaSim 时非常有用,但现在在 QuestaSim 中遇到了不同的问题:
当实例中的实际接口是一个数组实例元素或低于一个生成结构时,通过接口端口“sink”的参数引用“sink.bus.data”无效
对此的解决方法是什么,我不明白为什么只是在 generate 语句中会影响下游的事情。在这种情况下,我使用 generate 语句在不同的 FIFO 实现之间进行选择,在发生错误的代码行上方几层。
typedef sink.bus.data questasim_workaround;
localparam width = $bits(questasim_workaround);
后续实验 我已经尝试过传入类型,而不是限制自己传入 DATA_W。
interface MyInterface #(int ADDR_W,type DATA_TYPE) () ;
typedef struct packed
{ logic valid
; logic [ADDR_W-1:0] addr
; DATA_TYPE data
; } SimpleStruct;
SimpleStruct bus;
logic ready;
modport SNK (input bus,input ready);
endinterface
这提供了更大的灵活性。我观察到 Vivado 模拟器和综合工具可以毫无问题地处理这样的示例。
module SomeModule
( MyInterface myInt
blah...
);
localparam SOMETHING = $bits(myInt.DATA_TYPE);
// or equivalently
localparam SOMETHING_ELSE = $bits(myInt.data);
// or even this,for needs of a internal signal for pipelined processing steps
MyInterface # ($bits(myInt.addr),myInt.DATA_TYPE) internal_0 () ;
在 QUEstaSim 中,我们不得不实施 Dave 的工作来代替这一点:
module SomeModule
( MyInterface myInt
blah...
);
// this gets less elegant :/
typedef myInt.data questasim_workaround_data;
typedef myInt.addr questasim_workaround_addr;
localparam SOMETHING = $bits(questasim_workaround_data);
// or equivalently
localparam SOMETHING_ELSE = $bits(questasim_workaround_data);
// or even this,for needs of a internal signal for pipelined processing steps
MyInterface # ($bits(questasim_workaround_addr),questasim_workaround_data) internal_0 () ;
解决方法
当前的 SystemVerilog BNF 不允许任何带点的“.”参数初始化中的名称。但是你可以通过使用 typedef 来解决这个问题
interface MyInterface #(int DATA_W=0,ADDR_W=0) () ;
typedef logic [DATA_W-1:0] data_t;
...
endinterface
module InnerTest
( input wire Clock,input wire Reset,MyInterface.SNK Sink
) ;
typedef Sink.data_t data_t;
localparam BIT_WIDTH_SINK_DATA = $bits( data_t );
...
endmodule
,
每当您在 Vivado 中看到“[Synth 8-27] 不支持范围/层次类型名称”周围的意外错误时...检查实例化端口映射是否与实际模块定义端口映射的所有名称匹配.这是 Vivado 中仅此代码的问题。拼写不匹配,而不是“[Synth 8-448] 命名端口连接 'clkkkk' 不存在”,我收到了“[Synth 8-27] 不支持范围/层次类型名称”错误