Skip to content

Commit c6deb50

Browse files
authored
Merge pull request #418 from diffblue/verilog-always
Verilog: `always_comb`, `always_ff`, `always_latch`
2 parents fb82f4b + 3e7de3e commit c6deb50

16 files changed

+172
-67
lines changed

regression/verilog/delays/delay_with_unit1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ delay_with_unit1.v
33

44
^EXIT=2$
55
^SIGNAL=0$
6-
^file .*: permanent assignment without event guard$
6+
^file .*: assignment in 'always' context without event guard$
77

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
always_comb1.sv
3+
--module main --bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module main(input [7:0] data1);
2+
3+
logic [7:0] data2;
4+
always_comb data2 = data1;
5+
6+
p1: assert property (data2 == data1);
7+
8+
endmodule
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
always_comb2.sv
3+
--bound 0
4+
^\[main\.property\.p0\] always \(main\.data == 0 |-> main\.decoded == 1\): PROVED up to bound 0$
5+
^\[main\.property\.p1\] always \(main\.data == 1 |-> main\.decoded == 2\): PROVED up to bound 0$
6+
^\[main\.property\.p2\] always \(main\.data == 2 |-> main\.decoded == 4\): PROVED up to bound 0$
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module main(input [7:0] data);
2+
3+
// an 8-bit binary to unary decoder
4+
reg [255:0] decoded;
5+
6+
always_comb begin
7+
integer i;
8+
for(i = 0; i < 256; i = i + 1)
9+
decoded[i] = data == i;
10+
end
11+
12+
p0: assert property (data == 0 |-> decoded == 1);
13+
p1: assert property (data == 1 |-> decoded == 2);
14+
p2: assert property (data == 2 |-> decoded == 4);
15+
16+
endmodule
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
always_ff1.sv
3+
--module main --k-induction
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.property\.p0\] always main\.x >= 1 && main\.x <= 10: PROVED$
7+
--
8+
^warning: ignoring
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module main(input clk);
2+
reg [31:0] x;
3+
4+
initial x=1;
5+
always_ff @(posedge clk)
6+
if(x<10)
7+
x++;
8+
9+
// should pass
10+
p0: assert property (x >= 1 && x <= 10);
11+
12+
endmodule

src/hw_cbmc_irep_ids.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ IREP_ID_ONE(force)
6666
IREP_ID_ONE(deassign)
6767
IREP_ID_ONE(continuous_assign)
6868
IREP_ID_ONE(wait)
69-
IREP_ID_ONE(always)
69+
IREP_ID_ONE(verilog_always)
70+
IREP_ID_ONE(verilog_always_comb)
71+
IREP_ID_ONE(verilog_always_ff)
72+
IREP_ID_ONE(verilog_always_latch)
7073
IREP_ID_ONE(named_port_connection)
7174
IREP_ID_ONE(verilog_final)
7275
IREP_ID_ONE(initial)

src/verilog/parser.y

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2518,10 +2518,10 @@ always_construct: always_keyword statement
25182518
;
25192519

25202520
always_keyword:
2521-
TOK_ALWAYS { init($$, ID_always); }
2522-
| TOK_ALWAYS_COMB { init($$, ID_always); }
2523-
| TOK_ALWAYS_LATCH { init($$, ID_always); }
2524-
| TOK_ALWAYS_FF { init($$, ID_always); }
2521+
TOK_ALWAYS { init($$, ID_verilog_always); }
2522+
| TOK_ALWAYS_COMB { init($$, ID_verilog_always_comb); }
2523+
| TOK_ALWAYS_LATCH { init($$, ID_verilog_always_latch); }
2524+
| TOK_ALWAYS_FF { init($$, ID_verilog_always_ff); }
25252525
;
25262526

25272527
final_construct: TOK_FINAL function_statement

src/verilog/verilog_elaborate.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,13 @@ void verilog_typecheckt::collect_symbols(
729729
{
730730
collect_symbols(to_verilog_decl(module_item));
731731
}
732-
else if(module_item.id() == ID_always)
732+
else if(
733+
module_item.id() == ID_verilog_always ||
734+
module_item.id() == ID_verilog_always_comb ||
735+
module_item.id() == ID_verilog_always_ff ||
736+
module_item.id() == ID_verilog_always_latch)
733737
{
734-
collect_symbols(to_verilog_always(module_item).statement());
738+
collect_symbols(to_verilog_always_base(module_item).statement());
735739
}
736740
else if(module_item.id() == ID_initial)
737741
{

src/verilog/verilog_expr.h

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,20 @@ class verilog_statementt:public exprt
104104
{
105105
}
106106

107-
explicit verilog_statementt(const irep_idt &id, operandst _operands)
107+
verilog_statementt(const irep_idt &id, operandst _operands) : exprt(id)
108+
{
109+
operands() = std::move(_operands);
110+
}
111+
112+
verilog_statementt(
113+
const irep_idt &id,
114+
operandst _operands,
115+
source_locationt __source_location)
108116
: exprt(id)
109117
{
110118
operands() = std::move(_operands);
119+
if(__source_location.is_not_nil())
120+
add_source_location() = std::move(__source_location);
111121
}
112122

113123
verilog_statementt()
@@ -649,14 +659,21 @@ inline verilog_inst_builtint &to_verilog_inst_builtin(exprt &expr)
649659
return static_cast<verilog_inst_builtint &>(expr);
650660
}
651661

652-
class verilog_alwayst:public verilog_statementt
662+
/// SystemVerilog has always, always_comb, always_ff and always_latch
663+
class verilog_always_baset : public verilog_statementt
653664
{
654665
public:
655-
verilog_alwayst():verilog_statementt(ID_always)
666+
verilog_always_baset(
667+
irep_idt id,
668+
verilog_statementt __statement,
669+
source_locationt __source_location)
670+
: verilog_statementt(
671+
id,
672+
{std::move(__statement)},
673+
std::move(__source_location))
656674
{
657-
operands().resize(1);
658675
}
659-
676+
660677
verilog_statementt &statement()
661678
{
662679
return static_cast<verilog_statementt &>(op0());
@@ -668,18 +685,16 @@ class verilog_alwayst:public verilog_statementt
668685
}
669686
};
670687

671-
inline const verilog_alwayst &to_verilog_always(const exprt &expr)
688+
inline const verilog_always_baset &to_verilog_always_base(const exprt &expr)
672689
{
673-
PRECONDITION(expr.id() == ID_always);
674-
PRECONDITION(expr.operands().size() == 1);
675-
return static_cast<const verilog_alwayst &>(expr);
690+
unary_exprt::check(expr);
691+
return static_cast<const verilog_always_baset &>(expr);
676692
}
677693

678-
inline verilog_alwayst &to_verilog_always(exprt &expr)
694+
inline verilog_always_baset &to_verilog_always_base(exprt &expr)
679695
{
680-
PRECONDITION(expr.id() == ID_always);
681-
PRECONDITION(expr.operands().size() == 1);
682-
return static_cast<verilog_alwayst &>(expr);
696+
unary_exprt::check(expr);
697+
return static_cast<verilog_always_baset &>(expr);
683698
}
684699

685700
class verilog_declt:public verilog_statementt

src/verilog/verilog_interfaces.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,12 @@ void verilog_typecheckt::interface_module_item(
252252
interface_inst(to_verilog_inst(module_item));
253253
else if(module_item.id() == ID_inst_builtin)
254254
interface_inst(to_verilog_inst_builtin(module_item));
255-
else if(module_item.id()==ID_always)
256-
interface_statement(to_verilog_always(module_item).statement());
255+
else if(
256+
module_item.id() == ID_verilog_always ||
257+
module_item.id() == ID_verilog_always_comb ||
258+
module_item.id() == ID_verilog_always_ff ||
259+
module_item.id() == ID_verilog_always_latch)
260+
interface_statement(to_verilog_always_base(module_item).statement());
257261
else if(module_item.id()==ID_initial)
258262
interface_statement(to_verilog_initial(module_item).statement());
259263
else if(module_item.id()==ID_generate_block)

src/verilog/verilog_synthesis.cpp

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,7 @@ exprt verilog_synthesist::expand_function_call(const function_call_exprt &call)
164164
}
165165

166166
// check some restrictions
167-
if(construct!=constructt::INITIAL &&
168-
construct!=constructt::ALWAYS)
167+
if(construct == constructt::OTHER)
169168
{
170169
throw errort().with_location(call.source_location())
171170
<< "function call not allowed here";
@@ -366,17 +365,25 @@ void verilog_synthesist::assignment_rec(
366365
event_guard==event_guardt::NONE)
367366
{
368367
throw errort().with_location(lhs.source_location())
369-
<< "permanent assignment without event guard";
368+
<< "assignment in 'always' context without event guard";
369+
}
370+
371+
if(construct == constructt::ALWAYS_FF && event_guard == event_guardt::NONE)
372+
{
373+
throw errort().with_location(lhs.source_location())
374+
<< "assignment in 'always_ff' context without event guard";
370375
}
371376

372377
{
373378
event_guardt new_type;
374379

375-
if(construct==constructt::ALWAYS)
376-
new_type=event_guard;
377-
else
380+
if(construct == constructt::INITIAL)
378381
new_type=event_guardt::CLOCK;
379-
382+
else if(construct == constructt::ALWAYS_COMB)
383+
new_type = event_guardt::COMBINATIONAL;
384+
else
385+
new_type = event_guard;
386+
380387
assignmentt &assignment=assignments[symbol.name];
381388

382389
if(assignment.is_cycle_local)
@@ -968,11 +975,8 @@ void verilog_synthesist::instantiate_port(
968975
event_guard.add_source_location() = source_location;
969976
event_guard.body() = assignment;
970977

971-
verilog_alwayst always;
972-
always.add_source_location() = source_location;
973-
always.statement() = event_guard;
974-
975-
synth_always(always);
978+
verilog_always_baset always(ID_verilog_always, event_guard, source_location);
979+
synth_always_base(always);
976980
}
977981

978982
/*******************************************************************\
@@ -1340,7 +1344,7 @@ void verilog_synthesist::expand_module_instance(
13401344

13411345
/*******************************************************************\
13421346
1343-
Function: verilog_synthesist::synth_always
1347+
Function: verilog_synthesist::synth_always_base
13441348
13451349
Inputs:
13461350
@@ -1350,16 +1354,24 @@ Function: verilog_synthesist::synth_always
13501354
13511355
\*******************************************************************/
13521356

1353-
void verilog_synthesist::synth_always(
1354-
const verilog_alwayst &module_item)
1357+
void verilog_synthesist::synth_always_base(
1358+
const verilog_always_baset &module_item)
13551359
{
1356-
if(module_item.operands().size()!=1)
1360+
if(module_item.id() == ID_verilog_always)
1361+
construct = constructt::ALWAYS;
1362+
else if(module_item.id() == ID_verilog_always_comb)
1363+
construct = constructt::ALWAYS_COMB;
1364+
else if(module_item.id() == ID_verilog_always_ff)
1365+
construct = constructt::ALWAYS_FF;
1366+
else if(module_item.id() == ID_verilog_always_latch)
13571367
{
13581368
throw errort().with_location(module_item.source_location())
1359-
<< "always module item expected to have one operand";
1369+
<< "no synthesis support for always_latch";
13601370
}
1371+
else
1372+
DATA_INVARIANT(
1373+
false, "unknown always construct: " + module_item.id_string());
13611374

1362-
construct=constructt::ALWAYS;
13631375
event_guard=event_guardt::NONE;
13641376

13651377
value_mapt always_value_map;
@@ -1592,13 +1604,11 @@ void verilog_synthesist::synth_continuous_assign(
15921604

15931605
verilog_event_guardt event_guard;
15941606
event_guard.add_source_location()=module_item.source_location();
1595-
event_guard.body()=assignment;
1596-
1597-
verilog_alwayst always;
1598-
always.add_source_location()=module_item.source_location();
1599-
always.statement()=event_guard;
1607+
event_guard.body() = assignment;
16001608

1601-
synth_always(always);
1609+
verilog_always_baset always(
1610+
ID_verilog_always, event_guard, module_item.source_location());
1611+
synth_always_base(always);
16021612
}
16031613
}
16041614

@@ -1708,7 +1718,7 @@ Function: verilog_synthesist::synth_assign
17081718
\*******************************************************************/
17091719

17101720
void verilog_synthesist::synth_assign(
1711-
const exprt &statement,
1721+
const verilog_statementt &statement,
17121722
bool blocking)
17131723
{
17141724
if(statement.operands().size()!=2)
@@ -1717,8 +1727,7 @@ void verilog_synthesist::synth_assign(
17171727
<< "assign statement expected to have two operands";
17181728
}
17191729

1720-
if(construct!=constructt::ALWAYS &&
1721-
construct!=constructt::INITIAL)
1730+
if(construct == constructt::OTHER)
17221731
{
17231732
throw errort().with_location(statement.source_location())
17241733
<< "unexpected assignment statement";
@@ -2597,8 +2606,12 @@ void verilog_synthesist::synth_module_item(
25972606
module_item.id() == ID_parameter_override)
25982607
{
25992608
}
2600-
else if(module_item.id()==ID_always)
2601-
synth_always(to_verilog_always(module_item));
2609+
else if(
2610+
module_item.id() == ID_verilog_always ||
2611+
module_item.id() == ID_verilog_always_comb ||
2612+
module_item.id() == ID_verilog_always_ff ||
2613+
module_item.id() == ID_verilog_always_latch)
2614+
synth_always_base(to_verilog_always_base(module_item));
26022615
else if(module_item.id()==ID_initial)
26032616
synth_initial(to_verilog_initial(module_item));
26042617
else if(module_item.id()==ID_continuous_assign)
@@ -2819,7 +2832,9 @@ exprt verilog_synthesist::current_value(
28192832
return value; // done
28202833
}
28212834

2822-
if(construct==constructt::ALWAYS)
2835+
if(
2836+
construct == constructt::ALWAYS || construct == constructt::ALWAYS_FF ||
2837+
construct == constructt::ALWAYS_LATCH)
28232838
return symbol_expr(symbol, CURRENT);
28242839
else
28252840
{

src/verilog/verilog_synthesis_class.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,12 @@ class verilog_synthesist:
129129
{
130130
INITIAL,
131131
ALWAYS,
132+
ALWAYS_COMB,
133+
ALWAYS_FF,
134+
ALWAYS_LATCH,
132135
OTHER
133136
};
137+
134138
constructt construct;
135139
event_guardt event_guard;
136140

@@ -214,7 +218,7 @@ class verilog_synthesist:
214218
// module items
215219
virtual void convert_module_items(symbolt &);
216220
void synth_module_item(const verilog_module_itemt &, transt &);
217-
void synth_always(const verilog_alwayst &);
221+
void synth_always_base(const verilog_always_baset &);
218222
void synth_initial(const verilog_initialt &);
219223
void synth_assert_module_item(const verilog_module_itemt &);
220224
void synth_assume_module_item(const verilog_module_itemt &);
@@ -238,7 +242,7 @@ class verilog_synthesist:
238242
void synth_while(const verilog_whilet &);
239243
void synth_repeat(const verilog_repeatt &);
240244
void synth_function_call_or_task_enable(const verilog_function_callt &);
241-
void synth_assign(const exprt &, bool blocking);
245+
void synth_assign(const verilog_statementt &, bool blocking);
242246
void synth_assert(const verilog_assert_statementt &);
243247
void synth_assume(const verilog_assume_statementt &);
244248
void synth_prepostincdec(const verilog_statementt &);

0 commit comments

Comments
 (0)