Support SystemVerilog net declaration assignments
SystemVerilog allows initialized and uninitialized net declaration entries to be mixed in the same declaration, e.g. `wire x, y = 1'b1`. In Verilog, either all nets need to have an initializer or non can have one. In addition SystemVerilog also allows assignments to arrays of wires during declaration. E.g. `wire a[3:0] = b;` Currently there are two different rules for net declarations, one for each of the Verilog variants. Combine these into a single rule to support SystemVerilog mixed declarations as well as the assignment to array nets. When running in Verilog mode still reject mixed initialized and uninitialized with a check after the parsing. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
e7934d5e66
commit
3495889112
128
parse.y
128
parse.y
|
|
@ -101,6 +101,29 @@ static pform_name_t* pform_create_super(void)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void check_net_decl_assigns(const struct vlltype&loc,
|
||||
const std::list<decl_assignment_t*>*assign_list)
|
||||
{
|
||||
if (gn_system_verilog())
|
||||
return;
|
||||
|
||||
bool has_initializer = false;
|
||||
bool has_no_initializer = false;
|
||||
|
||||
for (const auto*cur : *assign_list) {
|
||||
if (cur->expr)
|
||||
has_initializer = true;
|
||||
else
|
||||
has_no_initializer = true;
|
||||
|
||||
if (has_initializer && has_no_initializer) {
|
||||
pform_requires_sv(loc, "Mixing initialized and uninitialized "
|
||||
"net declaration entries");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The rules sometimes push attributes into a global context where
|
||||
sub-rules may grab them. This makes parser rules a little easier to
|
||||
write in some cases. */
|
||||
|
|
@ -720,9 +743,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <wires> udp_port_decl udp_port_decls
|
||||
%type <statement> udp_initial udp_init_opt
|
||||
|
||||
%type <wire> net_variable
|
||||
%type <wires> net_variable_list
|
||||
|
||||
%type <text> event_variable label_opt class_declaration_endlabel_opt
|
||||
%type <text> block_identifier_opt
|
||||
%type <text> identifier_name
|
||||
|
|
@ -731,9 +751,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <perm_strings> loop_variables
|
||||
%type <port_list> list_of_port_identifiers list_of_variable_port_identifiers
|
||||
|
||||
%type <decl_assignments> net_decl_assigns
|
||||
%type <decl_assignment> net_decl_assign
|
||||
|
||||
%type <mport> port port_opt port_reference port_reference_list
|
||||
%type <mport> port_declaration
|
||||
%type <mports> list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign
|
||||
|
|
@ -780,7 +797,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <expr> assignment_pattern expression expression_opt expr_mintypmax
|
||||
%type <expr> expr_primary_or_typename expr_primary
|
||||
%type <expr> class_new dynamic_array_new
|
||||
%type <expr> var_decl_initializer_opt initializer_opt
|
||||
%type <expr> net_decl_initializer_opt var_decl_initializer_opt initializer_opt
|
||||
%type <expr> inc_or_dec_expression inside_expression lpvalue
|
||||
%type <expr> branch_probe_expression streaming_concatenation
|
||||
%type <expr> delay_value delay_value_simple
|
||||
|
|
@ -788,8 +805,8 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <exprs> expression_list_with_nuls expression_list_proper
|
||||
%type <exprs> cont_assign cont_assign_list
|
||||
|
||||
%type <decl_assignment> variable_decl_assignment
|
||||
%type <decl_assignments> list_of_variable_decl_assignments
|
||||
%type <decl_assignment> net_decl_assign variable_decl_assignment
|
||||
%type <decl_assignments> net_decl_assigns list_of_variable_decl_assignments
|
||||
|
||||
%type <data_type> data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void
|
||||
%type <data_type> data_type_or_implicit_no_opt
|
||||
|
|
@ -4983,70 +5000,30 @@ module_item
|
|||
/* Modules can contain further sub-module definitions. */
|
||||
: module
|
||||
|
||||
| attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';'
|
||||
|
||||
{ data_type_t*data_type = $3;
|
||||
pform_check_net_data_type(@2, $2, $3);
|
||||
if (data_type == 0) {
|
||||
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
|
||||
FILE_NAME(data_type, @2);
|
||||
}
|
||||
pform_set_data_type(@2, data_type, $5, $2, $1);
|
||||
if ($4 != 0) {
|
||||
yyerror(@2, "sorry: Net delays not supported.");
|
||||
delete $4;
|
||||
}
|
||||
delete $1;
|
||||
}
|
||||
|
||||
| attribute_list_opt K_wreal delay3 net_variable_list ';'
|
||||
{ real_type_t*tmpt = new real_type_t(real_type_t::REAL);
|
||||
pform_set_data_type(@2, tmpt, $4, NetNet::WIRE, $1);
|
||||
if ($3 != 0) {
|
||||
yyerror(@3, "sorry: Net delays not supported.");
|
||||
delete $3;
|
||||
}
|
||||
delete $1;
|
||||
}
|
||||
|
||||
| attribute_list_opt K_wreal net_variable_list ';'
|
||||
{ real_type_t*tmpt = new real_type_t(real_type_t::REAL);
|
||||
pform_set_data_type(@2, tmpt, $3, NetNet::WIRE, $1);
|
||||
delete $1;
|
||||
}
|
||||
|
||||
/* Very similar to the rule above, but this takes a list of
|
||||
net_decl_assigns, which are <name> = <expr> assignment
|
||||
declarations. */
|
||||
|
||||
| attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';'
|
||||
{ data_type_t*data_type = $3;
|
||||
pform_check_net_data_type(@2, $2, $3);
|
||||
if (data_type == 0) {
|
||||
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
|
||||
FILE_NAME(data_type, @2);
|
||||
}
|
||||
pform_makewire(@2, $4, str_strength, $5, $2, data_type, $1);
|
||||
delete $1;
|
||||
}
|
||||
|
||||
/* This form doesn't have the range, but does have strengths. This
|
||||
gives strength to the assignment drivers. */
|
||||
|
||||
| attribute_list_opt net_type drive_strength data_type_or_implicit net_decl_assigns ';'
|
||||
| attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3_opt net_decl_assigns ';'
|
||||
{ data_type_t*data_type = $4;
|
||||
pform_check_net_data_type(@2, $2, $4);
|
||||
check_net_decl_assigns(@6, $6);
|
||||
if (data_type == 0) {
|
||||
data_type = new vector_type_t(IVL_VT_LOGIC, false, 0);
|
||||
FILE_NAME(data_type, @2);
|
||||
}
|
||||
pform_makewire(@2, 0, $3, $5, $2, data_type, $1);
|
||||
pform_makewire(@2, $5, $3, $6, $2, data_type, $1);
|
||||
delete $1;
|
||||
}
|
||||
|
||||
| attribute_list_opt K_wreal net_decl_assigns ';'
|
||||
| attribute_list_opt K_wreal delay3_opt net_decl_assigns ';'
|
||||
{ real_type_t*data_type = new real_type_t(real_type_t::REAL);
|
||||
pform_makewire(@2, 0, str_strength, $3, NetNet::WIRE, data_type, $1);
|
||||
check_net_decl_assigns(@4, $4);
|
||||
if ($3) {
|
||||
yyerror(@2, "error: wreal net does not support delay.");
|
||||
delete $3;
|
||||
}
|
||||
pform_makewire(@2, 0, str_strength, $4, NetNet::WIRE, data_type, $1);
|
||||
delete $1;
|
||||
}
|
||||
|
||||
|
|
@ -5550,10 +5527,21 @@ generate_block
|
|||
Note that the continuous assignment statement is generated as a
|
||||
side effect, and all I pass up is the name of the l-value. */
|
||||
|
||||
net_decl_initializer_opt
|
||||
: '=' expression { $$ = $2; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
net_decl_assign
|
||||
: IDENTIFIER '=' expression
|
||||
: IDENTIFIER dimensions_opt net_decl_initializer_opt
|
||||
{ decl_assignment_t*tmp = new decl_assignment_t;
|
||||
tmp->name = { lex_strings.make($1), @1.lexical_pos };
|
||||
if ($2) {
|
||||
tmp->index = *$2;
|
||||
if ($3)
|
||||
pform_requires_sv(@$, "Assignment of net array during declaration");
|
||||
delete $2;
|
||||
}
|
||||
tmp->expr.reset($3);
|
||||
delete[]$1;
|
||||
$$ = tmp;
|
||||
|
|
@ -6026,26 +6014,6 @@ dimensions
|
|||
}
|
||||
;
|
||||
|
||||
net_variable
|
||||
: IDENTIFIER dimensions_opt
|
||||
{ pform_ident_t name = { lex_strings.make($1), @1.lexical_pos };
|
||||
$$ = pform_makewire(@1, name, NetNet::IMPLICIT, $2);
|
||||
delete [] $1;
|
||||
}
|
||||
;
|
||||
|
||||
net_variable_list
|
||||
: net_variable
|
||||
{ std::vector<PWire*> *tmp = new std::vector<PWire*>;
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| net_variable_list ',' net_variable
|
||||
{ $1->push_back($3);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
event_variable
|
||||
: IDENTIFIER dimensions_opt
|
||||
{ if ($2) {
|
||||
|
|
|
|||
12
pform.cc
12
pform.cc
|
|
@ -49,6 +49,10 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type,
|
||||
std::vector<PWire*> *wires, NetNet::Type net_type,
|
||||
list<named_pexpr_t>*attr, bool is_const = false);
|
||||
|
||||
/*
|
||||
* The "// synthesis translate_on/off" meta-comments cause this flag
|
||||
* to be turned off or on. The pform_make_behavior and similar
|
||||
|
|
@ -2724,6 +2728,8 @@ void pform_makewire(const struct vlltype&li,
|
|||
PGAssign*ass = pform_make_pgassign(lval, expr, delay, str);
|
||||
FILE_NAME(ass, li);
|
||||
}
|
||||
} else if (delay) {
|
||||
VLerror(li, "sorry: net delays not supported.");
|
||||
}
|
||||
delete first;
|
||||
}
|
||||
|
|
@ -3272,9 +3278,9 @@ void pform_set_port_type(const struct vlltype&li,
|
|||
* This function detects the derived class for the given type and
|
||||
* dispatches the type to the proper subtype function.
|
||||
*/
|
||||
void pform_set_data_type(const struct vlltype&li, data_type_t*data_type,
|
||||
std::vector<PWire*> *wires, NetNet::Type net_type,
|
||||
list<named_pexpr_t>*attr, bool is_const)
|
||||
static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type,
|
||||
std::vector<PWire*> *wires, NetNet::Type net_type,
|
||||
list<named_pexpr_t>*attr, bool is_const)
|
||||
{
|
||||
if (data_type == 0) {
|
||||
VLerror(li, "internal error: data_type==0.");
|
||||
|
|
|
|||
7
pform.h
7
pform.h
|
|
@ -384,13 +384,6 @@ extern void pform_set_port_type(const struct vlltype&li,
|
|||
data_type_t*dt,
|
||||
std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_data_type(const struct vlltype&li,
|
||||
data_type_t *data_type,
|
||||
std::vector<PWire*> *wires,
|
||||
NetNet::Type net_type,
|
||||
std::list<named_pexpr_t>*attr,
|
||||
bool is_const = false);
|
||||
|
||||
extern void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*addr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue