diff --git a/HName.h b/HName.h index 6008a0d33..1afce7c5d 100644 --- a/HName.h +++ b/HName.h @@ -1,7 +1,7 @@ #ifndef __HName_H #define __HName_H /* - * Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2008 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 @@ -18,11 +18,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: HName.h,v 1.7 2007/06/02 03:42:12 steve Exp $" -#endif # include +# include # include "StringHeap.h" #ifdef __GNUC__ #if __GNUC__ > 2 @@ -70,30 +68,16 @@ extern bool operator == (const hname_t&, const hname_t&); extern bool operator != (const hname_t&, const hname_t&); extern ostream& operator<< (ostream&, const hname_t&); -/* - * $Log: HName.h,v $ - * Revision 1.7 2007/06/02 03:42:12 steve - * Properly evaluate scope path expressions. - * - * Revision 1.6 2007/05/16 19:12:33 steve - * Fix hname_t use of space for 1 perm_string. - * - * Revision 1.5 2007/04/26 03:06:21 steve - * Rework hname_t to use perm_strings. - * - * Revision 1.4 2002/11/02 03:27:51 steve - * Allow named events to be referenced by - * hierarchical names. - * - * Revision 1.3 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/06/14 03:25:51 steve - * Compiler portability. - * - * Revision 1.1 2001/12/03 04:47:14 steve - * Parser and pform use hierarchical names as hname_t - * objects instead of encoded strings. - * - */ +inline ostream& operator<< (ostream&out, const list&ll) +{ + list::const_iterator cur = ll.begin(); + out << *cur; + cur ++; + while (cur != ll.end()) { + out << "." << *cur; + cur ++; + } + return out; +} + #endif diff --git a/Module.h b/Module.h index ef8816cf4..162761e88 100644 --- a/Module.h +++ b/Module.h @@ -22,6 +22,7 @@ # include # include +# include # include "svector.h" # include "StringHeap.h" # include "HName.h" @@ -118,7 +119,8 @@ class Module : public PScope, public LineInfo { new parameters within the module, but may be used to set values within this module (when instantiated) or in other instantiated modules. */ - mapdefparms; + typedef pair named_expr_t; + listdefparms; /* Parameters may be overridden at instantiation time; the overrides do not contain explicit parameter names, @@ -169,7 +171,7 @@ class Module : public PScope, public LineInfo { bool elaborate(Design*, NetScope*scope) const; typedef map replace_t; - bool elaborate_scope(Design*, NetScope*scope, const replace_t&rep) const; + bool elaborate_scope(Design*, NetScope*scope, const replace_t&rep); bool elaborate_sig(Design*, NetScope*scope) const; diff --git a/PGate.h b/PGate.h index df7578bf5..78d637ead 100644 --- a/PGate.h +++ b/PGate.h @@ -1,7 +1,7 @@ #ifndef __PGate_H #define __PGate_H /* - * Copyright (c) 1998-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2008 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 @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: PGate.h,v 1.32 2006/04/10 00:37:42 steve Exp $" -#endif # include "svector.h" # include "StringHeap.h" @@ -232,9 +229,11 @@ class PGModule : public PGate { PExpr*msb_; PExpr*lsb_; + friend class delayed_elaborate_scope_mod_instances; void elaborate_mod_(Design*, Module*mod, NetScope*scope) const; void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const; void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const; + void elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const; bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const; bool elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const; diff --git a/design_dump.cc b/design_dump.cc index ac6748521..ca8e71d8e 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1063,7 +1063,7 @@ void NetScope::dump(ostream&o) const /* Dump the saved defparam assignments here. */ { - map::const_iterator pp; + list >::const_iterator pp; for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) { o << " defparam " << (*pp).first << " = " << @@ -1071,6 +1071,15 @@ void NetScope::dump(ostream&o) const } } + { + list,NetExpr*> >::const_iterator pp; + for (pp = defparams_later.begin() + ; pp != defparams_later.end() ; pp ++ ) { + o << " defparam(later) " << pp->first << " = " << + *(pp->second) << ";" << endl; + } + } + /* Dump the events in this scope. */ for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) { o << " event " << cur->name() << "; nprobe=" diff --git a/elab_scope.cc b/elab_scope.cc index 6a4c55288..37f186e93 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -181,8 +181,40 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope, } +class generate_schemes_work_item_t : public elaborator_work_item_t { + public: + generate_schemes_work_item_t(Design*des, NetScope*scope, Module*mod) + : elaborator_work_item_t(des), scope_(scope), mod_(mod) + { } + + void elaborate_runrun() + { + if (debug_scopes) + cerr << mod_->get_fileline() << ": debug: " + << "Processing generate schemes for " + << scope_path(scope_) << endl; + + // Generate schemes can create new scopes in the form of + // generated code. Scan the generate schemes, and *generate* + // new scopes, which is slightly different from simple + // elaboration. + typedef list::const_iterator generate_it_t; + for (generate_it_t cur = mod_->generate_schemes.begin() + ; cur != mod_->generate_schemes.end() ; cur ++ ) { + (*cur) -> generate_scope(des, scope_); + } + } + + private: + // The scope_ is the scope that contains the generate scheme + // we are to work on. the mod_ is the Module definition for + // that scope, and contains the parsed generate schemes. + NetScope*scope_; + Module*mod_; +}; + bool Module::elaborate_scope(Design*des, NetScope*scope, - const replace_t&replacements) const + const replace_t&replacements) { if (debug_scopes) { cerr << get_fileline() << ": debug: Elaborate scope " @@ -201,8 +233,6 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // place of the elaborated expression. typedef map::const_iterator mparm_it_t; - typedef map::const_iterator pform_parm_it_t; - // This loop scans the parameters in the module, and creates // stub parameter entries in the scope for the parameter name. @@ -286,15 +316,17 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // here because the parameter receiving the assignment may be // in a scope not discovered by this pass. - for (pform_parm_it_t cur = defparms.begin() - ; cur != defparms.end() ; cur ++ ) { + while (! defparms.empty()) { + Module::named_expr_t cur = defparms.front(); + defparms.pop_front(); - PExpr*ex = (*cur).second; + PExpr*ex = cur.second; assert(ex); NetExpr*val = ex->elaborate_pexpr(des, scope); + delete ex; if (val == 0) continue; - scope->defparams[(*cur).first] = val; + scope->defparams.push_back(make_pair(cur.first, val)); } // Evaluate the attributes. Evaluate them in the scope of the @@ -307,17 +339,15 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, delete[]attr; - // Generate schemes can create new scopes in the form of - // generated code. Scan the generate schemes, and *generate* - // new scopes, which is slightly different from simple - // elaboration. - - typedef list::const_iterator generate_it_t; - for (generate_it_t cur = generate_schemes.begin() - ; cur != generate_schemes.end() ; cur ++ ) { - (*cur) -> generate_scope(des, scope); - } + // Generate schemes need to have their scopes elaborated, but + // we cannot do that until defparams are run, so push it off + // into an elaborate work item. + if (debug_scopes) + cerr << get_fileline() << ": debug: " + << "Schedule generates within " << scope_path(scope) + << " for elaboration after defparams." << endl; + des->elaboration_work_list.push_back(new generate_schemes_work_item_t(des, scope, this)); // Tasks introduce new scopes, so scan the tasks in this // module. Create a scope for the task and pass that to the @@ -654,6 +684,41 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) scope_list_.push_back(scope); } +class delayed_elaborate_scope_mod_instances : public elaborator_work_item_t { + + public: + delayed_elaborate_scope_mod_instances(Design*des, + const PGModule*obj, + Module*mod, + NetScope*sc) + : elaborator_work_item_t(des), obj_(obj), mod_(mod), sc_(sc) + { } + ~delayed_elaborate_scope_mod_instances() { } + + virtual void elaborate_runrun(); + + private: + const PGModule*obj_; + Module*mod_; + NetScope*sc_; +}; + +void delayed_elaborate_scope_mod_instances::elaborate_runrun() +{ + if (debug_scopes) + cerr << obj_->get_fileline() << ": debug: " + << "Resume scope elaboration of instances of " + << mod_->mod_name() << "." << endl; + + obj_->elaborate_scope_mod_instances_(des, mod_, sc_); +} + +/* + * Here we handle the elaborate scope of a module instance. The caller + * has already figured out that this "gate" is a module, and has found + * the module definition. The "sc" argument is the scope that will + * contain this instance. + */ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const { if (get_name() == "") { @@ -700,6 +765,36 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const return; } + if (msb_ || lsb_) { + // If there are expressions to evaluate in order to know + // the actual number of instances that will be + // instantiated, then we have to delay further scope + // elaboration until after defparams (above me) are + // run. Do that by appending a work item to the + // elaboration work list. + if (debug_scopes) + cerr << get_fileline() << ": debug: delay elaborate_scope" + << " of array of " << get_name() + << " in scope " << scope_path(sc) << "." << endl; + + elaborator_work_item_t*tmp + = new delayed_elaborate_scope_mod_instances(des, this, mod, sc); + des->elaboration_work_list.push_back(tmp); + + } else { + // If there are no expressions that need to be evaluated + // to elaborate the scope of this next instances, then + // get right to it. + elaborate_scope_mod_instances_(des, mod, sc); + } +} + +/* + * This method is called to process a module instantiation after basic + * sanity testing is already complete. + */ +void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const +{ NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0; NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0; NetEConst*msb = dynamic_cast (mse); diff --git a/elaborate.cc b/elaborate.cc index a0d8d73a0..f22e38f00 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1158,7 +1158,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const /* Input to module. elaborate the expression to the desired width. If this in an instance - array, then let the net determine it's own + array, then let the net determine its own width. We use that, then, to decide how to hook it up. @@ -2954,7 +2954,7 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const dev = new NetForce(lval, rexp); if (debug_elaborate) { - cerr << get_fileline() << ": debug: ELaborate force," + cerr << get_fileline() << ": debug: Elaborate force," << " lval width=" << lval->lwidth() << " rval width=" << rexp->expr_width() << " rval=" << *rexp @@ -3775,6 +3775,82 @@ struct root_elem { NetScope *scope; }; +class elaborate_root_scope_t : public elaborator_work_item_t { + public: + elaborate_root_scope_t(Design*des, NetScope*scope, Module*rmod) + : elaborator_work_item_t(des), scope_(scope), rmod_(rmod) + { } + + ~elaborate_root_scope_t() { } + + virtual void elaborate_runrun() + { + Module::replace_t stub; + if (! rmod_->elaborate_scope(des, scope_, stub)) + des->errors += 1; + } + + private: + NetScope*scope_; + Module*rmod_; +}; + +class top_defparams : public elaborator_work_item_t { + public: + top_defparams(Design*des) + : elaborator_work_item_t(des) + { } + + ~top_defparams() { } + + virtual void elaborate_runrun() + { + // This method recurses through the scopes, looking for + // defparam assignments to apply to the parameters in the + // various scopes. This needs to be done after all the scopes + // and basic parameters are taken care of because the defparam + // can assign to a parameter declared *after* it. + des->run_defparams(); + + // At this point, all parameter overrides are done. Scan the + // scopes and evaluate the parameters all the way down to + // constants. + des->evaluate_parameters(); + } +}; + +class later_defparams : public elaborator_work_item_t { + public: + later_defparams(Design*des) + : elaborator_work_item_t(des) + { } + + ~later_defparams() { } + + virtual void elaborate_runrun() + { + listtmp_list; + for (set::iterator cur = des->defparams_later.begin() + ; cur != des->defparams_later.end() ; cur ++ ) + tmp_list.push_back(*cur); + + des->defparams_later.clear(); + + while (! tmp_list.empty()) { + NetScope*cur = tmp_list.front(); + tmp_list.pop_front(); + cur->run_defparams_later(des); + } + des->evaluate_parameters(); + } +}; + +/* + * This function is the root of all elaboration. The input is the list + * of root module names. The function locates the Module definitions + * for each root, does the whole elaboration sequence, and fills in + * the resulting Design. + */ Design* elaborate(listroots) { svector root_elems(roots.size()); @@ -3785,7 +3861,7 @@ Design* elaborate(listroots) // module and elaborate what I find. Design*des = new Design; - // Scan the root modules, and elaborate their scopes. + // Scan the root modules by name, and elaborate their scopes. for (list::const_iterator root = roots.begin() ; root != roots.end() ; root++) { @@ -3804,47 +3880,74 @@ Design* elaborate(listroots) // Get the module definition for this root instance. Module *rmod = (*mod).second; - // Make the root scope. + // Make the root scope. This makes a NetScoep object and + // pushes it into the list of root scopes in the Design. NetScope*scope = des->make_root_scope(*root); + + // Collect some basic properties of this scope from the + // Module definition. scope->set_line(rmod); scope->time_unit(rmod->time_unit); scope->time_precision(rmod->time_precision); scope->default_nettype(rmod->default_nettype); des->set_precision(rmod->time_precision); - Module::replace_t stub; - - // Recursively elaborate from this root scope down. This - // does a lot of the grunt work of creating sub-scopes, etc. - if (! rmod->elaborate_scope(des, scope, stub)) { - delete des; - return 0; - } + // Save this scope, along with its defintion, in the + // "root_elems" list for later passes. struct root_elem *r = new struct root_elem; r->mod = rmod; r->scope = scope; root_elems[i++] = r; + + // Arrange for these scopes to be elaborated as root + // scopes. Create an "elaborate_root_scope" object to + // contain the work item, and append it to the scope + // elaborations work list. + elaborator_work_item_t*es = new elaborate_root_scope_t(des, scope, rmod); + des->elaboration_work_list.push_back(es); } + // After the work items for the root scope elaboration, push a + // work item to process the defparams. + des->elaboration_work_list.push_back(new top_defparams(des)); + + // Run the work list of scope elaborations until the list is + // empty. This list is initially populated above where the + // initial root scopes are primed. + while (! des->elaboration_work_list.empty()) { + // Transfer the queue to a temporary queue. + list cur_queue; + while (! des->elaboration_work_list.empty()) { + cur_queue.push_back(des->elaboration_work_list.front()); + des->elaboration_work_list.pop_front(); + } + + // Run from the temporary queue. If the temporary queue + // items create new work queue items, they will show up + // in the elaboration_work_list and then we get to run + // through them in the next pass. + while (! cur_queue.empty()) { + elaborator_work_item_t*tmp = cur_queue.front(); + cur_queue.pop_front(); + tmp->elaborate_runrun(); + delete tmp; + } + + if (! des->elaboration_work_list.empty()) { + des->elaboration_work_list.push_back(new later_defparams(des)); + } + } + + // Look for residual defparams (that point to a non-existent + // scope) and clean them out. + des->residual_defparams(); + // Errors already? Probably missing root modules. Just give up // now and return nothing. if (des->errors > 0) return des; - // This method recurses through the scopes, looking for - // defparam assignments to apply to the parameters in the - // various scopes. This needs to be done after all the scopes - // and basic parameters are taken care of because the defparam - // can assign to a parameter declared *after* it. - des->run_defparams(); - - - // At this point, all parameter overrides are done. Scan the - // scopes and evaluate the parameters all the way down to - // constants. - des->evaluate_parameters(); - // With the parameters evaluated down to constants, we have // what we need to elaborate signals and memories. This pass // creates all the NetNet and NetMemory objects for declared diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index c4ac34fc3..1624f172a 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -115,7 +115,7 @@ static void ifdef_enter(void) struct ifdef_stack_t*cur; cur = (struct ifdef_stack_t*) calloc(1, sizeof(struct ifdef_stack_t)); - cur->path = strdup(istack->path); + if (istack->path) cur->path = strdup(istack->path); cur->lineno = istack->lineno; cur->next = ifdef_stack; @@ -131,8 +131,10 @@ static void ifdef_leave(void) cur = ifdef_stack; ifdef_stack = cur->next; - if (strcmp(istack->path,cur->path) != 0) - { + /* If either path is from a non-file context e.g.(macro expansion) + * we assume that the non-file part is from this file. */ + if (istack->path != NULL && cur->path != NULL && + strcmp(istack->path,cur->path) != 0) { fprintf ( stderr, @@ -856,6 +858,7 @@ static int define_continue_flag = 0; static char *find_arg(char*ptr, char*head, char*arg) { char *cp = ptr; + size_t len = strlen(arg); while (1) { /* Look for a candidate match, just return if none is found. */ @@ -866,7 +869,8 @@ static char *find_arg(char*ptr, char*head, char*arg) * match is not in the middle of another identifier. */ if (cp != head && - (isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$')) { + (isalnum(*(cp-1)) || *(cp-1) == '_' || *(cp-1) == '$' || + isalnum(*(cp+len)) || *(cp+len) == '_' || *(cp+len) == '$')) { cp++; continue; } @@ -1468,7 +1472,7 @@ static void do_include() fprintf(depend_file, "%s\n", standby->path); if (line_direct_flag) - fprintf(yyout, "\n`line %u \"%s\" 1\n", istack->lineno+1, standby->path); + fprintf(yyout, "\n`line 1 \"%s\" 1\n", standby->path); standby->next = istack; standby->stringify_flag = 0; diff --git a/main.cc b/main.cc index 26b237e24..17235f3cf 100644 --- a/main.cc +++ b/main.cc @@ -54,6 +54,7 @@ const char NOTICE[] = #endif # include "pform.h" # include "parse_api.h" +# include "PGenerate.h" # include "netlist.h" # include "target.h" # include "compiler.h" @@ -272,6 +273,9 @@ static void parm_to_flagmap(const string&flag) flags[key] = value; } +static void find_module_mention(map&check_map, Module*m); +static void find_module_mention(map&check_map, PGenerate*s); + /* * Read the contents of a config file. This file is a temporary * configuration file made by the compiler driver to carry the bulky @@ -729,15 +733,7 @@ int main(int argc, char*argv[]) for (mod = pform_modules.begin() ; mod != pform_modules.end() ; mod++) { - list gates = (*mod).second->get_gates(); - list::const_iterator gate; - for (gate = gates.begin(); gate != gates.end(); gate++) { - PGModule *mod = dynamic_cast(*gate); - if (mod) { - // Note that this module has been instantiated - mentioned_p[mod->get_type()] = true; - } - } + find_module_mention(mentioned_p, mod->second); } for (mod = pform_modules.begin() @@ -907,3 +903,40 @@ int main(int argc, char*argv[]) return des? des->errors : 1; } + +static void find_module_mention(map&check_map, Module*mod) +{ + list gates = mod->get_gates(); + list::const_iterator gate; + for (gate = gates.begin(); gate != gates.end(); gate++) { + PGModule*tmp = dynamic_cast(*gate); + if (tmp) { + // Note that this module has been instantiated + check_map[tmp->get_type()] = true; + } + } + + list::const_iterator cur; + for (cur = mod->generate_schemes.begin() + ; cur != mod->generate_schemes.end() ; cur ++) { + find_module_mention(check_map, *cur); + } +} + +static void find_module_mention(map&check_map, PGenerate*schm) +{ + list::const_iterator gate; + for (gate = schm->gates.begin(); gate != schm->gates.end(); gate++) { + PGModule*tmp = dynamic_cast(*gate); + if (tmp) { + // Note that this module has been instantiated + check_map[tmp->get_type()] = true; + } + } + + list::const_iterator cur; + for (cur = schm->generate_schemes.begin() + ; cur != schm->generate_schemes.end() ; cur ++) { + find_module_mention(check_map, *cur); + } +} diff --git a/net_design.cc b/net_design.cc index 62a3b2efb..595c1a44a 100644 --- a/net_design.cc +++ b/net_design.cc @@ -20,6 +20,7 @@ # include "config.h" # include +# include # include /* @@ -208,10 +209,12 @@ void NetScope::run_defparams(Design*des) } } - map::const_iterator pp; - for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) { - NetExpr*val = (*pp).second; - pform_name_t path = (*pp).first; + while (! defparams.empty()) { + pair pp = defparams.front(); + defparams.pop_front(); + + pform_name_t path = pp.first; + NetExpr*val = pp.second; perm_string perm_name = peek_tail_name(path); path.pop_back(); @@ -222,8 +225,13 @@ void NetScope::run_defparams(Design*des) is the current scope. */ NetScope*targ_scope = des->find_scope(this, eval_path); if (targ_scope == 0) { - cerr << val->get_fileline() << ": warning: scope of " << - path << "." << perm_name << " not found." << endl; + + // Push the defparam onto a list for retry + // later. It is possible for the scope lookup to + // fail if the scope being defparam'd into is + // generated by an index array for generate. + eval_path.push_back(hname_t(perm_name)); + defparams_later.push_back(make_pair(eval_path,val)); continue; } @@ -239,6 +247,66 @@ void NetScope::run_defparams(Design*des) } } + + // If some of the defparams didn't find a scope in the name, + // then try again later. It may be that the target scope is + // created later by generate scheme or instance array. + if (! defparams_later.empty()) + des->defparams_later.insert(this); +} + +void NetScope::run_defparams_later(Design*des) +{ + set target_scopes; + list,NetExpr*> > defparams_even_later; + + while (! defparams_later.empty()) { + pair,NetExpr*> cur = defparams_later.front(); + defparams_later.pop_front(); + + listeval_path = cur.first; + perm_string name = eval_path.back().peek_name(); + eval_path.pop_back(); + + NetExpr*val = cur.second; + + NetScope*targ_scope = des->find_scope(this, eval_path); + if (targ_scope == 0) { + // If a scope in the target path is not found, + // then push this defparam for handling even + // later. Maybe a later generate scheme or + // instance array will create the scope. + defparams_even_later.push_back(cur); + continue; + } + + // Once placed in the parameter map, the expression may + // be deleted when evaluated, so give it a copy of this + // expression, not the original. + val = val->dup_expr(); + bool flag = targ_scope->replace_parameter(name, val); + if (! flag) { + cerr << val->get_fileline() << ": warning: parameter " + << name << " not found in " + << scope_path(targ_scope) << "." << endl; + } + + // We'll need to re-evaluate parameters in this scope + target_scopes.insert(targ_scope); + } + + // All the scopes that this defparam set touched should have + // their parameters re-evaluated. + for (set::iterator cur = target_scopes.begin() + ; cur != target_scopes.end() ; cur ++ ) + (*cur)->evaluate_parameters(des); + + // If there are some scopes that still have missing scopes, + // then sav them back into the defparams_later list for a + // later pass. + defparams_later = defparams_even_later; + if (! defparams_later.empty()) + des->defparams_later.insert(this); } void Design::evaluate_parameters() @@ -518,6 +586,9 @@ void NetScope::evaluate_parameters(Design*des) cur = cur->sib_; } + if (debug_scopes) + cerr << ":0" << ": debug: " + << "Evaluate parameters in " << scope_path(this) << endl; // Evaluate the parameter values. The parameter expressions // have already been elaborated and replaced by the scope @@ -552,6 +623,32 @@ void NetScope::evaluate_parameters(Design*des) } +void Design::residual_defparams() +{ + for (list::const_iterator scope = root_scopes_.begin(); + scope != root_scopes_.end(); scope++) + (*scope)->residual_defparams(this); +} + +void NetScope::residual_defparams(Design*des) +{ + // Clean out the list of defparams that never managed to match + // a scope. Print a warning for each. + while (! defparams_later.empty()) { + pair,NetExpr*> cur = defparams_later.front(); + defparams_later.pop_front(); + + cerr << cur.second->get_fileline() << ": warning: " + << "Scope of " << cur.first << " not found." << endl; + } + + NetScope*cur = sub_; + while (cur) { + cur->residual_defparams(des); + cur = cur->sib_; + } +} + const char* Design::get_flag(const string&key) const { map::const_iterator tmp = flags_.find(key); diff --git a/netlist.h b/netlist.h index d8963aeea..d6e01bab2 100644 --- a/netlist.h +++ b/netlist.h @@ -29,6 +29,8 @@ # include # include # include +# include +# include # include "ivl_target.h" # include "pform_types.h" # include "config.h" @@ -718,8 +720,13 @@ class NetScope : public Attrib { const hname_t& fullname() const { return name_; } void run_defparams(class Design*); + void run_defparams_later(class Design*); + void evaluate_parameters(class Design*); + // Look for defparams that never matched, and print warnings. + void residual_defparams(class Design*); + /* This method generates a non-hierarchical name that is guaranteed to be unique within this scope. */ perm_string local_symbol(); @@ -737,7 +744,8 @@ class NetScope : public Attrib { assignments from the scope pass to the parameter evaluation step. After that, it is not used. */ - mapdefparams; + list > defparams; + list,NetExpr*> > defparams_later; public: struct range_t { @@ -3598,6 +3606,18 @@ class NetESignal : public NetExpr { NetExpr*word_; }; +/* + * The Design object keeps a list of work items for processing + * elaboration. This is the type of those work items. + */ +struct elaborator_work_item_t { + explicit elaborator_work_item_t(Design*d) + : des(d) { } + virtual ~elaborator_work_item_t() { } + virtual void elaborate_runrun() =0; + protected: + Design*des; +}; /* * This class contains an entire design. It includes processes and a @@ -3647,10 +3667,23 @@ class Design { NetScope* find_scope(NetScope*, const std::list&path, NetScope::TYPE type = NetScope::MODULE) const; + /* These members help manage elaboration of scopes. When we + get to a point in scope elaboration where we want to put + off a scope elaboration, an object of scope_elaboration_t + is pushed onto the scope_elaborations list. The scope + elaborator will go through this list elaborating scopes + until the list is empty. */ + listelaboration_work_list; + void run_elaboration_work(void); + + set defparams_later; + // PARAMETERS void run_defparams(); void evaluate_parameters(); + // Look for defparams that never matched, and print warnings. + void residual_defparams(); /* This method locates a signal, starting at a given scope. The name parameter may be partially hierarchical, so diff --git a/netmisc.cc b/netmisc.cc index 2cab1dc8d..e6e6e5659 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -244,6 +244,57 @@ bool eval_as_double(double&value, NetExpr*expr) return false; } +/* + * At the parser level, a name component it a name with a collection + * of expressions. For example foo[N] is the name "foo" and the index + * expression "N". This function takes as input the name component and + * returns the path component name. It will evaulate the index + * expression if it is present. + */ +hname_t eval_path_component(Design*des, NetScope*scope, + const name_component_t&comp) +{ + // No index exression, so the path component is an undecorated + // name, for example "foo". + if (comp.index.empty()) + return hname_t(comp.name); + + // The parser will assure that path components will have only + // one index. For example, foo[N] is one index, foo[n][m] is two. + assert(comp.index.size() == 1); + + const index_component_t&index = comp.index.front(); + + // The parser will assure that path components will have only + // bit select index expressions. For example, "foo[n]" is OK, + // but "foo[n:m]" is not. + assert(index.sel == index_component_t::SEL_BIT); + + // Evaluate the bit select to get a number. + NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); + ivl_assert(*index.msb, tmp); + + // Now we should have a constant value for the bit select + // expression, and we can use it to make the final hname_t + // value, for example "foo[5]". + if (NetEConst*ctmp = dynamic_cast(tmp)) { + hname_t res(comp.name, ctmp->value().as_long()); + delete ctmp; + return res; + } + + // Darn, the expression doesn't evaluate to a constant. That's + // and error to be reported. And make up a fake index value to + // return to the caller. + cerr << index.msb->get_fileline() << ": error: " + << "Scope index expression is not constant: " + << *index.msb << endl; + des->errors += 1; + + delete tmp; + return hname_t (comp.name, 0); +} + std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path) { @@ -253,30 +304,7 @@ std::list eval_scope_path(Design*des, NetScope*scope, for (pform_path_it cur = path.begin() ; cur != path.end(); cur++) { const name_component_t&comp = *cur; - if (comp.index.empty()) { - res.push_back(hname_t(comp.name)); - continue; - } - - assert(comp.index.size() == 1); - const index_component_t&index = comp.index.front(); - assert(index.sel == index_component_t::SEL_BIT); - - NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); - ivl_assert(*index.msb, tmp); - - if (NetEConst*ctmp = dynamic_cast(tmp)) { - res.push_back(hname_t(comp.name, ctmp->value().as_long())); - delete ctmp; - continue; - } else { - cerr << index.msb->get_fileline() << ": error: " - << "Scope index expression is not constant: " - << *index.msb << endl; - des->errors += 1; - } - - return res; + res.push_back( eval_path_component(des,scope,comp) ); } return res; diff --git a/netmisc.h b/netmisc.h index 20efe2d98..7d1b42a90 100644 --- a/netmisc.h +++ b/netmisc.h @@ -152,6 +152,16 @@ void eval_expr(NetExpr*&expr, int prune_width =-1); bool eval_as_long(long&value, NetExpr*expr); bool eval_as_double(double&value, NetExpr*expr); +/* + * Evaluate the component of a scope path to get an hname_t value. Do + * the evaluation in the context of the given scope. + */ +extern hname_t eval_path_component(Design*des, NetScope*scope, + const name_component_t&comp); + +/* + * Evaluate an entire scope path in the context of the given scope. + */ extern std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path); diff --git a/parse.y b/parse.y index f63ee1d9b..c97dae85b 100644 --- a/parse.y +++ b/parse.y @@ -2519,7 +2519,7 @@ localparam_assign_decl localparam_assign_list { param_active_range = 0; param_active_signed = false; - param_active_type = IVL_VT_NO_TYPE; + param_active_type = IVL_VT_LOGIC; } | K_signed range { param_active_range = $2; diff --git a/pform.cc b/pform.cc index 022a30461..6b3612a06 100644 --- a/pform.cc +++ b/pform.cc @@ -1760,7 +1760,7 @@ void pform_set_specparam(perm_string name, PExpr*expr) void pform_set_defparam(const pform_name_t&name, PExpr*expr) { assert(expr); - pform_cur_module->defparms[name] = expr; + pform_cur_module->defparms.push_back(make_pair(name,expr)); } /* diff --git a/pform_dump.cc b/pform_dump.cc index 94bf55d59..ba6e60912 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -991,7 +991,6 @@ void Module::dump(ostream&out) const } typedef map::const_iterator parm_iter_t; - typedef map::const_iterator parm_hiter_t; for (parm_iter_t cur = parameters.begin() ; cur != parameters.end() ; cur ++) { out << " parameter " << (*cur).second.type << " "; @@ -1068,6 +1067,7 @@ void Module::dump(ostream&out) const << *(*cur).second << ";" << endl; } + typedef list::const_iterator parm_hiter_t; for (parm_hiter_t cur = defparms.begin() ; cur != defparms.end() ; cur ++) { out << " defparam " << (*cur).first << " = "; diff --git a/pform_types.cc b/pform_types.cc index 6f31725c0..1f5787f27 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2008 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 @@ -16,17 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: pform_types.cc,v 1.1 2007/05/24 04:07:12 steve Exp $" -#endif # include "pform_types.h" - -bool operator < (const name_component_t&lef, const name_component_t&rig) -{ - if (lef.name < rig.name) - return true; - - return false; -} diff --git a/pform_types.h b/pform_types.h index 25c3324a2..df88f6cab 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef __pform_types_H #define __pform_types_H /* - * Copyright (c) 2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2008 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 @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: pform_types.h,v 1.2 2007/06/04 02:19:07 steve Exp $" -#endif // This for the perm_string type. # include "StringHeap.h" @@ -50,13 +47,36 @@ struct name_component_t { std::listindex; }; -extern bool operator < (const name_component_t&lef, const name_component_t&rig); /* - * The pform_name_t is the general form for a hierarchical identifier. + * The pform_name_t is the general form for a hierarchical + * identifier. It is an ordered list of name components. Each name + * component is an identifier and an optional list of bit/part + * selects. The simplest name component is a simple identifier: + * + * foo + * + * The bit/part selects come from the source and are made part of the + * name component. A bit select is a single number that may be a bit + * select of a vector or a word select of an array: + * + * foo[5] -- a bit select/word index + * foo[6:4] -- a part select + * + * The index components of a name component are collected into an + * ordered list, so there may be many, for example: + * + * foo[5][6:4] -- a part select of an array word + * + * The pform_name_t, then, is an ordered list of these name + * components. The list of names comes from a hierarchical name in the + * source, like this: + * + * foo[5].bar[6:4] -- a part select of a vector in sub-scope foo[5]. */ typedef std::list pform_name_t; + inline perm_string peek_head_name(const pform_name_t&that) { return that.front().name; diff --git a/scripts/CREATE_VERSION.sh b/scripts/CREATE_VERSION.sh index 2cbec4707..ac018e4a0 100644 --- a/scripts/CREATE_VERSION.sh +++ b/scripts/CREATE_VERSION.sh @@ -8,6 +8,6 @@ # sh scripts/CREATE_VERSION.sh # -echo "Building verion.h with git describe" +echo "Building version.h with git describe" tmp=`git describe | sed -e 's;\(.*\);#define VERSION_TAG "\1";'` echo "$tmp" > version.h diff --git a/scripts/devel-stub.conf b/scripts/devel-stub.conf new file mode 100644 index 000000000..e3fecf5da --- /dev/null +++ b/scripts/devel-stub.conf @@ -0,0 +1,23 @@ +# +# This is a debug conf file that the scripts/devel-stub.sh script uses +# to control the ivl core. The contents of this file are normally written +# to a temporary file by the driver program, but for devel purposes, where +# the driver program is not used, this config substitutes. +# +# NOTE: DO NOT INSTALL THIS FILE! +# +generation:2005 +generation:specify +generation:xtypes +generation:verilog-ams +iwidth:32 +sys_func:vpi/system.sft +sys_func:vpi/va_math.sft +warnings:implicit +debug:eval_tree +debug:elaborate +debug:scopes +debug:synth2 +out:a.out +ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp +sys_func:scripts/devel-stub.sft diff --git a/scripts/devel-stub.sft b/scripts/devel-stub.sft new file mode 100644 index 000000000..fd5a8e3d7 --- /dev/null +++ b/scripts/devel-stub.sft @@ -0,0 +1,5 @@ + +# This is an example function table. +$realtime vpiSysFuncReal + +$verywide vpiSysFuncSized 128 signed diff --git a/scripts/devel-stub.sh b/scripts/devel-stub.sh new file mode 100644 index 000000000..10fe34f6d --- /dev/null +++ b/scripts/devel-stub.sh @@ -0,0 +1,14 @@ + +# This is a little developer convenience script to run the ivl core program +# in place with the stub target. It runs the ivl core verbose, with diagnostic +# output files enable, and without the driver program or preprocessor. +# It is useful only for development of the ivl core program. +# +# Run this script in the source directory for the ivl core program so that +# the patch to the other components is correct. +# +# NOTE: DO NOT INSTALL THIS FILE. + +./ivl -v -Ctgt-stub/stub.conf -C./scripts/devel-stub.conf -Pa.pf -Na.net -fDLL=tgt-stub/stub.tgt foo.vl + +echo "*** ivl command completed, rc=$?" diff --git a/t-dll.cc b/t-dll.cc index 5b6a22a52..06cd40220 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -30,6 +30,7 @@ # include #endif # include +# include "ivl_assert.h" #if defined(__WIN32__) @@ -538,6 +539,13 @@ void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp) } + if (expr_ == 0) { + cerr << etmp->get_fileline() << ": internal error: " + << "Parameter expression not reduced to constant? " + << *etmp << endl; + } + ivl_assert(*etmp, expr_); + cur_par->value = expr_; expr_ = 0; } @@ -1946,7 +1954,7 @@ void dll_target::lpm_mux(const NetMux*net) { ivl_lpm_t obj = new struct ivl_lpm_s; obj->type = IVL_LPM_MUX; - obj->name = net->name(); // The NetMux perallocates its name. + obj->name = net->name(); // The NetMux permallocates its name. obj->scope = find_scope(des_, net->scope()); assert(obj->scope); diff --git a/tgt-fpga/iverilog-fpga.man b/tgt-fpga/iverilog-fpga.man index 608077d81..a9f263a9c 100644 --- a/tgt-fpga/iverilog-fpga.man +++ b/tgt-fpga/iverilog-fpga.man @@ -160,7 +160,7 @@ device pins are connected. .SH EXAMPLES .TB 8 -.I COMPILING WITH XILINX FOUNDATION/iSE +.I COMPILING WITH XILINX FOUNDATION/ISE Compile a single-file design with command line tools like so: .nf diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index 87c13733d..1f9846d9b 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -315,7 +315,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) because it may be an array of reg vectors. */ snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin); - if (ivl_signal_array_count(sptr) > 1) { + if (ivl_signal_dimensions(sptr) > 0) { fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n", sptr, nptr_pin, sptr, nptr_pin); } diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 6860b8531..6ea3b3637 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -30,7 +30,7 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t exp) struct vector_info res; /* ports cannot be arrays. */ - assert(ivl_signal_array_count(port) == 1); + assert(ivl_signal_dimensions(port) == 0); res = draw_eval_expr_wid(exp, ivl_signal_width(port), 0); /* We could have extra bits so only select the ones we need. */ @@ -46,7 +46,7 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t exp) int res = draw_eval_real(exp); /* ports cannot be arrays. */ - assert(ivl_signal_array_count(port) == 1); + assert(ivl_signal_dimensions(port) == 0); fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res); clr_word(res); @@ -126,7 +126,7 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) if (load_wid > ivl_signal_width(retval)) load_wid = ivl_signal_width(retval); - assert(ivl_signal_array_count(retval) == 1); + assert(ivl_signal_dimensions(retval) == 0); fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n", res.base, retval, load_wid); @@ -157,7 +157,7 @@ int draw_ufunc_real(ivl_expr_t exp) fprintf(vvp_out, " %%join;\n"); /* Return value signal cannot be an array. */ - assert(ivl_signal_array_count(retval) == 1); + assert(ivl_signal_dimensions(retval) == 0); /* Load the result into a word. */ res = allocate_word(); diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 27e803d8d..8a7dda0f2 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -326,7 +326,7 @@ static int draw_signal_real_real(ivl_expr_t exp) int res = allocate_word(); unsigned long word = 0; - if (ivl_signal_array_count(sig) > 1) { + if (ivl_signal_dimensions(sig) > 0) { ivl_expr_t ix = ivl_expr_oper1(exp); if (!number_is_immediate(ix, 8*sizeof(word), 0)) { /* XXXX Need to generate a %load/ar instruction. */ diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index fa550cdde..41220c832 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -235,7 +235,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, if (dexp == 0) { /* Constant delay... */ if (number_is_immediate(word_ix, 64, 0)) { - fprintf(vvp_out, " %%ix/load 3, %lu; address\n", + fprintf(vvp_out, " %%ix/load 3, %lu; address\n", get_number_immediate(word_ix)); } else { /* Calculate array word index into index register 3 */ @@ -298,7 +298,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, ivl_expr_t word_ix = ivl_lval_idx(lval); const unsigned long use_word = 0; - if (ivl_signal_array_count(sig) > 1) { + if (ivl_signal_dimensions(sig) > 0) { assert(word_ix); assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width); return; @@ -480,7 +480,7 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) var = ivl_lval_sig(lval); assert(var != 0); - assert(ivl_signal_array_count(var) == 1); + assert(ivl_signal_dimensions(var) == 0); fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); @@ -540,7 +540,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) sig = ivl_lval_sig(lval); assert(sig); - if (ivl_signal_array_count(sig) > 1) { + if (ivl_signal_dimensions(sig) > 0) { word_ix = ivl_lval_idx(lval); assert(word_ix); assert(number_is_immediate(word_ix, 8*sizeof(use_word), 0)); @@ -1013,7 +1013,7 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) use_rword = get_number_immediate(rword_idx); } - assert(ivl_signal_array_count(rsig) == 1); + assert(ivl_signal_dimensions(rsig) == 0); use_rword = 0; fprintf(vvp_out, " %s/link", command_name); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c55bcb590..3be138c7e 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -879,15 +879,15 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr) fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr); sig = ivl_expr_signal(rise_exp); - assert(ivl_signal_array_count(sig) == 1); + assert(ivl_signal_dimensions(sig) == 0); fprintf(vvp_out, ", v%p_0", sig); sig = ivl_expr_signal(fall_exp); - assert(ivl_signal_array_count(sig) == 1); + assert(ivl_signal_dimensions(sig) == 0); fprintf(vvp_out, ", v%p_0", sig); sig = ivl_expr_signal(decay_exp); - assert(ivl_signal_array_count(sig) == 1); + assert(ivl_signal_dimensions(sig) == 0); fprintf(vvp_out, ", v%p_0;\n", sig); } } @@ -1564,7 +1564,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net) else fprintf(vvp_out, ", "); - assert(ivl_signal_array_count(psig) == 1); + assert(ivl_signal_dimensions(psig) == 0); fprintf(vvp_out, "v%p_0", psig); } @@ -1574,7 +1574,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net) result is collected. */ { ivl_signal_t psig = ivl_scope_port(def, 0); assert(ivl_lpm_width(net) == ivl_signal_width(psig)); - assert(ivl_signal_array_count(psig) == 1); + assert(ivl_signal_dimensions(psig) == 0); fprintf(vvp_out, " v%p_0", psig); } @@ -1602,9 +1602,10 @@ static void draw_lpm_part(ivl_lpm_t net) net, dly, draw_net_input(ivl_lpm_data(net, 0))); fprintf(vvp_out, ", %u, %u;\n", base, width); } else { + const char*sel_symbol = draw_net_input(sel); fprintf(vvp_out, "L_%p%s .part/v %s", net, dly, draw_net_input(ivl_lpm_data(net,0))); - fprintf(vvp_out, ", %s", draw_net_input(sel)); + fprintf(vvp_out, ", %s", sel_symbol); fprintf(vvp_out, ", %u;\n", width); } } diff --git a/vvp/README.txt b/vvp/README.txt index cdd51086f..188f58e36 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -802,7 +802,7 @@ syntax is: The is the label for a variable array, and the is the canonical word index as an unsigned integer. The second form -retrives the index from thread space ( bits starting at ). +retrieves the index from thread space ( bits starting at ). * The &PV<> argument diff --git a/vvp/npmos.h b/vvp/npmos.h index 0f938b382..dc97b7290 100644 --- a/vvp/npmos.h +++ b/vvp/npmos.h @@ -43,7 +43,7 @@ * * This class also implements the NMOS device, which is the same as * the PMOS device, but the Control input inverted. The enable_invert - * flag to the costructor activates this invertion. + * flag to the constructor activates this inversion. */ class vvp_fun_pmos_ : public vvp_net_fun_t { diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 292d7fb53..ef5c909b1 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -474,7 +474,7 @@ part. If any bit of the desired value is outside the vector, then that bit is set to X. The index register 1 is interpreted as a signed value. Even though the -address is cannonical (from 0 to the width of the signal) the value in +address is canonical (from 0 to the width of the signal) the value in index register 1 may be <0 or >=wid. The load instruction handles filling in the out-of-bounds bits with x. diff --git a/vvp/part.cc b/vvp/part.cc index 5b11485ce..3b7f6e500 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -109,6 +109,21 @@ void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit) vvp_send_vec4_pv(port.ptr()->out, bit, base_, wid_, vwid_); } +void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) +{ + assert(port.port() == 0); + + if (bit.size() != wid_) { + cerr << "internal error: part_pv (strength-aware) data mismatch. " + << "base_=" << base_ << ", wid_=" << wid_ + << ", vwid_=" << vwid_ << ", bit=" << bit + << endl; + } + assert(bit.size() == wid_); + + vvp_send_vec8_pv(port.ptr()->out, bit, base_, wid_, vwid_); +} + vvp_fun_part_var::vvp_fun_part_var(unsigned w) : base_(0), wid_(w) { diff --git a/vvp/part.h b/vvp/part.h index 8fa861b1a..3fdffd886 100644 --- a/vvp/part.h +++ b/vvp/part.h @@ -62,6 +62,7 @@ class vvp_fun_part_pv : public vvp_net_fun_t { public: void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit); + void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); private: unsigned base_; diff --git a/vvp/resolv.cc b/vvp/resolv.cc index 4448b15c8..d0db6ec3c 100644 --- a/vvp/resolv.cc +++ b/vvp/resolv.cc @@ -97,6 +97,24 @@ void resolv_functor::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) vvp_send_vec8(ptr->out, out); } +void resolv_functor::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + assert(bit.size() == wid); + vvp_vector8_t res (vwid); + + for (unsigned idx = 0 ; idx < base ; idx += 1) + res.set_bit(idx, vvp_scalar_t()); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) + res.set_bit(idx+base, bit.value(idx)); + + for (unsigned idx = base+wid ; idx < vwid ; idx += 1) + res.set_bit(idx, vvp_scalar_t()); + + recv_vec8(port, res); +} + resolv_wired_logic::resolv_wired_logic() { } diff --git a/vvp/resolv.h b/vvp/resolv.h index d7aa6fe94..4f0e683c6 100644 --- a/vvp/resolv.h +++ b/vvp/resolv.h @@ -45,6 +45,8 @@ class resolv_functor : public vvp_net_fun_t { void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid); + void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); private: vvp_vector8_t val_[4]; diff --git a/vvp/schedule.cc b/vvp/schedule.cc index c2546120d..50944c695 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -780,7 +780,7 @@ void schedule_simulate(void) ctim->rwsync = 0; /* If out of rw events, then run the rosync - events and delete this timestep. This also + events and delete this time step. This also deletes threads as needed. */ if (ctim->active == 0) { run_rosync(ctim); diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 54ef5dd47..eacbf1732 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -298,8 +298,7 @@ static void format_vpiIntVal(vvp_fun_signal_vec*sig, int base, unsigned wid, { vvp_vector4_t sub = sig->vec4_value().subvalue(base, wid); long val = 0; - bool flag = vector4_to_value(sub, val, signed_flag); - if (! flag) val = 0; + vector4_to_value(sub, val, signed_flag, false); vp->value.integer = val; } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index f8a6d5b49..31d1c8602 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1371,14 +1371,12 @@ bool of_CVT_RI(vthread_t thr, vvp_code_t cp) bool of_CVT_VR(vthread_t thr, vvp_code_t cp) { double r = thr->words[cp->bit_idx[1]].w_real; - long rl = lround(r); unsigned base = cp->bit_idx[0]; unsigned wid = cp->number; - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - thr_put_bit(thr, base+idx, (rl&1)? BIT4_1 : BIT4_0); - rl >>= 1; - } + vvp_vector4_t tmp(wid, r); + /* Make sure there is enough space for the new vector. */ + thr_check_addr(thr, base+wid-1); + thr->bits4.set_vec(base, tmp); return true; } diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index 439afca78..c258309a6 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -357,11 +357,11 @@ class vvp_island_tran : public vvp_island { void vvp_island_tran::run_island() { // Test to see if any of the branches are enabled. - bool runable = false; + bool runnable = false; for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) { - runable |= cur->run_test_enabled(); + runnable |= cur->run_test_enabled(); } - if (runable == false) + if (runnable == false) return; for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index b9d6b60be..f77850c3e 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -373,9 +373,10 @@ vvp_vector4_t::vvp_vector4_t(unsigned size, double val) return; } - /* We return 'b1 for + or - infinity. */ + /* We return 'b1 for + infinity or 'b0 for - infinity. */ if (val && (val == 0.5*val)) { - allocate_words_(size, WORD_1_ABITS, WORD_1_BBITS); + if (val > 0) allocate_words_(size, WORD_1_ABITS, WORD_1_BBITS); + else allocate_words_(size, WORD_0_ABITS, WORD_0_BBITS); return; } @@ -1133,10 +1134,12 @@ ostream& operator<< (ostream&out, const vvp_vector4_t&that) return out; } -bool vector4_to_value(const vvp_vector4_t&vec, long&val, bool is_signed) +bool vector4_to_value(const vvp_vector4_t&vec, long&val, + bool is_signed, bool is_arithmetic) { long res = 0; long msk = 1; + bool rc_flag = true; for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { switch (vec.value(idx)) { @@ -1146,7 +1149,10 @@ bool vector4_to_value(const vvp_vector4_t&vec, long&val, bool is_signed) res |= msk; break; default: - return false; + if (is_arithmetic) + return false; + else + rc_flag = false; } msk <<= 1L; @@ -1158,7 +1164,7 @@ bool vector4_to_value(const vvp_vector4_t&vec, long&val, bool is_signed) } val = res; - return true; + return rc_flag; } bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val) @@ -2118,7 +2124,16 @@ void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bits, unsigned base, unsigned wid, unsigned vwid) { cerr << "internal error: " << typeid(*this).name() << ": " - << "recv_vect_pv(" << bits << ", " << base + << "recv_vec4_pv(" << bits << ", " << base + << ", " << wid << ", " << vwid << ") not implemented" << endl; + assert(0); +} + +void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t, const vvp_vector8_t&bits, + unsigned base, unsigned wid, unsigned vwid) +{ + cerr << "internal error: " << typeid(*this).name() << ": " + << "recv_vec8_pv(" << bits << ", " << base << ", " << wid << ", " << vwid << ") not implemented" << endl; assert(0); } @@ -2397,6 +2412,12 @@ void vvp_fun_signal::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, } } +void vvp_fun_signal::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + recv_vec4_pv(ptr, reduce4(bit), base, wid, vwid); +} + void vvp_fun_signal::calculate_output_(vvp_net_ptr_t ptr) { if (force_mask_.size()) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 832689e72..6e6497179 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -381,8 +381,15 @@ template extern T coerce_to_width(const T&that, unsigned width); * place (this follows the rules of Verilog conversions from vector4 * to real and integers) and the return value becomes false to * indicate an error. + * + * The "is_arithmetic" flag true will cause a result to be entirely 0 + * if any bits are X/Z. That is normally what you want if this value + * is in the midst of an arithmetic expression. If is_arithmetic=false + * then the X/Z bits will be replaced with 0 bits, and the return + * value will be "false", but the other bits will be transferred. This + * is what you want if you are doing "vpi_get_value", for example. */ -extern bool vector4_to_value(const vvp_vector4_t&a, long&val, bool is_signed); +extern bool vector4_to_value(const vvp_vector4_t&a, long&val, bool is_signed, bool is_arithmetic =true); extern bool vector4_to_value(const vvp_vector4_t&a, unsigned long&val); extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed); @@ -863,6 +870,8 @@ class vvp_net_fun_t { // Part select variants of above virtual void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid); + virtual void recv_vec8_pv(vvp_net_ptr_t p, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); virtual void recv_long_pv(vvp_net_ptr_t port, long bit, unsigned base, unsigned wid); @@ -1107,6 +1116,8 @@ class vvp_fun_signal : public vvp_fun_signal_vec { // Part select variants of above void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid); + void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); // Get information about the vector value. unsigned size() const; @@ -1313,4 +1324,17 @@ inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val, } } +inline void vvp_send_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&val, + unsigned base, unsigned wid, unsigned vwid) +{ + while (struct vvp_net_t*cur = ptr.ptr()) { + vvp_net_ptr_t next = cur->port[ptr.port()]; + + if (cur->fun) + cur->fun->recv_vec8_pv(ptr, val, base, wid, vwid); + + ptr = next; + } +} + #endif