Fix for br974 - support SV types in non-ansi port declarations.

This commit is contained in:
Martin Whitaker 2016-04-04 20:40:30 +01:00
parent 9f88b26a67
commit 6ba2bee977
4 changed files with 209 additions and 82 deletions

161
parse.y
View File

@ -135,17 +135,17 @@ static list<named_pexpr_t>*attributes_in_context = 0;
static const struct str_pair_t pull_strength = { IVL_DR_PULL, IVL_DR_PULL };
static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG };
static list<pair<perm_string,PExpr*> >* make_port_list(char*id, PExpr*expr)
static list<pform_port_t>* make_port_list(char*id, list<pform_range_t>*udims, PExpr*expr)
{
list<pair<perm_string,PExpr*> >*tmp = new list<pair<perm_string,PExpr*> >;
tmp->push_back(make_pair(lex_strings.make(id), expr));
list<pform_port_t>*tmp = new list<pform_port_t>;
tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr));
delete[]id;
return tmp;
}
static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string, PExpr*> >*tmp,
char*id, PExpr*expr)
static list<pform_port_t>* make_port_list(list<pform_port_t>*tmp,
char*id, list<pform_range_t>*udims, PExpr*expr)
{
tmp->push_back(make_pair(lex_strings.make(id), expr));
tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr));
delete[]id;
return tmp;
}
@ -374,7 +374,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
char*text;
list<perm_string>*perm_strings;
list<pair<perm_string,PExpr*> >*port_list;
list<pform_port_t>*port_list;
vector<pform_tf_port_t>* tf_ports;
@ -582,7 +582,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <text> register_variable net_variable event_variable endlabel_opt class_declaration_endlabel_opt
%type <perm_strings> register_variable_list net_variable_list event_variable_list
%type <perm_strings> list_of_identifiers loop_variables
%type <port_list> list_of_port_identifiers
%type <port_list> list_of_port_identifiers list_of_variable_port_identifiers
%type <net_decl_assign> net_decl_assign net_decl_assigns
@ -642,7 +642,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <ranges> variable_dimension
%type <ranges> dimensions_opt dimensions
%type <nettype> net_type var_type net_type_opt
%type <nettype> net_type net_type_opt
%type <gatetype> gatetype switchtype
%type <porttype> port_direction port_direction_opt
%type <vartype> bit_logic bit_logic_opt
@ -4057,14 +4057,21 @@ list_of_identifiers
;
list_of_port_identifiers
: IDENTIFIER
{ $$ = make_port_list($1, 0); }
| IDENTIFIER '=' expression
{ $$ = make_port_list($1, $3); }
| list_of_port_identifiers ',' IDENTIFIER
{ $$ = make_port_list($1, $3, 0); }
| list_of_port_identifiers ',' IDENTIFIER '=' expression
{ $$ = make_port_list($1, $3, $5); }
: IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $2, 0); }
| list_of_port_identifiers ',' IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $3, $4, 0); }
;
list_of_variable_port_identifiers
: IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $2, 0); }
| IDENTIFIER dimensions_opt '=' expression
{ $$ = make_port_list($1, $2, $4); }
| list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $3, $4, 0); }
| list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt '=' expression
{ $$ = make_port_list($1, $3, $4, $6); }
;
@ -4652,58 +4659,102 @@ module_item
delete $4;
}
| attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt list_of_identifiers ';'
{ pform_set_port_type(@2, $6, $4, $3, $2, $1); }
/* The next two rules handle Verilog 2001 statements of the form:
/* The next two rules handle port declarations that include a net type, e.g.
input wire signed [h:l] <list>;
This creates the wire and sets the port type all at once. */
| attribute_list_opt port_direction net_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); }
| attribute_list_opt port_direction net_type data_type_or_implicit list_of_port_identifiers ';'
{ pform_module_define_port(@2, $5, $2, $3, $4, $1); }
| attribute_list_opt K_output var_type unsigned_signed_opt dimensions_opt list_of_port_identifiers ';'
{ list<pair<perm_string,PExpr*> >::const_iterator pp;
list<perm_string>*tmp = new list<perm_string>;
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
tmp->push_back((*pp).first);
}
pform_makewire(@2, $5, $4, tmp, $3, NetNet::POUTPUT,
IVL_VT_NO_TYPE, $1, SR_BOTH);
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
if ((*pp).second) {
pform_make_var_init(@2, (*pp).first, (*pp).second);
}
}
delete $6;
| attribute_list_opt port_direction K_wreal list_of_port_identifiers ';'
{ real_type_t*real_type = new real_type_t(real_type_t::REAL);
pform_module_define_port(@2, $4, $2, NetNet::WIRE, real_type, $1);
}
| attribute_list_opt port_direction K_wreal list_of_identifiers ';'
{ pform_makewire(@2, 0, true, $4, NetNet::WIRE, $2,
IVL_VT_REAL, $1, SR_BOTH);
/* The next three rules handle port declarations that include a variable
type, e.g.
output reg signed [h:l] <list>;
and also handle incomplete port declarations, e.g.
input signed [h:l] <list>;
*/
| attribute_list_opt K_inout data_type_or_implicit list_of_port_identifiers ';'
{ NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($3)) {
if (dtype->implicit_flag)
use_type = NetNet::NONE;
}
if (use_type == NetNet::NONE)
pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1);
else
pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1);
}
/* var_type declaration (reg variables) cannot be input or output,
because the port declaration implies an external driver, which
cannot be attached to a reg. These rules catch that error early. */
| attribute_list_opt K_input var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINPUT,
IVL_VT_NO_TYPE, $1);
yyerror(@3, "error: reg variables cannot be inputs.");
| attribute_list_opt K_input data_type_or_implicit list_of_port_identifiers ';'
{ NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($3)) {
if (dtype->implicit_flag)
use_type = NetNet::NONE;
}
if (use_type == NetNet::NONE)
pform_set_port_type(@2, $4, NetNet::PINPUT, $3, $1);
else
pform_module_define_port(@2, $4, NetNet::PINPUT, use_type, $3, $1);
}
| attribute_list_opt K_inout var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINOUT,
IVL_VT_NO_TYPE, $1);
yyerror(@3, "error: reg variables cannot be inouts.");
| attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';'
{ NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($3)) {
if (dtype->implicit_flag)
use_type = NetNet::NONE;
else if (dtype->reg_flag)
use_type = NetNet::REG;
else
use_type = NetNet::IMPLICIT_REG;
// The SystemVerilog types that can show up as
// output ports are implicitly (on the inside)
// variables because "reg" is not valid syntax
// here.
} else if (dynamic_cast<atom2_type_t*> ($3)) {
use_type = NetNet::IMPLICIT_REG;
} else if (dynamic_cast<struct_type_t*> ($3)) {
use_type = NetNet::IMPLICIT_REG;
} else if (enum_type_t*etype = dynamic_cast<enum_type_t*> ($3)) {
if(etype->base_type == IVL_VT_LOGIC)
use_type = NetNet::IMPLICIT_REG;
}
if (use_type == NetNet::NONE)
pform_set_port_type(@2, $4, NetNet::POUTPUT, $3, $1);
else
pform_module_define_port(@2, $4, NetNet::POUTPUT, use_type, $3, $1);
}
| attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';'
| attribute_list_opt port_direction net_type data_type_or_implicit error ';'
{ yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1;
if ($4) delete $4;
if ($5) delete $5;
yyerrok;
}
| attribute_list_opt K_inout data_type_or_implicit error ';'
{ yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1;
if ($3) delete $3;
yyerrok;
}
| attribute_list_opt K_input data_type_or_implicit error ';'
{ yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1;
if ($3) delete $3;
yyerrok;
}
| attribute_list_opt K_output data_type_or_implicit error ';'
{ yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1;
if ($3) delete $3;
yyerrok;
}
@ -5103,10 +5154,6 @@ net_type
| K_uwire { $$ = NetNet::UNRESOLVED_WIRE; }
;
var_type
: K_reg { $$ = NetNet::REG; }
;
param_type
: bit_logic_opt unsigned_signed_opt dimensions_opt
{ param_active_range = $3;

View File

@ -1944,6 +1944,7 @@ static void pform_set_net_range(perm_string name,
VLerror("error: name is not a valid net.");
return;
}
// If this is not implicit ("implicit" meaning we don't
// know what the type is yet) then set the type now.
if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) {
@ -2349,7 +2350,8 @@ void pform_module_define_port(const struct vlltype&li,
NetNet::PortType port_kind,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr)
list<named_pexpr_t>*attr,
bool keep_attr)
{
struct_type_t*struct_type = 0;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
@ -2438,10 +2440,37 @@ void pform_module_define_port(const struct vlltype&li,
cur->set_unpacked_idx(*urange);
}
pform_bind_attributes(cur->attributes, attr);
pform_bind_attributes(cur->attributes, attr, keep_attr);
pform_put_wire_in_scope(name, cur);
}
void pform_module_define_port(const struct vlltype&li,
list<pform_port_t>*ports,
NetNet::PortType port_kind,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr)
{
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
data_type_t*use_type = vtype;
if (cur->udims)
use_type = new uarray_type_t(vtype, cur->udims);
pform_module_define_port(li, cur->name, port_kind, type, use_type,
attr, true);
if (cur->udims)
delete use_type;
if (cur->expr)
pform_make_var_init(li, cur->name, cur->expr);
}
delete ports;
delete attr;
}
/*
* This function makes a single signal (a wire, a reg, etc) as
* requested by the parser. The name is unscoped, so I attach the
@ -3246,24 +3275,53 @@ static void pform_set_port_type(perm_string name, NetNet::PortType pt,
}
void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names,
list<pform_range_t>*range,
bool signed_flag,
list<pform_port_t>*ports,
NetNet::PortType pt,
data_type_t*dt,
list<named_pexpr_t>*attr)
{
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
perm_string txt = *cur;
pform_set_port_type(txt, pt, li.text, li.first_line);
pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE,
SR_PORT, attr);
list<pform_range_t>*range = 0;
bool signed_flag = false;
if (vector_type_t*vt = dynamic_cast<vector_type_t*> (dt)) {
assert(vt->implicit_flag);
range = vt->pdims.get();
signed_flag = vt->signed_flag;
} else {
assert(dt == 0);
}
delete names;
delete range;
bool have_init_expr = false;
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
pform_set_port_type(cur->name, pt, li.text, li.first_line);
pform_set_net_range(cur->name, NetNet::NONE, range, signed_flag,
IVL_VT_NO_TYPE, SR_PORT, attr);
if (cur->udims) {
cerr << li.text << ":" << li.first_line << ": warning: "
<< "Array dimensions in incomplete port declarations "
<< "are currently ignored." << endl;
cerr << li.text << ":" << li.first_line << ": : "
<< "The dimensions specified in the net or variable "
<< "declaration will be used." << endl;
delete cur->udims;
}
if (cur->expr) {
have_init_expr = true;
delete cur->expr;
}
}
if (have_init_expr) {
cerr << li.text << ":" << li.first_line << ": error: "
<< "Incomplete port declarations cannot be initialized."
<< endl;
error_count += 1;
}
delete ports;
delete dt;
delete attr;
}

25
pform.h
View File

@ -168,14 +168,21 @@ extern void pform_startmodule(const struct vlltype&loc, const char*name,
extern void pform_check_timeunit_prec();
extern void pform_module_set_ports(vector<Module::port_t*>*);
/* This function is used to support the port definition in a
port_definition_list. In this case, we have everything needed to
define the port, all in one place. */
/* These functions are used when we have a complete port definition, either
in an ansi style or non-ansi style declaration. In this case, we have
everything needed to define the port, all in one place. */
extern void pform_module_define_port(const struct vlltype&li,
perm_string name,
NetNet::PortType,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr,
bool keep_attr =false);
extern void pform_module_define_port(const struct vlltype&li,
list<pform_port_t>*ports,
NetNet::PortType,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr);
extern Module::port_t* pform_module_port_reference(perm_string name,
@ -364,14 +371,14 @@ extern void pform_makewire(const struct vlltype&li,
extern void pform_make_var_init(const struct vlltype&li,
perm_string name, PExpr*expr);
/* Look up the names of the wires, and set the port type,
i.e. input, output or inout. If the wire does not exist, create
it. The second form takes a single name. */
/* This function is used when we have an incomplete port definition in
a non-ansi style declaration. Look up the names of the wires, and set
the port type, i.e. input, output or inout, and, if specified, the
range and signedness. If the wire does not exist, create it. */
extern void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names,
list<pform_range_t>*range,
bool signed_flag,
list<pform_port_t>*ports,
NetNet::PortType,
data_type_t*dt,
list<named_pexpr_t>*attr);
extern void pform_set_reg_idx(perm_string name,

View File

@ -1,7 +1,7 @@
#ifndef IVL_pform_types_H
#define IVL_pform_types_H
/*
* Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-2016 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -72,6 +72,21 @@ typedef named<PExpr*> named_pexpr_t;
*/
typedef std::pair<PExpr*,PExpr*> pform_range_t;
/*
* The pform_port_t holds the name and optional unpacked dimensions
* and initialization expression for a single port in a list of port
* declarations.
*/
struct pform_port_t {
pform_port_t(perm_string n, list<pform_range_t>*ud, PExpr*e)
: name(n), udims(ud), expr(e) { }
~pform_port_t() { }
perm_string name;
list<pform_range_t>*udims;
PExpr*expr;
};
/*
* Semantic NOTES:
* - The SEL_BIT is a single expression. This might me a bit select