Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl
This commit is contained in:
commit
33885ed891
44
HName.h
44
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 <iostream>
|
||||
# include <list>
|
||||
# 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<hname_t>&ll)
|
||||
{
|
||||
list<hname_t>::const_iterator cur = ll.begin();
|
||||
out << *cur;
|
||||
cur ++;
|
||||
while (cur != ll.end()) {
|
||||
out << "." << *cur;
|
||||
cur ++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
6
Module.h
6
Module.h
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include <utility>
|
||||
# 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. */
|
||||
map<pform_name_t,PExpr*>defparms;
|
||||
typedef pair<pform_name_t,PExpr*> named_expr_t;
|
||||
list<named_expr_t>defparms;
|
||||
|
||||
/* 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<perm_string,NetExpr*> 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;
|
||||
|
||||
|
|
|
|||
7
PGate.h
7
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1063,7 +1063,7 @@ void NetScope::dump(ostream&o) const
|
|||
|
||||
/* Dump the saved defparam assignments here. */
|
||||
{
|
||||
map<pform_name_t,NetExpr*>::const_iterator pp;
|
||||
list<pair<pform_name_t,NetExpr*> >::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<pair<list<hname_t>,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="
|
||||
|
|
|
|||
129
elab_scope.cc
129
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<PGenerate*>::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<perm_string,param_expr_t>::const_iterator mparm_it_t;
|
||||
typedef map<pform_name_t,PExpr*>::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<PGenerate*>::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<NetEConst*> (mse);
|
||||
|
|
|
|||
153
elaborate.cc
153
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()
|
||||
{
|
||||
list<NetScope*>tmp_list;
|
||||
for (set<NetScope*>::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(list<perm_string>roots)
|
||||
{
|
||||
svector<root_elem*> root_elems(roots.size());
|
||||
|
|
@ -3785,7 +3861,7 @@ Design* elaborate(list<perm_string>roots)
|
|||
// 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<perm_string>::const_iterator root = roots.begin()
|
||||
; root != roots.end()
|
||||
; root++) {
|
||||
|
|
@ -3804,47 +3880,74 @@ Design* elaborate(list<perm_string>roots)
|
|||
// 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<elaborator_work_item_t*> 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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
51
main.cc
51
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<perm_string,bool>&check_map, Module*m);
|
||||
static void find_module_mention(map<perm_string,bool>&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<PGate*> gates = (*mod).second->get_gates();
|
||||
list<PGate*>::const_iterator gate;
|
||||
for (gate = gates.begin(); gate != gates.end(); gate++) {
|
||||
PGModule *mod = dynamic_cast<PGModule*>(*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<perm_string,bool>&check_map, Module*mod)
|
||||
{
|
||||
list<PGate*> gates = mod->get_gates();
|
||||
list<PGate*>::const_iterator gate;
|
||||
for (gate = gates.begin(); gate != gates.end(); gate++) {
|
||||
PGModule*tmp = dynamic_cast<PGModule*>(*gate);
|
||||
if (tmp) {
|
||||
// Note that this module has been instantiated
|
||||
check_map[tmp->get_type()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
list<PGenerate*>::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<perm_string,bool>&check_map, PGenerate*schm)
|
||||
{
|
||||
list<PGate*>::const_iterator gate;
|
||||
for (gate = schm->gates.begin(); gate != schm->gates.end(); gate++) {
|
||||
PGModule*tmp = dynamic_cast<PGModule*>(*gate);
|
||||
if (tmp) {
|
||||
// Note that this module has been instantiated
|
||||
check_map[tmp->get_type()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
list<PGenerate*>::const_iterator cur;
|
||||
for (cur = schm->generate_schemes.begin()
|
||||
; cur != schm->generate_schemes.end() ; cur ++) {
|
||||
find_module_mention(check_map, *cur);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
109
net_design.cc
109
net_design.cc
|
|
@ -20,6 +20,7 @@
|
|||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
# include <set>
|
||||
# include <cstdlib>
|
||||
|
||||
/*
|
||||
|
|
@ -208,10 +209,12 @@ void NetScope::run_defparams(Design*des)
|
|||
}
|
||||
}
|
||||
|
||||
map<pform_name_t,NetExpr*>::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<pform_name_t,NetExpr*> 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<NetScope*> target_scopes;
|
||||
list<pair<list<hname_t>,NetExpr*> > defparams_even_later;
|
||||
|
||||
while (! defparams_later.empty()) {
|
||||
pair<list<hname_t>,NetExpr*> cur = defparams_later.front();
|
||||
defparams_later.pop_front();
|
||||
|
||||
list<hname_t>eval_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<NetScope*>::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<NetScope*>::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<list<hname_t>,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<string,const char*>::const_iterator tmp = flags_.find(key);
|
||||
|
|
|
|||
35
netlist.h
35
netlist.h
|
|
@ -29,6 +29,8 @@
|
|||
# include <map>
|
||||
# include <list>
|
||||
# include <vector>
|
||||
# include <set>
|
||||
# include <utility>
|
||||
# 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. */
|
||||
|
||||
map<pform_name_t,NetExpr*>defparams;
|
||||
list<pair<pform_name_t,NetExpr*> > defparams;
|
||||
list<pair<list<hname_t>,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<hname_t>&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. */
|
||||
list<elaborator_work_item_t*>elaboration_work_list;
|
||||
void run_elaboration_work(void);
|
||||
|
||||
set<NetScope*> 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
|
||||
|
|
|
|||
76
netmisc.cc
76
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<NetEConst*>(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<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path)
|
||||
{
|
||||
|
|
@ -253,30 +304,7 @@ std::list<hname_t> 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<NetEConst*>(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;
|
||||
|
|
|
|||
10
netmisc.h
10
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<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path);
|
||||
|
||||
|
|
|
|||
2
parse.y
2
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;
|
||||
|
|
|
|||
2
pform.cc
2
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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -991,7 +991,6 @@ void Module::dump(ostream&out) const
|
|||
}
|
||||
|
||||
typedef map<perm_string,param_expr_t>::const_iterator parm_iter_t;
|
||||
typedef map<pform_name_t,PExpr*>::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<Module::named_expr_t>::const_iterator parm_hiter_t;
|
||||
for (parm_hiter_t cur = defparms.begin()
|
||||
; cur != defparms.end() ; cur ++) {
|
||||
out << " defparam " << (*cur).first << " = ";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::list<index_component_t>index;
|
||||
};
|
||||
|
||||
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<name_component_t> pform_name_t;
|
||||
|
||||
|
||||
inline perm_string peek_head_name(const pform_name_t&that)
|
||||
{
|
||||
return that.front().name;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
# This is an example function table.
|
||||
$realtime vpiSysFuncReal
|
||||
|
||||
$verywide vpiSysFuncSized 128 signed
|
||||
|
|
@ -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=$?"
|
||||
10
t-dll.cc
10
t-dll.cc
|
|
@ -30,6 +30,7 @@
|
|||
# include <malloc.h>
|
||||
#endif
|
||||
# include <stdlib.h>
|
||||
# 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -802,7 +802,7 @@ syntax is:
|
|||
|
||||
The <symbol> is the label for a variable array, and the <number> is
|
||||
the canonical word index as an unsigned integer. The second form
|
||||
retrives the index from thread space (<width> bits starting at <base>).
|
||||
retrieves the index from thread space (<width> bits starting at <base>).
|
||||
|
||||
* The &PV<> argument
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
15
vvp/part.cc
15
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -381,8 +381,15 @@ template <class T> 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue