参数化打包结构中字段的位宽,以便模块在端口映射中使用时可以推断出位宽
Parameterizing the Bit Widths of fields in a packed struct so that modules can infer bit width if used in port map
还在以下位置讨论:
我无法在 SystemVerilog 中实现我的意图,试图使用最新的语言功能使我的代码更优雅、更简洁。用于合成**
我想完成以下任务:
- 能够参数化我想要定义的打包结构中字段的位宽...我试图使用参数化接口构造来完成此操作
- 我希望具有该参数化接口的模块作为模块的输入能够推断接口内定义的打包结构内字段的位宽
我在过去的实验中大部分都是成功的,但我 运行 遇到了问题。
请看下面简单的接口定义:
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
, input wire Reset
, 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”无效
解决这个问题的方法是什么,我不明白为什么只是在生成语句中会影响下游的事情。在这种情况下,我使用生成语句在不同的 FIFO 实现之间进行选择,在发生错误的代码行上方几层。
typedef sink.bus.data questasim_workaround;
localparam width = $bits(questasim_workaround);
跟进实验
我尝试过传入 type 而不是限制自己传入 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, output ready);
modport SRC (output 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] scoped/hierarchical type name not supported”的意外错误时...检查实例化端口映射是否匹配所有名称实际模块定义端口映射。这是 Vivado 中仅此代码的问题。拼写不匹配,而不是“[Synth 8-448] 命名端口连接 'clkkkk' 不存在”,我收到了“[Synth 8-27] scoped/hierarchical 类型名称不支持”错误
还在以下位置讨论:
我无法在 SystemVerilog 中实现我的意图,试图使用最新的语言功能使我的代码更优雅、更简洁。用于合成**
我想完成以下任务:
- 能够参数化我想要定义的打包结构中字段的位宽...我试图使用参数化接口构造来完成此操作
- 我希望具有该参数化接口的模块作为模块的输入能够推断接口内定义的打包结构内字段的位宽
我在过去的实验中大部分都是成功的,但我 运行 遇到了问题。
请看下面简单的接口定义:
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
, input wire Reset
, 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”无效
解决这个问题的方法是什么,我不明白为什么只是在生成语句中会影响下游的事情。在这种情况下,我使用生成语句在不同的 FIFO 实现之间进行选择,在发生错误的代码行上方几层。
typedef sink.bus.data questasim_workaround;
localparam width = $bits(questasim_workaround);
跟进实验 我尝试过传入 type 而不是限制自己传入 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, output ready);
modport SRC (output 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] scoped/hierarchical type name not supported”的意外错误时...检查实例化端口映射是否匹配所有名称实际模块定义端口映射。这是 Vivado 中仅此代码的问题。拼写不匹配,而不是“[Synth 8-448] 命名端口连接 'clkkkk' 不存在”,我收到了“[Synth 8-27] scoped/hierarchical 类型名称不支持”错误