Skip to content

Commit 362a6f7

Browse files
authored
Merge pull request #300 from diffblue/verilog-let
Verilog: let
2 parents 15b3d93 + 3a56045 commit 362a6f7

12 files changed

+183
-1
lines changed

regression/verilog/let/let1.desc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
let1.sv
3+
--bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring

regression/verilog/let/let1.sv

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// The "let construct" was introduced by SystemVerilog 1800-2009.
2+
3+
module main;
4+
5+
let some_let = 8'd123;
6+
p0: assert property (some_let == 123 && $bits(some_let) == 8);
7+
8+
// The standard doesn't say, but we allow these to be elaboration-time
9+
// constants.
10+
parameter some_parameter = some_let;
11+
12+
p1: assert property (some_parameter == 123 && $bits(some_parameter) == 8);
13+
14+
// May depend on state.
15+
wire some_wire;
16+
let some_let_eq_wire = some_wire;
17+
18+
p2: assert property (some_let_eq_wire == some_wire);
19+
20+
endmodule
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
let_ports1.sv
3+
--bound 0
4+
^file .* line 5: let ports not supported yet$
5+
^EXIT=2$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

regression/verilog/let/let_ports1.sv

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// The "let construct" was introduced by SystemVerilog 1800-2009.
2+
3+
module main;
4+
5+
let some_let_with_port(x) = x + 1;
6+
p0: assert property (some_let_with_port(1) == 2);
7+
8+
endmodule

src/hw_cbmc_irep_ids.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ IREP_ID_ONE(trireg)
114114
IREP_ID_ONE(local_parameter_decl)
115115
IREP_ID_ONE(parameter_decl)
116116
IREP_ID_ONE(set_genvars)
117+
IREP_ID_ONE(verilog_let)
118+
IREP_ID_ONE(verilog_untyped)
117119
IREP_ID_ONE(verilog_genvar)
118120
IREP_ID_ONE(verilog_shortreal)
119121
IREP_ID_ONE(verilog_real)

src/verilog/parser.y

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,11 @@ package_or_generate_item_declaration:
10571057
| class_declaration
10581058
| local_parameter_declaration ';'
10591059
| parameter_declaration ';'
1060+
/* The following rule is not in the standard.
1061+
However, Section 11.12 explicitly states
1062+
that let constructs may be declared in a
1063+
module/interface/program/checker etc. */
1064+
| let_declaration
10601065
;
10611066

10621067
// System Verilog standard 1800-2017
@@ -1897,6 +1902,7 @@ block_item_declaration:
18971902
attribute_instance_brace data_declaration { $$=$2; }
18981903
| attribute_instance_brace local_parameter_declaration ';' { $$=$2; }
18991904
| attribute_instance_brace parameter_declaration ';' { $$=$2; }
1905+
| attribute_instance_brace let_declaration { $$=$2; }
19001906
;
19011907

19021908
// System Verilog standard 1800-2017
@@ -2014,6 +2020,59 @@ expression_or_dist:
20142020
expression
20152021
;
20162022

2023+
// System Verilog standard 1800-2017
2024+
// A.2.12 Let declarations
2025+
2026+
let_declaration:
2027+
TOK_LET let_identifier let_port_list_paren_opt '=' expression ';'
2028+
{
2029+
init($$, ID_verilog_let);
2030+
// These have one declarator exactly.
2031+
stack_expr($2).id(ID_declarator);
2032+
addswap($2, ID_type, $3);
2033+
addswap($2, ID_value, $5);
2034+
mto($$, $2);
2035+
}
2036+
;
2037+
2038+
let_identifier: identifier;
2039+
2040+
let_port_list_paren_opt:
2041+
/* Optional */
2042+
{ init($$, ID_nil); }
2043+
| '(' let_port_list_opt ')'
2044+
{ $$ = $2; }
2045+
;
2046+
2047+
let_port_list_opt:
2048+
/* Optional */
2049+
{ init($$, ID_nil); }
2050+
| let_port_list
2051+
;
2052+
2053+
let_port_list:
2054+
let_port_item
2055+
{ init($$); mts($$, $1); }
2056+
| let_port_list ',' let_port_item
2057+
{ $$ = $1; mts($$, $3); }
2058+
;
2059+
2060+
let_port_item:
2061+
attribute_instance_brace let_formal_type formal_port_identifier
2062+
variable_dimension_brace let_port_initializer_opt
2063+
;
2064+
2065+
let_port_initializer_opt:
2066+
/* Optional */
2067+
| '=' expression
2068+
;
2069+
2070+
let_formal_type:
2071+
data_type_or_implicit
2072+
| TOK_UNTYPED
2073+
{ init($$, ID_verilog_untyped); }
2074+
;
2075+
20172076
// System Verilog standard 1800-2017
20182077
// A.3.1 Primitive instantiation and instances
20192078

@@ -3236,6 +3295,8 @@ class_identifier: TOK_NON_TYPE_IDENTIFIER;
32363295
32373296
constraint_identifier: TOK_NON_TYPE_IDENTIFIER;
32383297
3298+
formal_port_identifier: identifier;
3299+
32393300
genvar_identifier: identifier;
32403301
32413302
hierarchical_parameter_identifier: hierarchical_identifier

src/verilog/verilog_elaborate.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,39 @@ void verilog_typecheckt::collect_symbols(const verilog_declt &decl)
592592
}
593593
}
594594

595+
#include <iostream>
596+
597+
void verilog_typecheckt::collect_symbols(const verilog_lett &let)
598+
{
599+
// These have one declarator.
600+
auto &declarator = let.declarator();
601+
602+
// We don't currently do let ports
603+
if(declarator.type().is_not_nil())
604+
{
605+
throw errort().with_location(let.source_location())
606+
<< "let ports not supported yet";
607+
}
608+
609+
const irep_idt &base_name = declarator.base_name();
610+
irep_idt identifier = hierarchical_identifier(base_name);
611+
612+
// The range type is always derived from the type of the
613+
// value expression.
614+
auto type = to_be_elaborated_typet(derive_from_value_typet());
615+
616+
// add the symbol
617+
symbolt new_symbol(identifier, type, mode);
618+
619+
new_symbol.module = module_identifier;
620+
new_symbol.is_macro = true;
621+
new_symbol.value = declarator.value();
622+
new_symbol.base_name = base_name;
623+
new_symbol.pretty_name = strip_verilog_prefix(new_symbol.name);
624+
625+
add_symbol(std::move(new_symbol));
626+
}
627+
595628
void verilog_typecheckt::collect_symbols(const verilog_statementt &statement)
596629
{
597630
if(statement.id() == ID_assert || statement.id() == ID_assume)
@@ -729,6 +762,10 @@ void verilog_typecheckt::collect_symbols(
729762
{
730763
collect_symbols(to_verilog_set_genvars(module_item).module_item());
731764
}
765+
else if(module_item.id() == ID_verilog_let)
766+
{
767+
collect_symbols(to_verilog_let(module_item));
768+
}
732769
else
733770
DATA_INVARIANT(false, "unexpected module item: " + module_item.id_string());
734771
}

src/verilog/verilog_expr.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,32 @@ to_verilog_local_parameter_decl(irept &irep)
512512
return static_cast<verilog_local_parameter_declt &>(irep);
513513
}
514514

515+
class verilog_lett : public verilog_module_itemt
516+
{
517+
public:
518+
// These have a single declarator.
519+
using declaratort = verilog_parameter_declt::declaratort;
520+
521+
const declaratort &declarator() const
522+
{
523+
return static_cast<const declaratort &>(op0());
524+
}
525+
};
526+
527+
inline const verilog_lett &to_verilog_let(const exprt &expr)
528+
{
529+
PRECONDITION(expr.id() == ID_verilog_let);
530+
validate_operands(expr, 1, "verilog_let must have 1 operand");
531+
return static_cast<const verilog_lett &>(expr);
532+
}
533+
534+
inline verilog_lett &to_verilog_let(exprt &expr)
535+
{
536+
PRECONDITION(expr.id() == ID_verilog_let);
537+
validate_operands(expr, 1, "verilog_let must have 1 operand");
538+
return static_cast<verilog_lett &>(expr);
539+
}
540+
515541
class verilog_inst_baset : public verilog_module_itemt
516542
{
517543
public:

src/verilog/verilog_interfaces.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ void verilog_typecheckt::interface_module_item(
274274
{
275275
// does not yield symbol
276276
}
277+
else if(module_item.id() == ID_verilog_let)
278+
{
279+
// already done during constant elaboration
280+
}
277281
else
278282
{
279283
DATA_INVARIANT(false, "unexpected module item: " + module_item.id_string());

src/verilog/verilog_synthesis.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2635,6 +2635,10 @@ void verilog_synthesist::synth_module_item(
26352635
{
26362636
// ignore for now
26372637
}
2638+
else if(module_item.id() == ID_verilog_let)
2639+
{
2640+
// done already
2641+
}
26382642
else
26392643
{
26402644
throw errort().with_location(module_item.source_location())

0 commit comments

Comments
 (0)