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

165
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 pull_strength = { IVL_DR_PULL, IVL_DR_PULL };
static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG }; 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*> >; list<pform_port_t>*tmp = new list<pform_port_t>;
tmp->push_back(make_pair(lex_strings.make(id), expr)); tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr));
delete[]id; delete[]id;
return tmp; return tmp;
} }
static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string, PExpr*> >*tmp, static list<pform_port_t>* make_port_list(list<pform_port_t>*tmp,
char*id, PExpr*expr) 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; delete[]id;
return tmp; return tmp;
} }
@ -374,7 +374,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
char*text; char*text;
list<perm_string>*perm_strings; 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; 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 <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> register_variable_list net_variable_list event_variable_list
%type <perm_strings> list_of_identifiers loop_variables %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 %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> variable_dimension
%type <ranges> dimensions_opt dimensions %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 <gatetype> gatetype switchtype
%type <porttype> port_direction port_direction_opt %type <porttype> port_direction port_direction_opt
%type <vartype> bit_logic bit_logic_opt %type <vartype> bit_logic bit_logic_opt
@ -4057,14 +4057,21 @@ list_of_identifiers
; ;
list_of_port_identifiers list_of_port_identifiers
: IDENTIFIER : IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, 0); } { $$ = make_port_list($1, $2, 0); }
| IDENTIFIER '=' expression | list_of_port_identifiers ',' IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $3); } { $$ = make_port_list($1, $3, $4, 0); }
| list_of_port_identifiers ',' IDENTIFIER ;
{ $$ = make_port_list($1, $3, 0); }
| list_of_port_identifiers ',' IDENTIFIER '=' expression list_of_variable_port_identifiers
{ $$ = make_port_list($1, $3, $5); } : 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; 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>; input wire signed [h:l] <list>;
This creates the wire and sets the port type all at once. */ 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 ';' | attribute_list_opt port_direction net_type data_type_or_implicit list_of_port_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); } { 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 ';' | attribute_list_opt port_direction K_wreal list_of_port_identifiers ';'
{ list<pair<perm_string,PExpr*> >::const_iterator pp; { real_type_t*real_type = new real_type_t(real_type_t::REAL);
list<perm_string>*tmp = new list<perm_string>; pform_module_define_port(@2, $4, $2, NetNet::WIRE, real_type, $1);
for (pp = $6->begin(); pp != $6->end(); ++ pp ) { }
tmp->push_back((*pp).first);
/* 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, if (use_type == NetNet::NONE)
IVL_VT_NO_TYPE, $1, SR_BOTH); pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1);
for (pp = $6->begin(); pp != $6->end(); ++ pp ) { else
if ((*pp).second) { pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1);
pform_make_var_init(@2, (*pp).first, (*pp).second); }
}
| 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 ';' | attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';'
{ pform_makewire(@2, 0, true, $4, NetNet::WIRE, $2, { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
IVL_VT_REAL, $1, SR_BOTH); 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, | attribute_list_opt port_direction net_type data_type_or_implicit error ';'
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_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 port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';'
{ yyerror(@2, "error: Invalid variable list in port declaration."); { yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1; if ($1) delete $1;
if ($4) delete $4; 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; yyerrok;
} }
@ -5103,10 +5154,6 @@ net_type
| K_uwire { $$ = NetNet::UNRESOLVED_WIRE; } | K_uwire { $$ = NetNet::UNRESOLVED_WIRE; }
; ;
var_type
: K_reg { $$ = NetNet::REG; }
;
param_type param_type
: bit_logic_opt unsigned_signed_opt dimensions_opt : bit_logic_opt unsigned_signed_opt dimensions_opt
{ param_active_range = $3; { 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."); VLerror("error: name is not a valid net.");
return; return;
} }
// If this is not implicit ("implicit" meaning we don't // If this is not implicit ("implicit" meaning we don't
// know what the type is yet) then set the type now. // know what the type is yet) then set the type now.
if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) { 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::PortType port_kind,
NetNet::Type type, NetNet::Type type,
data_type_t*vtype, data_type_t*vtype,
list<named_pexpr_t>*attr) list<named_pexpr_t>*attr,
bool keep_attr)
{ {
struct_type_t*struct_type = 0; struct_type_t*struct_type = 0;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE; 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); 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); 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 * This function makes a single signal (a wire, a reg, etc) as
* requested by the parser. The name is unscoped, so I attach the * 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, void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names, list<pform_port_t>*ports,
list<pform_range_t>*range,
bool signed_flag,
NetNet::PortType pt, NetNet::PortType pt,
data_type_t*dt,
list<named_pexpr_t>*attr) list<named_pexpr_t>*attr)
{ {
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
for (list<perm_string>::iterator cur = names->begin() list<pform_range_t>*range = 0;
; cur != names->end() ; ++ cur ) { bool signed_flag = false;
perm_string txt = *cur; if (vector_type_t*vt = dynamic_cast<vector_type_t*> (dt)) {
pform_set_port_type(txt, pt, li.text, li.first_line); assert(vt->implicit_flag);
pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE, range = vt->pdims.get();
SR_PORT, attr); signed_flag = vt->signed_flag;
} else {
assert(dt == 0);
} }
delete names; bool have_init_expr = false;
delete range; 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; 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_check_timeunit_prec();
extern void pform_module_set_ports(vector<Module::port_t*>*); extern void pform_module_set_ports(vector<Module::port_t*>*);
/* This function is used to support the port definition in a /* These functions are used when we have a complete port definition, either
port_definition_list. In this case, we have everything needed to in an ansi style or non-ansi style declaration. In this case, we have
define the port, all in one place. */ everything needed to define the port, all in one place. */
extern void pform_module_define_port(const struct vlltype&li, extern void pform_module_define_port(const struct vlltype&li,
perm_string name, perm_string name,
NetNet::PortType, NetNet::PortType,
NetNet::Type type, NetNet::Type type,
data_type_t*vtype, 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); list<named_pexpr_t>*attr);
extern Module::port_t* pform_module_port_reference(perm_string name, 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, extern void pform_make_var_init(const struct vlltype&li,
perm_string name, PExpr*expr); perm_string name, PExpr*expr);
/* Look up the names of the wires, and set the port type, /* This function is used when we have an incomplete port definition in
i.e. input, output or inout. If the wire does not exist, create a non-ansi style declaration. Look up the names of the wires, and set
it. The second form takes a single name. */ 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, extern void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names, list<pform_port_t>*ports,
list<pform_range_t>*range,
bool signed_flag,
NetNet::PortType, NetNet::PortType,
data_type_t*dt,
list<named_pexpr_t>*attr); list<named_pexpr_t>*attr);
extern void pform_set_reg_idx(perm_string name, extern void pform_set_reg_idx(perm_string name,

View File

@ -1,7 +1,7 @@
#ifndef IVL_pform_types_H #ifndef IVL_pform_types_H
#define 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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; 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: * Semantic NOTES:
* - The SEL_BIT is a single expression. This might me a bit select * - The SEL_BIT is a single expression. This might me a bit select