Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix for br974 - support SV types in non-ansi port declarations.
  • Loading branch information
martinwhitaker committed Apr 4, 2016
1 parent 9f88b26 commit 6ba2bee
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 78 deletions.
157 changes: 102 additions & 55 deletions parse.y
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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); }
;


Expand Down Expand Up @@ -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);
| 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);
}

/* 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;
}
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);
}
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);
}

| 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;
}
delete $6;
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 port_direction K_wreal list_of_identifiers ';'
{ pform_makewire(@2, 0, true, $4, NetNet::WIRE, $2,
IVL_VT_REAL, $1, SR_BOTH);
| 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);
}

/* 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 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;
yyerrok;
}

| 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_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_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_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 port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';'
| attribute_list_opt K_output 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;
if ($3) delete $3;
yyerrok;
}

Expand Down Expand Up @@ -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;
Expand Down
84 changes: 71 additions & 13 deletions pform.cc
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

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 names;
delete range;
delete ports;
delete dt;
delete attr;
}

Expand Down
25 changes: 16 additions & 9 deletions pform.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 6ba2bee

Please sign in to comment.