From 27dfdf99ddbc09be6b866b8d6f6d13f6967d8224 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 12 Nov 2010 18:47:06 -0800 Subject: [PATCH] Enumeration element values can be expressions Allow more complex enumeration expressions, which means putting off the evaluation of the expression values until elaboration. --- elab_scope.cc | 37 +++++++++- elab_sig.cc | 2 +- parse.y | 195 ++++++++++++++++++++++++-------------------------- pform.cc | 141 ++++++++++++------------------------ pform.h | 20 +++--- pform_dump.cc | 2 +- pform_types.h | 4 +- 7 files changed, 188 insertions(+), 213 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 35773f9c4..c7a47b844 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -226,12 +226,40 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, scope->add_enumeration_set(use_enum); - for (list::const_iterator cur = enum_type->names->begin() + verinum cur_value (0); + verinum one_value (1); + for (list::const_iterator cur = enum_type->names->begin() ; cur != enum_type->names->end() ; ++ cur) { + + if (cur->parm) { + // There is an explicit value. elaborate/evaluate + // the value and assign it to the enumeration name. + NetExpr*val = elab_and_eval(des, scope, cur->parm, -1); + NetEConst*val_const = dynamic_cast (val); + if (val_const == 0) { + cerr << "<>:0: error: Enumeration expression is not constant." << endl; + des->errors += 1; + continue; + } + cur_value = val_const->value(); + + if (enum_type->base_type==IVL_VT_BOOL && ! cur_value.is_defined()) { + cerr << "<>:0: error: Enumeration name " << cur->name + << " cannot have a logic value." << endl; + des->errors += 1; + } + + } else if (! cur_value.is_defined()) { + cerr << "<>:0: error: Enumeration name " << cur->name + << " cannot have an inferred value." << endl; + des->errors += 1; + continue; + } + // The values are explicitly sized to the width of the // base type of the enumeration. - verinum tmp_val (cur->parm, use_enum->base_width()); + verinum tmp_val (cur_value, use_enum->base_width()); tmp_val.has_sign(enum_type->signed_flag); rc_flag = use_enum->insert_name(cur->name, tmp_val); @@ -240,6 +268,11 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, cerr << "<>:0: error: Duplicate enumeration name " << cur->name << endl; des->errors += 1; } + + // In case the next name has an implicit value, + // increment the current value by one. + if (cur_value.is_defined()) + cur_value = cur_value + one_value; } } diff --git a/elab_sig.cc b/elab_sig.cc index 7ce32ca43..a479497d2 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1102,7 +1102,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const // the new signal. This turns it into an enumeration. if (enum_type_) { ivl_assert(*this, enum_type_->names->size() > 0); - list::const_iterator sample_name = enum_type_->names->begin(); + list::const_iterator sample_name = enum_type_->names->begin(); netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); sig->set_enumeration(use_enum); } diff --git a/parse.y b/parse.y index 50e866a14..a1f2acf39 100644 --- a/parse.y +++ b/parse.y @@ -193,35 +193,26 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) return tmp; } -static list* make_named_number(perm_string name) +static list* make_named_numbers(perm_string name, long first, long last, PExpr*val =0) { - list*lst = new list; - named_number_t tmp; - tmp.name = name; - lst->push_back(tmp); - return lst; -} - -static list* make_named_numbers(perm_string name, long first, long last, verinum*val =0) -{ - list*lst = new list; - named_number_t tmp; + list*lst = new list; + named_pexpr_t tmp; assert(first <= last); for (long idx = first ; idx <= last ; idx += 1) { ostringstream buf; buf << name.str() << idx << ends; tmp.name = lex_strings.make(buf.str()); - tmp.parm = val ? *val : verinum(); + tmp.parm = val; val = 0; lst->push_back(tmp); } return lst; } -static list* make_named_number(perm_string name, const verinum&val) +static list* make_named_number(perm_string name, PExpr*val =0) { - list*lst = new list; - named_number_t tmp; + list*lst = new list; + named_pexpr_t tmp; tmp.name = name; tmp.parm = val; lst->push_back(tmp); @@ -267,7 +258,7 @@ static list* make_named_number(perm_string name, const verinum&v list* named_numbers; named_pexpr_t*named_pexpr; - svector*named_pexprs; + list*named_pexprs; struct parmvalue_t*parmvalue; PExpr*expr; @@ -418,7 +409,7 @@ static list* make_named_number(perm_string name, const verinum&v %type parameter_value_ranges_opt %type value_range_expression -%type enum_name_list enum_name +%type enum_name_list enum_name %type enum_data_type %type task_item task_item_list task_item_list_opt @@ -531,18 +522,19 @@ attribute_list_opt ; attribute_list - : attribute_list ',' attribute - { svector*tmp = - new svector(*$1,$3); - delete $1; - $$ = tmp; - } - | attribute - { svector*tmp = new svector(1); - (*tmp)[0] = $1; - $$ = tmp; - } - ; + : attribute_list ',' attribute + { list*tmp = $1; + tmp->push_back(*$3); + delete $3; + $$ = tmp; + } + | attribute + { list*tmp = new list; + tmp->push_back(*$1); + delete $1; + $$ = tmp; + } + ; attribute @@ -719,7 +711,7 @@ enum_name_list { $$ = $1; } | enum_name_list ',' enum_name - { list*lst = $1; + { list*lst = $1; lst->splice(lst->end(), *$3); delete $3; $$ = lst; @@ -746,27 +738,24 @@ enum_name delete $3; delete $5; } - | IDENTIFIER '=' number + | IDENTIFIER '=' expression { perm_string name = lex_strings.make($1); delete[]$1; - $$ = make_named_number(name, *$3); - delete $3; + $$ = make_named_number(name, $3); } - | IDENTIFIER '[' DEC_NUMBER ']' '=' number + | IDENTIFIER '[' DEC_NUMBER ']' '=' expression { perm_string name = lex_strings.make($1); long count = $3->as_ulong(); $$ = make_named_numbers(name, 0, count-1, $6); delete[]$1; delete $3; - delete $6; } - | IDENTIFIER '[' DEC_NUMBER ':' DEC_NUMBER ']' '=' number + | IDENTIFIER '[' DEC_NUMBER ':' DEC_NUMBER ']' '=' expression { perm_string name = lex_strings.make($1); - $$ = make_named_numbers(name, $3->as_long(), $5->as_long(), $8); + $$ = make_named_numbers(name, $3->as_long(), $5->as_long(), $8); delete[]$1; delete $3; delete $5; - delete $8; } ; @@ -3165,18 +3154,19 @@ parameter_value_byname ; parameter_value_byname_list - : parameter_value_byname - { svector*tmp = new svector(1); - (*tmp)[0] = $1; - $$ = tmp; - } - | parameter_value_byname_list ',' parameter_value_byname - { svector*tmp = - new svector(*$1,$3); - delete $1; - $$ = tmp; - } - ; + : parameter_value_byname + { list*tmp = new list; + tmp->push_back(*$1); + delete $1; + $$ = tmp; + } + | parameter_value_byname_list ',' parameter_value_byname + { list*tmp = $1; + tmp->push_back(*$3); + delete $3; + $$ = tmp; + } + ; /* The port (of a module) is a fairly complex item. Each port is @@ -3234,6 +3224,58 @@ port_opt | { $$ = 0; } ; + /* The port_name rule is used with a module is being *instantiated*, + and not when it is being declared. See the port rule if you are + looking for the ports of a module declaration. */ + +port_name + : '.' IDENTIFIER '(' expression ')' + { named_pexpr_t*tmp = new named_pexpr_t; + tmp->name = lex_strings.make($2); + tmp->parm = $4; + delete[]$2; + $$ = tmp; + } + | '.' IDENTIFIER '(' error ')' + { yyerror(@3, "error: invalid port connection expression."); + named_pexpr_t*tmp = new named_pexpr_t; + tmp->name = lex_strings.make($2); + tmp->parm = 0; + delete[]$2; + $$ = tmp; + } + | '.' IDENTIFIER '(' ')' + { named_pexpr_t*tmp = new named_pexpr_t; + tmp->name = lex_strings.make($2); + tmp->parm = 0; + delete[]$2; + $$ = tmp; + } + | '.' IDENTIFIER + { named_pexpr_t*tmp = new named_pexpr_t; + tmp->name = lex_strings.make($2); + tmp->parm = new PEIdent(lex_strings.make($2), true); + FILE_NAME(tmp->parm, @1); + delete[]$2; + $$ = tmp; + } + ; + +port_name_list + : port_name_list ',' port_name + { list*tmp = $1; + tmp->push_back(*$3); + delete $3; + $$ = tmp; + } + | port_name + { list*tmp = new list; + tmp->push_back(*$1); + delete $1; + $$ = tmp; + } + ; + /* A port reference is an internal (to the module) name of the port, possibly with a part of bit select to attach it to specific bits @@ -3324,57 +3366,6 @@ port_reference_list } ; - /* The port_name rule is used with a module is being *instantiated*, - and not when it is being declared. See the port rule if you are - looking for the ports of a module declaration. */ - -port_name - : '.' IDENTIFIER '(' expression ')' - { named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($2); - tmp->parm = $4; - delete[]$2; - $$ = tmp; - } - | '.' IDENTIFIER '(' error ')' - { yyerror(@3, "error: invalid port connection expression."); - named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($2); - tmp->parm = 0; - delete[]$2; - $$ = tmp; - } - | '.' IDENTIFIER '(' ')' - { named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($2); - tmp->parm = 0; - delete[]$2; - $$ = tmp; - } - | '.' IDENTIFIER - { named_pexpr_t*tmp = new named_pexpr_t; - tmp->name = lex_strings.make($2); - tmp->parm = new PEIdent(lex_strings.make($2), true); - FILE_NAME(tmp->parm, @1); - delete[]$2; - $$ = tmp; - } - ; - -port_name_list - : port_name_list ',' port_name - { svector*tmp; - tmp = new svector(*$1, $3); - delete $1; - $$ = tmp; - } - | port_name - { svector*tmp = new svector(1); - (*tmp)[0] = $1; - $$ = tmp; - } - ; - port_type : K_input { $$ = NetNet::PINPUT; } | K_output { $$ = NetNet::POUTPUT; } diff --git a/pform.cc b/pform.cc index 8921bbf34..d95523c57 100644 --- a/pform.cc +++ b/pform.cc @@ -350,16 +350,18 @@ PGenerate* pform_parent_generate(void) } void pform_bind_attributes(map&attributes, - svector*attr) + list*attr, bool keep_attrs) { if (attr == 0) return; - for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { - named_pexpr_t*tmp = (*attr)[idx]; - attributes[tmp->name] = tmp->parm; + while (attr->size() > 0) { + named_pexpr_t tmp = attr->front(); + attr->pop_front(); + attributes[tmp.name] = tmp.parm; } - delete attr; + if (!keep_attrs) + delete attr; } static bool pform_at_module_level() @@ -689,7 +691,7 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val, } void pform_startmodule(const char*name, const char*file, unsigned lineno, - svector*attr) + list*attr) { assert( pform_cur_module == 0 ); @@ -724,12 +726,7 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno, cerr << pform_timescale_file << ":" << pform_timescale_line << ": ...: The inherited timescale is here." << endl; } - if (attr) { - for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { - named_pexpr_t*tmp = (*attr)[idx]; - pform_cur_module->attributes[tmp->name] = tmp->parm; - } - } + pform_bind_attributes(pform_cur_module->attributes, attr); } /* @@ -1505,11 +1502,11 @@ void pform_make_events(list*names, const char*fn, unsigned ln) * are ready to be instantiated. The function runs through the list of * gates and calls the pform_makegate function to make the individual gate. */ -void pform_makegate(PGBuiltin::Type type, - struct str_pair_t str, - list* delay, - const lgate&info, - svector*attr) +static void pform_makegate(PGBuiltin::Type type, + struct str_pair_t str, + list* delay, + const lgate&info, + list*attr) { if (info.parms_by_name) { cerr << info.file << ":" << info.lineno << ": Gates do not " @@ -1528,12 +1525,10 @@ void pform_makegate(PGBuiltin::Type type, if (info.range[0]) cur->set_range(info.range[0], info.range[1]); - if (attr) { - for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { - named_pexpr_t*tmp = (*attr)[idx]; - cur->attributes[tmp->name] = tmp->parm; - } - } + // The pform_makegates() that calls me will take care of + // deleting the attr pointer, so tell the + // pform_bind_attributes function to keep the attr object. + pform_bind_attributes(cur->attributes, attr, true); cur->strength0(str.str0); cur->strength1(str.str1); @@ -1549,20 +1544,13 @@ void pform_makegates(PGBuiltin::Type type, struct str_pair_t str, list*delay, svector*gates, - svector*attr) + list*attr) { for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) { pform_makegate(type, str, delay, (*gates)[idx], attr); } - if (attr) { - for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { - named_pexpr_t*cur = (*attr)[idx]; - delete cur; - } - delete attr; - } - + if (attr) delete attr; delete gates; } @@ -1597,13 +1585,13 @@ static void pform_make_modgate(perm_string type, cur->set_range(msb,lsb); if (overrides && overrides->by_name) { - unsigned cnt = overrides->by_name->count(); + unsigned cnt = overrides->by_name->size(); named*byname = new named[cnt]; - for (unsigned idx = 0 ; idx < cnt ; idx += 1) { - named_pexpr_t*curp = (*overrides->by_name)[idx]; - byname[idx].name = curp->name; - byname[idx].parm = curp->parm; + list::iterator by_name_cur = overrides->by_name->begin(); + for (unsigned idx = 0 ; idx < cnt ; idx += 1, ++ by_name_cur) { + byname[idx].name = by_name_cur->name; + byname[idx].parm = by_name_cur->parm; } cur->set_parameters(byname, cnt); @@ -1621,17 +1609,17 @@ static void pform_make_modgate(perm_string type, static void pform_make_modgate(perm_string type, perm_string name, struct parmvalue_t*overrides, - svector*bind, + list*bind, PExpr*msb, PExpr*lsb, const char*fn, unsigned ln) { - unsigned npins = bind->count(); + unsigned npins = bind->size(); named*pins = new named[npins]; - for (unsigned idx = 0 ; idx < npins ; idx += 1) { - named_pexpr_t*curp = (*bind)[idx]; - pins[idx].name = curp->name; - pins[idx].parm = curp->parm; - pform_declare_implicit_nets(curp->parm); + list::iterator bind_cur = bind->begin(); + for (unsigned idx = 0 ; idx < npins ; idx += 1, ++bind_cur) { + pins[idx].name = bind_cur->name; + pins[idx].parm = bind_cur->parm; + pform_declare_implicit_nets(bind_cur->parm); } PGModule*cur = new PGModule(type, name, pins, npins); @@ -1639,13 +1627,13 @@ static void pform_make_modgate(perm_string type, cur->set_range(msb,lsb); if (overrides && overrides->by_name) { - unsigned cnt = overrides->by_name->count(); + unsigned cnt = overrides->by_name->size(); named*byname = new named[cnt]; - for (unsigned idx = 0 ; idx < cnt ; idx += 1) { - named_pexpr_t*curp = (*overrides->by_name)[idx]; - byname[idx].name = curp->name; - byname[idx].parm = curp->parm; + list::iterator by_name_cur = overrides->by_name->begin(); + for (unsigned idx = 0 ; idx < cnt ; idx += 1, ++by_name_cur) { + byname[idx].name = by_name_cur->name; + byname[idx].parm = by_name_cur->parm; } cur->set_parameters(byname, cnt); @@ -1809,7 +1797,7 @@ void pform_module_define_port(const struct vlltype&li, ivl_variable_type_t data_type, bool signed_flag, list*range, - svector*attr) + list*attr) { PWire*cur = pform_get_wire_in_scope(name); if (cur) { @@ -1844,12 +1832,7 @@ void pform_module_define_port(const struct vlltype&li, false); } - if (attr) { - for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { - named_pexpr_t*tmp = (*attr)[idx]; - cur->attributes[tmp->name] = tmp->parm; - } - } + pform_bind_attributes(cur->attributes, attr); pform_put_wire_in_scope(name, cur); } @@ -1881,7 +1864,7 @@ void pform_module_define_port(const struct vlltype&li, void pform_makewire(const vlltype&li, perm_string name, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t dt, - svector*attr) + list*attr) { PWire*cur = pform_get_wire_in_scope(name); @@ -1929,9 +1912,9 @@ void pform_makewire(const vlltype&li, perm_string name, } if (attr) { - for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { - named_pexpr_t*tmp = (*attr)[idx]; - cur->attributes[tmp->name] = tmp->parm; + for (list::iterator attr_cur = attr->begin() + ; attr_cur != attr->end() ; ++attr_cur) { + cur->attributes[attr_cur->name] = attr_cur->parm; } } @@ -1951,7 +1934,7 @@ void pform_makewire(const vlltype&li, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t dt, - svector*attr, + list*attr, PWSRType rt) { for (list::iterator cur = names->begin() @@ -2484,40 +2467,6 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, listrange.get() != 0); assert(enum_type->range->size() == 2); - // Scan the list of enum name declarations and evaluate them - // to a map of names with values. This expands out the - // inferred values (if any) and checks for duplicates. - verinum cur_value (0); - verinum one_value (1); - for (list::iterator cur = enum_type->names->begin() - ; cur != enum_type->names->end() ; ++ cur) { - - verinum next_value = cur->parm; - if (next_value.len() == 0) { - if (! cur_value.is_defined()) { - cerr << li.text << ":" << li.first_line << ": " - << "error: Enumeration name " << cur->name - << " cannot have inferred value." << endl; - next_value = cur_value; - error_count += 1; - } else { - next_value = cur_value; - cur_value = cur_value + one_value; - } - - cur->parm = next_value; - - } else { - if (enum_type->base_type==IVL_VT_BOOL && ! next_value.is_defined()) { - cerr << li.text << ":" << li.first_line << ": " - << "error: Enumeration name " << cur->name - << " Cannot have logic value " << next_value << "." << endl; - error_count += 1; - } - cur_value = next_value + one_value; - } - } - // Attach the enumeration to the current scope. pform_put_enum_type_in_scope(enum_type); @@ -2554,7 +2503,7 @@ svector* pform_make_udp_input_ports(list*names) } PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, - svector*attr) + list*attr) { PProcess*pp = new PProcess(type, st); diff --git a/pform.h b/pform.h index 77d77042d..966b5fe8d 100644 --- a/pform.h +++ b/pform.h @@ -84,11 +84,10 @@ extern bool pform_library_flag; /* This is information about port name information for named port connections. */ -typedef named named_pexpr_t; struct parmvalue_t { list*by_order; - svector*by_name; + list*by_name; }; struct str_pair_t { ivl_drive_t str0, str1; }; @@ -110,7 +109,7 @@ struct lgate { string name; list*parms; - svector*parms_by_name; + list*parms_by_name; PExpr*range[2]; @@ -121,7 +120,8 @@ struct lgate { /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ extern void pform_bind_attributes(map&attributes, - svector*attr); + list*attr, + bool keep_attr =false); /* The lexor calls this function to change the default nettype. */ extern void pform_set_default_nettype(NetNet::Type net, @@ -143,7 +143,7 @@ extern PWire* pform_get_wire_in_scope(perm_string name); * pform to close up and finish the named module. */ extern void pform_startmodule(const char*, const char*file, unsigned lineno, - svector*attr); + list*attr); extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); @@ -157,7 +157,7 @@ extern void pform_module_define_port(const struct vlltype&li, ivl_variable_type_t data_type, bool signed_flag, list*range, - svector*attr); + list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, const char*file, @@ -230,7 +230,7 @@ extern void pform_makewire(const struct vlltype&li, perm_string name, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t, - svector*attr); + list*attr); /* This form handles simple declarations */ extern void pform_makewire(const struct vlltype&li, @@ -240,7 +240,7 @@ extern void pform_makewire(const struct vlltype&li, NetNet::Type type, NetNet::PortType, ivl_variable_type_t, - svector*attr, + list*attr, PWSRType rt = SR_NET); /* This form handles assignment declarations. */ @@ -329,7 +329,7 @@ extern void pform_module_specify_path(PSpecPath*obj); * or initial items. */ extern PProcess* pform_make_behavior(ivl_process_type_t, Statement*, - svector*attr); + list*attr); extern svector* pform_make_udp_input_ports(list*); @@ -349,7 +349,7 @@ extern void pform_makegates(PGBuiltin::Type type, struct str_pair_t str, list*delay, svector*gates, - svector*attr); + list*attr); extern void pform_make_modgates(perm_string type, struct parmvalue_t*overrides, diff --git a/pform_dump.cc b/pform_dump.cc index 31d6db5f3..b2845d129 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1112,7 +1112,7 @@ void LexicalScope::dump_enumerations_(ostream&out, unsigned indent) const ; cur != enum_sets.end() ; ++ cur) { out << setw(indent) << "" << "enum {" << endl; - for (list::const_iterator idx = (*cur)->names->begin() + for (list::const_iterator idx = (*cur)->names->begin() ; idx != (*cur)->names->end() ; ++ idx) { out << setw(indent+4) << "" << idx->name << " = " << idx->parm << endl; diff --git a/pform_types.h b/pform_types.h index e6d5f6d01..45c8a6469 100644 --- a/pform_types.h +++ b/pform_types.h @@ -32,7 +32,9 @@ * parse-form types. */ +class PExpr; typedef named named_number_t; +typedef named named_pexpr_t; struct index_component_t { enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; @@ -63,7 +65,7 @@ struct enum_type_t { ivl_variable_type_t base_type; bool signed_flag; auto_ptr< list > range; - auto_ptr< list > names; + auto_ptr< list > names; };