Merge branch 'master' of git://icarus.com/~steve-icarus/verilog into vhdl

This commit is contained in:
Nick Gasson 2008-08-01 08:25:38 +01:00
commit 33885ed891
41 changed files with 722 additions and 187 deletions

44
HName.h
View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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="

View File

@ -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);

View File

@ -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

View File

@ -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
View File

@ -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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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));
}
/*

View File

@ -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 << " = ";

View File

@ -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;
}

View File

@ -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;

View File

@ -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

23
scripts/devel-stub.conf Normal file
View File

@ -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

5
scripts/devel-stub.sft Normal file
View File

@ -0,0 +1,5 @@
# This is an example function table.
$realtime vpiSysFuncReal
$verywide vpiSysFuncSized 128 signed

14
scripts/devel-stub.sh Normal file
View File

@ -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=$?"

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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();

View File

@ -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. */

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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.

View File

@ -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)
{

View File

@ -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_;

View File

@ -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()
{
}

View File

@ -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];

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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()) {

View File

@ -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