From 360be597a86b6f50709aedc03b51cd446504a3f5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 21 Jun 2008 18:36:46 -0700 Subject: [PATCH 01/23] Minor cleanup and comments. The initial elaboration needs better comments/documentation. --- elaborate.cc | 39 +++++++++++++++++++------- netmisc.cc | 76 +++++++++++++++++++++++++++++++++++---------------- netmisc.h | 10 +++++++ pform_types.h | 26 +++++++++++++++++- 4 files changed, 116 insertions(+), 35 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index a0d8d73a0..cc8bbf90c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3775,6 +3775,12 @@ struct root_elem { NetScope *scope; }; +/* + * 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 +3791,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,29 +3810,42 @@ 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; } + // Elaborate the instances of the root modules into the root + // scopes that we created. The elaborate_scope for each will + // recurse down the design, furtner elaborating sub-scope all + // the way down to the leaves. + for (i = 0; i < root_elems.count(); i += 1) { + Module*rmod = root_elems[i]->mod; + NetScope*scope = root_elems[i]->scope; + + Module::replace_t stub; + if (! rmod->elaborate_scope(des, scope, stub)) { + delete des; + return 0; + } + } + // Errors already? Probably missing root modules. Just give up // now and return nothing. if (des->errors > 0) 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/pform_types.h b/pform_types.h index 25c3324a2..35f0039e8 100644 --- a/pform_types.h +++ b/pform_types.h @@ -53,10 +53,34 @@ struct name_component_t { 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; From 3ec8a867db4319b197c30a6f32d18e470e69aac2 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Tue, 24 Jun 2008 08:46:16 -0700 Subject: [PATCH 02/23] Spelling fixes comments, documentation, a variable name, and a couple of messages --- elaborate.cc | 4 ++-- scripts/CREATE_VERSION.sh | 2 +- t-dll.cc | 2 +- tgt-fpga/iverilog-fpga.man | 2 +- vvp/README.txt | 2 +- vvp/npmos.h | 2 +- vvp/opcodes.txt | 2 +- vvp/schedule.cc | 2 +- vvp/vvp_island.cc | 6 +++--- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index a0d8d73a0..4c7df215b 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 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/t-dll.cc b/t-dll.cc index 5b6a22a52..0d9380ac4 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1946,7 +1946,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/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/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/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) From c810406195301d44eb56d5c505b24ed20fbadafb Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 24 Jun 2008 20:28:08 -0700 Subject: [PATCH 03/23] run scope elaboration as queued work items. Putting scope elaboration into work queue items allows for handling more complex processing order. The elaboration_work_list queue drives the processing of elaborate_scope and parameter evaluation. --- elaborate.cc | 87 +++++++++++++++++++++++++++++++++++++--------------- netlist.h | 21 +++++++++++++ 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index cc8bbf90c..474e59bde 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3775,6 +3775,50 @@ 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(); + } +}; + /* * This function is the root of all elaboration. The input is the list * of root module names. The function locates the Module definitions @@ -3829,21 +3873,27 @@ Design* elaborate(listroots) 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); } - // Elaborate the instances of the root modules into the root - // scopes that we created. The elaborate_scope for each will - // recurse down the design, furtner elaborating sub-scope all - // the way down to the leaves. - for (i = 0; i < root_elems.count(); i += 1) { - Module*rmod = root_elems[i]->mod; - NetScope*scope = root_elems[i]->scope; + // 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)); - Module::replace_t stub; - if (! rmod->elaborate_scope(des, scope, stub)) { - delete des; - return 0; - } + // 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()) { + elaborator_work_item_t*tmp = des->elaboration_work_list.front(); + des->elaboration_work_list.pop_front(); + tmp->elaborate_runrun(); + delete tmp; } // Errors already? Probably missing root modules. Just give up @@ -3851,19 +3901,6 @@ Design* elaborate(listroots) 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/netlist.h b/netlist.h index d8963aeea..07b196077 100644 --- a/netlist.h +++ b/netlist.h @@ -3598,6 +3598,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,6 +3659,15 @@ 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); + // PARAMETERS void run_defparams(); From 533ee87bb1025ec3b5e0c07733bb67b1931820b8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 24 Jun 2008 22:03:28 -0700 Subject: [PATCH 04/23] Delay elaborate of instance array scopes to allow defparams to propagate. When we detect that a module instance is an array of instances, delay the elaboration of the array until after the first defparam processing is complete. This allows for defparam statements to control the instantiation of module instance arrays. --- PGate.h | 7 +++--- elab_scope.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) 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/elab_scope.cc b/elab_scope.cc index 6a4c55288..ce59c7020 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -654,6 +654,36 @@ 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() +{ + 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 +730,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); From 8c5480309446e74f776e5a0d981d69e84e6f50cb Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 25 Jun 2008 13:59:39 -0700 Subject: [PATCH 05/23] vpi_get_value of integer values replaces x/z bits with 0. In arithmetic expressions, vectors with x/z are replaced with 0, but vpi_get_value replaces x/z bits with 0 bits without replacing the whole vector. --- vvp/vpi_signal.cc | 3 +-- vvp/vvp_net.cc | 11 ++++++++--- vvp/vvp_net.h | 9 ++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 54ef5dd47..c3bdf03e9 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; + bool flag = vector4_to_value(sub, val, signed_flag, false); vp->value.integer = val; } diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index b9d6b60be..eb5f154b4 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1133,10 +1133,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 +1148,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 +1163,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) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 832689e72..2d352c4e3 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); From 4163eb28d0aa1e7a7d90bc1e926f9ad4b3ae7f92 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 25 Jun 2008 10:49:57 -0700 Subject: [PATCH 06/23] Copy file and line info during a macro expansion. The file and line number information needs to be copied when doing a macro expansion. This prevents a macro that expands to an `ifdef of other construct that needs to push the stack from core dumping. --- ivlpp/lexor.lex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index c4ac34fc3..dc1c7ebee 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1362,6 +1362,8 @@ static void do_expand(int use_args) } isp->next = istack; + isp->path = strdup(istack->path); + isp->lineno = istack->lineno; istack->yybs = YY_CURRENT_BUFFER; istack = isp; From 897f14e60a4b1c49a009d19790f9fda93173b0e2 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 25 Jun 2008 11:35:59 -0700 Subject: [PATCH 07/23] Fix memory leak in recent patch. --- ivlpp/lexor.lex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index dc1c7ebee..301602298 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1362,7 +1362,7 @@ static void do_expand(int use_args) } isp->next = istack; - isp->path = strdup(istack->path); + isp->path = istack->path; isp->lineno = istack->lineno; istack->yybs = YY_CURRENT_BUFFER; istack = isp; From c17ffcae2cf4302125471ba1d425e586c803be25 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 25 Jun 2008 14:22:42 -0700 Subject: [PATCH 08/23] Rework previous patch to use the correct method. --- ivlpp/lexor.lex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 301602298..7e4796047 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, @@ -1362,8 +1364,6 @@ static void do_expand(int use_args) } isp->next = istack; - isp->path = istack->path; - isp->lineno = istack->lineno; istack->yybs = YY_CURRENT_BUFFER; istack = isp; From 12783674cb4d14193b4ae827b06ce3d004e48ff1 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 25 Jun 2008 15:42:57 -0700 Subject: [PATCH 09/23] Clean up compiler warning. --- vvp/vpi_signal.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index c3bdf03e9..eacbf1732 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -298,7 +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, false); + vector4_to_value(sub, val, signed_flag, false); vp->value.integer = val; } From da2c4b0fa160a0237b198917635ac0f2242e6332 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 25 Jun 2008 22:02:22 -0700 Subject: [PATCH 10/23] Multiple passes for run_defparams. It is possible for defparams to not find their target the first time around, because the elaboration of the target scope is not yet done. So retry the defparams once for each scope by putting it on a work item in the elaborator_work_items list. --- HName.h | 44 +++++++++++--------------------- design_dump.cc | 11 +++++++- elab_scope.cc | 7 +++++- net_design.cc | 68 +++++++++++++++++++++++++++++++++++++++++++++++--- netlist.h | 6 ++++- 5 files changed, 99 insertions(+), 37 deletions(-) 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/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 ce59c7020..bba6eef63 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -294,7 +294,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, NetExpr*val = ex->elaborate_pexpr(des, scope); 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 @@ -675,6 +675,11 @@ class delayed_elaborate_scope_mod_instances : public elaborator_work_item_t { 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_); } diff --git a/net_design.cc b/net_design.cc index 62a3b2efb..666c1f40d 100644 --- a/net_design.cc +++ b/net_design.cc @@ -199,6 +199,22 @@ void Design::run_defparams() (*scope)->run_defparams(this); } +class run_defparams_later_t : public elaborator_work_item_t { + public: + run_defparams_later_t(Design*des, NetScope*scope) + : elaborator_work_item_t(des), scope_(scope) + { } + + void elaborate_runrun(); + private: + NetScope*scope_; +}; + +void run_defparams_later_t::elaborate_runrun() +{ + scope_->run_defparams_later(des); +} + void NetScope::run_defparams(Design*des) { { NetScope*cur = sub_; @@ -208,10 +224,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(); @@ -224,6 +242,13 @@ void NetScope::run_defparams(Design*des) 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 +264,41 @@ void NetScope::run_defparams(Design*des) } } + if (! defparams_later.empty()) { + des->elaboration_work_list.push_back(new run_defparams_later_t(des, this)); + } +} + +void NetScope::run_defparams_later(Design*des) +{ + 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) { + cerr << val->get_fileline() << ": warning: scope of " << + eval_path << "." << name << " not found." << endl; + 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; + } + } } void Design::evaluate_parameters() diff --git a/netlist.h b/netlist.h index 07b196077..5057af231 100644 --- a/netlist.h +++ b/netlist.h @@ -29,6 +29,7 @@ # include # include # include +# include # include "ivl_target.h" # include "pform_types.h" # include "config.h" @@ -718,6 +719,8 @@ 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*); /* This method generates a non-hierarchical name that is @@ -737,7 +740,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 { From 1ef7994ae291909c290a73eaf591b34fef8a6c65 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 28 Jun 2008 09:30:09 -0700 Subject: [PATCH 11/23] Handle indexed defparams. The l-value of a defparam assignment is a hierarchical name that may include array selects to select scopes from module arrays. Therefore it makes no sense to store parsed defparams in a map. Instead, they should go into an ordered list. This also maked more sense because later defparams *may* have the same name as a previous defparam, and will override the previous defparam. So replace the map of parsed defparams with a list of parsed defparams. Also, as soon as the defparam expression is elaborated, the list entry is no longer needed, so delete it. Save memory. --- Module.h | 6 ++++-- elab_scope.cc | 14 +++++++------- net_design.cc | 2 -- pform.cc | 2 +- pform_dump.cc | 2 +- pform_types.cc | 13 +------------ pform_types.h | 6 +----- 7 files changed, 15 insertions(+), 30 deletions(-) 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/elab_scope.cc b/elab_scope.cc index bba6eef63..098843e72 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -182,7 +182,7 @@ static void elaborate_scope_funcs(Design*des, NetScope*scope, } 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 +201,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 +284,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.push_back(make_pair(cur->first, val)); + scope->defparams.push_back(make_pair(cur.first, val)); } // Evaluate the attributes. Evaluate them in the scope of the diff --git a/net_design.cc b/net_design.cc index 666c1f40d..98900b180 100644 --- a/net_design.cc +++ b/net_design.cc @@ -240,8 +240,6 @@ 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 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 35f0039e8..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,7 +47,6 @@ 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 From e3d9cc30a82425d08a34695285b9147070f2f5d0 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 28 Jun 2008 09:51:42 -0700 Subject: [PATCH 12/23] Checkin some developer convenience scripts. --- scripts/devel-stub.conf | 23 +++++++++++++++++++++++ scripts/devel-stub.sft | 5 +++++ scripts/devel-stub.sh | 14 ++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 scripts/devel-stub.conf create mode 100644 scripts/devel-stub.sft create mode 100644 scripts/devel-stub.sh 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=$?" From d761a2273c439a1cfdf7fce94204937c055adb6e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 28 Jun 2008 13:06:14 -0500 Subject: [PATCH 13/23] Run generate schemes after defparams. We must run generate schemes after running defparams because the defparams may define the results of the generate schemes. So put the generate schemes for a module scope into elaborator work items. --- elab_scope.cc | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 098843e72..37f186e93 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -181,6 +181,38 @@ 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) { @@ -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 From d9b02657a7072eea66c9b7bed98853b46a222e69 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 28 Jun 2008 13:34:46 -0500 Subject: [PATCH 14/23] Modules within generate schemes are not default roots. Modules mentioned within generate schemes are not candidates for defaults guesses at root modules. They are, obviously, used within the generate schem. --- main.cc | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) 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); + } +} From e02d186946dc9e2fb78f46270586611b82fc4eff Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 Jun 2008 03:46:46 +0200 Subject: [PATCH 15/23] Handle multiple passes of scope and defparam elaboration. When generate schems and instance arrays are nested, it takes multiple iterations of elaborate scope, defparams and evaluate parameters before everything is worked out. Rework the work item processing so that the loop elaborates scopes and runs defparams in phases. The phases are needed so that we can tell when the remaining defparams are orphaned. --- elaborate.cc | 55 +++++++++++++++++++++++++++++++--- net_design.cc | 81 ++++++++++++++++++++++++++++++++++++++------------- netlist.h | 8 +++++ t-dll.cc | 8 +++++ 4 files changed, 127 insertions(+), 25 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 4cb32bdf7..f22e38f00 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3819,6 +3819,32 @@ class top_defparams : public elaborator_work_item_t { } }; +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 @@ -3890,12 +3916,33 @@ Design* elaborate(listroots) // empty. This list is initially populated above where the // initial root scopes are primed. while (! des->elaboration_work_list.empty()) { - elaborator_work_item_t*tmp = des->elaboration_work_list.front(); - des->elaboration_work_list.pop_front(); - tmp->elaborate_runrun(); - delete tmp; + // 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) diff --git a/net_design.cc b/net_design.cc index 98900b180..595c1a44a 100644 --- a/net_design.cc +++ b/net_design.cc @@ -20,6 +20,7 @@ # include "config.h" # include +# include # include /* @@ -199,22 +200,6 @@ void Design::run_defparams() (*scope)->run_defparams(this); } -class run_defparams_later_t : public elaborator_work_item_t { - public: - run_defparams_later_t(Design*des, NetScope*scope) - : elaborator_work_item_t(des), scope_(scope) - { } - - void elaborate_runrun(); - private: - NetScope*scope_; -}; - -void run_defparams_later_t::elaborate_runrun() -{ - scope_->run_defparams_later(des); -} - void NetScope::run_defparams(Design*des) { { NetScope*cur = sub_; @@ -262,13 +247,19 @@ void NetScope::run_defparams(Design*des) } } - if (! defparams_later.empty()) { - des->elaboration_work_list.push_back(new run_defparams_later_t(des, this)); - } + + // 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(); @@ -281,8 +272,11 @@ void NetScope::run_defparams_later(Design*des) NetScope*targ_scope = des->find_scope(this, eval_path); if (targ_scope == 0) { - cerr << val->get_fileline() << ": warning: scope of " << - eval_path << "." << name << " not found." << endl; + // 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; } @@ -296,7 +290,23 @@ void NetScope::run_defparams_later(Design*des) << 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() @@ -576,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 @@ -610,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 5057af231..d6e01bab2 100644 --- a/netlist.h +++ b/netlist.h @@ -29,6 +29,7 @@ # include # include # include +# include # include # include "ivl_target.h" # include "pform_types.h" @@ -723,6 +724,9 @@ class NetScope : public Attrib { 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(); @@ -3672,10 +3676,14 @@ class Design { 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/t-dll.cc b/t-dll.cc index 0d9380ac4..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; } From f9c67e21b289717df4dfe5dcf6569d76c87e6830 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 7 Jul 2008 11:03:06 -0700 Subject: [PATCH 16/23] Some variable part select arguments must be drawn before the part select. Some variable part selects need to draw the select argument before the variable part select is printed e.g.(.array/port). --- tgt-vvp/vvp_scope.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c55bcb590..1731a3a4d 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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); } } From 2ceb0539afd73949da8b73388c460a804ed3de2e Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 16 Jul 2008 13:58:16 -0700 Subject: [PATCH 17/23] IVL_VT_LOGIC is default localparam type not IVL_VT_NO_TYPE This patch fixes a bug where a local parameter with only a range was incorrectly setting the default parameter type to IVL_VT_NO_TYPE. This would create a compile time assert for any untyped parameter/localparam immediately following it. --- parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From 5207be0778be4c42e507cf09259d8276fab2bde6 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 16 Jul 2008 15:49:33 -0700 Subject: [PATCH 18/23] Use ivl_signal_dimensions to find arrays not ivl_signal_array_count ivl_signal_dimensions() is the correct call to use to determine if a signal is part of an array. If it is greater than zero the signal is an array. --- tgt-vvp/draw_net_input.c | 2 +- tgt-vvp/draw_ufunc.c | 8 ++++---- tgt-vvp/eval_real.c | 2 +- tgt-vvp/vvp_process.c | 10 +++++----- tgt-vvp/vvp_scope.c | 10 +++++----- 5 files changed, 16 insertions(+), 16 deletions(-) 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 1731a3a4d..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); } From 7a4f85d3828fd2ddcffe50384a450ba2b928fbca Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 16 Jul 2008 17:58:34 -0700 Subject: [PATCH 19/23] Make .part/pv strength aware and resolv vec8_pv aware. This patch makes .part/pv strength aware, resolv vec8_pv aware. vvp_net_fun_t adds vec8_pv as a virtual function with an appropriate error default. vvp_fun_signal should full support vec8_pv (not tested and may not be needed). --- vvp/part.cc | 15 +++++++++++++++ vvp/part.h | 1 + vvp/resolv.cc | 18 ++++++++++++++++++ vvp/resolv.h | 2 ++ vvp/vvp_net.cc | 17 ++++++++++++++++- vvp/vvp_net.h | 17 +++++++++++++++++ 6 files changed, 69 insertions(+), 1 deletion(-) 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/vvp_net.cc b/vvp/vvp_net.cc index eb5f154b4..f038777a2 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -2123,7 +2123,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); } @@ -2402,6 +2411,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 2d352c4e3..6e6497179 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -870,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); @@ -1114,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; @@ -1320,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 From 6cb3d86d15f6daff4ffb05dea0c83797011a35ce Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 22 Jul 2008 10:42:13 -0700 Subject: [PATCH 20/23] Update %cvt/vr to use new double to vector conversion (constructor). This patch updates the %cvt/vr command to use the new double to vector constructor. This allows the resulting bit pattern to be larger than a long. The old method was producing incorrect results without a warning for large bit values. --- vvp/vthread.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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; } From 6d4dd5ae3b12c429921039ce2a5b354e7ef3e532 Mon Sep 17 00:00:00 2001 From: nog Date: Wed, 23 Jul 2008 14:45:30 +0200 Subject: [PATCH 21/23] Fix macro argument replacements When searching for macro arguments to replace, make sure that the argument is not the begining of another identifier. --- ivlpp/lexor.lex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 7e4796047..58b1d069b 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -858,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. */ @@ -868,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; } From 1a41ac31453d0be9c63e36864105aa3ce5f9850d Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 23 Jul 2008 09:36:25 -0700 Subject: [PATCH 22/23] Update real to int conversion: -inf is 'b0 not 'b1 like +inf. The new real to int conversion was incorrectly setting the bits for minus infinity to all ones. This is incorrect in a two's complement encoding where the largest negative number would be a leading 1 followed by an infinite number of zeros. --- vvp/vvp_net.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index f038777a2..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; } From 3191b3efcb2cae02a9c301fe977b4380364dda9d Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 28 Jul 2008 20:55:47 -0700 Subject: [PATCH 23/23] An included file should start at line 1. The preprocessor was incorrectly setting the line when starting an include file to the line it was called from instead of 1. This would give incorrect line numbers for errors/warnings in the included file. --- ivlpp/lexor.lex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 58b1d069b..1624f172a 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1472,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;