Fix for br974 - support SV types in non-ansi port declarations.
This commit is contained in:
parent
9f88b26a67
commit
6ba2bee977
165
parse.y
165
parse.y
|
|
@ -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);
|
||||
| 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 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 ';'
|
||||
| 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;
|
||||
|
|
|
|||
84
pform.cc
84
pform.cc
|
|
@ -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
25
pform.h
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue