Open
Description
The more aggressive test code extraction may have surprising behavior when a module that is a candidate for aggressive extraction is dead in one code path, but not dead in another.
Consider:
circuit Foo:
module Baz:
input clock: Clock
input reset: UInt<1>
input a: UInt<1>
output b: UInt<1>
b <= a
assert(clock, eq(a, UInt<1>(0)), reset, "a != 0")
module Bar:
input clock: Clock
input reset: UInt<1>
input a: UInt<1>
output b: UInt<1>
b <= a
assert(clock, eq(a, UInt<1>(0)), reset, "a != 0")
module Foo:
input clock: Clock
input reset: UInt<1>
input a: UInt<1>
output b: UInt<1>
inst bar of Bar
bar.clock <= clock
bar.reset <= reset
bar.a <= a
inst baz of Baz
baz.clock <= clock
baz.reset <= reset
baz.a <= a
b <= baz.b
When running without dedup (firtool Foo.fir -extract-test-code
):
// Generated by CIRCT unknown git version
// VCS coverage exclude_file
module Baz_assert(
input a,
reset,
clock);
always @(posedge clock) begin
if (reset)
assert(~a) else $error("a != 0");
end // always @(posedge)
endmodule
module Baz(
input clock,
reset,
a,
output b);
/* This instance is elsewhere emitted as a bind statement.
Baz_assert Baz_assert (
.a (a),
.reset (reset),
.clock (clock)
);
*/
assign b = a;
endmodule
// VCS coverage exclude_file
module Bar_assert(
input a,
reset,
clock);
always @(posedge clock) begin
if (reset)
assert(~a) else $error("a != 0");
end // always @(posedge)
endmodule
module Foo(
input clock,
reset,
a,
output b);
/* This instance is elsewhere emitted as a bind statement.
Bar_assert Bar_assert (
.a (a),
.reset (reset),
.clock (clock)
);
*/
Baz baz (
.clock (clock),
.reset (reset),
.a (a),
.b (b)
);
endmodule
// ----- 8< ----- FILE "bindfile" ----- 8< -----
bind Baz Baz_assert Baz_assert (
.a (a),
.reset (reset),
.clock (clock)
);
bind Foo Bar_assert Bar_assert (
.a (a),
.reset (reset),
.clock (clock)
);
When running with dedup (firtool Foo.fir -dedup -extract-test-code
):
// Generated by CIRCT unknown git version
// VCS coverage exclude_file
module Bar_assert(
input a,
reset,
clock);
always @(posedge clock) begin
if (reset)
assert(~a) else $error("a != 0");
end // always @(posedge)
endmodule
module Bar(
input clock,
reset,
a,
output b);
/* This instance is elsewhere emitted as a bind statement.
Bar_assert Bar_assert (
.a (a),
.reset (reset),
.clock (clock)
);
*/
assign b = a;
endmodule
module Foo(
input clock,
reset,
a,
output b);
wire _bar_b;
Bar bar (
.clock (clock),
.reset (reset),
.a (a),
.b (_bar_b)
);
Bar baz (
.clock (clock),
.reset (reset),
.a (a),
.b (b)
);
endmodule
// ----- 8< ----- FILE "bindfile" ----- 8< -----
bind Bar Bar_assert Bar_assert (
.a (a),
.reset (reset),
.clock (clock)
);