Skip to content

Commit 04113eb

Browse files
authored
Merge pull request YosysHQ#5714 from likeamahoney/auto-proc-vars
support automatic lifetime qualifier on procedural variables
2 parents 1d3f9b7 + e944219 commit 04113eb

3 files changed

Lines changed: 129 additions & 5 deletions

File tree

frontends/ast/genrtlil.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,18 @@ struct AST_INTERNAL::ProcessGenerator
403403
if (GetSize(syncrule->signal) != 1)
404404
always->input_error("Found posedge/negedge event on a signal that is not 1 bit wide!\n");
405405
addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
406+
// Automatic (nosync) variables must not become flip-flops: remove
407+
// them from clocked sync rules so that proc_dff does not infer
408+
// an unnecessary register for a purely combinational temporary.
409+
syncrule->actions.erase(
410+
std::remove_if(syncrule->actions.begin(), syncrule->actions.end(),
411+
[](const RTLIL::SigSig &ss) {
412+
for (auto &chunk : ss.first.chunks())
413+
if (chunk.wire && chunk.wire->get_bool_attribute(ID::nosync))
414+
return true;
415+
return false;
416+
}),
417+
syncrule->actions.end());
406418
proc->syncs.push_back(syncrule);
407419
}
408420
if (proc->syncs.empty()) {

frontends/verilog/verilog_parser.y

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
int current_function_or_task_port_id;
8585
std::vector<char> case_type_stack;
8686
bool do_not_require_port_stubs;
87-
bool current_wire_rand, current_wire_const;
87+
bool current_wire_rand, current_wire_const, current_wire_automatic;
8888
bool current_modport_input, current_modport_output;
8989
bool default_nettype_wire = true;
9090
std::istream* lexin;
@@ -958,14 +958,18 @@ delay:
958958
non_opt_delay | %empty;
959959
960960
io_wire_type:
961-
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; }
961+
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; extra->current_wire_automatic = false; }
962962
wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness
963963
{ $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); };
964964
965965
non_io_wire_type:
966-
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; }
967-
wire_type_const_rand wire_type_token wire_type_signedness
968-
{ $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); };
966+
{ extra->astbuf3 = std::make_unique<AstNode>(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; extra->current_wire_automatic = false; }
967+
opt_lifetime wire_type_const_rand wire_type_token wire_type_signedness
968+
{
969+
if (extra->current_wire_automatic)
970+
extra->astbuf3->set_attribute(ID::nosync, AstNode::mkconst_int(extra->astbuf3->location, 1, false));
971+
$$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$);
972+
};
969973
970974
wire_type:
971975
io_wire_type { $$ = std::move($1); } |
@@ -1253,6 +1257,10 @@ opt_automatic:
12531257
TOK_AUTOMATIC |
12541258
%empty;
12551259

1260+
opt_lifetime:
1261+
TOK_AUTOMATIC { extra->current_wire_automatic = true; } |
1262+
%empty;
1263+
12561264
task_func_args_opt:
12571265
TOK_LPAREN TOK_RPAREN | %empty | TOK_LPAREN {
12581266
extra->albuf = nullptr;
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Automatic reg as intermediate value in always @(*)
2+
# The result must be provably equivalent to the direct expression.
3+
# No latch or DFF must be created for tmp.
4+
design -reset
5+
read_verilog -sv <<EOF
6+
module t1(input a, b, c, output reg y);
7+
always @(*) begin : blk
8+
automatic reg tmp;
9+
tmp = a ^ b;
10+
if (c) tmp = tmp & a;
11+
y = tmp;
12+
end
13+
// equivalent to: y = c ? ((a^b)&a) : (a^b)
14+
assert property (y === (c ? ((a ^ b) & a) : (a ^ b)));
15+
endmodule
16+
EOF
17+
proc
18+
async2sync
19+
# no state elements for tmp
20+
select -assert-none t:$dff t:$dlatch %%
21+
sat -verify -prove-asserts -show-all
22+
23+
# automatic logic in always_comb with chained computation
24+
# Two automatic intermediates used in sequence; result must match
25+
# the direct expression. No latch/DFF.
26+
design -reset
27+
read_verilog -sv <<EOF
28+
module t2(input [3:0] a, b, input sel, output reg [3:0] y, output reg co);
29+
always_comb begin : blk
30+
automatic reg [4:0] sum;
31+
automatic reg [3:0] pick;
32+
sum = {1'b0, a} + {1'b0, b};
33+
pick = sel ? sum[3:0] : (a & b);
34+
y = pick;
35+
co = sum[4];
36+
end
37+
assert property (y === (sel ? ((a + b) & 4'hf) : (a & b)));
38+
assert property (co === (((5'(a) + 5'(b)) >> 4) & 1'b1));
39+
endmodule
40+
EOF
41+
proc
42+
async2sync
43+
select -assert-none t:$dff t:$dlatch %%
44+
sat -verify -prove-asserts -show-all
45+
46+
# automatic in a clocked block — only the explicitly registered
47+
# output (result) must get a DFF; the automatic temp must not.
48+
design -reset
49+
read_verilog -sv <<EOF
50+
module t3(input clk, rst, input [7:0] data, output reg [7:0] result);
51+
always @(posedge clk) begin : compute
52+
automatic reg [7:0] tmp;
53+
tmp = data ^ 8'hA5;
54+
if (rst)
55+
result <= 8'h00;
56+
else
57+
result <= tmp;
58+
end
59+
endmodule
60+
EOF
61+
proc
62+
# Exactly one DFF (for result), zero latches, no DFF for tmp
63+
select -assert-count 1 t:$dff %%
64+
select -assert-none t:$dlatch %%
65+
66+
# automatic integer in named block — ensure integer-width
67+
# automatic variables work and produce no state elements.
68+
design -reset
69+
read_verilog -sv <<EOF
70+
module t4(input [7:0] a, b, input sub, output reg [7:0] y);
71+
always @(*) begin : arith
72+
automatic integer acc;
73+
if (sub)
74+
acc = $signed(a) - $signed(b);
75+
else
76+
acc = $signed(a) + $signed(b);
77+
y = acc[7:0];
78+
end
79+
assert property (y === (sub ? (a - b) : (a + b)));
80+
endmodule
81+
EOF
82+
proc
83+
async2sync
84+
select -assert-none t:$dff t:$dlatch %%
85+
sat -verify -prove-asserts -show-all
86+
87+
# automatic variable not assigned on all paths (X semantics)
88+
# With 'automatic', tmp holds no previous state; the undriven path
89+
# produces X, not the old register value. After proc, no latch may be
90+
# inferred for tmp.
91+
design -reset
92+
read_verilog -sv <<EOF
93+
module t5(input en, d, output reg q);
94+
always @(*) begin : blk
95+
automatic reg tmp;
96+
if (en) tmp = d;
97+
// tmp is X when en==0: automatic means no state retention
98+
q = tmp;
99+
end
100+
endmodule
101+
EOF
102+
proc
103+
# No latch for tmp — X propagates instead of old value
104+
select -assert-none t:$dff t:$dlatch %%

0 commit comments

Comments
 (0)