diff --git a/Makefile.in b/Makefile.in index 3abafbe55..ba3663735 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,10 +107,10 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ load_module.o netlist.o netmisc.o net_analog.o net_assign.o net_design.o \ - netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ + netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ - pform_disciplines.o pform_dump.o pform_types.o \ + pform_disciplines.o pform_dump.o pform_struct_type.o pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \ PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ diff --git a/PWire.cc b/PWire.cc index 6187528ca..a5d5407a3 100644 --- a/PWire.cc +++ b/PWire.cc @@ -30,7 +30,8 @@ PWire::PWire(perm_string n, signed_(false), isint_(false), port_msb_(0), port_lsb_(0), port_set_(false), net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), - error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), discipline_(0) + error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0), + discipline_(0) { if (t == NetNet::INTEGER) { type_ = NetNet::REG; @@ -217,9 +218,17 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) void PWire::set_enumeration(enum_type_t*enum_type) { assert(enum_type_ == 0); + assert(struct_type_ == 0); enum_type_ = enum_type; } +void PWire::set_struct_type(struct_type_t*type) +{ + assert(enum_type_ == 0); + assert(struct_type_ == 0); + struct_type_ = type; +} + void PWire::set_discipline(ivl_discipline_t d) { assert(discipline_ == 0); diff --git a/PWire.h b/PWire.h index 680593edb..96f1b4964 100644 --- a/PWire.h +++ b/PWire.h @@ -80,6 +80,7 @@ class PWire : public LineInfo { void set_memory_idx(PExpr*ldx, PExpr*rdx); void set_enumeration(enum_type_t*enum_type); + void set_struct_type(struct_type_t*type); void set_discipline(ivl_discipline_t); ivl_discipline_t get_discipline(void) const; @@ -116,6 +117,7 @@ class PWire : public LineInfo { PExpr*ridx_; enum_type_t*enum_type_; + struct_type_t*struct_type_; ivl_discipline_t discipline_; diff --git a/elab_expr.cc b/elab_expr.cc index 42ef38108..b3d3458d5 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1418,6 +1418,15 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, return sys_expr; } +static NetExpr* check_for_struct_members(const LineInfo*li, + Design*des, NetScope*scope, + NetNet*net, perm_string method_name) +{ + cerr << li->get_fileline() << ": sorry: structures not supported here." << endl; + des->errors += 1; + return 0; +} + NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { @@ -1456,8 +1465,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, // enumeration? If so then check to see if this is an // enumeration method call. if (net != 0) { - netenum_t*netenum = net->enumeration(); - if (netenum) { + if (netenum_t*netenum = net->enumeration()) { // We may need the net expression for the // enumeration variable so get it. NetESignal*expr = new NetESignal(net); @@ -1472,6 +1480,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, expr_wid, tmp, parms_.size()); } + } } @@ -2289,8 +2298,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // enumeration? If so then check to see if this is an // enumeration method call. if (net != 0) { - netenum_t*netenum = net->enumeration(); - if (netenum) { + // If this net is actually an enum, the method may + // be an enumeration method. + if (netenum_t*netenum = net->enumeration()) { // We may need the net expression for the // enumeration variable so get it. NetESignal*expr = new NetESignal(net); @@ -2303,6 +2313,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, use_path, method_name, expr, expr_wid, NULL, 0); } + + // If this net is a struct, the method name may be + // a struct member. + if (net->struct_type() != 0) { + ivl_assert(*this, use_path.back().index.empty()); + + return check_for_struct_members(this, des, scope, + net, method_name); + } + } } diff --git a/elab_sig.cc b/elab_sig.cc index 77cab98fe..cf435013e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -32,6 +32,7 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -1094,6 +1095,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig->set_enumeration(use_enum); } + if (struct_type_) { + netstruct_t*use_type = new netstruct_t; + sig->set_struct_type(use_type); + } + if (wtype == NetNet::WIRE) sig->devirtualize_pins(); ivl_variable_type_t use_data_type = data_type_; diff --git a/netlist.cc b/netlist.cc index 8d8e9af9a..67899ba0a 100644 --- a/netlist.cc +++ b/netlist.cc @@ -450,7 +450,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0), + enumeration_(0), struct_type_(0), discipline_(0), + msb_(npins-1), lsb_(0), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { assert(s); @@ -496,7 +497,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), discipline_(0), + enumeration_(0), struct_type_(0), discipline_(0), msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) @@ -544,7 +545,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, calculate_count(array_s, array_e)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), - is_scalar_(false), local_flag_(false), enumeration_(0), discipline_(0), + is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), + discipline_(0), msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e), eref_count_(0), lref_count_(0) @@ -692,10 +694,23 @@ netenum_t*NetNet::enumeration(void) const void NetNet::set_enumeration(netenum_t*es) { + ivl_assert(*this, struct_type_ == 0); ivl_assert(*this, enumeration_ == 0); enumeration_ = es; } +netstruct_t*NetNet::struct_type(void) const +{ + return struct_type_; +} + +void NetNet::set_struct_type(netstruct_t*type) +{ + ivl_assert(*this, struct_type_ == 0); + ivl_assert(*this, enumeration_ == 0); + struct_type_ = type; +} + ivl_discipline_t NetNet::get_discipline() const { return discipline_; diff --git a/netlist.h b/netlist.h index 055466b5d..5e6d2bd2c 100644 --- a/netlist.h +++ b/netlist.h @@ -75,6 +75,7 @@ class NetEvWait; class PExpr; class PFunction; class netenum_t; +class netstruct_t; struct target; struct functor_t; @@ -603,6 +604,9 @@ class NetNet : public NetObj { void set_enumeration(netenum_t*enum_set); netenum_t*enumeration(void) const; + void set_struct_type(netstruct_t*type); + netstruct_t*struct_type(void) const; + /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; void set_discipline(ivl_discipline_t dis); @@ -676,6 +680,7 @@ class NetNet : public NetObj { bool is_scalar_ : 1; bool local_flag_: 1; netenum_t*enumeration_; + netstruct_t*struct_type_; ivl_discipline_t discipline_; long msb_, lsb_; diff --git a/netstruct.cc b/netstruct.cc new file mode 100644 index 000000000..36ba3353a --- /dev/null +++ b/netstruct.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "netstruct.h" + +netstruct_t::netstruct_t() +: packed_(false) +{ +} + +netstruct_t::~netstruct_t() +{ +} diff --git a/netstruct.h b/netstruct.h new file mode 100644 index 000000000..48bdd0cc0 --- /dev/null +++ b/netstruct.h @@ -0,0 +1,34 @@ +#ifndef __netstruct_H +#define __netstruct_H +/* + * Copyright (c) 2011 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "LineInfo.h" + +class netstruct_t : public LineInfo { + + public: + netstruct_t(); + ~netstruct_t(); + + private: + bool packed_; +}; + +#endif diff --git a/parse.y b/parse.y index 3bc87a667..9e0a65ef9 100644 --- a/parse.y +++ b/parse.y @@ -330,6 +330,13 @@ static void current_task_set_statement(vector*s) net_decl_assign_t*net_decl_assign; enum_type_t*enum_type; + decl_assignment_t*decl_assignment; + list*decl_assignments; + + struct_member_t*struct_member; + list*struct_members; + struct_type_t*struct_type; + verinum* number; verireal* realtime; @@ -436,7 +443,8 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number -%type unsigned_signed_opt signed_unsigned_opt reg_opt +%type unsigned_signed_opt signed_unsigned_opt +%type K_packed_opt K_reg_opt %type udp_reg_opt edge_operator automatic_opt %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -491,6 +499,13 @@ static void current_task_set_statement(vector*s) %type expression_list_with_nuls expression_list_proper %type cont_assign cont_assign_list +%type variable_decl_assignment +%type list_of_variable_decl_assignments + +%type struct_union_member +%type struct_union_member_list +%type struct_data_type + %type range range_opt %type dimensions_opt dimensions %type net_type var_type net_type_opt @@ -695,6 +710,13 @@ block_item_decl if ($1) delete $1; } + /* struct data type declarations */ + + | attribute_list_opt struct_data_type register_variable_list ';' + { pform_set_struct_type($2, $3); + if ($1) delete $1; + } + /* real declarations are fairly simple as there is no range of signed flag in the declaration. Create the real as a NetNet::REG with real value. Note that real and realtime are interchangeable @@ -879,6 +901,63 @@ enum_name } ; +struct_data_type + : K_struct K_packed_opt '{' struct_union_member_list '}' + { struct_type_t*tmp = new struct_type_t; + FILE_NAME(tmp, @1); + tmp->packed_flag = $2; + tmp->members .reset($4); + $$ = tmp; + } + | K_struct K_packed_opt '{' error '}' + { yyerror(@4, "error: Errors in struct/union member list."); + yyerrok; + struct_type_t*tmp = new struct_type_t; + FILE_NAME(tmp, @1); + tmp->packed_flag = $2; + $$ = tmp; + } + ; + +struct_union_member_list + : struct_union_member_list struct_union_member + { list*tmp = $1; + tmp->push_back($2); + $$ = tmp; + } + | struct_union_member + { list*tmp = new list; + $$ = tmp; + } + ; + +struct_union_member + : attribute_list_opt K_bit range_opt list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_BOOL; + tmp->range .reset($3); + tmp->names .reset($4); + $$ = tmp; + } + | attribute_list_opt K_logic range_opt list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_LOGIC; + tmp->range .reset($3); + tmp->names .reset($4); + $$ = tmp; + } + | attribute_list_opt atom2_type list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_BOOL; + tmp->range .reset( make_range_from_width($2) ); + tmp->names .reset($3); + $$ = tmp; + } + ; + case_item : expression_list_proper ':' statement_or_null { PCase::Item*tmp = new PCase::Item; @@ -3954,6 +4033,40 @@ register_variable_list } ; +/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ +list_of_variable_decl_assignments + : variable_decl_assignment + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + | list_of_variable_decl_assignments ',' variable_decl_assignment + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + ; + +variable_decl_assignment + : IDENTIFIER dimensions_opt + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + if ($2) { + tmp->index = *$2; + delete $2; + } + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '=' expression + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + tmp->expr .reset($3); + delete[]$1; + $$ = tmp; + } + ; + real_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); @@ -4820,13 +4933,8 @@ task_item | task_port_item { $$ = $1; } ; -reg_opt - : K_reg { $$ = true; } - | { $$ = false; } - ; - task_port_item - : K_input reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + : K_input K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINPUT, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, @@ -4834,7 +4942,7 @@ task_port_item @1.text, @1.first_line); $$ = tmp; } - | K_output reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + | K_output K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, @@ -4842,7 +4950,7 @@ task_port_item @1.text, @1.first_line); $$ = tmp; } - | K_inout reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + | K_inout K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINOUT, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, @@ -4954,7 +5062,7 @@ task_item_list_opt task_port_decl - : K_input reg_opt unsigned_signed_opt range_opt IDENTIFIER + : K_input K_reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4968,7 +5076,7 @@ task_port_decl $$ = tmp; } - | K_output reg_opt unsigned_signed_opt range_opt IDENTIFIER + | K_output K_reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4981,7 +5089,7 @@ task_port_decl @1.text, @1.first_line); $$ = tmp; } - | K_inout reg_opt unsigned_signed_opt range_opt IDENTIFIER + | K_inout K_reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -5504,3 +5612,6 @@ udp_primitive delete[]$6; } ; + +K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; +K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; diff --git a/pform.cc b/pform.cc index 64405fc19..86a7f62a9 100644 --- a/pform.cc +++ b/pform.cc @@ -385,7 +385,7 @@ static void pform_put_enum_type_in_scope(enum_type_t*enum_set) lexical_scope->enum_sets.push_back(enum_set); } -static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) +PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { diff --git a/pform.h b/pform.h index 030e37105..e781109eb 100644 --- a/pform.h +++ b/pform.h @@ -135,6 +135,8 @@ extern void pform_set_default_nettype(NetNet::Type net, */ extern PWire* pform_get_wire_in_scope(perm_string name); +extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type); + /* * The parser uses startmodule and endmodule together to build up a * module as it parses it. The startmodule tells the pform code that a @@ -280,6 +282,8 @@ extern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); +extern void pform_set_struct_type(struct_type_t*struct_type, list*names); + /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to attributes. The functions keep the value strings that are diff --git a/pform_struct_type.cc b/pform_struct_type.cc new file mode 100644 index 000000000..6f5fad8a8 --- /dev/null +++ b/pform_struct_type.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "pform.h" +# include "ivl_assert.h" + +/* + * When we parse a packed struct, we can early on (right here) figure + * out the base type of the packed variable. Elaboration, later on, + * well figure out the rest. + */ +static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name) +{ + ivl_variable_type_t base_type = IVL_VT_BOOL; + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + struct_member_t*tmp = *cur; + + if (tmp->type == IVL_VT_BOOL) { + continue; + } + + if (tmp->type == IVL_VT_LOGIC) { + base_type = IVL_VT_LOGIC; + continue; + } + } + + PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); + net->set_struct_type(struct_type); +} + +static void pform_set_struct_type(struct_type_t*struct_type, perm_string name) +{ + if (struct_type->packed_flag) { + pform_set_packed_struct(struct_type, name); + return; + } + + // For now, can only handle packed structs. + ivl_assert(*struct_type, 0); +} + +void pform_set_struct_type(struct_type_t*struct_type, list*names) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set_struct_type(struct_type, *cur); + } +} diff --git a/pform_types.h b/pform_types.h index 609641e1f..3f6395fe8 100644 --- a/pform_types.h +++ b/pform_types.h @@ -57,6 +57,12 @@ struct name_component_t { std::listindex; }; +struct decl_assignment_t { + perm_string name; + std::listindex; + std::auto_ptr expr; +}; + /* * The enum_type_t holds the parsed declaration to represent an * enumeration. Since this is in the pform, it represents the type @@ -71,6 +77,16 @@ struct enum_type_t { LineInfo li; }; +struct struct_member_t : public LineInfo { + ivl_variable_type_t type; + std::auto_ptr< list > range; + std::auto_ptr< list > names; +}; + +struct struct_type_t : public LineInfo { + bool packed_flag; + std::auto_ptr< list > members; +}; /* * The pform_name_t is the general form for a hierarchical