接口中用于 RTL 可读性的 assign 语句会在综合中导致赋值或缓冲区
assign statement for RTL readability in an interface causes assignments or a buffer in synthesis
我们有一个与 modports 连接的接口,看起来像这样:
interface test_interface (clk, in1, out1);
input logic in1;
output logic out1;
input logic clk;
logic mid1;
logic aliased_signal;
modport a_to_b (
input in1,
input clk,
output mid1,
input aliased_signal
);
modport b_to_a (
input clk,
input mid1,
output out1,
output aliased_signal
);
endinterface : test_interface
module top(clock, inpad, outpad);
input logic clock;
input logic inpad;
output logic outpad;
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad));
a A0(.a2b(test_if));
b B0(.b2a(test_if));
endmodule
module a ( test_interface.a_to_b a2b);
always_ff @(posedge a2b.clk) begin
a2b.mid1 <= a2b.in1 & a2b.aliased_signal;
end
endmodule
module b (test_interface.b_to_a b2a);
assign b2a.aliased_signal = b2a.out1;
always_ff @(posedge b2a.clk) begin
b2a.out1 <= ~b2a.mid1;
end
endmodule
这是一个简单的例子,但可以说明问题。在实际设计中,例如,我们有 32 位输出和其中的 8 位可能到一个地方,8 位到另一个地方,等等。在目的地,他们想使用在目的地模块中更有意义的名称,因此正在使用赋值在接口中创建这些名称,以便目标代码不会仅使用接口中混淆总线名称的部分位。
虽然上面的模拟很好,结果是综合期间的赋值语句(即使显然使用 always_comb),虽然我们可以让综合工具插入缓冲区来使 APR 满意,但当这些信号基本上只是用作方便的别名。
是否有一种带有 SV 接口的 RTL 编码风格允许这样 "aliasing" 而不会在 synthesis/APR 工具的下游造成复杂性?
下面是一个更接近我正在尝试做的例子。 "obfuscated_name" 信号是 a 模块的输出,因为某些模块直接使用接口中的名称(这可以清理为仅执行 a->b 连接正在执行的操作),但我得到了相同的错误如果我连接到 mid2 a->c 而不是直接使用 obfuscated_name 信号,则来自 IUS 和 DC。
interface test_interface(clk, in1, out1, out2);
input logic [7:0] in1;
output logic [3:0] out1;
output logic [3:0] out2;
input logic clk;
logic [7:0] obfuscated_name;
logic [3:0] mid1;
logic [3:0] mid2;
modport a_mp (
input clk,
input in1,
output obfuscated_name
);
modport a_to_b (
input clk,
input .mid1(obfuscated_name[3:0]),
output out1
);
modport a_to_c (
input clk,
input obfuscated_name,
output out2
);
endinterface : test_interface
module a ( test_interface.a_mp a_intf);
always_ff @(posedge a_intf.clk) begin
a_intf.obfuscated_name <= ~a_intf.in1;
end
endmodule
module b (test_interface.a_to_b b_intf);
always_ff @(posedge b_intf.clk) begin
b_intf.out1 <= b_intf.mid1;
end
endmodule
module c (test_interface.a_to_c c_intf);
always_ff @(posedge c_intf.clk) begin
c_intf.out2 <= ~c_intf.obfuscated_name[7:4];
end
endmodule
module top( input logic clock,
input logic [7:0] inpad,
output logic [3:0] outpad1,
output logic [3:0] outpad2 );
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad1), .out2(outpad2));
a A0(.a_intf(test_if));
b B0(.b_intf(test_if));
c C0(.c_intf(test_if));
endmodule
我从 IUS 得到的错误是:
ncvlog: *E,MODPXE (test_interface.sv,18|18): Unsupported modport
expression for port identifier 'mid1'.
DC 给出了这个错误:
Error: ./b.sv:1: The construct 'b_intf.mid1 (modport expression without a modport from parent)' is not supported in synthesis. (VER-700)
我希望我在这里做了一些无知的事情,这可能是我正在尝试做的事情。
Verilog 中有一个称为 端口表达式 .name_of_port(expression_to_be_connected_to_port)
的功能,大多数人都在 模块实例端口列表 中识别它他们没有意识到的也可以用在模块减速端口列表头中。这声明了端口的名称,以及连接到端口的表达式。这样,可以将较大的内部总线的较小部分 select 制成端口。
module DUT(input clk, inout .data(bus[7:0]) );
wire [31:0] bus;
endmodule
module top;
reg clock;
wire [7:0] mydata;
DUT d1(.data(mydata), .clk(clock) );
endmodule
在 SystemVerilog 中,您可以使用 modport 表达式执行相同的操作。
interface test_interface (clk, in1, out1);
input logic in1;
output logic out1;
input logic clk;
logic mid1;
logic aliased_signal;
modport a_to_b (
input in1,
input clk,
output mid1,
input .aliased_signal(out1) // modport expression
);
modport b_to_a (
input clk,
input mid1,
output out1
);
endinterface : test_interface
module top( input logic clock,
input logic inpad,
output logic outpad );
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad));
a A0(.a2b(test_if));
b B0(.b2a(test_if));
endmodule
module a ( test_interface.a_to_b a2b);
always_ff @(posedge a2b.clk) begin
a2b.mid1 <= a2b.in1 & a2b.aliased_signal; // port reference to alias
end
endmodule
module b (test_interface.b_to_a b2a);
always_ff @(posedge b2a.clk) begin
b2a.out1 <= ~b2a.mid1;
end
endmodule
我们有一个与 modports 连接的接口,看起来像这样:
interface test_interface (clk, in1, out1);
input logic in1;
output logic out1;
input logic clk;
logic mid1;
logic aliased_signal;
modport a_to_b (
input in1,
input clk,
output mid1,
input aliased_signal
);
modport b_to_a (
input clk,
input mid1,
output out1,
output aliased_signal
);
endinterface : test_interface
module top(clock, inpad, outpad);
input logic clock;
input logic inpad;
output logic outpad;
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad));
a A0(.a2b(test_if));
b B0(.b2a(test_if));
endmodule
module a ( test_interface.a_to_b a2b);
always_ff @(posedge a2b.clk) begin
a2b.mid1 <= a2b.in1 & a2b.aliased_signal;
end
endmodule
module b (test_interface.b_to_a b2a);
assign b2a.aliased_signal = b2a.out1;
always_ff @(posedge b2a.clk) begin
b2a.out1 <= ~b2a.mid1;
end
endmodule
这是一个简单的例子,但可以说明问题。在实际设计中,例如,我们有 32 位输出和其中的 8 位可能到一个地方,8 位到另一个地方,等等。在目的地,他们想使用在目的地模块中更有意义的名称,因此正在使用赋值在接口中创建这些名称,以便目标代码不会仅使用接口中混淆总线名称的部分位。
虽然上面的模拟很好,结果是综合期间的赋值语句(即使显然使用 always_comb),虽然我们可以让综合工具插入缓冲区来使 APR 满意,但当这些信号基本上只是用作方便的别名。
是否有一种带有 SV 接口的 RTL 编码风格允许这样 "aliasing" 而不会在 synthesis/APR 工具的下游造成复杂性?
下面是一个更接近我正在尝试做的例子。 "obfuscated_name" 信号是 a 模块的输出,因为某些模块直接使用接口中的名称(这可以清理为仅执行 a->b 连接正在执行的操作),但我得到了相同的错误如果我连接到 mid2 a->c 而不是直接使用 obfuscated_name 信号,则来自 IUS 和 DC。
interface test_interface(clk, in1, out1, out2);
input logic [7:0] in1;
output logic [3:0] out1;
output logic [3:0] out2;
input logic clk;
logic [7:0] obfuscated_name;
logic [3:0] mid1;
logic [3:0] mid2;
modport a_mp (
input clk,
input in1,
output obfuscated_name
);
modport a_to_b (
input clk,
input .mid1(obfuscated_name[3:0]),
output out1
);
modport a_to_c (
input clk,
input obfuscated_name,
output out2
);
endinterface : test_interface
module a ( test_interface.a_mp a_intf);
always_ff @(posedge a_intf.clk) begin
a_intf.obfuscated_name <= ~a_intf.in1;
end
endmodule
module b (test_interface.a_to_b b_intf);
always_ff @(posedge b_intf.clk) begin
b_intf.out1 <= b_intf.mid1;
end
endmodule
module c (test_interface.a_to_c c_intf);
always_ff @(posedge c_intf.clk) begin
c_intf.out2 <= ~c_intf.obfuscated_name[7:4];
end
endmodule
module top( input logic clock,
input logic [7:0] inpad,
output logic [3:0] outpad1,
output logic [3:0] outpad2 );
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad1), .out2(outpad2));
a A0(.a_intf(test_if));
b B0(.b_intf(test_if));
c C0(.c_intf(test_if));
endmodule
我从 IUS 得到的错误是:
ncvlog: *E,MODPXE (test_interface.sv,18|18): Unsupported modport expression for port identifier 'mid1'.
DC 给出了这个错误:
Error: ./b.sv:1: The construct 'b_intf.mid1 (modport expression without a modport from parent)' is not supported in synthesis. (VER-700)
我希望我在这里做了一些无知的事情,这可能是我正在尝试做的事情。
Verilog 中有一个称为 端口表达式 .name_of_port(expression_to_be_connected_to_port)
的功能,大多数人都在 模块实例端口列表 中识别它他们没有意识到的也可以用在模块减速端口列表头中。这声明了端口的名称,以及连接到端口的表达式。这样,可以将较大的内部总线的较小部分 select 制成端口。
module DUT(input clk, inout .data(bus[7:0]) );
wire [31:0] bus;
endmodule
module top;
reg clock;
wire [7:0] mydata;
DUT d1(.data(mydata), .clk(clock) );
endmodule
在 SystemVerilog 中,您可以使用 modport 表达式执行相同的操作。
interface test_interface (clk, in1, out1);
input logic in1;
output logic out1;
input logic clk;
logic mid1;
logic aliased_signal;
modport a_to_b (
input in1,
input clk,
output mid1,
input .aliased_signal(out1) // modport expression
);
modport b_to_a (
input clk,
input mid1,
output out1
);
endinterface : test_interface
module top( input logic clock,
input logic inpad,
output logic outpad );
test_interface test_if(.clk(clock), .in1(inpad), .out1(outpad));
a A0(.a2b(test_if));
b B0(.b2a(test_if));
endmodule
module a ( test_interface.a_to_b a2b);
always_ff @(posedge a2b.clk) begin
a2b.mid1 <= a2b.in1 & a2b.aliased_signal; // port reference to alias
end
endmodule
module b (test_interface.b_to_a b2a);
always_ff @(posedge b2a.clk) begin
b2a.out1 <= ~b2a.mid1;
end
endmodule