Merge branch 'master' of git://github.com/steveicarus/iverilog into vhdl

This commit is contained in:
Nick Gasson 2008-06-23 13:48:56 +01:00
commit 181a53d3ed
127 changed files with 7464 additions and 4065 deletions

View File

@ -57,7 +57,7 @@ class hname_t {
private:
perm_string name_;
// If the number is anything other then INT_MIN, then this is
// If the number is anything other than INT_MIN, then this is
// the numeric part of the name. Otherwise, it is not part of
// the name at all.
int number_;

View File

@ -186,11 +186,14 @@ iverilog-vpi.pdf: iverilog-vpi.ps
# version.h file in the source tree (included in snapshots and releases), and
# finally use nothing.
.PHONY: version.h
version.h:
# "true" and "false" in the next few lines are Unix shell command names
ifeq ($(GIT),none)
@echo '#define VERSION_TAG ""' > $@;
GIT_PRESENT = false
else
@if test -d $(srcdir)/.git; then \
GIT_PRESENT = true
endif
version.h:
@if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \
echo "Using git-describe for VERSION_TAG"; \
tmp=`$(GIT) --git-dir $(srcdir)/.git describe \
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
@ -202,7 +205,6 @@ else
echo "Using empty VERSION_TAG"; \
echo '#define VERSION_TAG ""' > $@; \
fi
endif
ifeq (@MINGW32@,yes)
ifeq ($(MAN),none)

View File

@ -26,7 +26,7 @@
/* n is a permallocated string. */
Module::Module(perm_string n)
: PScope(n, 0)
: PScope(n)
{
library_flag = false;
default_nettype = NetNet::NONE;
@ -41,16 +41,6 @@ void Module::add_gate(PGate*gate)
gates_.push_back(gate);
}
void Module::add_task(perm_string name, PTask*task)
{
tasks_[name] = task;
}
void Module::add_function(perm_string name, PFunction *func)
{
funcs_[name] = func;
}
unsigned Module::port_count() const
{
return ports.count();

View File

@ -94,7 +94,7 @@ class Module : public PScope, public LineInfo {
module is elaborated. During parsing, I put the parameters
into this map. */
struct param_expr_t : public LineInfo {
param_expr_t() : range(0) { }
param_expr_t() : type(IVL_VT_NO_TYPE), msb(0), lsb(0), signed_flag(false), expr(0), range(0) { }
// Type information
ivl_variable_type_t type;
PExpr*msb;
@ -102,7 +102,7 @@ class Module : public PScope, public LineInfo {
bool signed_flag;
// Value expression
PExpr*expr;
// If there are range constrants, list them here
// If there are range constraints, list them here
range_t*range;
};
map<perm_string,param_expr_t>parameters;
@ -138,6 +138,10 @@ class Module : public PScope, public LineInfo {
set by the `timescale directive. */
int time_unit, time_precision;
/* Task definitions within this module */
map<perm_string,PTask*> tasks;
map<perm_string,PFunction*> funcs;
/* The module has a list of genvars that may be used in
various generate schemes. */
map<perm_string,LineInfo*> genvars;
@ -152,8 +156,6 @@ class Module : public PScope, public LineInfo {
perm_string mod_name() const { return pscope_name(); }
void add_gate(PGate*gate);
void add_task(perm_string name, PTask*def);
void add_function(perm_string name, PFunction*def);
unsigned port_count() const;
const svector<PEIdent*>& get_port(unsigned idx) const;
@ -173,8 +175,6 @@ class Module : public PScope, public LineInfo {
private:
list<PGate*> gates_;
map<perm_string,PTask*> tasks_;
map<perm_string,PFunction*> funcs_;
static void elaborate_parm_item_(perm_string name, const param_expr_t&cur,
Design*des, NetScope*scope);

18
PExpr.h
View File

@ -306,10 +306,16 @@ class PEIdent : public PExpr {
private:
// Common functions to calculate parts of part/bit selects.
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
bool calculate_param_range_(Design*, NetScope*,
const NetExpr*msb_ex, long&msb,
const NetExpr*lsb_ex, long&lsb) const;
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
private:
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
index_component_t::ctype_t) const;
@ -321,6 +327,18 @@ class PEIdent : public PExpr {
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_param_part_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_param_idx_up_(Design*des,
NetScope*scope,
const NetExpr*par,
NetScope*found,
const NetExpr*par_msb,
const NetExpr*par_lsb) const;
NetExpr*elaborate_expr_net(Design*des,
NetScope*scope,
NetNet*net,

View File

@ -27,27 +27,14 @@ PGenerate::PGenerate(unsigned id)
: id_number(id)
{
parent = 0;
lexical_scope = 0;
}
PGenerate::~PGenerate()
{
}
PWire* PGenerate::get_wire(perm_string name) const
{
map<perm_string,PWire*>::const_iterator obj = wires.find(name);
if (obj == wires.end())
return 0;
else
return (*obj).second;
}
void PGenerate::add_gate(PGate*gate)
{
gates.push_back(gate);
}
void PGenerate::add_behavior(PProcess*proc)
{
behaviors.push_back(proc);
}

View File

@ -1,7 +1,7 @@
#ifndef __PGenerate_H
#define __PGenerate_H
/*
* Copyright (c) 2006 Stephen Williams (steve@icarus.com)
* Copyright (c) 2006-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,13 +18,11 @@
* 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: PGenerate.h,v 1.4 2007/06/02 03:42:12 steve Exp $"
#endif
# include "LineInfo.h"
# include "StringHeap.h"
# include "HName.h"
# include "PScope.h"
# include <list>
# include <map>
# include "pform_types.h"
@ -32,7 +30,9 @@
class Design;
class NetScope;
class PExpr;
class PFunction;
class PProcess;
class PTask;
class PGate;
class PWire;
@ -49,10 +49,10 @@ class PWire;
* The parent points to the GS_CASE that contains this item.
* the loop_test is compared with the parent->loop_test expression.
*/
class PGenerate : public LineInfo {
class PGenerate : public LineInfo, public LexicalScope {
public:
PGenerate(unsigned id_number);
explicit PGenerate(unsigned id_number);
~PGenerate();
// Generate schemes have an ID number, for when the scope is
@ -60,6 +60,10 @@ class PGenerate : public LineInfo {
const unsigned id_number;
perm_string scope_name;
// This is used during parsing to stack lexical scopes within
// this generate scheme.
PScope*lexical_scope;
enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE,
GS_CASE, GS_CASE_ITEM};
scheme_t scheme_type;
@ -71,16 +75,17 @@ class PGenerate : public LineInfo {
PExpr*loop_test;
PExpr*loop_step;
map<perm_string,PWire*>wires;
PWire* get_wire(perm_string name) const;
list<PGate*> gates;
void add_gate(PGate*);
list<PProcess*> behaviors;
void add_behavior(PProcess*behave);
list<PGenerate*> generates;
// Tasks instantiated within this scheme.
map<perm_string,PTask*> tasks;
map<perm_string,PFunction*>funcs;
// Generate schemes can contain further generate schemes.
list<PGenerate*> generate_schemes;
PGenerate*parent;
// This method is called by the elaboration of a module to

View File

@ -19,8 +19,13 @@
# include "PScope.h"
PScope::PScope(perm_string n, PScope*p)
: name_(n), parent_(p)
PScope::PScope(perm_string n, PScope*parent)
: name_(n), parent_(parent)
{
}
PScope::PScope(perm_string n)
: name_(n), parent_(0)
{
}
@ -28,7 +33,7 @@ PScope::~PScope()
{
}
PWire* PScope::wires_find(perm_string name)
PWire* LexicalScope::wires_find(perm_string name)
{
map<perm_string,PWire*>::const_iterator cur = wires.find(name);
if (cur == wires.end())

View File

@ -38,7 +38,22 @@ class NetScope;
* NOTE: This is note the same concept as the "scope" of an elaborated
* hierarchy. That is represented by NetScope objects after elaboration.
*/
class PScope {
class LexicalScope {
public:
explicit LexicalScope() { }
// A virtual destructor is so that dynamic_cast can work.
virtual ~LexicalScope() { }
// Nets an variables (wires) in the scope
map<perm_string,PWire*>wires;
PWire* wires_find(perm_string name);
private:
};
class PScope : public LexicalScope {
public:
// When created, a scope has a name and a parent. The name is
@ -50,15 +65,12 @@ class PScope {
// modules. Scopes for tasks and functions point to their
// containing module.
PScope(perm_string name, PScope*parent);
PScope(perm_string name);
virtual ~PScope();
perm_string pscope_name() const { return name_; }
PScope* pscope_parent() { return parent_; }
// Nets an variables (wires) in the scope
map<perm_string,PWire*>wires;
PWire* wires_find(perm_string name);
// Named events in the scope.
map<perm_string,PEvent*>events;

View File

@ -92,7 +92,7 @@ PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t)
}
PBlock::PBlock(BL_TYPE t)
: PScope(perm_string(),0), bl_type_(t)
: PScope(perm_string()), bl_type_(t)
{
}

View File

@ -109,6 +109,9 @@ ostream& operator << (ostream&o, ivl_switch_type_t val)
case IVL_SW_RTRANIF1:
o << "rtranif1";
break;
case IVL_SW_TRAN_VP:
o << "tran(VP)";
break;
}
return o;
}
@ -299,6 +302,22 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetCastInt::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Cast to int. (NetCastInt): " <<
name() << " width=" << width() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCastReal::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Cast to real (NetCastReal): " <<
name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCLShift::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
@ -518,9 +537,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
case PV:
pt = "PV";
break;
case BI:
pt = "BI";
break;
}
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
<< name();
@ -638,7 +654,14 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
void NetTran::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << type_ << " " << name() << endl;
o << setw(ind) << "" << type_ << " " << name()
<< " island " << island;
if (type_ == IVL_SW_TRAN_VP) {
o << " width=" << vector_width()
<< " part=" << part_width()
<< " offset=" << part_offset();
}
o << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}

View File

@ -328,23 +328,24 @@ static int t_default(char*cmd, unsigned ncmd)
remove(compiled_defines_path);
}
#ifdef __MINGW32__ /* MinGW just returns the exit status, so return it! */
free(cmd);
return rc;
#else
int rtn = 0;
if (rc != 0) {
if (rc == 127) {
fprintf(stderr, "Failed to execute: %s\n", cmd);
return 1;
}
if (WIFEXITED(rc))
return WEXITSTATUS(rc);
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
rtn = 1;
} else if (WIFEXITED(rc)) {
rtn = WEXITSTATUS(rc);
} else {
fprintf(stderr, "Command signaled: %s\n", cmd);
rtn = -1;
}
}
return 0;
free(cmd);
return rtn;
#endif
}
@ -505,7 +506,7 @@ int process_generation(const char*name)
" 2005 -- IEEE1364-2005\n"
"Other generation flags:\n"
" specify | no-specify\n"
" verilog-ams | no-verinlog-ams\n"
" verilog-ams | no-verilog-ams\n"
" std-include | no-std-include\n"
" xtypes | no-xtypes\n"
" icarus-misc | no-icarus-misc\n"
@ -871,6 +872,7 @@ int main(int argc, char **argv)
}
fprintf(stderr, "Command signaled: %s\n", cmd);
free(cmd);
return -1;
}
@ -889,6 +891,4 @@ int main(int argc, char **argv)
fclose(iconfig_file);
return t_default(cmd, ncmd);
return 0;
}

View File

@ -716,6 +716,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
des->errors += 1;
}
if (!rep->value().is_defined()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be undefined (" << rep->value()
<< ")." << endl;
des->errors += 1;
concat_depth -= 1;
return 0;
}
if (rep->value().is_negative()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be negative (" << rep->value().as_long()
@ -873,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
return flag;
}
/*
* When we know that this is an indexed part select (up or down) this
* method calculates the up/down base, as far at it can be calculated.
*/
NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const
{
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.lsb != 0);
ivl_assert(*this, index_tail.msb != 0);
NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1);
return tmp;
}
bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
const NetExpr*par_msb, long&par_msv,
const NetExpr*par_lsb, long&par_lsv) const
{
if (par_msb == 0) {
// If the parameter doesn't have an explicit range, then
// just return range values of 0:0. The par_msv==0 is
// correct. The par_msv is not necessarily correct, but
// clients of this function don't need a correct value.
ivl_assert(*this, par_lsb == 0);
par_msv = 0;
par_lsv = 0;
return true;
}
const NetEConst*tmp = dynamic_cast<const NetEConst*> (par_msb);
ivl_assert(*this, tmp);
par_msv = tmp->value().as_long();
tmp = dynamic_cast<const NetEConst*> (par_lsb);
ivl_assert(*this, tmp);
par_lsv = tmp->value().as_long();
return true;
}
unsigned PEIdent::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
bool&unsized_flag) const
@ -1085,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
static verinum param_part_select_bits(const verinum&par_val, long wid,
long lsv, long par_lsv)
{
verinum result (verinum::Vx, wid, true);
for (long idx = 0 ; idx < wid ; idx += 1) {
long off = idx + lsv - par_lsv;
if (off < 0)
result.set(idx, verinum::Vx);
else if (off < (long)par_val.len())
result.set(idx, par_val.get(off));
else if (par_val.is_string()) // Pad strings with nulls.
result.set(idx, verinum::V0);
else if (par_val.has_len()) // Pad sized parameters with X
result.set(idx, verinum::Vx);
else // Unsized parameters are "infinite" width.
result.set(idx, sign_bit(par_val));
}
// If the input is a string, and the part select is working on
// byte boundaries, then make the result into a string.
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
return result.as_string();
return result;
}
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
long msv, lsv;
bool flag = calculate_parts_(des, scope, msv, lsv);
if (!flag)
return 0;
long par_msv, par_lsv;
flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
if (!flag)
return 0;
// Notice that the par_msv is not used in this function other
// than for this test. It is used to tell the direction that
// the bits are numbers, so that we can make sure the
// direction matches the part select direction. After that,
// we only need the par_lsv.
if ((msv>lsv && par_msv<par_lsv) || (msv<lsv && par_msv>=par_lsv)) {
cerr << get_fileline() << ": error: Part select "
<< "[" << msv << ":" << lsv << "] is out of order." << endl;
des->errors += 1;
return 0;
}
long wid = 1 + labs(msv-lsv);
if (debug_elaborate)
cerr << get_fileline() << ": debug: Calculate part select "
<< "[" << msv << ":" << lsv << "] from range "
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex);
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
const NetExpr*par,
NetScope*found_in,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
long par_msv, par_lsv;
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
if (!flag)
return 0;
NetExpr*base = calculate_up_do_base_(des, scope);
if (base == 0)
return 0;
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
ivl_assert(*this, par_ex);
if (debug_elaborate)
cerr << get_fileline() << ": debug: Calculate part select "
<< "[" << *base << "+:" << wid << "] from range "
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
// Handle the special case that the base is constant. In this
// case, just precalculate the entire constant result.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
long lsv = base_c->value().as_long();
// Watch out for reversed bit numbering. We're making
// the part select from LSB to MSB.
if (par_msv < par_lsv)
lsv = lsv - wid + 1;
verinum result = param_part_select_bits(par_ex->value(), wid,
lsv, par_lsv);
NetEConst*result_ex = new NetEConst(result);
result_ex->set_line(*this);
return result_ex;
}
if ((par_msb < par_lsb) && (wid>1))
base = make_add_expr(base, 1-(long)wid);
NetExpr*tmp = par->dup_expr();
tmp = new NetESelect(tmp, base, wid);
tmp->set_line(*this);
return tmp;
}
/*
* Handle the case that the identifier is a parameter reference. The
* parameter expression has already been located for us (as the par
@ -1097,84 +1276,29 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
const NetExpr*par_msb,
const NetExpr*par_lsb) const
{
NetExpr*tmp = par->dup_expr();
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
if (use_sel == index_component_t::SEL_PART) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
ivl_assert(*this, index_tail.lsb);
// NOTE TO SELF: This is the way I want to see this code
// structured. This closely follows the structure of the
// elaborate_expr_net_ code, which splits all the various
// selects to different methods.
if (use_sel == index_component_t::SEL_PART)
return elaborate_expr_param_part_(des, scope, par, found_in,
par_msb, par_lsb);
/* If the identifier has a part select, we support
it by pulling the right bits out and making a
sized unsigned constant. This code assumes the
lsb of a parameter is 0 and the msb is the
width of the parameter. */
if (use_sel == index_component_t::SEL_IDX_UP)
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
par_msb, par_lsb);
verinum*lsn = index_tail.lsb->eval_const(des, scope);
verinum*msn = index_tail.msb->eval_const(des, scope);
if ((lsn == 0) || (msn == 0)) {
cerr << get_fileline() << ": error: "
"Part select expressions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
// NOTE TO SELF (continued): The code below should be
// rewritten in the above format, as I get to it.
long lsb = lsn->as_long();
long msb = msn->as_long();
if ((lsb < 0) || (msb < lsb)) {
cerr << get_fileline() << ": error: invalid part "
<< "select: " << path_
<< "["<<msb<<":"<<lsb<<"]" << endl;
des->errors += 1;
return 0;
}
unsigned long ulsb=lsb;
unsigned long umsb=msb;
NetExpr*tmp = par->dup_expr();
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
assert(le);
verinum result (verinum::V0, msb-lsb+1, true);
verinum exl = le->value();
/* Pull the bits from the parameter, one at a
time. If the bit is within the range, simply
copy it to the result. If the bit is outside
the range, we sign extend signed unsized
numbers, zero extend unsigned unsigned numbers,
and X extend sized numbers. */
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
if (idx < exl.len())
result.set(idx-lsb, exl.get(idx));
else if (exl.is_string())
result.set(idx-lsb, verinum::V0);
else if (exl.has_len())
result.set(idx-lsb, verinum::Vx);
else if (exl.has_sign())
result.set(idx-lsb, exl.get(exl.len()-1));
else
result.set(idx-lsb, verinum::V0);
}
/* If the input is a string, and the part select
is working on byte boundaries, then the result
can be made into a string. */
if (exl.is_string()
&& (lsb%8 == 0)
&& (result.len()%8 == 0))
result = verinum(result.as_string());
delete tmp;
tmp = new NetEConst(result);
} else if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) {
if (use_sel == index_component_t::SEL_IDX_DO) {
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
@ -1249,7 +1373,7 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
par_mv = par_me->value().as_long();
par_lv = par_le->value().as_long();
}
/* Convert the index to cannonical bit address. */
/* Convert the index to canonical bit address. */
long ridx = rv.as_long();
if (par_mv >= par_lv) {
ridx -= par_lv;
@ -1361,8 +1485,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
// Special case: The index is out of range, so the value
// of this expression is a 'bx vector the width of a word.
if (!net->array_index_is_valid(addr)) {
verinum xxx (verinum::Vx, net->vector_width());
NetEConst*resx = new NetEConst(xxx);
NetEConst*resx = make_const_x(net->vector_width());
resx->set_line(*this);
delete word_index;
return resx;
@ -1428,16 +1551,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
negative values. However, the width that they represent is
unsigned. Remember that any order is possible,
i.e., [1:0], [-4:6], etc. */
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
if (wid > net->vector_width()) {
cerr << get_fileline() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return net;
}
ivl_assert(*this, wid <= net->vector_width());
unsigned long wid = 1 + labs(msv-lsv);
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
cerr << get_fileline() << ": error: part select ["
@ -1448,26 +1562,29 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
return net;
}
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
cerr << get_fileline() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
//delete lsn;
//delete msn;
return net;
}
long sb_lsb = net->sig()->sb_to_idx(lsv);
long sb_msb = net->sig()->sb_to_idx(msv);
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
// signal itself, casting to unsigned if necessary.
if (sb_lsb == 0 && wid == net->vector_width()) {
net->cast_signed(false);
return net;
}
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
// If the part select covers NONE of the vector, then return a
// constant X.
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
NetEConst*tmp = make_const_x(wid);
tmp->set_line(*this);
return tmp;
}
NetExpr*ex = new NetEConst(verinum(sb_lsb));
NetESelect*ss = new NetESelect(net, ex, wid);
ss->set_line(*this);
return ss;
}
@ -1477,14 +1594,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetESignal*net, NetScope*found_in) const
{
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.lsb != 0);
ivl_assert(*this, index_tail.msb != 0);
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
NetExpr*base = calculate_up_do_base_(des, scope);
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);
@ -1609,8 +1719,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
/* The bit select is out of range of the
vector. This is legal, but returns a
constant 1'bx value. */
verinum x (verinum::Vx);
NetEConst*tmp = new NetEConst(x);
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
cerr << get_fileline() << ": warning: Bit select ["

View File

@ -208,101 +208,18 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return 0;
}
long msb, lsb;
NetExpr*mux;
if (use_sel == index_component_t::SEL_BIT) {
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
/* If there is only a single select expression, it is a
bit select. Evaluate the constant value and treat it
as a part select with a bit width of 1. If the
expression it not constant, then return the
expression as a mux. */
NetExpr*index_expr = elab_and_eval(des, scope, index_tail.msb, -1);
if (NetEConst*index_con = dynamic_cast<NetEConst*> (index_expr)) {
msb = index_con->value().as_long();
lsb = index_con->value().as_long();
mux = 0;
} else {
msb = 0;
lsb = 0;
mux = index_expr;
}
} else {
/* No select expressions, so presume a part select the
width of the register. */
msb = reg->msb();
lsb = reg->lsb();
mux = 0;
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_bit_(des, scope, lv);
return lv;
}
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
NetAssign_*lv;
if (mux) {
/* If there is a non-constant bit select, make a
NetAssign_ to the target reg and attach a
bmux to select the target bit. */
lv = new NetAssign_(reg);
/* Correct the mux for the range of the vector. */
if (reg->msb() < reg->lsb())
mux = make_sub_expr(reg->lsb(), mux);
else if (reg->lsb() != 0)
mux = make_add_expr(mux, - reg->lsb());
lv->set_part(mux, 1);
} else if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
lv = new NetAssign_(reg);
} else {
/* If the bit/part select is constant, then make the
NetAssign_ only as wide as it needs to be and connect
only to the selected bits of the reg. */
unsigned loff = reg->sb_to_idx(lsb);
unsigned moff = reg->sb_to_idx(msb);
unsigned wid = moff - loff + 1;
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return 0;
}
/* If the part select extends beyond the extreme of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if ((wid + loff) > reg->vector_width()) {
cerr << get_fileline() << ": error: bit/part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
}
lv = new NetAssign_(reg);
lv->set_part(new NetEConst(verinum(loff)), wid);
}
/* No select expressions. */
NetAssign_*lv = new NetAssign_(reg);
return lv;
}
@ -374,10 +291,67 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
return lv;
}
bool PEIdent::elaborate_lval_net_bit_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
const name_component_t&name_tail = path_.back();
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
NetNet*reg = lv->sig();
// Bit selects have a single select expression. Evaluate the
// constant value and treat it as a part select with a bit
// width of 1.
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
long lsb = 0;
if (NetEConst*index_con = dynamic_cast<NetEConst*> (mux)) {
lsb = index_con->value().as_long();
mux = 0;
}
if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select expression.
if (reg->msb() < reg->lsb())
mux = make_sub_expr(reg->lsb(), mux);
else if (reg->lsb() != 0)
mux = make_add_expr(mux, - reg->lsb());
lv->set_part(mux, 1);
} else if (lsb == reg->msb() && lsb == reg->lsb()) {
// Constant bit mux that happens to select the only bit
// of the l-value. Don't bother with any select at all.
} else {
// Constant bit select that does something useful.
long loff = reg->sb_to_idx(lsb);
if (loff < 0 || loff >= (long)reg->vector_width()) {
cerr << get_fileline() << ": error: bit select "
<< reg->name() << "[" <<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
}
lv->set_part(new NetEConst(verinum(loff)), 1);
}
return true;
}
bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
// The range expressions of a part select must be
// constant. The calculate_parts_ function calculates the
// values into msb and lsb.
long msb, lsb;
bool flag = calculate_parts_(des, scope, msb, lsb);
if (!flag)
@ -388,17 +362,14 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
/* Part select covers the entire vector. Simplest case. */
} else {
/* If the bit/part select is constant, then make the
NetAssign_ only as wide as it needs to be and connect
only to the selected bits of the reg. */
unsigned loff = reg->sb_to_idx(lsb);
unsigned moff = reg->sb_to_idx(msb);
unsigned wid = moff - loff + 1;
/* Get the canonical offsets into the vector. */
long loff = reg->sb_to_idx(lsb);
long moff = reg->sb_to_idx(msb);
long wid = moff - loff + 1;
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
@ -408,17 +379,15 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
return false;
}
/* If the part select extends beyond the extreme of the
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if ((wid + loff) > reg->vector_width()) {
cerr << get_fileline() << ": error: bit/part select "
if (loff < 0 || moff >= (signed)reg->vector_width()) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return false;
}
lv->set_part(new NetEConst(verinum(loff)), wid);

View File

@ -137,7 +137,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
@ -449,26 +449,21 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
/* Elaborate the operands of the compare first as expressions
(so that the eval_tree method can reduce constant
expressions, including parameters) then turn those results
into synthesized nets. */
NetExpr*lexp = elab_and_eval(des, scope, left_, lwidth),
*rexp = elab_and_eval(des, scope, right_, lwidth);
NetExpr*lexp = elab_and_eval(des, scope, left_, -1),
*rexp = elab_and_eval(des, scope, right_, -1);
if (lexp == 0 || rexp == 0) return 0;
unsigned operand_width;
bool real_arg = false;
if (lexp->expr_type() == IVL_VT_REAL ||
rexp->expr_type() == IVL_VT_REAL) {
operand_width = 1;
real_arg = true;
} else {
bool real_arg = true;
if (lexp->expr_type() != IVL_VT_REAL &&
rexp->expr_type() != IVL_VT_REAL) {
/* Choose the operand width to be the width of the widest
self-determined operand. */
operand_width = lexp->expr_width();
unsigned operand_width = lexp->expr_width();
if (rexp->expr_width() > operand_width)
operand_width = rexp->expr_width();
@ -476,6 +471,8 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
lexp = pad_to_width(lexp, operand_width);
rexp->set_width(operand_width);
rexp = pad_to_width(rexp, operand_width);
real_arg = false;
}
NetNet*lsig = 0;
@ -719,6 +716,16 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope,
unsigned rwidth = lwidth;
// If either operand is IVL_VT_REAL, then cast the other to
// IVL_VT_REAL so that the division can become IVL_VT_REAL.
if (lsig->data_type()==IVL_VT_REAL || rsig->data_type()==IVL_VT_REAL) {
if (lsig->data_type() != IVL_VT_REAL)
lsig = cast_to_real(des, scope, lsig);
if (rsig->data_type() != IVL_VT_REAL)
rsig = cast_to_real(des, scope, rsig);
}
if (rwidth == 0) {
rwidth = lsig->vector_width();
if (rsig->vector_width() > rwidth)
@ -790,8 +797,8 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
@ -1578,6 +1585,14 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
return 0;
}
if (!erep->value().is_defined()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be undefined (" << erep->value()
<< ")." << endl;
des->errors += 1;
return 0;
}
if (erep->value().is_negative()) {
cerr << get_fileline() << ": error: Concatenation repeat "
<< "may not be negative (" << erep->value().as_long()
@ -1779,8 +1794,32 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
that connects to a signal with the correct name. */
if (par != 0) {
// Detect and handle the special case that we have a
// real valued parameter. Return a NetLiteral and a
// properly typed net.
if (const NetECReal*pc = dynamic_cast<const NetECReal*>(par)) {
NetLiteral*tmp = new NetLiteral(scope, scope->local_symbol(),
pc->value());
des->add_node(tmp);
tmp->set_line(*par);
sig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT);
sig->set_line(*tmp);
sig->data_type(tmp->data_type());
sig->local_flag(true);
connect(tmp->pin(0), sig->pin(0));
return sig;
}
const NetEConst*pc = dynamic_cast<const NetEConst*>(par);
assert(pc);
if (pc == 0) {
cerr << get_fileline() << ": internal error: "
<< "Non-consant parameter value?: " << *par << endl;
cerr << get_fileline() << ": : "
<< "Expression type is " << par->expr_type() << endl;
}
ivl_assert(*this, pc);
verinum pvalue = pc->value();
/* If the parameter has declared dimensions, then apply
@ -2367,30 +2406,53 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
osig->local_flag(true);
osig->set_line(*this);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Generating part selects "
<< "to connect input l-value to subexpressions."
<< endl;
if (bidirectional_flag) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Generating tran(VP) "
<< "to connect input l-value to subexpressions."
<< endl;
}
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetTran*ps = new NetTran(scope, scope->local_symbol(),
osig->vector_width(), wid, off);
des->add_node(ps);
ps->set_line(*this);
connect(ps->pin(0), osig->pin(0));
connect(ps->pin(1), nets[idx]->pin(0));
ivl_assert(*this, wid <= width);
width -= wid;
}
} else {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Generating part selects "
<< "to connect input l-value to subexpressions."
<< endl;
}
NetPartSelect::dir_t part_dir = NetPartSelect::VP;
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
des->add_node(ps);
ps->set_line(*this);
connect(ps->pin(1), osig->pin(0));
connect(ps->pin(0), nets[idx]->pin(0));
assert(wid <= width);
width -= wid;
}
assert(width == 0);
}
NetPartSelect::dir_t part_dir = bidirectional_flag
? NetPartSelect::BI
: NetPartSelect::VP;
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
des->add_node(ps);
connect(ps->pin(1), osig->pin(0));
connect(ps->pin(0), nets[idx]->pin(0));
assert(wid <= width);
width -= wid;
}
assert(width == 0);
osig->data_type(nets[0]->data_type());
osig->local_flag(true);
return osig;
@ -2743,11 +2805,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
/* If we are processing a tran or inout, then the
partselect is bi-directional. Otherwise, it is a
Part-to-Vector select. */
NetPartSelect::dir_t part_dir;
if (bidirectional_flag)
part_dir = NetPartSelect::BI;
else
part_dir = NetPartSelect::PV;
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
@ -2764,11 +2821,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
subsig->local_flag(true);
subsig->set_line(*this);
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
part_dir);
des->add_node(sub);
connect(sub->pin(0), subsig->pin(0));
if (bidirectional_flag) {
// Make a tran(VP)
NetTran*sub = new NetTran(scope, scope->local_symbol(),
sig->vector_width(),
subnet_wid, lidx);
sub->set_line(*this);
des->add_node(sub);
connect(sub->pin(0), sig->pin(0));
connect(sub->pin(1), subsig->pin(0));
} else {
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
NetPartSelect::PV);
des->add_node(sub);
sub->set_line(*this);
connect(sub->pin(0), subsig->pin(0));
}
sig = subsig;
}

View File

@ -98,7 +98,16 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
tmp->low_expr = 0;
}
if (range->high_expr) {
if (range->high_expr && range->high_expr==range->low_expr) {
// Detect the special case of a "point"
// range. These are called out by setting the high
// and low expression ranges to the same
// expression. The exclude_flags should be false
// in this case
ivl_assert(*range->high_expr, tmp->low_open_flag==false && tmp->high_open_flag==false);
tmp->high_expr = tmp->low_expr;
} else if (range->high_expr) {
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
ivl_assert(*range->high_expr, tmp->high_expr);
} else {
@ -114,6 +123,64 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
delete val;
}
static void elaborate_scope_tasks(Design*des, NetScope*scope,
const LineInfo&loc,
const map<perm_string,PTask*>&tasks)
{
typedef map<perm_string,PTask*>::const_iterator tasks_it_t;
for (tasks_it_t cur = tasks.begin()
; cur != tasks.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << loc.get_fileline() << ": error: task/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*task_scope = new NetScope(scope, use_name,
NetScope::TASK);
task_scope->set_line((*cur).second);
if (debug_scopes)
cerr << cur->second->get_fileline() << ": debug: "
<< "Elaborate task scope " << scope_path(task_scope) << endl;
(*cur).second->elaborate_scope(des, task_scope);
}
}
static void elaborate_scope_funcs(Design*des, NetScope*scope,
const LineInfo&loc,
const map<perm_string,PFunction*>&funcs)
{
typedef map<perm_string,PFunction*>::const_iterator funcs_it_t;
for (funcs_it_t cur = funcs.begin()
; cur != funcs.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << loc.get_fileline() << ": error: function/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*func_scope = new NetScope(scope, use_name,
NetScope::FUNC);
func_scope->set_line((*cur).second);
if (debug_scopes)
cerr << cur->second->get_fileline() << ": debug: "
<< "Elaborate function scope " << scope_path(func_scope) << endl;
(*cur).second->elaborate_scope(des, func_scope);
}
}
bool Module::elaborate_scope(Design*des, NetScope*scope,
const replace_t&replacements) const
{
@ -257,49 +324,14 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
// elaborate_scope method of the PTask for detailed
// processing.
typedef map<perm_string,PTask*>::const_iterator tasks_it_t;
for (tasks_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << get_fileline() << ": error: task/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*task_scope = new NetScope(scope, use_name,
NetScope::TASK);
task_scope->set_line((*cur).second);
(*cur).second->elaborate_scope(des, task_scope);
}
elaborate_scope_tasks(des, scope, *this, tasks);
// Functions are very similar to tasks, at least from the
// perspective of scopes. So handle them exactly the same
// way.
typedef map<perm_string,PFunction*>::const_iterator funcs_it_t;
for (funcs_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++ ) {
hname_t use_name( (*cur).first );
if (scope->child(use_name)) {
cerr << get_fileline() << ": error: function/scope name "
<< use_name << " already used in this context."
<< endl;
des->errors += 1;
continue;
}
NetScope*func_scope = new NetScope(scope, use_name,
NetScope::FUNC);
func_scope->set_line((*cur).second);
(*cur).second->elaborate_scope(des, func_scope);
}
elaborate_scope_funcs(des, scope, *this, funcs);
// Gates include modules, which might introduce new scopes, so
// scan all of them to create those scopes.
@ -539,8 +571,8 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
PGenerate*default_item = 0;
typedef list<PGenerate*>::const_iterator generator_it_t;
generator_it_t cur = generates.begin();
while (cur != generates.end()) {
generator_it_t cur = generate_schemes.begin();
while (cur != generate_schemes.end()) {
PGenerate*item = *cur;
assert( item->scheme_type == PGenerate::GS_CASE_ITEM );
@ -569,7 +601,7 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
delete case_value_co;
case_value_co = 0;
PGenerate*item = (cur == generates.end())? default_item : *cur;
PGenerate*item = (cur == generate_schemes.end())? default_item : *cur;
if (item == 0) {
cerr << get_fileline() << ": debug: "
<< "No generate items found" << endl;
@ -596,11 +628,14 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
// from simple elaboration.
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++ ) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur) -> generate_scope(des, scope);
}
elaborate_scope_tasks(des, scope, *this, tasks);
elaborate_scope_funcs(des, scope, *this, funcs);
// Scan the generated scope for gates that may create
// their own scopes.
typedef list<PGate*>::const_iterator pgate_list_it_t;
@ -609,6 +644,12 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
(*cur) ->elaborate_scope(des, scope);
}
typedef list<PProcess*>::const_iterator proc_it_t;
for (proc_it_t cur = behaviors.begin()
; cur != behaviors.end() ; cur ++ ) {
(*cur) -> statement() -> elaborate_scope(des, scope);
}
// Save the scope that we created, for future use.
scope_list_.push_back(scope);
}

View File

@ -108,6 +108,42 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
return flag;
}
static void elaborate_sig_funcs(Design*des, NetScope*scope,
const map<perm_string,PFunction*>&funcs)
{
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs.begin()
; cur != funcs.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
if (scope == 0) {
cerr << (*cur).second->get_fileline() << ": internal error: "
<< "Child scope for function " << (*cur).first
<< " missing in " << scope_path(scope) << "." << endl;
des->errors += 1;
continue;
}
(*cur).second->elaborate_sig(des, fscope);
}
}
static void elaborate_sig_tasks(Design*des, NetScope*scope,
const map<perm_string,PTask*>&tasks)
{
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks.begin()
; cur != tasks.end() ; cur ++) {
NetScope*tscope = scope->child( hname_t((*cur).first) );
assert(tscope);
(*cur).second->elaborate_sig(des, tscope);
}
}
bool Module::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
@ -182,38 +218,12 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
flag &= (*gt)->elaborate_sig(des, scope);
}
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
if (scope == 0) {
cerr << (*cur).second->get_fileline() << ": internal error: "
<< "Child scope for function " << (*cur).first
<< " missing in " << scope_path(scope) << "." << endl;
des->errors += 1;
continue;
}
(*cur).second->elaborate_sig(des, fscope);
}
// After all the wires are elaborated, we are free to
// elaborate the ports of the tasks defined within this
// module. Run through them now.
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
NetScope*tscope = scope->child( hname_t((*cur).first) );
assert(tscope);
(*cur).second->elaborate_sig(des, tscope);
}
elaborate_sig_funcs(des, scope, funcs);
elaborate_sig_tasks(des, scope, tasks);
// initial and always blocks may contain begin-end and
// fork-join blocks that can introduce scopes. Therefore, I
@ -415,8 +425,8 @@ bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
<< scope_path(container) << "." << endl;
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (! item->scope_list_.empty()) {
flag &= item->elaborate_sig(des, container);
@ -461,9 +471,12 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
cur->elaborate_sig(des, scope);
}
elaborate_sig_funcs(des, scope, funcs);
elaborate_sig_tasks(des, scope, tasks);
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++ ) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur) -> elaborate_sig(des, scope);
}

View File

@ -94,7 +94,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
assert(lval->pin_count() == 1);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGassign: elaborated l-value"
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
<< " width=" << lval->vector_width()
<< ", type=" << lval->data_type() << endl;
}
@ -113,14 +113,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return;
}
/* If either lval or rid are real then both must be real. */
if ((lval->data_type() == IVL_VT_REAL ||
rid->data_type() == IVL_VT_REAL) &&
lval->data_type() != rid->data_type()) {
cerr << get_fileline() << ": sorry: Both the r-value and "
"the l-value must be real in this context." << endl;
des->errors += 1;
return;
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rid->data_type() != IVL_VT_REAL)) {
rid = cast_to_real(des, scope, rid);
} else if ((lval->data_type() != IVL_VT_REAL &&
rid->data_type() == IVL_VT_REAL)) {
rid = cast_to_int(des, scope, rid, lval->vector_width());
}
ivl_assert(*this, rid);
@ -287,14 +286,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
assert(lval && rval);
assert(rval->pin_count() == 1);
/* If either lval or rval are real then both must be real. */
if ((lval->data_type() == IVL_VT_REAL ||
rval->data_type() == IVL_VT_REAL) &&
lval->data_type() != rval->data_type()) {
cerr << get_fileline() << ": sorry: Both the r-value and "
"the l-value must be real in this context." << endl;
des->errors += 1;
return;
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rval->data_type() != IVL_VT_REAL)) {
rval = cast_to_real(des, scope, rval);
} else if ((lval->data_type() != IVL_VT_REAL &&
rval->data_type() == IVL_VT_REAL)) {
rval = cast_to_int(des, scope, rval, lval->vector_width());
}
/* If the r-value insists on being smaller then the l-value
@ -386,7 +384,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
high = msb.as_long();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGBuiltin: Make arrray "
cerr << get_fileline() << ": debug: PGBuiltin: Make array "
<< "[" << high << ":" << low << "]"
<< " of " << count << " gates for " << name << endl;
}
@ -864,6 +862,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
}
}
// "cur" is an array of pointers, and we don't need it any more.
delete[]cur;
}
NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
@ -878,6 +879,31 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
tmp->local_flag(true);
tmp->set_line(*sig);
// Handle the special case of a bi-directional part
// select. Create a NetTran(VP) instead of a uni-directional
// NetPartSelect node.
if (dir == NetNet::PINOUT) {
unsigned wida = sig->vector_width();
unsigned widb = tmp->vector_width();
bool part_b = widb < wida;
NetTran*node = new NetTran(scope, scope->local_symbol(),
part_b? wida : widb,
part_b? widb : wida,
0);
if (part_b) {
connect(node->pin(0), sig->pin(0));
connect(node->pin(1), tmp->pin(0));
} else {
connect(node->pin(0), tmp->pin(0));
connect(node->pin(1), sig->pin(0));
}
node->set_line(*this);
des->add_node(node);
return tmp;
}
NetPartSelect*node = 0;
switch (dir) {
@ -906,15 +932,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
break;
case NetNet::PINOUT:
if (sig->vector_width() > tmp->vector_width()) {
node = new NetPartSelect(sig, 0, tmp->vector_width(),
NetPartSelect::BI);
connect(node->pin(0), tmp->pin(0));
} else {
node = new NetPartSelect(tmp, 0, sig->vector_width(),
NetPartSelect::BI);
connect(node->pin(0), sig->pin(0));
}
ivl_assert(*this, 0);
break;
default:
@ -1169,8 +1187,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
identifier elaborates to the same NetNet in
both cases so the extra elaboration has no
effect. But if the expression passed to the
inout port is a part select, aspecial part
select must be created that can paqss data in
inout port is a part select, a special part
select must be created that can pass data in
both directions.
Use the elaborate_bi_net method to handle all
@ -1932,7 +1950,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
if (nscope == 0) {
cerr << get_fileline() << ": internal error: "
"unable to find block scope " << scope_path(scope)
<< "<" << pscope_name() << ">" << endl;
<< "." << pscope_name() << endl;
des->errors += 1;
return 0;
}
@ -3035,7 +3053,7 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
sig = des->find_signal(scope, id2->path());
if (sig == 0) {
cerr << get_fileline() << ": error: Unable to find variable "
<< id2->path() << " in for-loop increment expressin." << endl;
<< id2->path() << " in for-loop increment expression." << endl;
des->errors += 1;
return body;
}
@ -3536,6 +3554,34 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
}
static void elaborate_functions(Design*des, NetScope*scope,
const map<perm_string,PFunction*>&funcs)
{
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs.begin()
; cur != funcs.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
assert(fscope);
(*cur).second->elaborate(des, fscope);
}
}
static void elaborate_tasks(Design*des, NetScope*scope,
const map<perm_string,PTask*>&tasks)
{
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks.begin()
; cur != tasks.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*tscope = scope->child(use_name);
assert(tscope);
(*cur).second->elaborate(des, tscope);
}
}
/*
* When a module is instantiated, it creates the scope then uses this
* method to elaborate the contents of the module.
@ -3595,28 +3641,12 @@ bool Module::elaborate(Design*des, NetScope*scope) const
}
// Elaborate functions.
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*fscope = scope->child(use_name);
assert(fscope);
(*cur).second->elaborate(des, fscope);
}
elaborate_functions(des, scope, funcs);
// Elaborate the task definitions. This is done before the
// behaviors so that task calls may reference these, and after
// the signals so that the tasks can reference them.
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
hname_t use_name ( (*cur).first );
NetScope*tscope = scope->child(use_name);
assert(tscope);
(*cur).second->elaborate(des, tscope);
}
elaborate_tasks(des, scope, tasks);
// Get all the gates of the module and elaborate them by
// connecting them to the signals. The gate may be simple or
@ -3661,8 +3691,8 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
<< scope_path(container) << "." << endl;
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (! item->scope_list_.empty()) {
flag &= item->elaborate(des, container);
@ -3704,6 +3734,9 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
bool PGenerate::elaborate_(Design*des, NetScope*scope) const
{
elaborate_functions(des, scope, funcs);
elaborate_tasks(des, scope, tasks);
typedef list<PGate*>::const_iterator gates_it_t;
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; cur ++ )
(*cur)->elaborate(des, scope);
@ -3713,8 +3746,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
(*cur)->elaborate(des, scope);
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generates.begin()
; cur != generates.end() ; cur ++ ) {
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur)->elaborate(des, scope);
}

12
emit.cc
View File

@ -72,6 +72,16 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const
return true;
}
bool NetCastInt::emit_node(struct target_t*tgt) const
{
return tgt->lpm_cast_int(this);
}
bool NetCastReal::emit_node(struct target_t*tgt) const
{
return tgt->lpm_cast_real(this);
}
bool NetCLShift::emit_node(struct target_t*tgt) const
{
tgt->lpm_clshift(this);
@ -362,7 +372,7 @@ void NetScope::emit_scope(struct target_t*tgt) const
/* Run the signals again, but this time to connect the
delay paths. This is done as a second pass because
the paths reference other signals that may be later
in the list. We can do it here becase delay paths are
in the list. We can do it here because delay paths are
always connected within the scope. */
cur = signals_->sig_next_;
do {

View File

@ -154,7 +154,7 @@
*
* The POST_MAP compiler directive causes the GSR manipulations
* included in the test bench to be compiled in, to simulate the chip
* startup. Other then that, the test bench runs the post-map design
* startup. Other than that, the test bench runs the post-map design
* the same way the pre-synthesis design works.
*
* Run this design with the command:

View File

@ -459,7 +459,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
default: {
cerr << get_fileline() << ": internal error: "
<< "NetEBDiv has unexpeced op() code: "
<< "NetEBDiv has unexpected op() code: "
<< op() << endl;
des->errors += 1;

12
ivl.def
View File

@ -53,6 +53,9 @@ ivl_file_table_index
ivl_file_table_item
ivl_file_table_size
ivl_island_flag_set
ivl_island_flag_test
ivl_logic_attr
ivl_logic_attr_cnt
ivl_logic_attr_val
@ -115,6 +118,7 @@ ivl_nexus_ptr_pin
ivl_nexus_ptr_lpm
ivl_nexus_ptr_log
ivl_nexus_ptr_sig
ivl_nexus_ptr_switch
ivl_parameter_basename
ivl_parameter_expr
@ -222,10 +226,14 @@ ivl_switch_a
ivl_switch_b
ivl_switch_basename
ivl_switch_enable
ivl_switch_file
ivl_switch_island
ivl_switch_lineno
ivl_switch_offset
ivl_switch_part
ivl_switch_scope
ivl_switch_type
ivl_switch_attr_cnt;
ivl_switch_attr_val;
ivl_switch_width
ivl_udp_init
ivl_udp_name

View File

@ -80,6 +80,13 @@ _BEGIN_DECL
* processes. Structural expressions are instead treated as logic
* gates.
*
* ivl_island_t
* Certain types of objects may belong to islands. The island that
* they belong to is represented by the ivl_island_t cookie. To
* know if object belong to the same island, it is sufficient to
* compare island cookies. If a==b, then island a is the same as
* island b.
*
* ivl_lpm_t
* This object is the base class for all the various LPM type
* device nodes. This object carries a few base properties
@ -146,6 +153,7 @@ typedef struct ivl_delaypath_s*ivl_delaypath_t;
typedef struct ivl_design_s *ivl_design_t;
typedef struct ivl_event_s *ivl_event_t;
typedef struct ivl_expr_s *ivl_expr_t;
typedef struct ivl_island_s *ivl_island_t;
typedef struct ivl_lpm_s *ivl_lpm_t;
typedef struct ivl_lval_s *ivl_lval_t;
typedef struct ivl_net_const_s*ivl_net_const_t;
@ -237,7 +245,8 @@ typedef enum ivl_switch_type_e {
IVL_SW_TRANIF1 = 2,
IVL_SW_RTRAN = 3,
IVL_SW_RTRANIF0 = 4,
IVL_SW_RTRANIF1 = 5
IVL_SW_RTRANIF1 = 5,
IVL_SW_TRAN_VP = 6
} ivl_switch_type_t;
/* This is the type of an LPM object. */
@ -245,6 +254,8 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_ABS = 32,
IVL_LPM_ADD = 0,
IVL_LPM_ARRAY = 30,
IVL_LPM_CAST_INT = 34,
IVL_LPM_CAST_REAL = 33,
IVL_LPM_CONCAT = 16,
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
IVL_LPM_CMP_EQ = 10,
@ -257,7 +268,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_MOD = 13,
IVL_LPM_MULT = 4,
IVL_LPM_MUX = 5,
IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
/* IVL_LPM_PART_BI= 28, / obsolete */
IVL_LPM_PART_VP= 15, /* part select: vector to part */
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
IVL_LPM_POW = 31,
@ -713,6 +724,16 @@ extern unsigned ivl_file_table_index(const char *);
extern unsigned ivl_file_table_size(void);
/* ISLAND
*
* ivl_island_flag_set
* ivl_island_flag_test
* Allow the user to test or set a boolean flag associated with the
* island.
*/
extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value);
extern int ivl_island_flag_test(ivl_island_t net, unsigned flag);
/* LOGIC
* These types and functions support manipulation of logic gates. The
* ivl_logic_t enumeration identifies the various kinds of gates that
@ -1327,6 +1348,7 @@ extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net);
extern ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net);
extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net);
extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net);
extern ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net);
extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
/* PARAMETER
@ -1854,9 +1876,6 @@ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
* ivl_switch_basename
* This is the name given to the device in the source code.
*
* ivl_switch_scope
* The scope where the switch device appears.
*
* ivl_switch_a
* ivl_switch_b
* The a and b ports are the two ports of the switch.
@ -1867,17 +1886,31 @@ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
*
* SEMANTIC NOTES
* The a/b ports can be any type, but the types must exactly
* match. The enable must be a scalar.
* match, including vector widths. The enable must be a scalar.
*
* The IVL_SW_TRAN_VP is an exception to the above. In this case,
* the B side may be a different size, and the a side will have a
* a fixed width. The unused bits are padded to Z on the A side.
*/
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
extern const char*ivl_switch_basename(ivl_switch_t net);
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
extern const char*ivl_switch_basename(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_a(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
extern ivl_island_t ivl_switch_island(ivl_switch_t net);
/* These are only support for IVL_SW_TRAN_VP switches. */
extern unsigned ivl_switch_width(ivl_switch_t net);
extern unsigned ivl_switch_part(ivl_switch_t net);
extern unsigned ivl_switch_offset(ivl_switch_t net);
/* Not implemented yet
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
*** */
extern const char* ivl_switch_file(ivl_switch_t net);
extern unsigned ivl_switch_lineno(ivl_switch_t net);
#if defined(__MINGW32__) || defined (__CYGWIN32__)
# define DLLEXPORT __declspec(dllexport)

44
ivl_target_priv.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef __ivl_target_priv_H
#define __ivl_target_H
/*
* Copyright (c) 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include <inttypes.h>
/*
* This deader has declarations related to the ivl_target.h API that
* are not to be exported outside of the core via the ivl_target.h
* interface.
*/
/*
* Information about islands. Connected branches within a net are
* collected into islands. Branches that are purely ddiscrete do not
* have disciplines and do not belong to islands.
*/
class discipline_t;
struct ivl_island_s {
discipline_t*discipline;
// user accessible flags. They are initially false, always.
vector<bool> flags;
};
#endif

View File

@ -941,7 +941,7 @@ static void do_define()
}
/* Detect the continuation sequence. If I find it, remove it
* and the white space that preceeds it, then replace all that
* and the white space that precedes it, then replace all that
* with a single newline.
*/
if ((cp > yytext) && (cp[-1] == '\\'))

View File

@ -843,7 +843,7 @@ static verinum*make_unsized_dec(const char*ptr)
if (ptr[0] == '\'') {
/* The number has decorations of the form 'sd<digits>,
possibly with space between the d and the <digits>.
Also, the 's' is optional, and markes the number as
Also, the 's' is optional, and marks the number as
signed. */
ptr += 1;

View File

@ -825,6 +825,11 @@ int main(int argc, char*argv[])
func(des);
}
if (verbose_flag) {
cout << "CALCULATING ISLANDS" << endl;
}
des->join_islands();
if (net_path) {
if (verbose_flag)
cerr<<" dumping netlist to " <<net_path<< "..." <<endl;

View File

@ -227,6 +227,10 @@ void NetScope::run_defparams(Design*des)
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(perm_name, val);
if (! flag) {
cerr << val->get_fileline() << ": warning: parameter "
@ -335,6 +339,14 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
wid += 1;
/* If we have a real value convert it to an integer. */
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
verinum nval(tmp->value().as_long64());
expr = new NetEConst(nval);
expr->set_line(*((*cur).second.expr));
(*cur).second.expr = expr;
}
NetEConst*val = dynamic_cast<NetEConst*>(expr);
assert(val);
@ -348,7 +360,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
tmp.has_sign ( (*cur).second.signed_flag );
delete val;
val = new NetEConst(tmp);
expr = val;
(*cur).second.expr = expr = val;
}
}
@ -529,6 +541,10 @@ void NetScope::evaluate_parameters(Design*des)
cerr << (*cur).second.get_fileline() << ": internal error: "
<< "Unexpected expression type " << (*cur).second.type
<< "." << endl;
cerr << (*cur).second.get_fileline() << ": : "
<< "Parameter name: " << (*cur).first << endl;
cerr << (*cur).second.get_fileline() << ": : "
<< "Expression is: " << *(*cur).second.expr << endl;
ivl_assert((*cur).second, 0);
break;
}
@ -673,3 +689,14 @@ void Design::delete_process(NetProcTop*top)
delete top;
}
void Design::join_islands(void)
{
if (nodes_ == 0)
return;
NetNode*cur = nodes_->node_next_;
do {
join_island(cur);
cur = cur->node_next_;
} while (cur != nodes_->node_next_);
}

View File

@ -121,6 +121,9 @@ NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
ivl_assert(file_line, ref.range == 0);
ref.range = range_list;
ref.set_line(file_line);
ivl_assert(file_line, type != IVL_VT_NO_TYPE);
return res;
}
@ -163,7 +166,7 @@ bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
/*
* This is not really complete (msb, lsb, sign). It is currently only
* used to add a genver to the local parameter list.
* used to add a genvar to the local parameter list.
*/
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
const LineInfo&file_line)
@ -272,7 +275,7 @@ const NetFuncDef* NetScope::func_def() const
void NetScope::set_module_name(perm_string n)
{
assert(type_ == MODULE);
module_name_ = n; /* NOTE: n mus have been permallocated. */
module_name_ = n; /* NOTE: n must have been permallocated. */
}
perm_string NetScope::module_name() const

View File

@ -26,6 +26,7 @@
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "ivl_target_priv.h"
# include "ivl_assert.h"
static bool has_enable(ivl_switch_type_t tt)
@ -42,7 +43,7 @@ static bool has_enable(ivl_switch_type_t tt)
}
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
: NetNode(scope, n, has_enable(tt)? 3 : 2)
: NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
{
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
@ -52,6 +53,108 @@ NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
}
}
NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off)
: NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off)
{
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
}
NetTran::~NetTran()
{
}
unsigned NetTran::vector_width() const
{
return wid_;
}
unsigned NetTran::part_width() const
{
return part_;
}
unsigned NetTran::part_offset() const
{
return off_;
}
void join_island(NetObj*obj)
{
IslandBranch*branch = dynamic_cast<IslandBranch*> (obj);
// If this is not even a branch, then stop now.
if (branch == 0)
return;
// If this is a branch, but already given to an island, then
// stop.
if (branch->island)
return;
list<NetObj*> uncommitted_neighbors;
// Look for neighboring objects that might already be in
// islands. If we find something, then join that island.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
Nexus*nex = obj->pin(idx).nexus();
for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {
unsigned pin;
NetObj*tmp;
cur->cur_link(tmp, pin);
// Skip self.
if (tmp == obj)
continue;
// If tmb is not a branch, then skip it.
IslandBranch*tmp_branch = dynamic_cast<IslandBranch*> (tmp);
if (tmp_branch == 0)
continue;
// If that is an uncommitted branch, then save
// it. When I finally choose an island for self,
// these branches will be scanned so that they join
// this island as well.
if (tmp_branch->island == 0) {
uncommitted_neighbors.push_back(tmp);
continue;
}
ivl_assert(*obj, branch->island==0 || branch->island==tmp_branch->island);
// We found an existing island to join. Join it
// now. Keep scanning in order to find more neighbors.
if (branch->island == 0) {
if (debug_elaborate)
cerr << obj->get_fileline() << ": debug: "
<< "Join branch to existing island." << endl;
branch->island = tmp_branch->island;
} else if (branch->island != tmp_branch->island) {
cerr << obj->get_fileline() << ": internal error: "
<< "Oops, Found 2 neighboring islands." << endl;
ivl_assert(*obj, 0);
}
}
}
// If after all that we did not find an island to join, then
// start the island not and join it.
if (branch->island == 0) {
branch->island = new ivl_island_s;
branch->island->discipline = 0;
if (debug_elaborate)
cerr << obj->get_fileline() << ": debug: "
<< "Create new island for this branch" << endl;
}
// Now scan all the uncommitted neighbors I found. Calling
// join_island() on them will cause them to notice me in the
// process, and thus they will join my island. This process
// will recurse until all the connected branches join this island.
for (list<NetObj*>::iterator cur = uncommitted_neighbors.begin()
; cur != uncommitted_neighbors.end() ; cur ++ ) {
join_island(*cur);
}
}

View File

@ -761,10 +761,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
pin(0).set_dir(Link::INPUT);
pin(1).set_dir(Link::OUTPUT);
break;
case NetPartSelect::BI:
pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::OUTPUT);
break;
}
pin(0).set_name(perm_string::literal("Part"), 0);
pin(1).set_name(perm_string::literal("Vect"), 0);
@ -787,10 +783,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
pin(0).set_dir(Link::INPUT);
pin(1).set_dir(Link::OUTPUT);
break;
case NetPartSelect::BI:
pin(0).set_dir(Link::PASSIVE);
pin(1).set_dir(Link::PASSIVE);
break;
}
pin(2).set_dir(Link::INPUT);
@ -857,6 +849,24 @@ const NetScope* NetProcTop::scope() const
return scope_;
}
NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width)
: NetNode(scope, n, 2), width_(width)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("O"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("I"), 0);
}
NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag)
: NetNode(scope, n, 2), signed_flag_(signed_flag)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("O"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("I"), 0);
}
NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt)
: NetNode(scope, n, cnt+1), width_(wid)
{
@ -1504,6 +1514,11 @@ NetLiteral::~NetLiteral()
{
}
ivl_variable_type_t NetLiteral::data_type() const
{
return IVL_VT_REAL;
}
const verireal& NetLiteral::value_real() const
{
return real_;

View File

@ -52,6 +52,7 @@ class Nexus;
class NetEvent;
class NetNet;
class NetNode;
class NetObj;
class NetProc;
class NetProcTop;
class NetRelease;
@ -71,6 +72,8 @@ struct functor_t;
ostream& operator << (ostream&o, ivl_variable_type_t val);
extern void join_island(NetObj*obj);
/* =========
* A NetObj is anything that has any kind of behavior in the
* netlist. Nodes can be gates, registers, etc. and are linked
@ -131,6 +134,20 @@ class NetObj : public Attrib, public virtual LineInfo {
const NetExpr* delay3_;
};
/*
* Objects that can be island branches are derived from this. (It is
* possible for an object to be a NetObj and an IslandBranch.) This is
* used to collect island information about the node.
*/
class IslandBranch {
public:
IslandBranch() : island(0) { }
public:
struct ivl_island_s* island;
};
class Link {
friend void connect(Link&, Link&);
@ -810,7 +827,7 @@ class NetScope : public Attrib {
/*
* This class implements the LPM_ABS component. The node has a single
* input, a signe expression, that it converts to the absolute
* input, a signed expression, that it converts to the absolute
* value. The gate is simple: pin(0) is the output and pin(1) is the input.
*/
class NetAbs : public NetNode {
@ -899,6 +916,44 @@ class NetArrayDq : public NetNode {
};
/*
* Convert an IVL_VT_REAL input to a logical value with the
* given width. The input is pin(1) and the output is pin(0).
*/
class NetCastInt : public NetNode {
public:
NetCastInt(NetScope*s, perm_string n, unsigned width);
unsigned width() const { return width_; }
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
unsigned width_;
};
/*
* Convert an input to IVL_VT_REAL. The input is pin(1), which can be
* any vector type (VT_BOOL or VT_LOGIC) and the output is pin(0),
* which is IVL_VT_REAL. The conversion interprets the input as an
* unsigned value unless the signed_flag is true.
*/
class NetCastReal : public NetNode {
public:
NetCastReal(NetScope*s, perm_string n, bool signed_flag);
bool signed_flag() const { return signed_flag_; }
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
bool signed_flag_;
};
/*
* This type represents the LPM_CLSHIFT device.
*/
@ -1359,19 +1414,31 @@ class NetSysFunc : public NetNode {
const struct sfunc_return_type*def_;
};
class NetTran : public NetNode {
class NetTran : public NetNode, public IslandBranch {
public:
// Tran devices other than TRAN_VP
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
// Create a TRAN_VP
NetTran(NetScope*scope, perm_string n, unsigned wid,
unsigned part, unsigned off);
~NetTran();
ivl_switch_type_t type() const { return type_; }
// These are only used for IVL_SW_TRAN_PV
unsigned vector_width() const;
unsigned part_width() const;
unsigned part_offset() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
ivl_switch_type_t type_;
unsigned wid_;
unsigned part_;
unsigned off_;
};
/* =========
@ -1588,8 +1655,8 @@ class NetECRealParam : public NetECReal {
* selector as the input.
*
* The NetPartSelect can be output from the signal (i.e. reading a
* part), input into the signal, or bi-directional. The DIR method
* gives the type of the node.
* part) or input into the signal. The DIR method gives the type of
* the node.
*
* VP (Vector-to-Part)
* Output pin 0 is the part select, and input pin 1 is connected to
@ -1599,10 +1666,6 @@ class NetECRealParam : public NetECReal {
* Output pin 1 is connected to the NetNet, and input pin 0 is the
* part select. In this case, the node is driving the NetNet.
*
* BI (BI-directional)
* Pin 0 is the part select and pin 1 is connected to the NetNet, but
* the ports are intended to be bi-directional.
*
* Note that whatever the direction that data is intended to flow,
* pin-0 is the part select and pin-1 is connected to the NetNet.
*/
@ -1610,7 +1673,7 @@ class NetPartSelect : public NetNode {
public:
// enum for the device direction
enum dir_t { VP, PV, BI };
enum dir_t { VP, PV};
explicit NetPartSelect(NetNet*sig,
unsigned off, unsigned wid, dir_t dir);
@ -3613,6 +3676,7 @@ class Design {
// Iterate over the design...
void dump(ostream&) const;
void functor(struct functor_t*);
void join_islands(void);
int emit(struct target_t*) const;
// This is incremented by elaboration when an error is

View File

@ -76,6 +76,46 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
#endif
}
NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid)
{
if (src->data_type() != IVL_VT_REAL)
return src;
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid);
tmp->data_type(IVL_VT_LOGIC);
tmp->set_line(*src);
tmp->local_flag(true);
NetCastInt*cast = new NetCastInt(scope, scope->local_symbol(), wid);
cast->set_line(*src);
des->add_node(cast);
connect(cast->pin(0), tmp->pin(0));
connect(cast->pin(1), src->pin(0));
return tmp;
}
NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
{
if (src->data_type() == IVL_VT_REAL)
return src;
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
tmp->data_type(IVL_VT_REAL);
tmp->set_line(*src);
tmp->local_flag(true);
NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed());
cast->set_line(*src);
des->add_node(cast);
connect(cast->pin(0), tmp->pin(0));
connect(cast->pin(1), src->pin(0));
return tmp;
}
/*
* Add a signed constant to an existing expression. Generate a new
* NetEBAdd node that has the input expression and an expression made
@ -123,6 +163,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
NetEConst* make_const_x(unsigned long wid)
{
verinum xxx (verinum::Vx, wid);
NetEConst*resx = new NetEConst(xxx);
return resx;
}
NetExpr* condition_reduce(NetExpr*expr)
{
if (expr->expr_width() == 1)

View File

@ -64,6 +64,13 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w);
/*
* Generate the nodes necessary to cast an expression (a net) to a
* real value.
*/
extern NetNet*cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid);
extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src);
/*
* Take the input expression and return a variation that assures that
* the expression is 1-bit wide and logical. This reflects the needs
@ -102,6 +109,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
extern NetExpr*make_add_expr(NetExpr*expr, long val);
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
/*
* Make a NetEConst object that contains only X bits.
*/
extern NetEConst*make_const_x(unsigned long wid);
/*
* In some cases the lval is accessible as a pointer to the head of
* a list of NetAssign_ objects. This function returns the width of

101
parse.y
View File

@ -323,10 +323,15 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
%left K_POW
%left UNARY_PREC
/* to resolve dangling else ambiguity. */
%nonassoc less_than_K_else
%nonassoc K_else
/* to resolve exclude (... ambiguity */
%nonassoc '('
%nonassoc K_exclude
%%
/* A degenerate source file can be completely empty. */
@ -427,7 +432,7 @@ block_item_decl
/* Integer declarations are simpler in that they do not have all the
trappings of a general variable declaration. All of that is
implicit in the "integer" of the declaratin. */
implicit in the "integer" of the declaration. */
| attribute_list_opt K_integer register_variable_list ';'
{ pform_set_reg_integer($3);
@ -440,7 +445,7 @@ block_item_decl
/* real declarations are fairly simple as there is no range of
signed flag in the declaration. Create the real as a NetNet::REG
with real value. Note that real and realtime are interchangable
with real value. Note that real and realtime are interchangeable
in this context. */
| attribute_list_opt K_real real_variable_list ';'
@ -1181,7 +1186,7 @@ expr_primary
}
/* Many of the VAMS built-in functions are available as builtin
functions with $system_function equivilents. */
functions with $system_function equivalents. */
| K_acos '(' expression ')'
{ perm_string tn = perm_string::literal("$acos");
@ -2195,6 +2200,15 @@ module_item
K_endcase
{ pform_endgenerate(); }
/* Handle some anachronistic syntax cases. */
| K_generate K_begin module_item_list_opt K_end K_endgenerate
{ /* Detect and warn about anachronistic begin/end use */
if (generation_flag > GN_VER2001) {
warn_count += 1;
cerr << @2 << ": warning: Anachronistic use of begin/end to surround generate schemes." << endl;
}
}
/* specify blocks are parsed but ignored. */
| K_specify K_endspecify
@ -2379,7 +2393,14 @@ parameter_assign_decl
param_active_type = IVL_VT_LOGIC;
}
| K_integer
{ param_active_range = 0;
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The default range is [31:0] */
param_active_range = range_stub;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
@ -2388,6 +2409,23 @@ parameter_assign_decl
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_time
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The range is [63:0] */
param_active_range = range_stub;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
{ param_active_range = 0;
param_active_signed = true;
@ -2398,6 +2436,16 @@ parameter_assign_decl
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_realtime
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
}
parameter_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
;
parameter_assign_list
@ -2432,7 +2480,8 @@ parameter_value_range
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
| from_exclude '(' value_range_expression ':' value_range_expression ')'
{ $$ = pform_parameter_value_range($1, true, $3, true, $5); }
/* | K_exclude expression */
| K_exclude expression
{ $$ = pform_parameter_value_range(true, false, $2, false, $2); }
;
value_range_expression
@ -2480,17 +2529,41 @@ 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_integer
{ param_active_range = 0;
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The default range is [31:0] */
param_active_range = range_stub;
param_active_signed = true;
param_active_type = IVL_VT_LOGIC;
}
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_time
{ svector<PExpr*>*range_stub = new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum((uint64_t)63, integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
/* The range is [63:0] */
param_active_range = range_stub;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
| K_real
{ param_active_range = 0;
@ -2500,7 +2573,17 @@ 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_realtime
{ param_active_range = 0;
param_active_signed = true;
param_active_type = IVL_VT_REAL;
}
localparam_assign_list
{ param_active_range = 0;
param_active_signed = false;
param_active_type = IVL_VT_LOGIC;
}
;

View File

@ -30,6 +30,15 @@ unsigned error_count = 0;
unsigned warn_count = 0;
unsigned long based_size = 0;
std::ostream& operator << (std::ostream&o, const YYLTYPE&loc)
{
if (loc.text)
o << loc.text << ":";
o << loc.first_line;
return o;
}
void VLerror(const char*msg)
{
error_count += 1;
@ -39,20 +48,14 @@ void VLerror(const char*msg)
void VLerror(const YYLTYPE&loc, const char*msg)
{
error_count += 1;
if (loc.text)
cerr << loc.text << ":";
cerr << loc.first_line << ": " << msg << endl;
cerr << loc << ": " << msg << endl;
based_size = 0; /* Clear the base information if we have an error. */
}
void yywarn(const YYLTYPE&loc, const char*msg)
{
warn_count += 1;
if (loc.text)
cerr << loc.text << ":";
cerr << loc.first_line << ": warning: " << msg << endl;
cerr << loc << ": warning: " << msg << endl;
}
int VLwrap()

View File

@ -23,6 +23,7 @@
#endif
# include <list>
# include <ostream>
# include "compiler.h"
# include "pform.h"
@ -62,6 +63,8 @@ extern void VLerror(const YYLTYPE&loc, const char*msg);
#define yywarn VLwarn
extern void VLwarn(const YYLTYPE&loc, const char*msg);
extern ostream& operator << (ostream&, const YYLTYPE&loc);
extern unsigned error_count, warn_count;
extern unsigned long based_size;

123
pform.cc
View File

@ -93,40 +93,64 @@ static PScope* lexical_scope = 0;
void pform_pop_scope()
{
lexical_scope = lexical_scope->pscope_parent();
if (pform_cur_generate) {
assert(pform_cur_generate->lexical_scope);
PScope*cur = pform_cur_generate->lexical_scope;
pform_cur_generate->lexical_scope = cur->pscope_parent();
} else {
assert(lexical_scope);
lexical_scope = lexical_scope->pscope_parent();
}
}
PTask* pform_push_task_scope(char*name)
{
perm_string task_name = lex_strings.make(name);
PTask*task = new PTask(task_name, pform_cur_module);
// Add the task to the current module
pform_cur_module->add_task(task->pscope_name(), task);
// Make this the current lexical scope
lexical_scope = task;
PTask*task;
if (pform_cur_generate) {
task = new PTask(task_name, pform_cur_generate->lexical_scope);
pform_cur_generate->tasks[task->pscope_name()] = task;
pform_cur_generate->lexical_scope = task;
} else {
task = new PTask(task_name, lexical_scope);
pform_cur_module->tasks[task->pscope_name()] = task;
lexical_scope = task;
}
return task;
}
PFunction* pform_push_function_scope(char*name)
{
perm_string func_name = lex_strings.make(name);
PFunction*func = new PFunction(func_name, lexical_scope);
// Add the task to the current module
pform_cur_module->add_function(func->pscope_name(), func);
// Make this the current lexical scope
lexical_scope = func;
PFunction*func;
if (pform_cur_generate) {
func = new PFunction(func_name, pform_cur_generate->lexical_scope);
pform_cur_generate->funcs[func->pscope_name()] = func;
pform_cur_generate->lexical_scope = func;
} else {
func = new PFunction(func_name, lexical_scope);
pform_cur_module->funcs[func->pscope_name()] = func;
lexical_scope = func;
}
return func;
}
PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
{
perm_string block_name = lex_strings.make(name);
PBlock*block = new PBlock(block_name, lexical_scope, bt);
// Make this the current lexical scope
lexical_scope = block;
PBlock*block;
if (pform_cur_generate) {
block = new PBlock(block_name, pform_cur_generate->lexical_scope, bt);
pform_cur_generate->lexical_scope = block;
} else {
block = new PBlock(block_name, lexical_scope, bt);
lexical_scope = block;
}
return block;
}
@ -138,9 +162,34 @@ PWire*pform_get_wire_in_scope(perm_string name)
cannot be within sub-scopes. Only directly in
modules. */
if (pform_cur_generate)
return pform_cur_generate->get_wire(name);
if (pform_cur_generate->lexical_scope)
return pform_cur_generate->lexical_scope->wires_find(name);
else
return pform_cur_generate->wires_find(name);
else
return lexical_scope->wires_find(name);
}
return lexical_scope->wires_find(name);
static void pform_put_wire_in_scope(perm_string name, PWire*net)
{
if (pform_cur_generate)
if (pform_cur_generate->lexical_scope)
pform_cur_generate->lexical_scope->wires[name] = net;
else
pform_cur_generate->wires[name] = net;
else
lexical_scope->wires[name] = net;
}
static void pform_put_behavior_in_scope(PProcess*pp)
{
if (pform_cur_generate)
if (pform_cur_generate->lexical_scope)
pform_cur_generate->lexical_scope->behaviors.push_back(pp);
else
pform_cur_generate->behaviors.push_back(pp);
else
lexical_scope->behaviors.push_back(pp);
}
void pform_set_default_nettype(NetNet::Type type,
@ -508,7 +557,7 @@ void pform_endgenerate()
if (pform_cur_generate != 0) {
assert(cur->scheme_type == PGenerate::GS_CASE_ITEM
|| pform_cur_generate->scheme_type != PGenerate::GS_CASE);
pform_cur_generate->generates.push_back(cur);
pform_cur_generate->generate_schemes.push_back(cur);
} else {
assert(cur->scheme_type != PGenerate::GS_CASE_ITEM);
pform_cur_module->generate_schemes.push_back(cur);
@ -1236,7 +1285,7 @@ void pform_make_pgassign_list(svector<PExpr*>*alist,
void pform_make_reginit(const struct vlltype&li,
perm_string name, PExpr*expr)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
VLerror(li, "internal error: reginit to non-register?");
delete expr;
@ -1250,7 +1299,7 @@ void pform_make_reginit(const struct vlltype&li,
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
FILE_NAME(top, li);
lexical_scope->behaviors.push_back(top);
pform_put_behavior_in_scope(top);
}
/*
@ -1271,7 +1320,7 @@ void pform_module_define_port(const struct vlltype&li,
svector<PExpr*>*range,
svector<named_pexpr_t*>*attr)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur) {
ostringstream msg;
msg << name << " definition conflicts with "
@ -1305,7 +1354,7 @@ void pform_module_define_port(const struct vlltype&li,
cur->attributes[tmp->name] = tmp->parm;
}
}
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
}
/*
@ -1388,12 +1437,8 @@ void pform_makewire(const vlltype&li, perm_string name,
}
}
if (new_wire_flag) {
if (pform_cur_generate)
pform_cur_generate->wires[name] = cur;
else
lexical_scope->wires[name] = cur;
}
if (new_wire_flag)
pform_put_wire_in_scope(name, cur);
}
/*
@ -1469,11 +1514,11 @@ void pform_makewire(const vlltype&li,
void pform_set_port_type(perm_string name, NetNet::PortType pt,
const char*file, unsigned lineno)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE);
FILE_NAME(cur, file, lineno);
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
}
switch (cur->get_port_type()) {
@ -1555,13 +1600,13 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
/* Look for a preexisting wire. If it exists, set the
port direction. If not, create it. */
PWire*curw = lexical_scope->wires_find(name);
PWire*curw = pform_get_wire_in_scope(name);
if (curw) {
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype);
FILE_NAME(curw, file, lineno);
lexical_scope->wires[name] = curw;
pform_put_wire_in_scope(name, curw);
}
curw->set_signed(signed_flag);
@ -1622,7 +1667,7 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
{
PWire*cur = 0;
if (pform_cur_generate) {
cur = pform_cur_generate->get_wire(name);
cur = pform_cur_generate->wires_find(name);
} else {
cur = lexical_scope->wires_find(name);
}
@ -1805,13 +1850,13 @@ void pform_set_port_type(const struct vlltype&li,
static void pform_set_reg_integer(perm_string name)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::INTEGER,
NetNet::NOT_A_PORT,
IVL_VT_LOGIC);
cur->set_signed(true);
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
@ -1839,10 +1884,10 @@ void pform_set_reg_integer(list<perm_string>*names)
static void pform_set_reg_time(perm_string name)
{
PWire*cur = lexical_scope->wires_find(name);
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC);
lexical_scope->wires[name] = cur;
pform_put_wire_in_scope(name, cur);
} else {
bool rc = cur->set_wire_type(NetNet::REG);
assert(rc);
@ -1901,11 +1946,7 @@ PProcess* pform_make_behavior(PProcess::Type type, Statement*st,
delete attr;
}
if (pform_cur_generate)
pform_cur_generate->add_behavior(pp);
else
pform_cur_module->behaviors.push_back(pp);
pform_put_behavior_in_scope(pp);
return pp;
}

View File

@ -937,8 +937,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const
(*idx)->dump(out, indent+2);
}
for (list<PGenerate*>::const_iterator idx = generates.begin()
; idx != generates.end() ; idx++) {
for (list<PGenerate*>::const_iterator idx = generate_schemes.begin()
; idx != generate_schemes.end() ; idx++) {
(*idx)->dump(out, indent+2);
}
@ -1089,8 +1089,8 @@ void Module::dump(ostream&out) const
// Dump the task definitions.
typedef map<perm_string,PTask*>::const_iterator task_iter_t;
for (task_iter_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
for (task_iter_t cur = tasks.begin()
; cur != tasks.end() ; cur ++) {
out << " task " << (*cur).first << ";" << endl;
(*cur).second->dump(out, 6);
out << " endtask;" << endl;
@ -1098,8 +1098,8 @@ void Module::dump(ostream&out) const
// Dump the function definitions.
typedef map<perm_string,PFunction*>::const_iterator func_iter_t;
for (func_iter_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
for (func_iter_t cur = funcs.begin()
; cur != funcs.end() ; cur ++) {
out << " function " << (*cur).first << ";" << endl;
(*cur).second->dump(out, 6);
out << " endfunction;" << endl;

13
scripts/CREATE_VERSION.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# This script manually creates a version.h file.
#
# It is used when creating a MinGW executable from a Cygwin
# hosted git repository. It assumes that git is available.
#
# sh scripts/CREATE_VERSION.sh
#
echo "Building verion.h with git describe"
tmp=`git describe | sed -e 's;\(.*\);#define VERSION_TAG "\1";'`
echo "$tmp" > version.h

View File

@ -7,7 +7,7 @@
# sh scripts/MAKE_SNAPSHOT.sh 20080428 ~/tmp
#
# The above assumes that there is a tag "s20080428" at the point
# to be snaphot. (The tag has the "s", but the argument to this
# to be snapshot. (The tag has the "s", but the argument to this
# script does not have the "s"). This script extracts based on the
# tag, uses the temporary directory to stage intermediate results,
# and finally creates a file called verilog-20080428.tar.gz that

View File

@ -598,7 +598,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
delete expr_input;
/* Detect the case that this is a *synchronous* set/reset. It
is not asyncronous because we know the condition is not
is not asynchronous because we know the condition is not
included in the sensitivity list, but if the if_ case is
constant (has no inputs) then we can model this as a
synchronous set/reset.

View File

@ -555,6 +555,28 @@ extern "C" unsigned ivl_file_table_size()
return fn_vector.size();
}
extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value)
{
if (flag >= net->flags.size()) {
if (value == 0)
return 0;
else
net->flags.resize(flag+1, false);
}
int old_flag = net->flags[flag];
net->flags[flag] = value != 0;
return old_flag;
}
extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag)
{
if (flag >= net->flags.size())
return 0;
else
return net->flags[flag];
}
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
{
assert(net);
@ -782,7 +804,6 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
switch (net->type) {
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
return net->u_.part.base;
default:
assert(0);
@ -865,6 +886,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
assert(net);
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
assert(idx == 0);
return net->u_.arith.a;
@ -918,7 +941,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
assert(idx <= 1);
if (idx == 0)
return net->u_.part.a;
@ -1008,20 +1030,19 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
case IVL_LPM_POW:
case IVL_LPM_SUB:
assert(idx == 0);
return net->u_.arith.q;
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_NEE:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_MULT:
case IVL_LPM_POW:
case IVL_LPM_SUB:
assert(idx == 0);
return net->u_.arith.q;
@ -1061,7 +1082,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
assert(idx == 0);
return net->u_.part.q;
@ -1125,6 +1145,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
@ -1147,6 +1168,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.signed_flag;
case IVL_LPM_CAST_INT:
case IVL_LPM_SIGN_EXT: // Sign extend is always signed.
return 1;
case IVL_LPM_SFUNC:
@ -1157,7 +1179,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_PART_BI:
return net->u_.part.signed_flag;
case IVL_LPM_REPEAT:
return 0;
@ -1338,6 +1359,15 @@ extern "C" ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net)
return net->l.sig;
}
extern "C" ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net)
{
if (net == 0)
return 0;
if (net->type_ != __NEXUS_PTR_SWI)
return 0;
return net->l.swi;
}
extern "C" const char* ivl_parameter_basename(ivl_parameter_t net)
{
assert(net);
@ -2162,6 +2192,11 @@ extern "C" const char*ivl_switch_basename(ivl_switch_t net)
return net->name;
}
extern "C" ivl_scope_t ivl_switch_scope(ivl_switch_t net)
{
return net->scope;
}
extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net)
{
return net->type;
@ -2181,3 +2216,33 @@ extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
{
return net->pins[2];
}
extern "C" unsigned ivl_switch_width(ivl_switch_t net)
{
return net->width;
}
extern "C" unsigned ivl_switch_part(ivl_switch_t net)
{
return net->part;
}
extern "C" unsigned ivl_switch_offset(ivl_switch_t net)
{
return net->offset;
}
extern "C" const char* ivl_switch_file(ivl_switch_t net)
{
return net->file;
}
extern "C" ivl_island_t ivl_switch_island(ivl_switch_t net)
{
return net->island;
}
extern "C" unsigned ivl_switch_lineno(ivl_switch_t net)
{
return net->lineno;
}

107
t-dll.cc
View File

@ -1037,9 +1037,14 @@ bool dll_target::tran(const NetTran*net)
{
struct ivl_switch_s*obj = new struct ivl_switch_s;
obj->type = net->type();
obj->width = 0;
obj->part = 0;
obj->offset = 0;
obj->name = net->name();
obj->scope = find_scope(des_, net->scope());
obj->island = net->island;
assert(obj->scope);
assert(obj->island);
const Nexus*nex;
@ -1063,6 +1068,15 @@ bool dll_target::tran(const NetTran*net)
obj->pins[2] = 0;
}
if (obj->type == IVL_SW_TRAN_VP) {
obj->width = net->vector_width();
obj->part = net->part_width();
obj->offset= net->part_offset();
}
obj->file = net->get_file();
obj->lineno = net->get_lineno();
switch_attributes(obj, net);
scope_add_switch(obj->scope, obj);
@ -1536,6 +1550,71 @@ void dll_target::lpm_clshift(const NetCLShift*net)
scope_add_lpm(obj->scope, obj);
}
bool dll_target::lpm_cast_int(const NetCastInt*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CAST_INT;
obj->name = net->name(); // NetCastInt names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->width = net->width();
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.arith.q = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.arith.a = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
make_lpm_delays_(obj, net);
scope_add_lpm(obj->scope, obj);
return true;
}
bool dll_target::lpm_cast_real(const NetCastReal*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CAST_REAL;
obj->name = net->name(); // NetCastReal names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->width = 0;
obj->u_.arith.signed_flag = net->signed_flag()? 1 : 0;
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.arith.q = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.arith.a = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
make_lpm_delays_(obj, net);
scope_add_lpm(obj->scope, obj);
return true;
}
/*
* Make out of the NetCompare object an ivl_lpm_s object. The
* comparators in ivl_target do not support < or <=, but they can be
@ -1991,9 +2070,6 @@ bool dll_target::part_select(const NetPartSelect*net)
case NetPartSelect::PV:
obj->type = IVL_LPM_PART_PV;
break;
case NetPartSelect::BI:
obj->type = IVL_LPM_PART_BI;
break;
}
obj->name = net->name(); // NetPartSelect names are permallocated.
assert(net->scope());
@ -2047,35 +2123,12 @@ bool dll_target::part_select(const NetPartSelect*net)
obj->u_.part.a = nex->t_cookie();
break;
case IVL_LPM_PART_BI:
/* For now, handle this exactly the same as a PV */
/* NetPartSelect:pin(0) is the output pin. */
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.part.q = nex->t_cookie();
/* NetPartSelect:pin(1) is the input pin. */
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.part.a = nex->t_cookie();
break;
default:
assert(0);
}
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
/* If the device is a PART_BI, then the "input" is also a
strength aware output, so attach it to the nexus with
strong driver. */
if (obj->type == IVL_LPM_PART_BI)
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
else
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
/* The select input is optional. */
if (obj->u_.part.s)

View File

@ -21,6 +21,7 @@
# include "target.h"
# include "ivl_target.h"
# include "ivl_target_priv.h"
# include "StringHeap.h"
# include "netlist.h"
# include <vector>
@ -75,6 +76,8 @@ struct dll_target : public target_t, public expr_scan_t {
void lpm_abs(const NetAbs*);
void lpm_add_sub(const NetAddSub*);
bool lpm_array_dq(const NetArrayDq*);
bool lpm_cast_int(const NetCastInt*);
bool lpm_cast_real(const NetCastReal*);
void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*);
void lpm_divide(const NetDivide*);
@ -450,9 +453,13 @@ struct ivl_net_logic_s {
struct ivl_switch_s {
ivl_switch_type_t type;
unsigned width;
unsigned part;
unsigned offset;
perm_string name;
ivl_scope_t scope;
ivl_island_t island;
struct ivl_attribute_s*attr;
unsigned nattr;

View File

@ -107,6 +107,20 @@ bool target_t::lpm_array_dq(const NetArrayDq*)
return false;
}
bool target_t::lpm_cast_int(const NetCastInt*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCastInt." << endl;
return false;
}
bool target_t::lpm_cast_real(const NetCastReal*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCastReal." << endl;
return false;
}
void target_t::lpm_clshift(const NetCLShift*)
{
cerr << "target (" << typeid(*this).name() << "): "

View File

@ -72,6 +72,8 @@ struct target_t {
virtual void lpm_add_sub(const NetAddSub*);
virtual bool lpm_array_dq(const NetArrayDq*);
virtual void lpm_clshift(const NetCLShift*);
virtual bool lpm_cast_int(const NetCastInt*);
virtual bool lpm_cast_real(const NetCastReal*);
virtual void lpm_compare(const NetCompare*);
virtual void lpm_divide(const NetDivide*);
virtual void lpm_modulo(const NetModulo*);

View File

@ -178,6 +178,11 @@ void show_unary_expression(ivl_expr_t net, unsigned ind)
break;
}
if (ivl_expr_opcode(net) == '!' && ivl_expr_type(net)==IVL_VT_REAL) {
fprintf(out, "%*sERROR: Real argument to unary ! !?\n", ind,"");
stub_errors += 1;
}
fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
name, width, sign, vt);
show_expression(ivl_expr_oper1(net), ind+4);

View File

@ -240,6 +240,56 @@ static void show_lpm_array(ivl_lpm_t net)
}
}
static void show_lpm_cast_int(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CAST_INT %s: <width=%u>\n",
ivl_lpm_basename(net), width);
ivl_nexus_t q = ivl_lpm_q(net,0);
ivl_nexus_t a = ivl_lpm_data(net,0);
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
if (type_of_nexus(q) == IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of Q is %s, expecting !real\n",
data_type_string(type_of_nexus(q)));
stub_errors += 1;
}
if (type_of_nexus(a) != IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of A is %s, expecting real\n",
data_type_string(type_of_nexus(a)));
stub_errors += 1;
}
}
static void show_lpm_cast_real(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CAST_REAL %s: <width=%u>\n",
ivl_lpm_basename(net), width);
ivl_nexus_t q = ivl_lpm_q(net,0);
ivl_nexus_t a = ivl_lpm_data(net,0);
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
if (type_of_nexus(q) != IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of Q is %s, expecting real\n",
data_type_string(type_of_nexus(q)));
stub_errors += 1;
}
if (type_of_nexus(a) == IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of A is %s, expecting !real\n",
data_type_string(type_of_nexus(a)));
stub_errors += 1;
}
}
static void show_lpm_divide(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
@ -555,38 +605,6 @@ static void show_lpm_part(ivl_lpm_t net)
}
}
static void show_lpm_part_bi(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned base = ivl_lpm_base(net);
ivl_nexus_t port_p = ivl_lpm_q(net,0);
ivl_nexus_t port_v = ivl_lpm_data(net,0);
fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
width_of_nexus(port_v));
/* The data(0) port must be large enough for the part select. */
if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
fprintf(out, " ERROR: Part select is out of range."
" Data nexus width=%u, width+base=%u\n",
width_of_nexus(ivl_lpm_data(net,0)), width+base);
stub_errors += 1;
}
/* The Q vector must be exactly the width of the part select. */
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
fprintf(out, " ERROR: Part select input mismatch."
" Nexus width=%u, expect width=%u\n",
width_of_nexus(ivl_lpm_q(net,0)), width);
stub_errors += 1;
}
}
/*
* The reduction operators have similar characteristics and are
* displayed here.
@ -834,6 +852,14 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_array(net);
break;
case IVL_LPM_CAST_INT:
show_lpm_cast_int(net);
break;
case IVL_LPM_CAST_REAL:
show_lpm_cast_real(net);
break;
case IVL_LPM_DIVIDE:
show_lpm_divide(net);
break;
@ -905,11 +931,6 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_part(net);
break;
/* The BI part select is slightly special. */
case IVL_LPM_PART_BI:
show_lpm_part_bi(net);
break;
case IVL_LPM_REPEAT:
show_lpm_repeat(net);
break;
@ -1059,6 +1080,7 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
ivl_net_logic_t log;
ivl_lpm_t lpm;
ivl_signal_t sig;
ivl_switch_t swt;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
@ -1092,6 +1114,11 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
ivl_scope_name(ivl_lpm_scope(lpm)),
ivl_lpm_basename(lpm), dr0, dr1);
} else if ((swt = ivl_nexus_ptr_switch(ptr))) {
fprintf(out, " SWITCH %s.%s\n",
ivl_scope_name(ivl_switch_scope(swt)),
ivl_switch_basename(swt));
} else if ((con = ivl_nexus_ptr_con(ptr))) {
signal_nexus_const(net, ptr, con);

View File

@ -52,18 +52,23 @@ void show_switch(ivl_switch_t net)
fprintf(out, " rtranif1 %s", name);
has_enable = 1;
break;
case IVL_SW_TRAN_VP:
fprintf(out, " tran(VP wid=%u, part=%u, off=%u) %s",
ivl_switch_width(net), ivl_switch_part(net),
ivl_switch_offset(net), name);
break;
}
fprintf(out, "\n");
fprintf(out, " island=%p\n", ivl_switch_island(net));
ivl_nexus_t nex = ivl_switch_a(net);
const char*nex_name = nex? ivl_nexus_name(nex) : "";
ivl_variable_type_t nex_type_a = nex? type_of_nexus(nex) : IVL_VT_NO_TYPE;
ivl_nexus_t nexa = ivl_switch_a(net);
const char*nex_name = nexa? ivl_nexus_name(nexa) : "";
ivl_variable_type_t nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
nex = ivl_switch_b(net);
nex_name = nex? ivl_nexus_name(nex) : "";
ivl_variable_type_t nex_type_b = nex? type_of_nexus(nex) : IVL_VT_NO_TYPE;
ivl_nexus_t nexb = ivl_switch_b(net);
nex_name = nexb? ivl_nexus_name(nexb) : "";
ivl_variable_type_t nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
/* The A/B pins of the switch must be present, and must match. */
@ -80,13 +85,40 @@ void show_switch(ivl_switch_t net)
stub_errors += 1;
}
if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
/* The TRAN_VP nodes are special in that the specific
width matters for each port and should be exactly
right for both. */
if (width_of_nexus(nexa) != ivl_switch_width(net)) {
fprintf(out, " A: ERROR: part vector nexus "
"width=%u, expecting width=%u\n",
width_of_nexus(nexa), ivl_switch_width(net));
stub_errors += 1;
}
if (width_of_nexus(nexb) != ivl_switch_part(net)) {
fprintf(out, " B: ERROR: part select nexus "
"width=%u, expecting width=%u\n",
width_of_nexus(nexb), ivl_switch_part(net));
stub_errors += 1;
}
} else {
/* All other TRAN nodes will have matching vector
widths, but the actual value doesn't matter. */
if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
fprintf(out, " A/B: ERROR: Width of ports don't match"
": A=%u, B=%u\n",
width_of_nexus(nexa), width_of_nexus(nexb));
stub_errors += 1;
}
}
if (has_enable) {
nex = ivl_switch_enable(net);
nex_name = nex? ivl_nexus_name(nex) : "";
ivl_nexus_t nexe = ivl_switch_enable(net);
nex_name = nexe? ivl_nexus_name(nexe) : "";
fprintf(out, " E: %s\n", nex_name);
if (width_of_nexus(nex) != 1) {
if (width_of_nexus(nexe) != 1) {
fprintf(out, " E: ERROR: Nexus width is %u\n",
width_of_nexus(nex));
width_of_nexus(nexe));
}
}
}

View File

@ -51,7 +51,8 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = vvp.o draw_mux.o draw_ufunc.o draw_vpi.o eval_bool.o eval_expr.o \
O = vvp.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \
eval_bool.o eval_expr.o \
eval_real.o modpath.o vector.o \
vvp_process.o vvp_scope.o

View File

@ -47,9 +47,9 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
const char*dly = "";
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
dly = "/d";
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise),

689
tgt-vvp/draw_net_input.c Normal file
View File

@ -0,0 +1,689 @@
/*
* 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "vvp_priv.h"
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include <inttypes.h>
# include <assert.h>
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
#define snprintf _snprintf
#endif
static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
{
unsigned idx;
ivl_signal_type_t out = IVL_SIT_TRI;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_signal_type_t stype;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
stype = ivl_signal_type(sig);
if (stype == IVL_SIT_REG)
continue;
if (stype == IVL_SIT_TRI)
continue;
if (stype == IVL_SIT_NONE)
continue;
out = stype;
}
return out;
}
static void draw_C4_repeated_constant(char bit_char, unsigned width)
{
unsigned idx;
fprintf(vvp_out, "C4<");
for (idx = 0 ; idx < width ; idx += 1)
fprintf(vvp_out, "%c", bit_char);
fprintf(vvp_out, ">");
}
static char* draw_C4_to_string(ivl_net_const_t cptr)
{
const char*bits = ivl_const_bits(cptr);
unsigned idx;
size_t result_len = 5 + ivl_const_width(cptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
char bitchar = bits[ivl_const_width(cptr)-idx-1];
*dp++ = bitchar;
assert((dp - result) < result_len);
}
strcpy(dp, ">");
return result;
}
static char* draw_C8_to_string(ivl_net_const_t cptr,
ivl_drive_t dr0, ivl_drive_t dr1)
{
size_t nresult = 5 + 3*ivl_const_width(cptr);
char*result = malloc(nresult);
const char*bits = ivl_const_bits(cptr);
unsigned idx;
char dr0c = "01234567"[dr0];
char dr1c = "01234567"[dr1];
char*dp = result;
strcpy(dp, "C8<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
switch (bits[ivl_const_width(cptr)-idx-1]) {
case '0':
*dp++ = dr0c;
*dp++ = dr0c;
*dp++ = '0';
break;
case '1':
*dp++ = dr1c;
*dp++ = dr1c;
*dp++ = '1';
break;
case 'x':
case 'X':
*dp++ = dr0c;
*dp++ = dr1c;
*dp++ = 'x';
break;
case 'z':
case 'Z':
*dp++ = '0';
*dp++ = '0';
*dp++ = 'z';
break;
default:
assert(0);
break;
}
assert(dp - result < nresult);
}
strcpy(dp, ">");
return result;
}
static struct vvp_nexus_data*new_nexus_data()
{
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
return data;
}
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
{
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
return 1;
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
return 1;
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
if (log != 0) {
/* These logic gates are able to generate unusual
strength values and so their outputs are considered
strength aware. */
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
return 1;
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
return 1;
if (ivl_logic_type(log) == IVL_LO_PMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_NMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_CMOS)
return 1;
}
return 0;
}
/*
* Given a nexus, look for a signal that has module delay
* paths. Return that signal. (There should be no more than 1.) If we
* don't find any, then return nil.
*/
static ivl_signal_t find_modpath(ivl_nexus_t nex)
{
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
if (ivl_signal_npath(sig) == 0)
continue;
return sig;
}
return 0;
}
static void str_repeat(char*buf, const char*str, unsigned rpt)
{
unsigned idx;
size_t len = strlen(str);
for (idx = 0 ; idx < rpt ; idx += 1) {
strcpy(buf, str);
buf += len;
}
}
/*
* This function takes a nexus and looks for an input functor. It then
* draws to the output a string that represents that functor. What we
* are trying to do here is find the input to the net that is attached
* to this nexus.
*/
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
{
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
ivl_net_const_t cptr;
ivl_net_logic_t lptr;
ivl_signal_t sptr;
ivl_lpm_t lpm;
lptr = ivl_nexus_ptr_log(nptr);
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
do {
if (! can_elide_bufz(lptr, nptr))
break;
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
} while(0);
/* If this is a pulldown device, then there is a single pin
that drives a constant value to the entire width of the
vector. The driver normally drives a pull0 value, so a C8<>
constant is appropriate, but if the drive is really strong,
then we can draw a C4<> constant instead. */
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
size_t result_len = ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "0", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 3*ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '0';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
size_t result_len = 5 + ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "1", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 5 + 3*ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '1';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (nptr_pin == 0)) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lptr);
return strdup(tmp);
}
sptr = ivl_nexus_ptr_sig(nptr);
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
char tmp[128];
/* Input is a .var. This device may be a non-zero pin
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) {
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
sptr, nptr_pin, sptr, nptr_pin);
}
return strdup(tmp);
}
cptr = ivl_nexus_ptr_con(nptr);
if (cptr) {
/* Constants should have exactly 1 pin, with a literal value. */
assert(nptr_pin == 0);
char *result = 0;
switch (ivl_const_type(cptr)) {
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
result = draw_C4_to_string(cptr);
} else {
result = draw_C8_to_string(cptr,
ivl_nexus_ptr_drive0(nptr),
ivl_nexus_ptr_drive1(nptr));
}
break;
case IVL_VT_REAL:
result = draw_Cr_to_string(ivl_const_real(cptr));
break;
default:
assert(0);
break;
}
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
/* We have a delayed constant, so we need to build some code. */
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
cptr, get_number_immediate(d_rise),
get_number_immediate(d_rise),
get_number_immediate(d_rise), cptr);
free(result);
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
}
return result;
}
lpm = ivl_nexus_ptr_lpm(nptr);
if (lpm) switch (ivl_lpm_type(lpm)) {
case IVL_LPM_FF:
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_NEE:
case IVL_LPM_RE_AND:
case IVL_LPM_RE_OR:
case IVL_LPM_RE_XOR:
case IVL_LPM_RE_NAND:
case IVL_LPM_RE_NOR:
case IVL_LPM_RE_XNOR:
case IVL_LPM_SFUNC:
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
case IVL_LPM_SIGN_EXT:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
case IVL_LPM_MUX:
case IVL_LPM_POW:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_UFUNC:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
case IVL_LPM_REPEAT:
if (ivl_lpm_q(lpm, 0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lpm);
return strdup(tmp);
}
break;
}
fprintf(stderr, "internal error: no input to nexus %s\n",
ivl_nexus_name(nex));
assert(0);
return strdup("C<z>");
}
static char* draw_island_port(ivl_island_t island,
ivl_nexus_t nex, const char*src)
{
char result[64];
if (ivl_island_flag_test(island,0) == 0) {
fprintf(vvp_out, "I%p .island tran;\n", island);
ivl_island_flag_set(island,0,1);
}
fprintf(vvp_out, "p%p .port I%p, %s;\n", nex, island, src);
snprintf(result, sizeof result, "p%p", nex);
return strdup(result);
}
/*
* This function draws the input to a net into a string. What that
* means is that it returns a static string that can be used to
* represent a resolved driver to a nexus. If there are multiple
* drivers to the nexus, then it writes out the resolver declarations
* needed to perform strength resolution.
*
* The string that this returns is malloced, and that means that the
* caller must free the string or store it permanently. This function
* does *not* check for a previously calculated string. Use the
* draw_net_input for the general case.
*/
/* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001
char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data)
{
ivl_island_t island = 0;
ivl_signal_type_t res;
char result[512];
unsigned idx;
int level;
unsigned ndrivers = 0;
static ivl_nexus_ptr_t *drivers = 0x0;
static unsigned adrivers = 0;
const char*resolv_type;
char*nex_private = 0;
/* Accumulate nex_data flags. */
int nex_flags = 0;
res = signal_type_of_nexus(nex);
switch (res) {
case IVL_SIT_TRI:
resolv_type = "tri";
break;
case IVL_SIT_TRI0:
resolv_type = "tri0";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRI1:
resolv_type = "tri1";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRIAND:
resolv_type = "triand";
break;
case IVL_SIT_TRIOR:
resolv_type = "trior";
break;
default:
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
assert(0);
resolv_type = "tri";
break;
}
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_lpm_t lpm_tmp;
ivl_switch_t sw = 0;
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
/* If this object is part of an island, then we'll be
making a port. Save the island cookie. */
if ( (sw = ivl_nexus_ptr_switch(nptr)) ) {
island = ivl_switch_island(sw);
}
/* If we are supposed to skip LPM_PART_BI data pins,
check that this driver is that. */
if ((omit_flags&OMIT_PART_BI_DATA)
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
&& (nex == ivl_lpm_data(lpm_tmp,0)))
continue;
if (nptr == omit_ptr)
continue;
/* Skip input only pins. */
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
continue;
/* Mark the strength-aware flag if the driver can
generate values other than the standard "6"
strength. */
if (nexus_drive_is_strength_aware(nptr))
nex_flags |= VVP_NEXUS_DATA_STR;
/* Save this driver. */
if (ndrivers >= adrivers) {
adrivers += 4;
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
assert(drivers);
}
drivers[ndrivers] = nptr;
ndrivers += 1;
}
/* If the caller is collecting nexus information, then save
the nexus driver count in the nex_data. */
if (nex_data) {
nex_data->drivers_count = ndrivers;
nex_data->flags |= nex_flags;
}
/* If the nexus has no drivers, then send a constant HiZ into
the net. */
if (ndrivers == 0) {
unsigned idx, wid = width_of_nexus(nex);
char*tmp = malloc(wid + 5);
nex_private = tmp;
strcpy(tmp, "C4<");
tmp += strlen(tmp);
switch (res) {
case IVL_SIT_TRI:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = 'z';
break;
case IVL_SIT_TRI0:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '0';
break;
case IVL_SIT_TRI1:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '1';
break;
default:
assert(0);
}
*tmp++ = '>';
*tmp = 0;
if (island) {
char*tmp = draw_island_port(island, nex, nex_private);
free(nex_private);
nex_private = tmp;
}
return nex_private;
}
/* If the nexus has exactly one driver, then simply draw
it. Note that this will *not* work if the nexus is not a
TRI type nexus. */
if (ndrivers == 1 && res == IVL_SIT_TRI) {
ivl_signal_t path_sig = find_modpath(nex);
if (path_sig) {
char*nex_str = draw_net_input_drive(nex, drivers[0]);
char modpath_label[64];
snprintf(modpath_label, sizeof modpath_label,
"V_%p/m", path_sig);
nex_private = strdup(modpath_label);
draw_modpath(path_sig, nex_str);
} else {
nex_private = draw_net_input_drive(nex, drivers[0]);
}
if (island) {
char*tmp = draw_island_port(island, nex, nex_private);
free(nex_private);
nex_private = tmp;
}
return nex_private;
}
level = 0;
while (ndrivers) {
unsigned int inst;
for (inst = 0; inst < ndrivers; inst += 4) {
if (ndrivers > 4)
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
nex, level, inst);
else
fprintf(vvp_out, "RS_%p .resolv %s",
nex, resolv_type);
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
if (level) {
fprintf(vvp_out, ", RS_%p/%d/%d",
nex, level - 1, idx*4);
} else {
char*drive = draw_net_input_drive(nex, drivers[idx]);
fprintf(vvp_out, ", %s", drive);
free(drive);
}
}
for ( ; idx < inst+4 ; idx += 1) {
fprintf(vvp_out, ", ");
draw_C4_repeated_constant('z',width_of_nexus(nex));
}
fprintf(vvp_out, ";\n");
}
if (ndrivers > 4)
ndrivers = (ndrivers+3) / 4;
else
ndrivers = 0;
level += 1;
}
snprintf(result, sizeof result, "RS_%p", nex);
if (island)
nex_private = draw_island_port(island, nex, result);
else
nex_private = strdup(result);
return nex_private;
}
/*
* Get a cached description of the nexus input, or create one if this
* nexus has not been cached yet. This is a wrapper for the common
* case call to draw_net_input_x.
*/
const char*draw_net_input(ivl_nexus_t nex)
{
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
ivl_nexus_get_private(nex);
/* If this nexus already has a label, then its input is
already figured out. Just return the existing label. */
if (nex_data && nex_data->net_input)
return nex_data->net_input;
if (nex_data == 0) {
nex_data = new_nexus_data();
ivl_nexus_set_private(nex, nex_data);
}
assert(nex_data->net_input == 0);
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
return nex_data->net_input;
}

81
tgt-vvp/draw_switch.c Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "vvp_priv.h"
# include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h>
# include <string.h>
static void draw_tran_island(ivl_island_t island)
{
fprintf(vvp_out, "I%p .island tran;\n", island);
ivl_island_flag_set(island, 0, 1);
}
void draw_switch_in_scope(ivl_switch_t sw)
{
ivl_island_t island = ivl_switch_island(sw);
if (ivl_island_flag_test(island, 0) == 0)
draw_tran_island(island);
ivl_nexus_t nex_a = ivl_switch_a(sw);
assert(nex_a);
const char*str_a = draw_net_input(nex_a);
ivl_nexus_t nex_b = ivl_switch_b(sw);
assert(nex_b);
const char*str_b = draw_net_input(nex_b);
ivl_nexus_t enable = ivl_switch_enable(sw);
const char*str_e = 0;
if (enable)
str_e = draw_net_input(enable);
switch (ivl_switch_type(sw)) {
case IVL_SW_TRAN:
fprintf(vvp_out, " .tran");
break;
case IVL_SW_TRANIF0:
fprintf(vvp_out, " .tranif0");
break;
case IVL_SW_TRANIF1:
fprintf(vvp_out, " .tranif1");
break;
case IVL_SW_TRAN_VP:
fprintf(vvp_out, " .tranvp %u %u %u,",
ivl_switch_width(sw), ivl_switch_part(sw), ivl_switch_offset(sw));
break;
default:
fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n",
ivl_switch_file(sw), ivl_switch_lineno(sw));
vvp_errors += 1;
return;
}
fprintf(vvp_out, " I%p, %s %s", island, str_a, str_b);
if (enable)
fprintf(vvp_out, ", %s", str_e);
fprintf(vvp_out, ";\n");
}

View File

@ -62,7 +62,7 @@ static int is_fixed_memory_word(ivl_expr_t net)
if (ivl_signal_type(sig) == IVL_SIT_REG)
return 0;
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned), 0))
return 1;
return 0;
@ -182,7 +182,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
@ -204,19 +204,72 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_expr_t word_ex = ivl_expr_oper1(expr);
if (word_ex) {
/* Some array select have been evaluated. */
if (number_is_immediate(word_ex, 8*sizeof(unsigned))) {
if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) {
use_word = get_number_immediate(word_ex);
word_ex = 0;
}
}
if (word_ex)
break;
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
if (word_ex && ivl_expr_type(word_ex)==IVL_EX_SIGNAL) {
/* Special case: the index is a signal. */
snprintf(buffer, sizeof buffer,
"&A<v%p, v%p_0 >", sig,
ivl_expr_signal(word_ex));
} else if (word_ex) {
/* Fallback case: evaluate expression. */
struct vector_info av;
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer,
"&A<v%p, %u %u>", sig, av.base, av.wid);
args[idx].vec = av;
args[idx].vec_flag = 1;
} else {
snprintf(buffer, sizeof buffer,
"&A<v%p, %u>", sig, use_word);
}
args[idx].text = strdup(buffer);
continue;
}
case IVL_EX_SELECT: {
ivl_expr_t vexpr = ivl_expr_oper1(expr);
assert(vexpr);
/* This code is only for signals. */
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break;
/* The signal is part of an array. */
/* Add &APV<> code here when it is finished. */
if (ivl_expr_oper1(vexpr)) break;
ivl_expr_t bexpr = ivl_expr_oper2(expr);
assert(bexpr);
/* This is a constant bit/part select. */
if (number_is_immediate(bexpr, 64, 1)) {
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
ivl_expr_signal(vexpr),
get_number_immediate(bexpr),
ivl_expr_width(expr));
/* This is an indexed bit/part select. */
} else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL) {
/* Sepcial case: the base is a signal. */
snprintf(buffer, sizeof buffer, "&PV<v%p_0, v%p_0, %u>",
ivl_expr_signal(vexpr),
ivl_expr_signal(bexpr),
ivl_expr_width(expr));
} else {
/* Fallback case: evaluate the expression. */
struct vector_info rv;
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
ivl_expr_signal(vexpr),
rv.base, rv.wid,
ivl_expr_width(expr));
}
args[idx].text = strdup(buffer);
continue;
}
/* Everything else will need to be evaluated and
passed as a constant to the vpi task. */
default:

View File

@ -28,7 +28,7 @@
static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
int ok_flags);
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
int add_index, unsigned long immediate);
int add_index, long immediate);
int number_is_unknown(ivl_expr_t ex)
{
@ -54,9 +54,11 @@ int number_is_unknown(ivl_expr_t ex)
* above bitX. The maximum size of the immediate may vary, so use
* lim_wid at the width limit to use.
*/
int number_is_immediate(ivl_expr_t ex, unsigned lim_wid)
int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_ok_flag)
{
const char*bits;
unsigned nbits = ivl_expr_width(ex);
char pad_bit = '0';
unsigned idx;
if (ivl_expr_type(ex) != IVL_EX_NUMBER
@ -64,20 +66,23 @@ int number_is_immediate(ivl_expr_t ex, unsigned lim_wid)
return 0;
bits = ivl_expr_bits(ex);
for (idx = lim_wid ; idx < ivl_expr_width(ex) ; idx += 1)
if (bits[idx] != '0')
return 0;
/* Negative numbers are not "immediate". */
if (ivl_expr_signed(ex) && bits[ivl_expr_width(ex)-1]=='1')
if (ivl_expr_signed(ex) && bits[nbits-1]=='1')
pad_bit = '1';
if (pad_bit == '1' && !negative_ok_flag)
return 0;
for (idx = lim_wid ; idx < nbits ; idx += 1)
if (bits[idx] != pad_bit)
return 0;
return 1;
}
unsigned long get_number_immediate(ivl_expr_t ex)
long get_number_immediate(ivl_expr_t ex)
{
unsigned long imm = 0;
long imm = 0;
unsigned idx;
switch (ivl_expr_type(ex)) {
@ -92,11 +97,14 @@ unsigned long get_number_immediate(ivl_expr_t ex)
case '0':
break;
case '1':
imm |= 1UL << idx;
assert(idx < 8*sizeof(imm));
imm |= 1L << idx;
break;
default:
assert(0);
}
if (ivl_expr_signed(ex) && bits[nbits-1]=='1' && nbits < 8*sizeof(imm))
imm |= -1L << nbits;
break;
}
@ -111,30 +119,18 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
{
switch (ivl_expr_type(expr)) {
case IVL_EX_NUMBER: {
unsigned value = 0;
unsigned idx, nbits = ivl_expr_width(expr);
const char*bits = ivl_expr_bits(expr);
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) {
case '0':
break;
case '1':
assert(idx < (8*sizeof value));
value |= 1 << idx;
break;
default:
assert(0);
}
fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value);
break;
}
case IVL_EX_NUMBER:
case IVL_EX_ULONG:
fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr));
break;
{
long imm = get_number_immediate(expr);
if (imm >= 0) {
fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm);
} else {
fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm);
fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm);
}
}
break;
case IVL_EX_SIGNAL: {
ivl_signal_t sig = ivl_expr_signal(expr);
@ -155,7 +151,7 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
}
ivl_expr_t ixe = ivl_expr_oper1(expr);
if (number_is_immediate(ixe, 8*sizeof(unsigned long)))
if (number_is_immediate(ixe, 8*sizeof(unsigned long), 0))
word = get_number_immediate(ixe);
else {
struct vector_info rv;
@ -383,7 +379,7 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t exp,
return draw_binary_expr_eq_real(exp);
}
if (number_is_immediate(re,16) && !number_is_unknown(re))
if (number_is_immediate(re,16,0) && !number_is_unknown(re))
return draw_eq_immediate(exp, ewid, le, re, stuff_ok_flag);
assert(ivl_expr_value(le) == IVL_VT_LOGIC
@ -814,7 +810,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
switch (ivl_expr_opcode(exp)) {
case 'G':
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
if (number_is_immediate(le,16) && !number_is_unknown(le)) {
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
unsigned imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@ -830,7 +826,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
case 'L':
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
if (number_is_immediate(re,16) && !number_is_unknown(re)) {
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
unsigned imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@ -846,7 +842,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
case '<':
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
if (number_is_immediate(re,16) && !number_is_unknown(re)) {
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
unsigned imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@ -861,7 +857,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
case '>':
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
if (number_is_immediate(le,16) && !number_is_unknown(le)) {
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
unsigned imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
@ -940,9 +936,9 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
ivl_expr_t re = ivl_expr_oper2(exp);
if (ivl_expr_opcode(exp) == '&') {
if (number_is_immediate(re, IMM_WID) && !number_is_unknown(re))
if (number_is_immediate(re, IMM_WID, 0) && !number_is_unknown(re))
return draw_logic_immediate(exp, le, re, wid);
if (number_is_immediate(le, IMM_WID) && !number_is_unknown(le))
if (number_is_immediate(le, IMM_WID, 0) && !number_is_unknown(le))
return draw_logic_immediate(exp, re, le, wid);
}
@ -1162,12 +1158,11 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
static struct vector_info draw_load_add_immediate(ivl_expr_t le,
ivl_expr_t re,
unsigned wid)
unsigned wid,
int signed_flag)
{
struct vector_info lv;
unsigned long imm;
imm = get_number_immediate(re);
long imm = get_number_immediate(re);
lv.base = allocate_vector(wid);
lv.wid = wid;
if (lv.base == 0) {
@ -1180,7 +1175,7 @@ static struct vector_info draw_load_add_immediate(ivl_expr_t le,
/* Load the signal value with a %load that adds the index
register to the value being loaded. */
draw_signal_dest(le, lv, 0, imm);
draw_signal_dest(le, lv, signed_flag, imm);
return lv;
}
@ -1197,23 +1192,50 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
imm = get_number_immediate(re);
/* Now generate enough %addi instructions to add the entire
immediate value to the destination. The adds are done IMM_WID
bits at a time, but +1 bits are done to push the carry into
the higher bits if needed. */
{ unsigned base;
for (base = 0 ; base < lv.wid ; base += IMM_WID) {
unsigned long tmp = imm & 0xffffffffUL;
unsigned add_wid = lv.wid - base;
/* This shouldn't generally happen, because the elaborator
should take care of simple constant propagation like this,
but it doesn't have to and it is easy to catch here. */
if (imm == 0)
return lv;
imm >>= IMM_WID;
switch (lv.base) {
case 0: /* Left expression is 0. */
lv.base = allocate_vector(wid);
if (lv.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of addition.\n",
ivl_expr_file(re), ivl_expr_lineno(re), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
break;
fprintf(vvp_out, " %%addi %u, %lu, %u;\n",
lv.base+base, tmp, add_wid);
case 1: /* Left expression is 1...1 (i.e. -1) */
imm -= 1;
if (imm == 0) {
lv.base = 0;
} else {
lv.base = allocate_vector(wid);
if (lv.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of addition.\n",
ivl_expr_file(re), ivl_expr_lineno(re), wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
}
break;
if (imm == 0)
break;
}
case 2: /* Left expression is X or Z */
case 3:
lv.base = 2;
break;
default: /* The regular case. */
fprintf(vvp_out, " %%addi %u, %lu, %u;\n", lv.base, imm, wid);
break;
}
return lv;
@ -1234,7 +1256,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
assert(lv.wid == wid);
imm = get_number_immediate(re);
assert( (imm & ~0xffffffffUL) == 0 );
if (imm == 0)
return lv;
switch (lv.base) {
case 0:
@ -1248,21 +1271,21 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
lv.base = tmp;
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
return lv;
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
break;
case 2:
case 3:
lv.base = 2;
return lv;
break;
default:
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
break;
}
return lv;
}
@ -1277,8 +1300,10 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le,
assert(lv.wid == wid);
imm = get_number_immediate(re);
if (imm == 0)
return lv;
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
return lv;
}
@ -1293,25 +1318,27 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
const char*sign_string = ivl_expr_signed(le) && ivl_expr_signed(re)? "/s" : "";
int signed_flag = ivl_expr_signed(exp)? 1 : 0;
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
&& (ivl_expr_type(re) == IVL_EX_ULONG))
return draw_load_add_immediate(le, re, wid);
return draw_load_add_immediate(le, re, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
&& (ivl_expr_type(re) == IVL_EX_NUMBER))
return draw_load_add_immediate(le, re, wid);
return draw_load_add_immediate(le, re, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_SIGNAL)
&& (ivl_expr_type(le) == IVL_EX_ULONG))
return draw_load_add_immediate(re, le, wid);
return draw_load_add_immediate(re, le, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_SIGNAL)
&& (ivl_expr_type(le) == IVL_EX_NUMBER))
return draw_load_add_immediate(re, le, wid);
return draw_load_add_immediate(re, le, wid, signed_flag);
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_ULONG))
@ -1320,7 +1347,7 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
if ((ivl_expr_opcode(exp) == '+')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, 8*sizeof(unsigned long)))
&& number_is_immediate(re, 8*sizeof(unsigned long), 0))
return draw_add_immediate(le, re, wid);
if ((ivl_expr_opcode(exp) == '-')
@ -1330,13 +1357,13 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
if ((ivl_expr_opcode(exp) == '-')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, IMM_WID))
&& number_is_immediate(re, IMM_WID, 0))
return draw_sub_immediate(le, re, wid);
if ((ivl_expr_opcode(exp) == '*')
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
&& (! number_is_unknown(re))
&& number_is_immediate(re, IMM_WID))
&& number_is_immediate(re, IMM_WID, 0))
return draw_mul_immediate(le, re, wid);
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
@ -1643,7 +1670,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
vvp_errors += 1;
}
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID)) {
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) {
unsigned long val = get_number_immediate(exp);
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
return res;
@ -1937,11 +1964,13 @@ void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned swid)
* offsetting the read from the lsi (least significant index) of the
* signal.
*
* If the add_index is >=0, then generate a %load/vp0 to add the
* word0 value to the loaded value before storing it into the destination.
* If the add_index is 0, then generate a %load/vp0 to add the
* word0 value to the loaded value before storing it into the
* destination. If the add_index is 1, then generate a %load/vp0/s to
* do a signed load.
*/
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
int add_index, unsigned long immediate)
int add_index, long immediate)
{
unsigned swid = ivl_expr_width(exp);
ivl_signal_t sig = ivl_expr_signal(exp);
@ -1958,17 +1987,17 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
draw_eval_expr_into_integer(ix, 3);
if (add_index < 0) {
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
res.base, sig, swid);
pad_expr_in_place(exp, res, swid);
} else {
assert(add_index == 0);
const char*sign_flag = (add_index>0)? "/s" : "";
/* Add an immediate value to an array value. */
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n",
res.base, sig, swid);
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n",
sign_flag, res.base, sig, res.wid);
}
pad_expr_in_place(exp, res, swid);
return;
}
@ -1983,13 +2012,17 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
} else if (add_index >= 0) {
assert(add_index == 0);
const char*sign_flag = add_index==1? "/s" : "";
/* If this is a REG (a variable) then I can do a vector read. */
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
fprintf(vvp_out, " %%ix/load 2, %u;\n", res.wid);
fprintf(vvp_out, " %%load/vp0 %u, v%p_%u, %u;\n",
res.base, sig, word, swid);
if (immediate >= 0) {
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
} else {
fprintf(vvp_out, " %%ix/load 0, 0; immediate=%ld\n", immediate);
fprintf(vvp_out, " %%ix/sub 0, %ld;\n", -immediate);
}
fprintf(vvp_out, " %%load/vp0%s %u, v%p_%u, %u;\n", sign_flag,
res.base, sig,word, res.wid);
swid = res.wid;
} else {
@ -2078,7 +2111,6 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
{
ivl_signal_t sig = ivl_expr_signal(sube);
struct vector_info res;
unsigned idx;
/* Use this word of the signal. */
unsigned use_word = 0;
@ -2093,7 +2125,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
ivl_expr_t ix = ivl_expr_oper1(sube);
if (ivl_signal_type(sig)==IVL_SIT_REG
|| !number_is_immediate(ix, 8*sizeof(unsigned long)))
|| !number_is_immediate(ix, 8*sizeof(unsigned long),0))
return draw_select_array(sube, bit_idx, bit_wid, wid);
/* The index is constant, so we can return to direct
@ -2104,7 +2136,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
/* Try the special case that the part is at the beginning of
the signal (or the entire width). Just load the early bits
in one go. */
if (number_is_immediate(bit_idx, 32)
if (number_is_immediate(bit_idx, 32, 0)
&& get_number_immediate(bit_idx) == 0
&& (ivl_expr_width(sube) >= bit_wid)) {
@ -2122,23 +2154,23 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
return res;
}
draw_eval_expr_into_integer(bit_idx, 0);
/* Alas, do it the hard way. */
draw_eval_expr_into_integer(bit_idx, 1);
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
for (idx = 0 ; idx < res.wid ; idx += 1) {
if (idx >= bit_wid) {
fprintf(vvp_out, " %%movi %u, 0, %u; Pad from %u to %u\n",
res.base+idx, res.wid-idx,
ivl_expr_width(sube), wid);
break;
}
fprintf(vvp_out, " %%load/x.p %u, v%p_%u, 0;\n",
res.base+idx, sig, use_word);
}
unsigned use_wid = res.wid;
if (use_wid > bit_wid)
use_wid = bit_wid;
fprintf(vvp_out, " %%load/x1p %u, v%p_%u, %u;\n",
res.base, sig, use_word, use_wid);
if (use_wid < res.wid)
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
res.base + use_wid, res.wid - use_wid);
return res;
}

View File

@ -328,7 +328,7 @@ static int draw_signal_real_real(ivl_expr_t exp)
if (ivl_signal_array_count(sig) > 1) {
ivl_expr_t ix = ivl_expr_oper1(exp);
if (!number_is_immediate(ix, 8*sizeof(word))) {
if (!number_is_immediate(ix, 8*sizeof(word), 0)) {
/* XXXX Need to generate a %load/ar instruction. */
assert(0);
return res;
@ -441,7 +441,22 @@ static int draw_unary_real(ivl_expr_t exp)
return res;
}
if (ivl_expr_opcode(exp) == '!') {
struct vector_info vi;
vi = draw_eval_expr(exp, STUFF_OK_XZ);
int res = allocate_word();
const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
}
ivl_expr_t sube = ivl_expr_oper1(exp);
int sub = draw_eval_real(sube);
if (ivl_expr_opcode(exp) == '+')
@ -461,8 +476,8 @@ static int draw_unary_real(ivl_expr_t exp)
return sub;
}
fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp));
fprintf(stderr, "XXXX evaluate unary (%c)\n", ivl_expr_opcode(exp));
fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n", ivl_expr_opcode(exp), sub);
fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n", ivl_expr_opcode(exp), sub);
return 0;
}

View File

@ -1,7 +1,7 @@
#ifndef __vvp_priv_H
#define __vvp_priv_H
/*
* Copyright (c) 2001-2005 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
@ -51,6 +51,8 @@ struct vector_info {
extern const char *vvp_mangle_id(const char *);
extern const char *vvp_mangle_name(const char *);
extern char* draw_Cr_to_string(double value);
/*
* This generates a string from a signal that uniquely identifies
* that signal with letters that can be used in a label.
@ -65,6 +67,8 @@ extern const char* vvp_signal_label(ivl_signal_t sig);
extern unsigned width_of_nexus(ivl_nexus_t nex);
extern ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex);
extern int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr);
/*
* This function draws a process (initial or always) into the output
* file. It normally returns 0, but returns !0 of there is some sort
@ -90,7 +94,7 @@ extern void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned s
* draw_modpath arranges for a .modpath record to be written out.
*
* cleanup_modpath() cleans up any pending .modpath records that may
* have been scheduled by draw_modpath() but not yet writte.
* have been scheduled by draw_modpath() but not yet written.
*
* Note: draw_modpath drive_label must be malloc'ed by the
* caller. This function will free the string sometime in the future.
@ -110,6 +114,24 @@ extern struct vector_info draw_vpi_func_call(ivl_expr_t exp,
unsigned wid);
extern int draw_vpi_rfunc_call(ivl_expr_t exp);
/*
* Switches (tran)
*/
extern void draw_switch_in_scope(ivl_switch_t sw);
/* Draw_net_input and friends uses this. */
struct vvp_nexus_data {
/* draw_net_input uses this */
const char*net_input;
unsigned drivers_count;
int flags;
/* draw_net_in_scope uses these to identify the controlling word. */
ivl_signal_t net;
unsigned net_word;
};
#define VVP_NEXUS_DATA_STR 0x0001
/*
* Given a nexus, draw a string that represents the functor output
* that feeds the nexus. This function can be used to get the input to
@ -120,6 +142,17 @@ extern int draw_vpi_rfunc_call(ivl_expr_t exp);
*/
extern const char* draw_net_input(ivl_nexus_t nex);
/*
* See draw_net_input.c for details on draw_net_input_x. (It would be
* nice if this can be made private.)
*/
/* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001
struct vvp_nexus_data;
extern char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data);
/*
* This function is different from draw_net_input in that it will
* return a reference to a net as its first choice. This reference
@ -236,8 +269,8 @@ extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
int exclusive_flag);
extern int number_is_unknown(ivl_expr_t ex);
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid);
extern unsigned long get_number_immediate(ivl_expr_t ex);
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
extern long get_number_immediate(ivl_expr_t ex);
/*
* draw_eval_real evaluates real value expressions. The return code

View File

@ -83,7 +83,7 @@ static void set_to_lvariable(ivl_lval_t lval,
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
} else if (number_is_immediate(part_off_ex, 64, 0)) {
part_off = get_number_immediate(part_off_ex);
part_off_ex = 0;
}
@ -91,7 +91,7 @@ static void set_to_lvariable(ivl_lval_t lval,
/* If the word index is a constant expression, then evaluate
it to select the word, and pay no further heed to the
expression itself. */
if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word))) {
if (word_ix && number_is_immediate(word_ix, 8*sizeof(use_word), 0)) {
use_word = get_number_immediate(word_ix);
word_ix = 0;
}
@ -227,14 +227,14 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
unsigned part_off = 0;
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
} else if (number_is_immediate(part_off_ex, 64, 0)) {
part_off = get_number_immediate(part_off_ex);
part_off_ex = 0;
}
if (dexp == 0) {
/* Constant delay... */
if (number_is_immediate(word_ix, 64)) {
if (number_is_immediate(word_ix, 64, 0)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
get_number_immediate(word_ix));
} else {
@ -259,7 +259,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
/* Calculated delay... */
int delay_index = allocate_word();
draw_eval_expr_into_integer(dexp, delay_index);
if (number_is_immediate(word_ix, 64)) {
if (number_is_immediate(word_ix, 64, 0)) {
fprintf(vvp_out, " %%ix/load 3, %lu; address\n",
get_number_immediate(word_ix));
} else {
@ -306,7 +306,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit,
if (part_off_ex == 0) {
part_off = 0;
} else if (number_is_immediate(part_off_ex, 64)) {
} else if (number_is_immediate(part_off_ex, 64, 0)) {
part_off = get_number_immediate(part_off_ex);
part_off_ex = 0;
}
@ -543,7 +543,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
if (ivl_signal_array_count(sig) > 1) {
word_ix = ivl_lval_idx(lval);
assert(word_ix);
assert(number_is_immediate(word_ix, 8*sizeof(use_word)));
assert(number_is_immediate(word_ix, 8*sizeof(use_word), 0));
use_word = get_number_immediate(word_ix);
}
@ -700,7 +700,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
if ((ivl_statement_type(net) == IVL_ST_CASE)
&& (ivl_expr_type(cex) == IVL_EX_NUMBER)
&& (! number_is_unknown(cex))
&& number_is_immediate(cex, 16)) {
&& number_is_immediate(cex, 16, 0)) {
unsigned long imm = get_number_immediate(cex);
@ -926,12 +926,12 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
if (part_off_ex == 0) {
part_off = 0;
} else {
assert(number_is_immediate(part_off_ex, 64));
assert(number_is_immediate(part_off_ex, 64, 0));
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(unsigned long)));
assert(number_is_immediate(word_idx, 8*sizeof(unsigned long), 0));
use_word = get_number_immediate(word_idx);
}
@ -1004,12 +1004,12 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
/* At least for now, only handle force to fixed words of an array. */
if ((lword_idx = ivl_lval_idx(lval)) != 0) {
assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long)));
assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long), 0));
use_lword = get_number_immediate(lword_idx);
}
if ((rword_idx = ivl_expr_oper1(rval)) != 0) {
assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long)));
assert(number_is_immediate(rword_idx, 8*sizeof(unsigned long), 0));
use_rword = get_number_immediate(rword_idx);
}
@ -1087,12 +1087,12 @@ static int show_stmt_deassign(ivl_statement_t net)
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64));
assert(number_is_immediate(part_off_ex, 64, 0));
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
assert(number_is_immediate(word_idx, 8*sizeof(use_word), 0));
use_word = get_number_immediate(word_idx);
}
@ -1369,7 +1369,7 @@ static int show_stmt_release(ivl_statement_t net)
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
unsigned part_off = 0;
if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64));
assert(number_is_immediate(part_off_ex, 64, 0));
part_off = get_number_immediate(part_off_ex);
}
@ -1383,7 +1383,7 @@ static int show_stmt_release(ivl_statement_t net)
}
if (word_idx != 0) {
assert(number_is_immediate(word_idx, 8*sizeof(use_word)));
assert(number_is_immediate(word_idx, 8*sizeof(use_word), 0));
use_word = get_number_immediate(word_idx);
}

View File

@ -31,23 +31,6 @@
#define snprintf _snprintf
#endif
struct vvp_nexus_data {
/* draw_net_input uses this */
const char*net_input;
unsigned drivers_count;
int flags;
/* draw_net_in_scope uses these to identify the controlling word. */
ivl_signal_t net;
unsigned net_word;
};
#define VVP_NEXUS_DATA_STR 0x0001
static struct vvp_nexus_data*new_nexus_data()
{
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
return data;
}
/*
* Escape non-symbol characters in ids, and quotes in strings.
@ -147,27 +130,6 @@ const char *vvp_mangle_name(const char *id)
return out;
}
static void draw_C4_repeated_constant(char bit_char, unsigned width)
{
unsigned idx;
fprintf(vvp_out, "C4<");
for (idx = 0 ; idx < width ; idx += 1)
fprintf(vvp_out, "%c", bit_char);
fprintf(vvp_out, ">");
}
static void str_repeat(char*buf, const char*str, unsigned rpt)
{
unsigned idx;
size_t len = strlen(str);
for (idx = 0 ; idx < rpt ; idx += 1) {
strcpy(buf, str);
buf += len;
}
}
/* REMOVE ME: vvp_signal_label should not be used. DEAD CODE
* Given a signal, generate a string name that is suitable for use as
* a label. The only rule is that the same signal will always have the
@ -198,31 +160,6 @@ ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word)
return 0;
}
ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
{
unsigned idx;
ivl_signal_type_t out = IVL_SIT_TRI;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_signal_type_t stype;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
stype = ivl_signal_type(sig);
if (stype == IVL_SIT_REG)
continue;
if (stype == IVL_SIT_TRI)
continue;
if (stype == IVL_SIT_NONE)
continue;
out = stype;
}
return out;
}
unsigned width_of_nexus(ivl_nexus_t nex)
{
unsigned idx;
@ -332,7 +269,7 @@ const char*drive_string(ivl_drive_t drive)
* gate will be generated for this node. Otherwise, the code generator
* will connect its input to its output and skip the gate.
*/
static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
{
ivl_nexus_t in_n;
unsigned idx;
@ -380,100 +317,7 @@ static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
return 1;
}
/*
* Given a nexus, look for a signal that has module delay
* paths. Return that signal. (There should be no more than 1.) If we
* don't find any, then return nil.
*/
static ivl_signal_t find_modpath(ivl_nexus_t nex)
{
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
if (sig == 0)
continue;
if (ivl_signal_npath(sig) == 0)
continue;
return sig;
}
return 0;
}
static char* draw_C4_to_string(ivl_net_const_t cptr)
{
const char*bits = ivl_const_bits(cptr);
unsigned idx;
size_t result_len = 5 + ivl_const_width(cptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
char bitchar = bits[ivl_const_width(cptr)-idx-1];
*dp++ = bitchar;
assert((dp - result) < result_len);
}
strcpy(dp, ">");
return result;
}
static char* draw_C8_to_string(ivl_net_const_t cptr,
ivl_drive_t dr0, ivl_drive_t dr1)
{
size_t nresult = 5 + 3*ivl_const_width(cptr);
char*result = malloc(nresult);
const char*bits = ivl_const_bits(cptr);
unsigned idx;
char dr0c = "01234567"[dr0];
char dr1c = "01234567"[dr1];
char*dp = result;
strcpy(dp, "C8<");
dp += strlen(dp);
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
switch (bits[ivl_const_width(cptr)-idx-1]) {
case '0':
*dp++ = dr0c;
*dp++ = dr0c;
*dp++ = '0';
break;
case '1':
*dp++ = dr1c;
*dp++ = dr1c;
*dp++ = '1';
break;
case 'x':
case 'X':
*dp++ = dr0c;
*dp++ = dr1c;
*dp++ = 'x';
break;
case 'z':
case 'Z':
*dp++ = '0';
*dp++ = '0';
*dp++ = 'z';
break;
default:
assert(0);
break;
}
assert(dp - result < nresult);
}
strcpy(dp, ">");
return result;
}
static char* draw_Cr_to_string(double value)
char* draw_Cr_to_string(double value)
{
char tmp[256];
@ -508,488 +352,6 @@ static char* draw_Cr_to_string(double value)
return strdup(tmp);
}
/*
* This function takes a nexus and looks for an input functor. It then
* draws to the output a string that represents that functor. What we
* are trying to do here is find the input to the net that is attached
* to this nexus.
*/
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
{
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
ivl_net_const_t cptr;
ivl_net_logic_t lptr;
ivl_signal_t sptr;
ivl_lpm_t lpm;
lptr = ivl_nexus_ptr_log(nptr);
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
do {
if (! can_elide_bufz(lptr, nptr))
break;
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
} while(0);
/* If this is a pulldown device, then there is a single pin
that drives a constant value to the entire width of the
vector. The driver normally drives a pull0 value, so a C8<>
constant is appropriate, but if the drive is really strong,
then we can draw a C4<> constant instead. */
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
size_t result_len = ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "0", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 3*ivl_logic_width(lptr) + 5;
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '0';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
size_t result_len = 5 + ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
strcpy(dp, "C4<");
dp += strlen(dp);
str_repeat(dp, "1", ivl_logic_width(lptr));
dp += ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
} else {
char val[4];
size_t result_len = 5 + 3*ivl_logic_width(lptr);
char*result = malloc(result_len);
char*dp = result;
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
val[1] = val[0];
val[2] = '1';
val[3] = 0;
strcpy(dp, "C8<");
dp += strlen(dp);
str_repeat(dp, val, ivl_logic_width(lptr));
dp += 3*ivl_logic_width(lptr);
*dp++ = '>';
*dp = 0;
assert((dp-result) <= result_len);
return result;
}
}
if (lptr && (nptr_pin == 0)) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lptr);
return strdup(tmp);
}
sptr = ivl_nexus_ptr_sig(nptr);
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
char tmp[128];
/* Input is a .var. This device may be a non-zero pin
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) {
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
sptr, nptr_pin, sptr, nptr_pin);
}
return strdup(tmp);
}
cptr = ivl_nexus_ptr_con(nptr);
if (cptr) {
/* Constants should have exactly 1 pin, with a literal value. */
assert(nptr_pin == 0);
char *result = 0;
switch (ivl_const_type(cptr)) {
case IVL_VT_LOGIC:
case IVL_VT_BOOL:
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
result = draw_C4_to_string(cptr);
} else {
result = draw_C8_to_string(cptr,
ivl_nexus_ptr_drive0(nptr),
ivl_nexus_ptr_drive1(nptr));
}
break;
case IVL_VT_REAL:
result = draw_Cr_to_string(ivl_const_real(cptr));
break;
default:
assert(0);
break;
}
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
/* We have a delayed constant, so we need to build some code. */
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
cptr, get_number_immediate(d_rise),
get_number_immediate(d_rise),
get_number_immediate(d_rise), cptr);
free(result);
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
}
return result;
}
lpm = ivl_nexus_ptr_lpm(nptr);
if (lpm) switch (ivl_lpm_type(lpm)) {
case IVL_LPM_FF:
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_NE:
case IVL_LPM_CMP_NEE:
case IVL_LPM_RE_AND:
case IVL_LPM_RE_OR:
case IVL_LPM_RE_XOR:
case IVL_LPM_RE_NAND:
case IVL_LPM_RE_NOR:
case IVL_LPM_RE_XNOR:
case IVL_LPM_SFUNC:
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
case IVL_LPM_SIGN_EXT:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
case IVL_LPM_MUX:
case IVL_LPM_POW:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_UFUNC:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
case IVL_LPM_REPEAT:
if (ivl_lpm_q(lpm, 0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", lpm);
return strdup(tmp);
}
break;
case IVL_LPM_PART_BI:
if (ivl_lpm_q(lpm, 0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
return strdup(tmp);
} else if (ivl_lpm_data(lpm,0) == nex) {
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
return strdup(tmp);
}
break;
}
fprintf(stderr, "internal error: no input to nexus %s\n",
ivl_nexus_name(nex));
assert(0);
return strdup("C<z>");
}
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
{
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
return 1;
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
return 1;
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
if (log != 0) {
/* These logic gates are able to generate unusual
strength values and so their outputs are considered
strength aware. */
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
return 1;
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
return 1;
if (ivl_logic_type(log) == IVL_LO_PMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_NMOS)
return 1;
if (ivl_logic_type(log) == IVL_LO_CMOS)
return 1;
}
return 0;
}
/*
* This function draws the input to a net into a string. What that
* means is that it returns a static string that can be used to
* represent a resolved driver to a nexus. If there are multiple
* drivers to the nexus, then it writes out the resolver declarations
* needed to perform strength resolution.
*
* The string that this returns is malloced, and that means that the
* caller must free the string or store it permanently. This function
* does *not* check for a previously calculated string. Use the
* draw_net_input for the general case.
*/
/* Omit LPMPART_BI device pin-data(0) drivers. */
# define OMIT_PART_BI_DATA 0x0001
static char* draw_net_input_x(ivl_nexus_t nex,
ivl_nexus_ptr_t omit_ptr, int omit_flags,
struct vvp_nexus_data*nex_data)
{
ivl_signal_type_t res;
char result[512];
unsigned idx;
int level;
unsigned ndrivers = 0;
static ivl_nexus_ptr_t *drivers = 0x0;
static unsigned adrivers = 0;
const char*resolv_type;
char*nex_private = 0;
/* Accumulate nex_data flags. */
int nex_flags = 0;
res = signal_type_of_nexus(nex);
switch (res) {
case IVL_SIT_TRI:
resolv_type = "tri";
break;
case IVL_SIT_TRI0:
resolv_type = "tri0";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRI1:
resolv_type = "tri1";
nex_flags |= VVP_NEXUS_DATA_STR;
break;
case IVL_SIT_TRIAND:
resolv_type = "triand";
break;
case IVL_SIT_TRIOR:
resolv_type = "trior";
break;
default:
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
assert(0);
resolv_type = "tri";
break;
}
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_lpm_t lpm_tmp;
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
/* If we are supposed to skip LPM_PART_BI data pins,
check that this driver is that. */
if ((omit_flags&OMIT_PART_BI_DATA)
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
&& (nex == ivl_lpm_data(lpm_tmp,0)))
continue;
if (nptr == omit_ptr)
continue;
/* Skip input only pins. */
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
continue;
/* Mark the strength-aware flag if the driver can
generate values other than the standard "6"
strength. */
if (nexus_drive_is_strength_aware(nptr))
nex_flags |= VVP_NEXUS_DATA_STR;
/* Save this driver. */
if (ndrivers >= adrivers) {
adrivers += 4;
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
assert(drivers);
}
drivers[ndrivers] = nptr;
ndrivers += 1;
}
/* If the caller is collecting nexus information, then save
the nexus driver count in the nex_data. */
if (nex_data) {
nex_data->drivers_count = ndrivers;
nex_data->flags |= nex_flags;
}
/* If the nexus has no drivers, then send a constant HiZ into
the net. */
if (ndrivers == 0) {
unsigned idx, wid = width_of_nexus(nex);
char*tmp = malloc(wid + 5);
nex_private = tmp;
strcpy(tmp, "C4<");
tmp += strlen(tmp);
switch (res) {
case IVL_SIT_TRI:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = 'z';
break;
case IVL_SIT_TRI0:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '0';
break;
case IVL_SIT_TRI1:
for (idx = 0 ; idx < wid ; idx += 1)
*tmp++ = '1';
break;
default:
assert(0);
}
*tmp++ = '>';
*tmp = 0;
return nex_private;
}
/* If the nexus has exactly one driver, then simply draw
it. Note that this will *not* work if the nexus is not a
TRI type nexus. */
if (ndrivers == 1 && res == IVL_SIT_TRI) {
ivl_signal_t path_sig = find_modpath(nex);
if (path_sig) {
char*nex_str = draw_net_input_drive(nex, drivers[0]);
char modpath_label[64];
snprintf(modpath_label, sizeof modpath_label,
"V_%p/m", path_sig);
nex_private = strdup(modpath_label);
draw_modpath(path_sig, nex_str);
} else {
nex_private = draw_net_input_drive(nex, drivers[0]);
}
return nex_private;
}
level = 0;
while (ndrivers) {
unsigned int inst;
for (inst = 0; inst < ndrivers; inst += 4) {
if (ndrivers > 4)
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
nex, level, inst);
else
fprintf(vvp_out, "RS_%p .resolv %s",
nex, resolv_type);
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
if (level) {
fprintf(vvp_out, ", RS_%p/%d/%d",
nex, level - 1, idx*4);
} else {
char*drive = draw_net_input_drive(nex, drivers[idx]);
fprintf(vvp_out, ", %s", drive);
free(drive);
}
}
for ( ; idx < inst+4 ; idx += 1) {
fprintf(vvp_out, ", ");
draw_C4_repeated_constant('z',width_of_nexus(nex));
}
fprintf(vvp_out, ";\n");
}
if (ndrivers > 4)
ndrivers = (ndrivers+3) / 4;
else
ndrivers = 0;
level += 1;
}
sprintf(result, "RS_%p", nex);
nex_private = strdup(result);
return nex_private;
}
/*
* Get a cached description of the nexus input, or create one if this
* nexus has not been cached yet. This is a wrapper for the common
* case call to draw_net_input_x.
*/
const char*draw_net_input(ivl_nexus_t nex)
{
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
ivl_nexus_get_private(nex);
/* If this nexus already has a label, then its input is
already figured out. Just return the existing label. */
if (nex_data && nex_data->net_input)
return nex_data->net_input;
if (nex_data == 0) {
nex_data = new_nexus_data();
ivl_nexus_set_private(nex, nex_data);
}
assert(nex_data->net_input == 0);
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
return nex_data->net_input;
}
const char*draw_input_from_net(ivl_nexus_t nex)
{
static char result[32];
@ -1184,9 +546,9 @@ static void draw_delay(ivl_net_logic_t lptr)
return;
/* FIXME: Assume that the expression is a constant */
assert(number_is_immediate(d0, 64));
assert(number_is_immediate(d1, 64));
assert(number_is_immediate(d2, 64));
assert(number_is_immediate(d0, 64, 0));
assert(number_is_immediate(d1, 64, 0));
assert(number_is_immediate(d2, 64, 0));
if (d0 == d1 && d1 == d2)
fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
@ -1500,9 +862,9 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
ivl_expr_t fall_exp = ivl_logic_delay(lptr,1);
ivl_expr_t decay_exp = ivl_logic_delay(lptr,2);
if (number_is_immediate(rise_exp,64)
&& number_is_immediate(fall_exp,64)
&& number_is_immediate(decay_exp,64)) {
if (number_is_immediate(rise_exp,64,0)
&& number_is_immediate(fall_exp,64,0)
&& number_is_immediate(decay_exp,64,0)) {
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
lptr, get_number_immediate(rise_exp),
@ -1693,9 +1055,9 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
const char*dly = "";
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
dly = "/d";
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
net, get_number_immediate(d_rise),
@ -1717,6 +1079,31 @@ static void draw_lpm_abs(ivl_lpm_t net)
net, dly, src_table[0]);
}
static void draw_lpm_cast_int(ivl_lpm_t net)
{
const char*src_table[1];
draw_lpm_data_inputs(net, 0, 1, src_table);
const char*dly = draw_lpm_output_delay(net);
fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n",
net, dly, ivl_lpm_width(net), src_table[0]);
}
static void draw_lpm_cast_real(ivl_lpm_t net)
{
const char*src_table[1];
draw_lpm_data_inputs(net, 0, 1, src_table);
const char*dly = draw_lpm_output_delay(net);
const char*is_signed = "";
if (ivl_lpm_signed(net)) is_signed = ".s";
fprintf(vvp_out, "L_%p%s .cast/real%s %s;\n",
net, dly, is_signed, src_table[0]);
}
static void draw_lpm_add(ivl_lpm_t net)
{
const char*src_table[2];
@ -1767,20 +1154,9 @@ static void draw_lpm_add(ivl_lpm_t net)
case IVL_LPM_POW:
if (dto == IVL_VT_REAL)
type = "pow.r";
else if (ivl_lpm_signed(net)) {
else if (ivl_lpm_signed(net))
type = "pow.s";
if (width > 8*sizeof(long)) {
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
#ifdef __MINGW32__ /* MinGW does not know about z. */
"result must be no more than %u bits.\n",
#else
"result must be no more than %zu bits.\n",
#endif
ivl_lpm_file(net), ivl_lpm_lineno(net),
8*sizeof(long));
exit(1);
}
} else
else
type = "pow";
break;
default:
@ -2249,94 +1625,6 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
}
/*
* Handle the drawing of a bi-directional part select. The two ports
* are simultaneously input and output. A simple minded connect of the
* input to the output causes a functor cycle which will lock into an
* X value, so something special is needed.
*
* NOTE: The inputs of the tran device at this point need to be from
* all the drivers of the nexus *except* the tran itself. This
* function will draw three labels that can be linked:
*
* The ivl_lpm_q of a part(bi) may be a smaller vector then the
* ivl_lpm_data, the tran acts like a forward part select in that
* way.
*
* The device creates these nodes:
*
* - L_%p/i
* This is the Q port of the tran resolved and padded to the maximum
* width of the tran. The tran itself is not included in the
* resolution of this port.
*
* - L_%p/V
* This is the Q and D parts resolved together, still without the tran
* driving anything.
*
* - L_%p/P
* This is the /V node part-selected back to the dimensions of the Q
* side.
*/
static void draw_lpm_part_bi(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned base = ivl_lpm_base(net);
unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
unsigned idx;
ivl_nexus_t nex;
ivl_nexus_ptr_t ptr = 0;
char*p_str;
char*v_str;
/* It seems implausible that the two inputs of a tran will be
connected together. So assert that this is so to simplify
the code to look for the nexus_ptr_t objects. */
assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
nex = ivl_lpm_q(net,0);
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ptr = ivl_nexus_ptr(nex, idx);
if (ivl_nexus_ptr_lpm(ptr) == net)
break;
}
assert(ptr != 0);
p_str = draw_net_input_x(nex, ptr, 0, 0);
nex = ivl_lpm_data(net,0);
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ptr = ivl_nexus_ptr(nex, idx);
if (ivl_nexus_ptr_lpm(ptr) == net)
break;
}
v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
/* Pad the part-sized input out to a common width...
The /i label is the Q side of the tran, resolved except for
the tran itself and padded (with z) to the larger width. */
fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
net, p_str, base, width, signal_width);
/* Resolve together the two halves of the tran...
The /V label is the ports of the tran (now the same width)
resolved together. Neither input to this resolver includes
the tran itself. */
fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
net, net, v_str);
/* The full-width side is created by the tran device, all we
have left to to is take a part select of that for the
smaller output, and this becomes the part select output of
the BI device. */
fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
net, base, width);
free(p_str);
free(v_str);
}
/*
* Draw unary reduction devices.
*/
@ -2370,6 +1658,14 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_abs(net);
return;
case IVL_LPM_CAST_INT:
draw_lpm_cast_int(net);
return;
case IVL_LPM_CAST_REAL:
draw_lpm_cast_real(net);
return;
case IVL_LPM_ADD:
case IVL_LPM_SUB:
case IVL_LPM_MULT:
@ -2383,10 +1679,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_array(net);
return;
case IVL_LPM_PART_BI:
draw_lpm_part_bi(net);
return;
case IVL_LPM_PART_VP:
draw_lpm_part(net);
return;
@ -2569,6 +1861,11 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
draw_lpm_in_scope(lpm);
}
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) {
ivl_switch_t sw = ivl_scope_switch(net, idx);
draw_switch_in_scope(sw);
}
if (ivl_scope_type(net) == IVL_SCT_TASK)
draw_task_definition(net);

View File

@ -205,7 +205,7 @@ verinum::verinum(int64_t that)
bits_ = new V[nbits_];
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
bits_[idx] = (that & 1)? V1 : V0;
that /= 2;
that >>= 1;
}
}
@ -508,7 +508,7 @@ verinum trim_vnum(const verinum&that)
/* Now top is the index of the highest non-zero bit. If
that turns out to the highest bit in the vector, then
tere is no trimming possible. */
there is no trimming possible. */
if (top+1 == that.len())
return that;

View File

@ -59,7 +59,8 @@ O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \
sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
mt19937int.o priv.o sdf_lexor.o sdf_parse.o stringheap.o
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
vams_simparam.o
ifeq (@HAVE_LIBZ@,yes)
ifeq (@HAVE_LIBBZ2@,yes)

View File

@ -139,7 +139,7 @@ static int lookup_keyword(const char*text)
}
/*
* Create a string witout the leading and trailing quotes.
* Create a string without the leading and trailing quotes.
*/
static void process_quoted_string(void)
{

View File

@ -60,16 +60,6 @@ struct strobe_cb_info {
unsigned mcd;
};
int is_constant(vpiHandle obj)
{
if (vpi_get(vpiType, obj) == vpiConstant)
return vpiConstant;
if (vpi_get(vpiType, obj) == vpiParameter)
return vpiParameter;
return 0;
}
// The number of decimal digits needed to represent a
// nr_bits binary number is floor(nr_bits*log_10(2))+1,
// where log_10(2) = 0.30102999566398.... and I approximate
@ -277,7 +267,7 @@ static void format_time(unsigned mcd, int fsize,
/* Fill the leading characters to make up the desired
width. This may require a '0' if the last character
written was the decimal point. This may also require a '0'
if there are no other characters at all in the ouput. */
if there are no other characters at all in the output. */
if (fusize > 0) {
while (bp > start_address) {
if (*bp == '.' || strcmp(bp, timeformat_info.suff) == 0)
@ -665,7 +655,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd,
return 0;
}
if (is_constant(argv[idx])
if (is_constant_obj(argv[idx])
&& (vpi_get(vpiConstType, argv[idx]) == vpiRealConst)) {
value.format = vpiRealVal;
@ -827,6 +817,7 @@ static void do_display(unsigned int mcd, struct strobe_cb_info*info)
case vpiReg:
case vpiIntegerVar:
case vpiMemoryWord:
case vpiPartSelect:
do_display_numeric(mcd, info, item);
break;
@ -1118,11 +1109,17 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
switch (vpi_get(vpiType, monitor_info.items[idx])) {
case vpiMemoryWord:
/*
* We only support constant selections. Make this
* better when we add a real compiletf routine.
*/
assert(vpi_get(vpiConstantSelect, monitor_info.items[idx]));
case vpiNet:
case vpiReg:
case vpiIntegerVar:
case vpiRealVar:
case vpiMemoryWord:
case vpiPartSelect:
/* Monitoring reg and net values involves setting
a callback for value changes. Pass the storage
pointer for the callback itself as user_data so
@ -1418,7 +1415,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
fmtb);
} else {
/* If a width was not giveni, use a width of zero. */
/* If a width was not given, use a width of zero. */
if (width == -1) width = 0;
if (ljust == 0) sprintf(result, "%*c", width,
value.value.str[strlen(value.value.str)-1]);
@ -1662,7 +1659,7 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
/* If a width was not given use a width of zero. */
if (width == -1) width = 0;
nbits = vpi_get(vpiSize, info->items[*idx]);
/* This is 4 chars for all but the last bit (strenght + "_")
/* This is 4 chars for all but the last bit (strength + "_")
* which only needs three chars (strength), but then you need
* space for the EOS '\0', so it is just number of bits * 4. */
rsize = nbits*4;
@ -1836,6 +1833,7 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info)
case vpiReg:
case vpiIntegerVar:
case vpiMemoryWord:
case vpiPartSelect:
width = get_numeric(&result, info, item);
rtn = realloc(rtn, (size+width)*sizeof(char));
memcpy(rtn+size-1, result, width);
@ -2185,12 +2183,7 @@ static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx)
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle scope;
if (!argv) {
vpiHandle parent = vpi_handle(vpiScope, sys);
scope = NULL; /* fallback value if parent is NULL */
while (parent) {
scope = parent;
parent = vpi_handle(vpiScope, scope);
}
scope = sys_func_module(sys);
} else {
scope = vpi_scan(argv);
vpi_free_object(argv);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-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,44 +16,11 @@
* 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: sys_finish.c,v 1.11 2007/04/09 22:49:33 steve Exp $"
#endif
# include "vpi_config.h"
# include "vpi_user.h"
# include <string.h>
static PLI_INT32 sys_finish_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* The argument is optional. */
if (argv == 0) return 0;
arg = vpi_scan(argv);
/* A string diagnostic message level makes no sense. */
if (vpi_get(vpiType, arg) == vpiConstant &&
vpi_get(vpiConstType, arg) == vpiStringConst) {
vpi_printf("Error: %s does not take a string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* These functions take at most one argument (diagnostic message). */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("Error: %s takes at most one argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* vpi_scan returning 0 (NULL) has already freed argv. */
return 0;
}
#include "vpi_config.h"
#include "vpi_user.h"
#include "sys_priv.h"
#include <string.h>
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
{
@ -88,55 +55,16 @@ void sys_finish_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$finish";
tf_data.calltf = sys_finish_calltf;
tf_data.compiletf = sys_finish_compiletf;
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = (PLI_BYTE8*)"$finish";
tf_data.user_data = "$finish";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$stop";
tf_data.calltf = sys_finish_calltf;
tf_data.compiletf = sys_finish_compiletf;
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = (PLI_BYTE8*)"$stop";
tf_data.user_data = "$stop";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_finish.c,v $
* Revision 1.11 2007/04/09 22:49:33 steve
* More strict use of PLI_BYTE8 type.
*
* Revision 1.10 2006/10/30 22:45:37 steve
* Updates for Cygwin portability (pr1585922)
*
* Revision 1.9 2004/01/21 01:22:53 steve
* Give the vip directory its own configure and vpi_config.h
*
* Revision 1.8 2003/02/21 03:24:03 steve
* Make the $stop system task really vpiStop.
*
* Revision 1.7 2002/08/12 01:35:04 steve
* conditional ident string using autoconfig.
*
* Revision 1.6 2001/07/25 03:10:50 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.5 2001/01/01 19:33:44 steve
* Add $stop that does a finish.
*
* Revision 1.4 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/08/28 02:10:44 steve
* Call the right vpiFinish code.
*
* Revision 1.2 1999/08/19 02:51:03 steve
* Add vpi_sim_control
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/

View File

@ -16,110 +16,17 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "vpi_config.h"
#include <assert.h>
#include <vpi_user.h>
#include "sys_priv.h"
/*
* Routine to return the width in bits of a CPU word (long).
*/
static PLI_INT32 vvp_cpu_wordsize_calltf(PLI_BYTE8* ud)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
assert(callh != 0);
s_vpi_value val;
(void) ud; /* Not used! */
/* Calculate the result */
val.format = vpiIntVal;
val.value.integer = 8*sizeof(long);
/* Return the result */
vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0;
}
static PLI_INT32 size_32(PLI_BYTE8* ud)
{
(void) ud; /* Not used! */
return 32;
}
/*
* Routine to finish the simulation and return a value to the
* calling environment.
*/
static PLI_INT32 finish_and_return_compiletf(PLI_BYTE8* ud)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
(void) ud; /* Not used! */
/* We must have at least one argument. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$finish_and_return requires an argument.\n");
vpi_control(vpiFinish, 1);
return 0;
}
/* This must be a numeric argument. */
arg = vpi_scan(argv);
switch(vpi_get(vpiType, arg)) {
case vpiConstant:
case vpiParameter:
/* String constants are invalid numeric values. */
if (vpi_get(vpiConstType, arg) == vpiStringConst) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("The argument to $finish_and_return must be numeric.\n");
vpi_control(vpiFinish, 1);
return 0;
}
break;
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
break;
default:
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("The argument to $finish_and_return must be numeric.\n");
vpi_control(vpiFinish, 1);
return 0;
break;
}
/* We can only have one argument. */
if (vpi_scan(argv) != 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$finish_and_return takes a single argument.\n");
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* ud)
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
(void) ud; /* Not used! */
(void) name; /* Not used! */
/* Get the return value. */
arg = vpi_scan(argv);
@ -142,20 +49,11 @@ void sys_special_register(void)
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.calltf = vvp_cpu_wordsize_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = size_32;
tf_data.tfname = "$vvp_cpu_wordsize";
tf_data.user_data = 0;
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.calltf = finish_and_return_calltf;
tf_data.compiletf = finish_and_return_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.tfname = "$finish_and_return";
tf_data.user_data = 0;
tf_data.user_data = "$finish_and_return";
vpi_register_systf(&tf_data);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-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,9 +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: sys_lxt.c,v 1.28 2007/03/14 04:05:51 steve Exp $"
#endif
# include "sys_priv.h"
# include "lxt_write.h"
@ -324,9 +321,9 @@ inline static int install_dumpvars_callback(void)
return 0;
if (dumpvars_status == 2) {
vpi_mcd_printf(1, "LXT warning:" " $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
vpi_printf("LXT warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
return 1;
}
@ -431,22 +428,23 @@ static void *close_dumpfile(void)
return (dump_file = NULL);
}
static void open_dumpfile(void)
static void open_dumpfile(vpiHandle callh)
{
if (dump_path == 0) dump_path = strdup("dump.lxt");
dump_file = lt_init(dump_path);
if (dump_file == 0) {
vpi_mcd_printf(1, "LXT Error: Unable to open %s for output.\n",
dump_path);
vpi_printf("LXT Error: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open %s for output.\n", dump_path);
vpi_control(vpiFinish, 1);
return;
} else {
int prec = vpi_get(vpiTimePrecision, 0);
vpi_mcd_printf(1, "LXT info: dumpfile %s opened for output.\n",
dump_path);
vpi_printf("LXT info: dumpfile %s opened for output.\n",
dump_path);
assert(prec >= -15);
lt_set_timescale(dump_file, prec);
@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
/* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) {
vpi_mcd_printf(1, "LXT warning: %s called after $dumpvars started"
",\n using existing file (%s).\n",
name, dump_path);
vpi_printf("LXT warning: %s called after $dumpvars started,\n"
" using existing file (%s).\n",
name, dump_path);
return 0;
}
@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
path = strdup(value.value.str);
if (dump_path) {
vpi_mcd_printf(1, "LXT warning: Overriding dump file %s with"
" %s\n", dump_path, path);
vpi_printf("LXT warning: Overriding dump file %s with %s\n",
dump_path, path);
free(dump_path);
}
dump_path = path;
@ -542,16 +540,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) {
case vpiMemory:
/* don't know how to watch memories. */
break;
case vpiNamedEvent:
/* There is nothing in named events to dump. */
break;
case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord:
case vpiTimeVar:
case vpiReg: type = "reg"; }
@ -644,18 +635,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
vpi_get_str(vpiFullName, item);
#if 0
vpi_mcd_printf(1,
"LXT info:"
" scanning scope %s, %u levels\n",
fullname, depth);
vpi_printf("LXT info: scanning scope %s, %u levels\n",
fullname, depth);
#endif
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
if (!nskip)
vcd_names_add(&lxt_tab, fullname);
else
vpi_mcd_printf(1, "LXT warning: ignoring signals in"
" previously scanned scope %s\n", fullname);
vpi_printf("LXT warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item);
@ -674,8 +663,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
break;
default:
vpi_mcd_printf(1, "LXT warning: $dumpvars: Unsupported parameter"
" type (%d)\n", vpi_get(vpiType, item));
vpi_printf("LXT warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
}
}
@ -684,7 +673,6 @@ static int draw_scope(vpiHandle item)
{
int depth;
const char *name;
// char *type; // Not needed, see below.
vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope)
@ -693,20 +681,6 @@ static int draw_scope(vpiHandle item)
depth = 1 + draw_scope(scope);
name = vpi_get_str(vpiName, scope);
#if 0 /* The type information is not needed by the LXT dumper. */
switch (vpi_get(vpiType, scope)) {
case vpiNamedBegin: type = "begin"; break;
case vpiTask: type = "task"; break;
case vpiFunction: type = "function"; break;
case vpiNamedFork: type = "fork"; break;
case vpiModule: type = "module"; break;
default:
vpi_mcd_printf(1, "LXT Error: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get(vpiType, item));
assert(0);
}
#endif
push_scope(name);
return depth;
@ -721,7 +695,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
unsigned depth = 0;
if (dump_file == 0) {
open_dumpfile();
open_dumpfile(callh);
if (dump_file == 0) return 0;
}
@ -784,7 +758,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
@ -792,7 +766,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.compiletf = sys_one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
@ -800,7 +774,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dumpflush_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
@ -808,7 +782,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dumplimit_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
@ -816,7 +790,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dumpoff_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
@ -824,7 +798,7 @@ void sys_lxt_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dumpon_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@ -837,4 +811,3 @@ void sys_lxt_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2004 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-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,9 +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: sys_lxt2.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
#endif
# include "sys_priv.h"
# include "lxt2_write.h"
@ -322,9 +319,9 @@ inline static int install_dumpvars_callback(void)
if (dumpvars_status == 1) return 0;
if (dumpvars_status == 2) {
vpi_mcd_printf(1, "LXT2 warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
vpi_printf("LXT2 warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
return 1;
}
@ -429,22 +426,23 @@ static void *close_dumpfile(void)
return 0;
}
static void open_dumpfile(void)
static void open_dumpfile(vpiHandle callh)
{
if (dump_path == 0) dump_path = strdup("dump.lx2");
dump_file = lxt2_wr_init(dump_path);
if (dump_file == 0) {
vpi_mcd_printf(1, "LXT2 Error: Unable to open %s for output.\n",
dump_path);
vpi_printf("LXT2 Error: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open %s for output.\n", dump_path);
vpi_control(vpiFinish, 1);
return;
} else {
int prec = vpi_get(vpiTimePrecision, 0);
vpi_mcd_printf(1, "LXT2 info: dumpfile %s opened for output.\n",
dump_path);
vpi_printf("LXT2 info: dumpfile %s opened for output.\n",
dump_path);
assert(prec >= -15);
lxt2_wr_set_timescale(dump_file, prec);
@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
/* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) {
vpi_mcd_printf(1, "LXT2 warning: %s called after $dumpvars started"
",\n using existing file (%s).\n",
name, dump_path);
vpi_printf("LXT2 warning: %s called after $dumpvars started,\n"
" using existing file (%s).\n",
name, dump_path);
return 0;
}
@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
path = strdup(value.value.str);
if (dump_path) {
vpi_mcd_printf(1, "LXT2 warning: Overriding dump file %s with"
" %s.\n", dump_path, path);
vpi_printf("LXT2 warning: Overriding dump file %s with %s.\n",
dump_path, path);
free(dump_path);
}
dump_path = path;
@ -548,16 +546,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) {
case vpiMemory:
/* don't know how to watch memories. */
break;
case vpiNamedEvent:
/* There is nothing in named events to dump. */
break;
case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord:
case vpiTimeVar:
case vpiReg: type = "reg"; }
@ -657,18 +648,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
vpi_get_str(vpiFullName, item);
#if 0
vpi_mcd_printf(1,
"LXT2 info:"
" scanning scope %s, %u levels\n",
fullname, depth);
vpi_printf("LXT2 info: scanning scope %s, %u levels\n",
fullname, depth);
#endif
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
if (!nskip)
vcd_names_add(&lxt_tab, fullname);
else
vpi_mcd_printf(1, "LXT2 warning: ignoring signals in"
" previously scanned scope %s\n", fullname);
vpi_printf("LXT2 warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item);
@ -687,8 +676,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
break;
default:
vpi_mcd_printf(1, "LXT2 warning: $dumpvars: Unsupported parameter"
" type (%d)\n", vpi_get(vpiType, item));
vpi_printf("LXT2 warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
}
}
@ -697,7 +686,6 @@ static int draw_scope(vpiHandle item)
{
int depth;
const char *name;
// char *type; // Not needed, see below.
vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope) return 0;
@ -705,20 +693,6 @@ static int draw_scope(vpiHandle item)
depth = 1 + draw_scope(scope);
name = vpi_get_str(vpiName, scope);
#if 0 /* The type information is not needed by the LXT2 dumper. */
switch (vpi_get(vpiType, item)) {
case vpiNamedBegin: type = "begin"; break;
case vpiTask: type = "task"; break;
case vpiFunction: type = "function"; break;
case vpiNamedFork: type = "fork"; break;
case vpiModule: type = "module"; break;
default:
vpi_mcd_printf(1, "LXT2 Error: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get(vpiType, item));
assert(0);
}
#endif
push_scope(name);
return depth;
@ -733,7 +707,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
unsigned depth = 0;
if (dump_file == 0) {
open_dumpfile();
open_dumpfile(callh);
if (dump_file == 0) return 0;
}
@ -799,7 +773,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
@ -807,7 +781,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.compiletf = sys_one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
@ -815,7 +789,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dumpflush_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
@ -823,7 +797,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dumplimit_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
@ -831,7 +805,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dumpoff_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
@ -839,7 +813,7 @@ void sys_lxt2_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dumpon_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@ -852,4 +826,3 @@ void sys_lxt2_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}

336
vpi/sys_priv.c Normal file
View File

@ -0,0 +1,336 @@
/*
* Copyright (c) 2003-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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <assert.h>
#include <string.h>
#include "sys_priv.h"
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
{
PLI_UINT64 tmp;
tmp = time->high;
tmp <<= 32;
tmp |= (PLI_UINT64) time->low;
return tmp;
}
/*
* This routine returns 1 if the argument is a constant value,
* otherwise it returns 0.
*/
unsigned is_constant_obj(vpiHandle obj)
{
assert(obj);
unsigned rtn = 0;
switch(vpi_get(vpiType, obj)) {
case vpiConstant:
case vpiParameter:
rtn = 1;
break;
}
return rtn;
}
/*
* This routine returns 1 if the argument supports has a numeric value,
* otherwise it returns 0.
*/
unsigned is_numeric_obj(vpiHandle obj)
{
assert(obj);
unsigned rtn = 0;
switch(vpi_get(vpiType, obj)) {
case vpiConstant:
case vpiParameter:
/* These cannot be a string constant. */
if (vpi_get(vpiConstType, obj) != vpiStringConst) rtn = 1;
break;
/* These can have a valid numeric value. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiPartSelect:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
rtn = 1;;
break;
}
return rtn;
}
/*
* This routine returns 1 if the argument supports a valid string value,
* otherwise it returns 0.
*/
unsigned is_string_obj(vpiHandle obj)
{
assert(obj);
unsigned rtn = 0;
switch(vpi_get(vpiType, obj)) {
case vpiConstant:
case vpiParameter: {
/* These must be a string or binary constant. */
PLI_INT32 ctype = vpi_get(vpiConstType, obj);
if (ctype == vpiStringConst || ctype == vpiBinaryConst) rtn = 1;
break;
}
/* These can have a valid string value. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiPartSelect:
case vpiReg:
case vpiTimeVar:
rtn = 1;;
break;
}
return rtn;
}
/*
* Find the enclosing module.
*/
vpiHandle sys_func_module(vpiHandle obj)
{
assert(obj);
while (vpi_get(vpiType, obj) != vpiModule) {
obj = vpi_handle(vpiScope, obj);
assert(obj);
}
return obj;
}
/*
* Standard compiletf routines.
*/
/* For system tasks/functions that do not take an argument. */
PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Make sure there are no arguments. */
if (argv != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 0;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s does not take an argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
/* For system tasks/functions that take a single numeric argument. */
PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Check that there is an argument and that it is numeric. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a single numeric argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
/* For system tasks/functions that take a single optional numeric argument. */
PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* The argument is optional so just return if none are found. */
if (argv == 0) return 0;
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes at most one numeric argument.\n",
msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
/* For system tasks/functions that take two numeric arguments. */
PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* Check that there are two argument and that they are numeric. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires two numeric arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's first argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if (! arg) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a second (numeric) argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes two numeric arguments.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
/* For system tasks/functions that take a single string argument. */
PLI_INT32 sys_one_string_arg_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Check that there is an argument and that it is a string. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a single string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_string_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be a string.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes a single string argument.\n", msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}

View File

@ -1,7 +1,7 @@
#ifndef __vpi_sys_priv_H
#define __vpi_sys_priv_H
/*
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-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,12 +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: sys_priv.h,v 1.8 2007/03/14 04:05:51 steve Exp $"
#endif
# include "vpi_config.h"
# include "vpi_user.h"
#include "vpi_config.h"
#include "vpi_user.h"
/*
* Context structure for PRNG in mt19937int.c
@ -36,9 +33,6 @@ struct context_s {
extern void sgenrand(struct context_s *context, unsigned long seed);
extern unsigned long genrand(struct context_s *context);
extern int is_constant(vpiHandle obj);
extern PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time);
struct timeformat_info_s {
@ -50,4 +44,19 @@ struct timeformat_info_s {
extern struct timeformat_info_s timeformat_info;
extern unsigned is_constant_obj(vpiHandle obj);
extern unsigned is_numeric_obj(vpiHandle obj);
extern unsigned is_string_obj(vpiHandle obj);
extern vpiHandle sys_func_module(vpiHandle obj);
/*
* The standard compiletf routines.
*/
extern PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_one_string_arg_compiletf(PLI_BYTE8 *name);
#endif

View File

@ -397,7 +397,7 @@ static PLI_INT32 sys_rand_two_args_compiletf(PLI_BYTE8 *name)
break;
default:
vpi_printf("ERROR: %s's seed must be an integer/time"
" varible or a register.\n", name);
" variable or a register.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
@ -449,7 +449,7 @@ static PLI_INT32 sys_rand_three_args_compiletf(PLI_BYTE8 *name)
break;
default:
vpi_printf("ERROR: %s's seed must be an integer/time"
" varible or a register.\n", name);
" variable or a register.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
@ -484,7 +484,7 @@ static PLI_INT32 sys_random_compiletf(PLI_BYTE8 *name)
break;
default:
vpi_printf("ERROR: %s's seed must be an integer/time"
" varible or a register.\n", name);
" variable or a register.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}

View File

@ -445,7 +445,7 @@ static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name)
/* Open the data file. */
file = fopen(path, "w");
if (file == 0) {
vpi_printf("%s: Unable to open %s for writeing.\n", name, path);
vpi_printf("%s: Unable to open %s for writing.\n", name, path);
free(path);
return 0;
}

View File

@ -250,7 +250,7 @@ static int scan_format(vpiHandle sys, struct byte_source*src, vpiHandle argv)
if (isspace(*fmtp)) {
/* White space matches a string of white space in
the input. The number of spaces is not
relevent, and the match may be 0 or more
relevant, and the match may be 0 or more
spaces. */
while (*fmtp && isspace(*fmtp))
fmtp += 1;

View File

@ -38,6 +38,7 @@ extern void sys_time_register();
extern void sys_vcd_register();
extern void sys_vcdoff_register();
extern void sys_special_register();
extern void vams_simparam_register();
#ifdef HAVE_LIBZ
#ifdef HAVE_LIBBZ2
@ -180,5 +181,6 @@ void (*vlog_startup_routines[])() = {
sys_lxt_or_vcd_register,
sys_sdf_register,
sys_special_register,
vams_simparam_register,
0
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-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,36 +16,14 @@
* 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: sys_time.c,v 1.12 2007/03/14 04:05:51 steve Exp $"
#endif
# include "vpi_config.h"
#include "vpi_config.h"
# include "vpi_user.h"
# include <string.h>
# include <math.h>
# include <assert.h>
static vpiHandle module_of_function(vpiHandle obj)
{
while (vpi_get(vpiType, obj) != vpiModule) {
obj = vpi_handle(vpiScope, obj);
assert(obj);
}
return obj;
}
static PLI_INT32 sys_time_sizetf(PLI_BYTE8*x)
{
return 64;
}
static PLI_INT32 sys_stime_sizetf(PLI_BYTE8*x)
{
return 32;
}
#include "vpi_user.h"
#include <string.h>
#include <math.h>
#include <assert.h>
#include <sys_priv.h>
static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
{
@ -60,7 +38,7 @@ static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
call_handle = vpi_handle(vpiSysTfCall, 0);
assert(call_handle);
mod = module_of_function(call_handle);
mod = sys_func_module(call_handle);
now.type = vpiSimTime;
vpi_get_time(0, &now);
@ -113,7 +91,7 @@ static PLI_INT32 sys_realtime_calltf(PLI_BYTE8*name)
call_handle = vpi_handle(vpiSysTfCall, 0);
assert(call_handle);
mod = module_of_function(call_handle);
mod = sys_func_module(call_handle);
now.type = vpiSimTime;
vpi_get_time(0, &now);
@ -134,82 +112,39 @@ void sys_time_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.tfname = "$time";
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_time_sizetf;
tf_data.user_data = "$time";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$time";
tf_data.sysfunctype = vpiTimeFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$time";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$realtime";
tf_data.calltf = sys_realtime_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$realtime";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$realtime";
tf_data.sysfunctype = vpiRealFunc;
tf_data.calltf = sys_realtime_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$realtime";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$stime";
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_stime_sizetf;
tf_data.user_data = "$stime";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$stime";
tf_data.sysfunctype = vpiIntFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$stime";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.tfname = "$simtime";
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_time_sizetf;
tf_data.user_data = "$simtime";
tf_data.type = vpiSysFunc;
tf_data.tfname = "$simtime";
tf_data.sysfunctype = vpiTimeFunc;
tf_data.calltf = sys_time_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$simtime";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_time.c,v $
* Revision 1.12 2007/03/14 04:05:51 steve
* VPI tasks take PLI_BYTE* by the standard.
*
* Revision 1.11 2006/10/30 22:45:37 steve
* Updates for Cygwin portability (pr1585922)
*
* Revision 1.10 2004/01/21 01:22:53 steve
* Give the vip directory its own configure and vpi_config.h
*
* Revision 1.9 2003/06/18 00:54:28 steve
* Account for all 64 bits in results of $time.
*
* Revision 1.8 2003/02/07 02:44:25 steve
* Properly round inter time values from $time.
*
* Revision 1.7 2003/01/28 04:41:55 steve
* Use more precise pow function to scale time by units.
*
* Revision 1.6 2003/01/27 00:14:37 steve
* Support in various contexts the $realtime
* system task.
*
* Revision 1.5 2002/12/21 00:55:58 steve
* The $time system task returns the integer time
* scaled to the local units. Change the internal
* implementation of vpiSystemTime the $time functions
* to properly account for this. Also add $simtime
* to get the simulation time.
*
* Revision 1.4 2002/08/12 01:35:05 steve
* conditional ident string using autoconfig.
*
* Revision 1.3 2002/01/11 05:20:59 steve
* Add the stime system function.
*
* Revision 1.2 2001/07/25 03:10:50 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.1 2000/11/01 03:19:36 steve
* Add the general $time system function.
*
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-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,9 +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: sys_vcd.c,v 1.58 2007/03/14 04:05:51 steve Exp $"
#endif
# include "sys_priv.h"
@ -269,9 +266,9 @@ inline static int install_dumpvars_callback(void)
if (dumpvars_status == 1) return 0;
if (dumpvars_status == 2) {
vpi_mcd_printf(1, "VCD warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
vpi_printf("VCD warning: $dumpvars ignored, previously"
" called at simtime %" PLI_UINT64_FMT "\n",
dumpvars_time);
return 1;
}
@ -374,15 +371,16 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
return 0;
}
static void open_dumpfile(void)
static void open_dumpfile(vpiHandle callh)
{
if (dump_path == 0) dump_path = strdup("dump.vcd");
dump_file = fopen(dump_path, "w");
if (dump_file == 0) {
vpi_mcd_printf(1, "VCD Error: Unable to open %s for output.\n",
dump_path);
vpi_printf("VCD Error: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open %s for output.\n", dump_path);
vpi_control(vpiFinish, 1);
return;
} else {
@ -391,8 +389,7 @@ static void open_dumpfile(void)
unsigned udx = 0;
time_t walltime;
vpi_mcd_printf(1, "VCD info: dumpfile %s opened for output.\n",
dump_path);
vpi_printf("VCD info: dumpfile %s opened for output.\n", dump_path);
time(&walltime);
@ -428,9 +425,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
/* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) {
vpi_mcd_printf(1, "VCD warning: %s called after $dumpvars started"
",\n using existing file (%s).\n",
name, dump_path);
vpi_printf("VCD warning: %s called after $dumpvars started,\n"
" using existing file (%s).\n",
name, dump_path);
return 0;
}
@ -440,8 +437,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
path = strdup(value.value.str);
if (dump_path) {
vpi_mcd_printf(1, "VCD warning: Overriding dump file %s with"
" %s\n", dump_path, path);
vpi_printf("VCD warning: Overriding dump file %s with %s\n",
dump_path, path);
free(dump_path);
}
dump_path = path;
@ -502,16 +499,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
switch (vpi_get(vpiType, item)) {
case vpiMemory:
/* don't know how to watch memories. */
break;
case vpiNamedEvent:
/* There is nothing in named events to dump. */
break;
case vpiNet: type = "wire"; if(0){
case vpiIntegerVar:
case vpiMemoryWord:
case vpiTimeVar:
case vpiReg: type = "reg"; }
@ -635,18 +625,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
vpi_get_str(vpiFullName, item);
#if 0
vpi_mcd_printf(1,
"VCD info:"
" scanning scope %s, %u levels\n",
fullname, depth);
vpi_printf("VCD info: scanning scope %s, %u levels\n",
fullname, depth);
#endif
nskip = 0 != vcd_names_search(&vcd_tab, fullname);
if (!nskip)
vcd_names_add(&vcd_tab, fullname);
else
vpi_mcd_printf(1, "VCD warning: ignoring signals in"
" previously scanned scope %s\n", fullname);
vpi_printf("VCD warning: ignoring signals in "
"previously scanned scope %s\n", fullname);
name = vpi_get_str(vpiName, item);
@ -665,12 +653,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
break;
default:
vpi_mcd_printf(1, "VCD warning: $dumpvars: Unsupported parameter "
"type (%d)\n", vpi_get(vpiType, item));
vpi_printf("VCD warning: $dumpvars: Unsupported parameter "
"type (%s)\n", vpi_get_str(vpiType, item));
}
}
static int draw_scope(vpiHandle item)
static int draw_scope(vpiHandle item, vpiHandle callh)
{
int depth;
const char *name;
@ -679,7 +667,7 @@ static int draw_scope(vpiHandle item)
vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope) return 0;
depth = 1 + draw_scope(scope);
depth = 1 + draw_scope(scope, callh);
name = vpi_get_str(vpiName, scope);
switch (vpi_get(vpiType, scope)) {
@ -689,8 +677,9 @@ static int draw_scope(vpiHandle item)
case vpiNamedFork: type = "fork"; break;
case vpiModule: type = "module"; break;
default:
vpi_mcd_printf(1, "VCD Error: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get(vpiType, item));
vpi_printf("VCD Error: %s line %d: $dumpvars: Unsupported scope "
"type (%d)\n", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh), vpi_get(vpiType, item));
assert(0);
}
@ -708,7 +697,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
unsigned depth = 0;
if (dump_file == 0) {
open_dumpfile();
open_dumpfile(callh);
if (dump_file == 0) return 0;
}
@ -739,23 +728,23 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
* been included. */
switch (vpi_get(vpiType, item)) {
case vpiIntegerVar:
/* What about MemoryWord? */
case vpiMemoryWord:
case vpiNet:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
scname = vpi_get_str(vpiFullName, vpi_handle(vpiScope, item));
if (vcd_names_search(&vcd_tab, scname)) {
vpi_mcd_printf(1, "VCD warning: skipping signal %s, "
"it was previously included.\n",
vpi_get_str(vpiFullName, item));
vpi_printf("VCD warning: skipping signal %s, "
"it was previously included.\n",
vpi_get_str(vpiFullName, item));
continue;
} else {
add_var = 1;
}
}
int dep = draw_scope(item);
int dep = draw_scope(item, callh);
scan_item(depth, item, 0);
@ -782,7 +771,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
@ -790,7 +779,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.compiletf = sys_one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
@ -798,7 +787,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dumpflush_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
@ -806,7 +795,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dumplimit_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
@ -814,7 +803,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dumpoff_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
@ -822,7 +811,7 @@ void sys_vcd_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dumpon_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@ -835,4 +824,3 @@ void sys_vcd_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-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,9 +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: sys_vcdoff.c,v 1.5 2007/03/14 04:05:52 steve Exp $"
#endif
# include "sys_priv.h"
@ -40,7 +37,7 @@
static int dump_flag = 0;
static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
static PLI_INT32 sys_dummy_calltf(PLI_BYTE8*name)
{
return 0;
}
@ -48,7 +45,7 @@ static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
{
if (dump_flag == 0) {
vpi_mcd_printf(1, "VCD info: dumping is suppressed.\n");
vpi_printf("VCD info: dumping is suppressed.\n");
dump_flag = 1;
}
@ -63,48 +60,48 @@ void sys_vcdoff_register()
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpall_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpfile_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpflush";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpflush_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpflush";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumplimit";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumplimit_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_one_numeric_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumplimit";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpoff";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpoff_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpoff";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpon";
tf_data.calltf = sys_dump_calltf;
tf_data.compiletf = sys_dumpon_compiletf;
tf_data.calltf = sys_dummy_calltf;
tf_data.compiletf = sys_no_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpon";
vpi_register_systf(&tf_data);
@ -117,4 +114,3 @@ void sys_vcdoff_register()
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}

View File

@ -14,4 +14,6 @@ $dist_poisson vpiSysFuncInt
$dist_chi_square vpiSysFuncInt
$dist_t vpiSysFuncInt
$dist_erlang vpiSysFuncInt
$vvp_cpu_wordsize vpiSysFuncInt
$simparam vpiSysFuncReal
$simparam$str vpiSysFuncSized 1024 unsigned

View File

@ -68,7 +68,7 @@ typedef struct s_single_data {
static t_single_data va_single_data[]= {
{"$sqrt", sqrt},
{"$ln", log},
{"$log", log10}, /* FIXME: The $log function is replaced by the
{"$log", log10}, /* NOTE: The $log function is replaced by the
$log10 function to eliminate confusion with
the natural log. In C, "log" is ln and log10
is log-base-10. The $log is being left in for
@ -141,8 +141,8 @@ typedef struct {
* Standard error message routine. The format string must take one
* string argument (the name of the function).
*/
static void va_error_message(vpiHandle callh, const char* format,
const char* name) {
static void va_error_message(vpiHandle callh, const char *format,
const char *name) {
vpi_printf("%s:%d: error: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf(format, name);
@ -153,8 +153,8 @@ static void va_error_message(vpiHandle callh, const char* format,
/*
* Process an argument.
*/
vpiHandle va_process_argument(vpiHandle callh, const char* name,
vpiHandle arg, const char* post) {
vpiHandle va_process_argument(vpiHandle callh, const char *name,
vpiHandle arg, const char *post) {
PLI_INT32 type;
if (arg == NULL) return 0;
@ -178,7 +178,7 @@ vpiHandle va_process_argument(vpiHandle callh, const char* name,
/*
* Routine to check all the single argument math functions.
*/
static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8* ud)
static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8 *ud)
{
assert(ud != 0);
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
@ -225,7 +225,7 @@ static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8* ud)
/*
* Routine to implement the single argument math functions.
*/
static PLI_INT32 va_single_argument_calltf(PLI_BYTE8* ud)
static PLI_INT32 va_single_argument_calltf(PLI_BYTE8 *ud)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
s_vpi_value val;
@ -249,7 +249,7 @@ static PLI_INT32 va_single_argument_calltf(PLI_BYTE8* ud)
/*
* Routine to check all the double argument math functions.
*/
static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8* ud)
static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8 *ud)
{
assert(ud != 0);
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);

280
vpi/vams_simparam.c Normal file
View File

@ -0,0 +1,280 @@
/*
* Copyright (C) 2008 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vpi_user.h>
#include "sys_priv.h"
/* Once we have real string objects replace this with a dynamic string. */
#define MAX_STRING_RESULT 1024
/*
* Check that the routines are called with the correct arguments.
*/
static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
assert(callh != 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* We must have at least one argument. */
if (argv == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$simparam%s requires a string argument.\n", name_ext);
vpi_control(vpiFinish, 1);
return 0;
}
/* The first argument must be a string. */
arg = vpi_scan(argv);
if (! is_string_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("The first argument to $simparam%s must be a string.\n",
name_ext);
vpi_control(vpiFinish, 1);
}
/* The second argument (default value) is optional. */
arg = vpi_scan(argv);
if (arg == 0) return 0;
/* For the string version the default must also be a string. */
if (strcmp(name_ext, "$str") == 0) {
if (! is_string_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("When provided, the second argument to $simparam%s"
"must be a string.\n", name_ext);
vpi_control(vpiFinish, 1);
}
/* For the rest the default must be numeric. */
} else {
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("When provided, the second argument to $simparam%s"
"must be numeric.\n", name_ext);
vpi_control(vpiFinish, 1);
}
}
/* We can have a maximum of two arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
unsigned argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s $simparam%s takes at most two arguments.\n",
msg, name_ext);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
static PLI_INT32 simparam_calltf(PLI_BYTE8 *name_ext)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
char *param;
unsigned have_def_val = 0;
double retval, defval = 0.0;
/* Get the parameter we are looking for. */
arg = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(arg, &val);
param = strdup(val.value.str);
/* See if there is a default value. */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_free_object(argv);
have_def_val = 1;
val.format = vpiRealVal;
vpi_get_value(arg, &val);
defval = val.value.real;
}
/* Now check the various things we can return. */
if (strcmp(param, "gdev") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "gmin") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "imax") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "imelt") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "iteration") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "scale") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "shrink") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "simulatorSubversion") == 0) {
retval = 0.0;
} else if (strcmp(param, "simulatorVersion") == 0) {
retval = 0.9;
} else if (strcmp(param, "sourceScaleFactor") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "tnom") == 0) {
retval = 0.0; /* Nothing for now. */
} else if (strcmp(param, "timeUnit") == 0) {
retval = pow(10, vpi_get(vpiTimeUnit, sys_func_module(callh)));
} else if (strcmp(param, "timePrecision") == 0) {
retval = pow(10, vpi_get(vpiTimePrecision, sys_func_module(callh)));
} else if (strcmp(param, "CPUWordSize") == 0) {
retval = 8.0*sizeof(long);
} else {
if (! have_def_val) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
name_ext, param);
}
retval = defval;
}
free(param);
/* Return the value to the system. */
val.format = vpiRealVal;
val.value.real = retval;
vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0;
}
static PLI_INT32 simparam_str_calltf(PLI_BYTE8 *name_ext)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
s_vpi_value val;
char *param;
char *retval, *defval = NULL;
/* Get the parameter we are looking for. */
arg = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(arg, &val);
param = strdup(val.value.str);
/* See if there is a default value. */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_free_object(argv);
val.format = vpiStringVal;
vpi_get_value(arg, &val);
defval = strdup(val.value.str);
}
/* Now check the various things we can return. */
/* For now we limit the result to 1024 characters. */
if (strcmp(param, "analysis_name") == 0) {
retval = strdup("N/A"); /* Nothing for now. */
} else if (strcmp(param, "analysis_type") == 0) {
retval = strdup("N/A"); /* Nothing for now. */
} else if (strcmp(param, "cwd") == 0) {
char path [MAX_STRING_RESULT];
char *ptr = getcwd(path, MAX_STRING_RESULT);
if (ptr == NULL) {
ptr = strcpy(path, "<error getting the cwd, "
"is it too long?>");
}
retval = strdup(path);
} else if (strcmp(param, "module") == 0) {
retval = strdup(vpi_get_str(vpiDefName, sys_func_module(callh)));
} else if (strcmp(param, "instance") == 0) {
retval = strdup(vpi_get_str(vpiFullName, sys_func_module(callh)));
} else if (strcmp(param, "path") == 0) {
retval = strdup(vpi_get_str(vpiFullName,
vpi_handle(vpiScope,callh)));
} else {
if (defval == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
name_ext, param);
defval = strdup("<error>");
}
retval = defval;
}
free(param);
/* Return the value to the system. */
val.format = vpiStringVal;
val.value.str = retval;
vpi_put_value(callh, &val, 0, vpiNoDelay);
free(retval);
return 0;
}
static PLI_INT32 simparam_str_sizetf(PLI_BYTE8 *name_ext)
{
(void) name_ext; /* Not used! */
return MAX_STRING_RESULT; // 128 characters max!
}
/*
* Register the function with Verilog.
*/
void vams_simparam_register(void)
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiRealFunc;
tf_data.calltf = simparam_calltf;
tf_data.compiletf = simparam_compiletf;
tf_data.sizetf = 0;
tf_data.tfname = "$simparam";
tf_data.user_data = "";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiSizedFunc; /* What should this be? */
tf_data.calltf = simparam_str_calltf;
tf_data.compiletf = simparam_compiletf;
tf_data.sizetf = simparam_str_sizetf; /* Only 128 characters! */
tf_data.tfname = "$simparam$str";
tf_data.user_data = "$str";
vpi_register_systf(&tf_data);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-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,21 +16,19 @@
* 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: vcd_priv.c,v 1.6 2004/10/04 01:10:58 steve Exp $"
#endif
# include "vpi_config.h"
# include "vcd_priv.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
#include "vpi_config.h"
#include "vcd_priv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <ctype.h>
# include "stringheap.h"
#include <ctype.h>
#include "stringheap.h"
#include <sys_priv.h>
int is_escaped_id(const char *name)
{
@ -133,7 +131,7 @@ void vcd_names_sort(struct vcd_names_list_s*tab)
The new signal will be listed as a $var, but no callback
will be installed. This saves considerable CPU time and leads
to smalle VCD files.
to smaller VCD files.
The _vpiNexusId is a private (int) property of IVL simulators.
*/
@ -188,184 +186,12 @@ void set_nexus_ident(int nex, const char *id)
vcd_ids[ihash(nex)] = bucket;
}
/* This is used by the compiletf routines to check if an argument
* is numeric. */
static void check_numeric_arg(vpiHandle arg, char *msg, PLI_BYTE8 *name)
{
assert(arg);
switch (vpi_get(vpiType, arg)) {
case vpiConstant:
case vpiParameter:
/* String constants are invalid numeric values. */
if (vpi_get(vpiConstType, arg) == vpiStringConst) {
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
}
break;
/* These have valid numeric values. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiRealVar:
case vpiReg:
case vpiTimeVar:
break;
default:
/* Anything else is not a numeric value. */
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
break;
}
}
/* This is used by the compiletf routines to check if an argument
* is a string value. */
static void check_string_arg(vpiHandle arg, char *msg, PLI_BYTE8 *name)
{
assert(arg);
PLI_INT32 ctype = 0;
switch (vpi_get(vpiType, arg)) {
case vpiConstant:
case vpiParameter:
/* These must be a string or binary constant. */
ctype = vpi_get(vpiConstType, arg);
if (ctype != vpiStringConst && ctype != vpiBinaryConst) {
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
}
break;
/* These have valid string values. */
case vpiIntegerVar:
case vpiMemoryWord:
case vpiNet:
case vpiReg:
case vpiTimeVar:
break;
default:
/* Anything else is not a string. */
vpi_mcd_printf(1, msg, name);
vpi_control(vpiFinish, 1);
break;
}
}
/*
* Since the compiletf routines are all the same they are located here,
* so we only need a single copy.
* so we only need a single copy. Some are generic enough they can use
* the ones in sys_priv.c (no arg, one numeric argument, etc.).
*/
/* $dumpall does not take an argument. */
PLI_INT32 sys_dumpall_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumpfile takes a single string argument. */
PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Check that there is an argument and that it is a string. */
if (argv == 0) {
vpi_mcd_printf(1, "ERROR: %s requires an argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
check_string_arg(vpi_scan(argv), "ERROR: %s's argument must be a"
" string.\n", name);
/* Check that there is only a single argument. */
if (vpi_scan(argv) != 0) {
vpi_mcd_printf(1, "ERROR: %s takes a single argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
/* $dumpflush does not take an argument. */
PLI_INT32 sys_dumpflush_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumplimit takes a single numeric argument. */
PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
/* Check that there is an argument and that it is numeric. */
if (argv == 0) {
vpi_mcd_printf(1, "ERROR: %s requires an argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
check_numeric_arg(vpi_scan(argv), "ERROR: %s's argument must be"
" numeric.\n", name);
/* Check that there is only a single argument. */
if (vpi_scan(argv) != 0) {
vpi_mcd_printf(1, "ERROR: %s takes a single argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
/* $dumpoff does not take an argument. */
PLI_INT32 sys_dumpoff_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumpon does not take an argument. */
PLI_INT32 sys_dumpon_compiletf(PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
if (argv != 0) {
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
vpi_control(vpiFinish, 1);
}
return 0;
}
/* $dumpvars takes a variety of arguments. */
PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
{
@ -374,16 +200,27 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
vpiHandle arg;
/* No arguments is OK, dump everything. */
if (argv == 0)
return 0;
if (argv == 0) return 0;
/* The first argument is the numeric level. */
check_numeric_arg(vpi_scan(argv), "ERROR: %s's first argument must be"
" numeric.\n", name);
if (! is_numeric_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's argument must be numeric.\n", name);
vpi_control(vpiFinish, 1);
}
/* The rest of the arguments are either a module or a variable. */
while ((arg=vpi_scan(argv)) != NULL) {
switch(vpi_get(vpiType, arg)) {
case vpiMemoryWord:
if (vpi_get(vpiConstantSelect, arg) == 0) {
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot dump a non-constant select %s.\n", name,
vpi_get_str(vpiType, arg));
vpi_control(vpiFinish, 1);
}
/* The module types. */
case vpiModule:
case vpiTask:
@ -393,18 +230,18 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
/* The variable types. */
case vpiNet:
case vpiReg:
case vpiMemoryWord:
case vpiIntegerVar:
case vpiTimeVar:
case vpiRealVar:
break;
default:
vpi_mcd_printf(1, "ERROR: %s cannot dump a %s.\n",
name, vpi_get_str(vpiType, arg));
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s cannot dump a %s.\n", name,
vpi_get_str(vpiType, arg));
vpi_control(vpiFinish, 1);
}
}
return 0;
}

View File

@ -1,7 +1,7 @@
#ifndef __vcd_priv_H
#define __vcd_priv_H
/*
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-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: vcd_priv.h,v 1.2 2003/02/13 18:13:28 steve Exp $"
#endif
#include "vpi_user.h"
@ -47,12 +44,6 @@ extern const char*find_nexus_ident(int nex);
extern void set_nexus_ident(int nex, const char *id);
/* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */
extern PLI_INT32 sys_dumpall_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpflush_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpoff_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpon_compiletf(PLI_BYTE8 *name);
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
#endif

View File

@ -143,7 +143,7 @@ typedef struct t_vpi_value {
(1) The number of delays to be retrieved
( normally this is used in vpi_get_delays (..) )
{
(1.1) Setted by "no_of_delays" field
(1.1) Set by "no_of_delays" field
(1.2) For the primitive_object, the no_of_delays
shall be 2 or 3
@ -279,6 +279,7 @@ typedef struct t_vpi_delay {
#define vpiNamedFork 35
#define vpiNet 36
#define vpiParameter 41
#define vpiPartSelect 42
#define vpiPathTerm 43
#define vpiRealVar 47
#define vpiReg 48
@ -297,6 +298,7 @@ typedef struct t_vpi_delay {
#define vpiModPathIn 95
#define vpiModPathOut 96
#define vpiVariables 100
#define vpiExpr 102
#define vpiCallback 1000
@ -346,8 +348,8 @@ typedef struct t_vpi_delay {
# define vpiSysFuncReal vpiRealFunc
# define vpiSysFuncTime vpiTimeFunc
# define vpiSysFuncSized vpiSizedFunc
#define vpiSigned 65
#define vpiExpr 102
#define vpiConstantSelect 53
#define vpiSigned 65
/* IVL private properties */
#define _vpiNexusId 0x1000000

View File

@ -83,7 +83,7 @@ void vpip_run_value_changes(struct __vpiSignal*sig)
/*
* Handle read-only synch events. This causes the callback to be
* scheduled for a moment at the end of the time period. This method
* handles scheduling with itme delays.
* handles scheduling with time delays.
*/
static void go_readonly_synch(struct __vpiCallback*rfp)
{

View File

@ -79,7 +79,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
concat.o \
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
ufunc.o codes.o \
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \
event.o logic.o delay.o words.o $V
ifeq (@WIN32@,yes)

View File

@ -345,6 +345,24 @@ The .alias statements do not create new nodes, but instead create net
names that are aliases of an existing node. This handles special cases
where a net has different names, possibly in different scopes.
CAST STATEMENTS:
Sometimes nets need to be cast from a real valued net to a bit based
net or from a bit based net to a real valued net. These statements
are used to performa that operation:
<label> .case/int <width>, <symbol>;
<label> .case/real <symbol>;
<label> .case/real.s <symbol>;
For .case/int the output <label> is a bit based net that is <width>
bits wide. The input <symbol> is expected to put real values to
this functor.
For .case/real the output <label> is a real valued net. The input
<symbol> is expected to put bit based values and for .case/real.s
the bits will be interpreted as a signed value.
DELAY STATEMENTS:
Delay nodes are structural net delay nodes that carry and manage
@ -386,82 +404,6 @@ at <src>.
<label> .array "name", <src> ;
MEMORY STATEMENTS:
Memories are arrays of words, each word a vvp_vector4_t vector of the
same width. The memory is canonically addressed as a 1-dimensional
array of words, although indices are stored with the memory for
calculating a canonical address from a multi-dimensional address.
Three types of memory statement perform (1) creation of a memory, (2)
connecting a read port to an existing memory, and (3) initializing the
memory's contents.
<label> .mem "name", <msb>,<lsb>, <last>,<first> ... ;
The pair of numbers <msb>,<lsb> defines the word width. The pair
<last>,<first> defines the address range. Multiple address ranges are
allowed for multidimensional indexing. This statement creates the
memory array and makes it available to procedural code.
Procedural access to the memory references the memory as single array
of words, with the base address==0, and the last address the size (in
words) of the memory -1. It is up to the compiler to convert Verilog
index sets to a canonical address. The multi-dimensional index set is
available for VPI use.
Structural read access is implemented in terms of address and data
ports. The addresses applied to the address port are expected to be
in canonical form.
A read port is a functor that takes a single input, the read address,
and outputs the word value at the given (canonical) address.
<label> .mem/port <memid>, <address> ;
<label> identifies the vector of output functors, to allow connections
to the data output. <memid> is the label of the memory.
Any address input change, or any change in the addressed memory
contents, is immediately propagated to the port output.
A write port is a superset of a read port. It is a 4-input functor
that accepts the word address, an event input, a write enable input,
and the data input.
<label> .mem/port <memid>, <address>, <event>, <we>, <data> ;
<event> is an event functor that triggers a write, if the <we> input
is true. <data> is the input that connect to the data input
port. For asynchronous transparent write operation, connect
<event> to C4<z>, the RAM will transparently follow any changes on
address and data lines, while <we> is true.
There is no Verilog construct that calls for a structural write port
to a memory, but synthesis may ask for lpm_ram_d[pq] objects.
To initialize a memory, use:
.mem/init <memid> <start>, val , val ... ;
<memid> is the label of the memory, and the <start> is the start
address (canonical) of the first word to be initialized. The start
address allows multiple statements be used to initialize words of a
memory.
The values are one per word.
Procedural access to the memory employs an index register to address a
bit location in the memory, via the commands:
%load/m <bit>, <memid> ;
%set/m <memid>, <bit> ;
%assign/m <memid>, <delay>, <bit> ;
The memory bit is addressed by index register 3. The value of
register 3 is the index in the memory's bit space, where each data
word occupies a multiple of four bits.
EVENT STATEMENTS
@ -830,6 +772,61 @@ by the fork atomically joins that scope. Once the transient thread
joins the scope, it stays there until it ends. Threads never change
scopes, not even transient threads.
VPI TASK/FUNCTION CALLS
Threads call vpi tasks with the %vpi_call or %vpi_func
instructions. The formats are:
%vpi_call <file-index> <lineno> <name>, <args>... ;
%vpi_func <file-index> <lineno> <name>, <args>... ;
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
The <file-index> is an index into the string table. The indexed string
is the source code file name where this call appears. The <lineno> is
the line number from the source code where this task/function appears.
The <name> is a string that is the name of the system
task/function. For example, "$display", $strobe", etc. This name is
looked up and compared with the registered system tasks/functions.
The <args>... is a comma (",") separated list of arguments. These are
made available to the VPI code as vpi handles.
* The &A<> argument
The &A<> argument is a reference to the word of a variable array. The
syntax is:
&A '<' <symbol> , <number> '>'
&A '<' <symbol> , <base> <width> '>'
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>).
* The &PV<> argument
The &PV<> argument is a reference to part of a signal. The syntax is:
&PV '<' <symbol> , <base> , <width> '>'
&PV '<' <symbol> , <tbase> <twid> , <width> '>'
The <symbol> is the label for a signal, the <base> is the canonical
starting bit of the part select and <width> is the number of bits in
the select. The second form retrieves the <base> from thread space
using <twid> bits starting at <tbase>.
* The T<> argument
This is the catch-all for arguments that are not otherwise
handled. This references the bits directly in the thread. The format
is:
T '<' <base>, <wid>, <su> '>'
The <base> and <wid> are the base of a vector value in the thread and
the width of the vector. The <su> is 's' or 'u' for signed or unsigned.
TRUTH TABLES
The logic that a functor represents is expressed as a truth table. The

View File

@ -90,6 +90,36 @@ void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit)
vvp_send_real(ptr.ptr()->out, out);
}
vvp_arith_cast_int::vvp_arith_cast_int(unsigned wid)
: wid_(wid)
{
}
vvp_arith_cast_int::~vvp_arith_cast_int()
{
}
void vvp_arith_cast_int::recv_real(vvp_net_ptr_t ptr, double bit)
{
vvp_send_vec4(ptr.ptr()->out, vvp_vector4_t(wid_, bit));
}
vvp_arith_cast_real::vvp_arith_cast_real(bool signed_flag)
: signed_(signed_flag)
{
}
vvp_arith_cast_real::~vvp_arith_cast_real()
{
}
void vvp_arith_cast_real::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{
double val;
vector4_to_value(bit, val, signed_);
vvp_send_real(ptr.ptr()->out, val);
}
// Division
vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag)
@ -459,7 +489,7 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
vector4_to_value(op_a_, ad, true);
vector4_to_value(op_b_, bd, true);
res4 = double_to_vector4(pow(ad, bd), wid_);
res4 = vvp_vector4_t(wid_, pow(ad, bd));
} else {
vvp_vector2_t a2 (op_a_);
vvp_vector2_t b2 (op_b_);

View File

@ -60,6 +60,28 @@ class vvp_arith_abs : public vvp_net_fun_t {
private:
};
class vvp_arith_cast_int : public vvp_net_fun_t {
public:
explicit vvp_arith_cast_int(unsigned wid);
~vvp_arith_cast_int();
void recv_real(vvp_net_ptr_t ptr, double bit);
private:
unsigned wid_;
};
class vvp_arith_cast_real : public vvp_net_fun_t {
public:
explicit vvp_arith_cast_real(bool signed_flag);
~vvp_arith_cast_real();
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
private:
bool signed_;
};
class vvp_arith_div : public vvp_arith_ {
public:

View File

@ -1,6 +1,6 @@
/*
* 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
* General Public License as published by the Free Software
@ -30,7 +30,14 @@
# include "compile.h"
# include <assert.h>
static symbol_table_t array_table =0;
unsigned long count_net_arrays = 0;
unsigned long count_net_array_words = 0;
unsigned long count_var_arrays = 0;
unsigned long count_var_array_words = 0;
unsigned long count_real_arrays = 0;
unsigned long count_real_array_words = 0;
static symbol_map_s<struct __vpiArray>* array_table =0;
class vvp_fun_arrayport;
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
@ -40,8 +47,8 @@ vvp_array_t array_find(const char*label)
if (array_table == 0)
return 0;
symbol_value_t v = sym_get_value(array_table, label);
return (vvp_array_t)v.ptr;
vvp_array_t v = array_table->sym_get_value(label);
return v;
}
/*
@ -49,17 +56,21 @@ vvp_array_t array_find(const char*label)
* represent the words of the array. The vpi_array_t is a pointer to this.
*/
struct __vpiArray {
__vpiArray() { }
struct __vpiHandle base;
struct __vpiScope*scope;
const char*name; /* Permanently allocated string */
unsigned array_count;
struct __vpiDecConst first_addr;
struct __vpiDecConst last_addr;
struct __vpiDecConst msb;
struct __vpiDecConst lsb;
unsigned vals_width;
// If this is a net array, nets lists the handles.
vpiHandle*nets;
// If this is a var array, then these are used instead of nets.
vvp_vector4_t *vals;
unsigned vals_width;
vvp_vector4array_t *vals;
struct __vpiArrayWord*vals_words;
class vvp_fun_arrayport*ports_;
@ -81,7 +92,35 @@ struct __vpiArrayIndex {
struct __vpiArrayVthrA {
struct __vpiHandle base;
struct __vpiArray*array;
// If this is set, then use it to get the index value.
vpiHandle address_handle;
// If wid==0, then address is the address into the array.
unsigned address;
// If wid >0, then the address is the base and wid the vector
// width of the index to pull from the thread.
unsigned wid;
unsigned get_address() const
{
if (address_handle) {
s_vpi_value vp;
vp.format = vpiIntVal;
vpi_get_value(address_handle, &vp);
return vp.value.integer;
}
if (wid == 0)
return address;
vvp_vector4_t tmp (wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread, address+idx);
tmp.set_bit(idx, bit);
}
unsigned long val;
vector4_to_value(tmp, val);
return val;
}
};
/*
@ -98,9 +137,16 @@ struct __vpiArrayVthrA {
* pointer.
*
* To then get to the parent, use word0[-1].parent.
*
* The vpiArrayWord is also used as a handle for the index (vpiIndex)
* for the word. To make that work, return the pointer to the as_index
* member instead of the as_word member. The result is a different set
* of vpi functions is bound to the same structure. All the details
* for the word also apply when treating this as an index.
*/
struct __vpiArrayWord {
struct __vpiHandle base;
struct __vpiHandle as_word;
struct __vpiHandle as_index;
union {
struct __vpiArray*parent;
struct __vpiArrayWord*word0;
@ -121,12 +167,18 @@ static vpiHandle array_index_scan(vpiHandle ref, int);
static int array_index_free_object(vpiHandle ref);
static int vpi_array_var_word_get(int code, vpiHandle);
static char*vpi_array_var_word_get_str(int code, vpiHandle);
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref);
static void vpi_array_var_index_get_value(vpiHandle, p_vpi_value);
static int vpi_array_vthr_A_get(int code, vpiHandle);
static char*vpi_array_vthr_A_get_str(int code, vpiHandle);
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref);
static const struct __vpirt vpip_arraymem_rt = {
vpiMemory,
@ -169,9 +221,21 @@ static const struct __vpirt vpip_array_index_rt = {
static const struct __vpirt vpip_array_var_word_rt = {
vpiMemoryWord,
&vpi_array_var_word_get,
0,
&vpi_array_var_word_get_str,
&vpi_array_var_word_get_value,
&vpi_array_var_word_put_value,
&vpi_array_var_word_get_handle,
0,
0,
0
};
static const struct __vpirt vpip_array_var_index_rt = {
vpiIndex,
0,
0,
&vpi_array_var_index_get_value,
0,
0,
0,
0,
@ -181,10 +245,10 @@ static const struct __vpirt vpip_array_var_word_rt = {
static const struct __vpirt vpip_array_vthr_A_rt = {
vpiMemoryWord,
&vpi_array_vthr_A_get,
0,
&vpi_array_vthr_A_get_str,
&vpi_array_vthr_A_get_value,
&vpi_array_vthr_A_put_value,
0,
&vpi_array_vthr_A_get_handle,
0,
0,
0
@ -203,6 +267,16 @@ static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref)
return (struct __vpiArrayWord*) ref;
}
static struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref)
{
if (ref == 0)
return 0;
if (ref->vpi_type != &vpip_array_var_index_rt)
return 0;
return (struct __vpiArrayWord*) (ref-1);
}
static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref)
{
if (ref == 0)
@ -225,7 +299,8 @@ static void array_make_vals_words(struct __vpiArray*parent)
struct __vpiArrayWord*words = parent->vals_words;
for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) {
words[idx].base.vpi_type = &vpip_array_var_word_rt;
words[idx].as_word.vpi_type = &vpip_array_var_word_rt;
words[idx].as_index.vpi_type = &vpip_array_var_index_rt;
words[idx].word0 = words;
}
}
@ -325,7 +400,7 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index)
if (obj->vals_words == 0)
array_make_vals_words(obj);
return &(obj->vals_words[index].base);
return &(obj->vals_words[index].as_word);
}
static int vpi_array_var_word_get(int code, vpiHandle ref)
@ -338,13 +413,36 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
switch (code) {
case vpiSize:
return (int) parent->vals_width;
return (int) parent->vals->width();
case vpiLeftRange:
return parent->msb.value;
case vpiRightRange:
return parent->lsb.value;
default:
return 0;
}
}
static char*vpi_array_var_word_get_str(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)index + parent->first_addr.value);
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
}
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
@ -352,9 +450,9 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
unsigned width = parent->vals->width();
vpip_vec4_get_value(parent->vals[index], parent->vals_width,
false, value);
vpip_vec4_get_value(parent->vals->get_word(index), width, false, value);
}
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
@ -370,6 +468,47 @@ static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int
return ref;
}
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
decode_array_word_pointer(obj, parent);
switch (code) {
case vpiIndex:
return &(obj->as_index);
case vpiLeftRange:
return &parent->msb.base;
case vpiRightRange:
return &parent->lsb.base;
case vpiParent:
return &parent->base;
case vpiScope:
return &parent->scope->base;
}
return 0;
}
static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayWord*obj = array_var_index_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
assert(value->format == vpiIntVal);
value->value.integer = index;
}
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
(struct __vpiArrayIterator*)ref)
@ -393,7 +532,7 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int)
if (obj->array->vals_words == 0)
array_make_vals_words(obj->array);
return &(obj->array->vals_words[use_index].base);
return &(obj->array->vals_words[use_index].as_word);
}
static int array_iterator_free_object(vpiHandle ref)
@ -453,13 +592,39 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
return 0; // Not implemented for now!
case vpiSize:
assert(parent->vals);
return parent->vals_width;
case vpiLeftRange:
return parent->msb.value;
case vpiRightRange:
return parent->lsb.value;
// For now &A<> is only a constant select. This will need
// to be changed when it supports variable selection.
case vpiConstantSelect:
return 1;
default:
return 0;
}
}
static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value);
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
}
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
@ -467,11 +632,10 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
struct __vpiArray*parent = obj->array;
assert(parent);
assert(parent->vals);
assert(obj->address < parent->array_count);
vpip_vec4_get_value(parent->vals[obj->address],
parent->vals_width, false, value);
unsigned index = obj->get_address();
vvp_vector4_t tmp = array_get_word(parent, index);
vpip_vec4_get_value(tmp, parent->vals_width, false, value);
}
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
@ -480,10 +644,10 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
assert(obj);
struct __vpiArray*parent = obj->array;
unsigned index = obj->address;
unsigned index = obj->get_address();
assert(parent);
assert(obj->address < parent->array_count);
assert(index < parent->array_count);
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
array_set_word(parent, index, 0, val);
@ -491,6 +655,32 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
return ref;
}
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
switch (code) {
case vpiIndex:
break; // Not implemented!
case vpiLeftRange:
return &parent->msb.base;
case vpiRightRange:
return &parent->lsb.base;
case vpiParent:
return &parent->base;
case vpiScope:
return &parent->scope->base;
}
return 0;
}
void array_set_word(vvp_array_t arr,
unsigned address,
@ -503,18 +693,18 @@ void array_set_word(vvp_array_t arr,
if (arr->vals) {
assert(arr->nets == 0);
if (part_off != 0 || val.size() != arr->vals_width) {
if (arr->vals[address].size() == 0)
arr->vals[address] = vvp_vector4_t(arr->vals_width, BIT4_X);
if ((part_off + val.size()) > arr->vals[address].size()) {
vvp_vector4_t tmp = arr->vals->get_word(address);
if ((part_off + val.size()) > tmp.size()) {
cerr << "part_off=" << part_off
<< " val.size()=" << val.size()
<< " arr->vals[address].size()=" << arr->vals[address].size()
<< " arr->vals[address].size()=" << tmp.size()
<< " arr->vals_width=" << arr->vals_width << endl;
assert(0);
}
arr->vals[address].set_vec(part_off, val);
tmp.set_vec(part_off, val);
arr->vals->set_word(address, tmp);
} else {
arr->vals[address] = val;
arr->vals->set_word(address, val);
}
array_word_change(arr, address);
return;
@ -537,14 +727,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
if (arr->vals) {
assert(arr->nets == 0);
vvp_vector4_t tmp;
if (address < arr->array_count)
tmp = arr->vals[address];
if (tmp.size() == 0)
tmp = vvp_vector4_t(arr->vals_width, BIT4_X);
return tmp;
return arr->vals->get_word(address);
}
assert(arr->vals == 0);
@ -596,6 +779,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,
obj->nets = 0;
obj->vals = 0;
obj->vals_width = 0;
vpip_make_dec_const(&obj->msb, 0);
vpip_make_dec_const(&obj->lsb, 0);
obj->vals_words = 0;
// Initialize (clear) the read-ports list.
@ -604,12 +789,10 @@ static vpiHandle vpip_make_array(char*label, const char*name,
/* Add this symbol to the array_symbols table for later lookup. */
if (!array_table)
array_table = new_symbol_table();
array_table = new symbol_map_s<struct __vpiArray>;
assert(!array_find(label));
symbol_value_t v;
v.ptr = obj;
sym_set_value(array_table, label, v);
array_table->sym_set_value(label, obj);
/* Add this into the table of VPI objects. This is used for
contexts that try to look up VPI objects in
@ -641,7 +824,8 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
vvp_fun_signal_base*fun = dynamic_cast<vvp_fun_signal_base*>(net->fun);
assert(fun);
fun->attach_as_word(array, addr);
sig->parent = &array->base;
sig->is_netarray = 1;
sig->within.parent = &array->base;
sig->id.index = vpip_make_dec_const(addr + array->first_addr.value);
}
}
@ -654,8 +838,13 @@ void compile_var_array(char*label, char*name, int last, int first,
struct __vpiArray*arr = ARRAY_HANDLE(obj);
/* Make the words. */
arr->vals = new vvp_vector4_t[arr->array_count];
arr->vals_width = labs(msb-lsb) + 1;
arr->vals = new vvp_vector4array_t(arr->vals_width, arr->array_count);
vpip_make_dec_const(&arr->msb, msb);
vpip_make_dec_const(&arr->lsb, lsb);
count_var_arrays += 1;
count_var_array_words += arr->array_count;
free(label);
free(name);
@ -676,6 +865,9 @@ void compile_real_array(char*label, char*name, int last, int first,
compile_varw_real(strdup(buf), array, idx, msb, lsb);
}
count_real_arrays += 1;
count_real_array_words += arr->array_count;
free(label);
free(name);
}
@ -687,6 +879,9 @@ void compile_net_array(char*label, char*name, int last, int first)
struct __vpiArray*arr = ARRAY_HANDLE(obj);
arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle));
count_net_arrays += 1;
count_net_array_words += arr->array_count;
free(label);
free(name);
}
@ -768,7 +963,7 @@ void array_word_change(vvp_array_t array, unsigned long addr)
for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_)
cur->check_word_change(addr);
// Run callbacks attatched to the array itself.
// Run callbacks attached to the array itself.
struct __vpiCallback *next = array->vpi_callbacks;
struct __vpiCallback *prev = 0;
@ -784,7 +979,8 @@ void array_word_change(vvp_array_t array, unsigned long addr)
if (cur->cb_data.cb_rtn != 0) {
if (cur->cb_data.value)
vpip_vec4_get_value(array->vals[addr], array->vals_width,
vpip_vec4_get_value(array->vals->get_word(addr),
array->vals_width,
false, cur->cb_data.value);
callback_execute(cur);
@ -909,9 +1105,7 @@ void compile_array_alias(char*label, char*name, char*src)
assert(array_table);
assert(!array_find(label));
symbol_value_t v;
v.ptr = obj;
sym_set_value(array_table, label, v);
array_table->sym_set_value(label, obj);
compile_vpi_symbol(label, &obj->base);
vpip_attach_to_current_scope(&obj->base);
@ -930,9 +1124,57 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
obj->array = array_find(label);
assert(obj->array);
free(label);
obj->address_handle = 0;
obj->address = addr;
obj->wid = 0;
assert(addr < obj->array->array_count);
return &(obj->base);
}
vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid)
{
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
malloc(sizeof (struct __vpiArrayVthrA));
obj->base.vpi_type = &vpip_array_vthr_A_rt;
obj->array = array_find(label);
assert(obj->array);
free(label);
obj->address_handle = 0;
obj->address = tbase;
obj->wid = twid;
return &(obj->base);
}
vpiHandle vpip_make_vthr_A(char*label, char*symbol)
{
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
malloc(sizeof (struct __vpiArrayVthrA));
obj->base.vpi_type = &vpip_array_vthr_A_rt;
obj->array = array_find(label);
assert(obj->array);
free(label);
obj->address_handle = 0;
compile_vpi_lookup(&obj->address_handle, symbol);
obj->address = 0;
obj->wid = 0;
return &(obj->base);
}
void compile_array_cleanup(void)
{
if (array_table) {
delete array_table;
array_table = 0;
}
}

View File

@ -43,7 +43,7 @@ extern void array_set_word(vvp_array_t arr,
unsigned off,
vvp_vector4_t val);
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned adddress);
extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address);
/* VPI hooks */

View File

@ -97,13 +97,13 @@ extern bool of_JMP1(vthread_t thr, vvp_code_t code);
extern bool of_JOIN(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_WR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_X(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_XP(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_X1P(vthread_t thr, vvp_code_t code);
extern bool of_LOADI_WR(vthread_t thr, vvp_code_t code);
extern bool of_MOD(vthread_t thr, vvp_code_t code);
extern bool of_MOD_S(vthread_t thr, vvp_code_t code);

View File

@ -140,13 +140,13 @@ const static struct opcode_table_s opcode_table[] = {
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/vp0/s",of_LOAD_VP0_S,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/wr",of_LOAD_WR,2, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
{ "%load/x", of_LOAD_X, 3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/x.p",of_LOAD_XP, 3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/x1p",of_LOAD_X1P,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%loadi/wr",of_LOADI_WR,3,{OA_BIT1, OA_NUMBER, OA_BIT2} },
{ "%mod", of_MOD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mod/s", of_MOD_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@ -645,6 +645,8 @@ void compile_cleanup(void)
delete_symbol_table(sym_functors);
sym_functors = 0;
compile_island_cleanup();
if (verbose_flag) {
fprintf(stderr, " ... Compiletf functions\n");
fflush(stderr);
@ -887,6 +889,38 @@ template <class T_> void make_arith(T_ *arith, char*label,
free(argv);
}
void compile_arith_cast_int(char*label, long width,
unsigned argc, struct symb_s*argv)
{
vvp_arith_cast_int*arith = new vvp_arith_cast_int((unsigned) width);
vvp_net_t* ptr = new vvp_net_t;
ptr->fun = arith;
define_functor_symbol(label, ptr);
free(label);
assert(argc == 1);
inputs_connect(ptr, argc, argv);
free(argv);
}
void compile_arith_cast_real(char*label, bool signed_flag,
unsigned argc, struct symb_s*argv)
{
vvp_arith_cast_real*arith = new vvp_arith_cast_real(signed_flag);
vvp_net_t* ptr = new vvp_net_t;
ptr->fun = arith;
define_functor_symbol(label, ptr);
free(label);
assert(argc == 1);
inputs_connect(ptr, argc, argv);
free(argv);
}
void compile_arith_abs(char*label, unsigned argc, struct symb_s*argv)
{
vvp_arith_abs*arith = new vvp_arith_abs;
@ -992,11 +1026,6 @@ void compile_arith_pow(char*label, long wid, bool signed_flag,
unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
/* For now we need to do a double to long cast, so the number
of bits is limited. This should be caught in the compiler. */
if (signed_flag) {
assert( wid <= (long)(8*sizeof(long)) );
}
if (argc != 2) {
const char *suffix = "";
@ -1397,16 +1426,16 @@ void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
vvp_net_fun_t* obj = 0;
if (strcmp(type,"tri") == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0));
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0,0));
} else if (strncmp(type,"tri$",4) == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0), strdup(type+4));
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0,0), strdup(type+4));
} else if (strcmp(type,"tri0") == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5));
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5,5));
} else if (strcmp(type,"tri1") == 0) {
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5));
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5,5));
} else if (strcmp(type,"triand") == 0) {
obj = new resolv_triand;

View File

@ -151,6 +151,10 @@ extern void compile_arith_pow(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_abs(char*label,
unsigned argc, struct symb_s*argv);
extern void compile_arith_cast_int(char*label, long width,
unsigned argc, struct symb_s*argv);
extern void compile_arith_cast_real(char*label, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_div(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_mod(char*label, long width,
@ -335,6 +339,8 @@ extern void compile_array_port(char*label, char*name, char*addr);
/* Index is a constant address */
extern void compile_array_port(char*label, char*name, long addr);
extern void compile_array_cleanup(void);
/*
* Compile the .ufunc statement.
*/
@ -451,4 +457,16 @@ extern void compile_aliasw(char*label, char*array_symbol,
unsigned long array_addr, int msb, int lsb,
unsigned argc, struct symb_s*argv);
extern void compile_island(char*label, char*type);
extern void compile_island_port(char*label, char*island, char*src);
extern void compile_island_import(char*label, char*island, char*src);
extern void compile_island_export(char*label, char*island);
extern void compile_island_tranif(int sense, char*island,
char*ba, char*bb, char*src);
extern void compile_island_tranvp(char*island, char*ba, char*bb,
unsigned width, unsigned part, unsigned off);
extern void compile_island_cleanup(void);
#endif

View File

@ -242,7 +242,7 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
}
}
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit)
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
{
assert(port.port() == 0);

View File

@ -86,7 +86,7 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s {
~vvp_fun_delay();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
void recv_real(vvp_net_ptr_t port, double bit);
//void recv_long(vvp_net_ptr_t port, long bit);

View File

@ -25,7 +25,7 @@
/*
* The vvp_dff implements a D-type FF that is agnostic to the data
* type that is holds. The clock and clock-enable inputs are single
* bits and may be invertable. An output is propagated on the logical
* bits and may be invertible. An output is propagated on the logical
* rising edge of the clock input, or whenever an asynchronous input
* is received. Ports are:
*

View File

@ -66,7 +66,7 @@ m .var "m", 6,0;
;;; memory words occupy 8 bits each, that is 7 rounded up to the next
;;; multiple of 4.
;;; Four bits ber byte. Word fill bits are included. Commas are
;;; Four bits per byte. Word fill bits are included. Commas are
;;; optional, there may be a comma after the last byte.
.mem/init memory[20],

View File

@ -107,6 +107,9 @@
".array/real" { return K_ARRAY_R; }
".array/s" { return K_ARRAY_S; }
".array/port" { return K_ARRAY_PORT; }
".cast/int" { return K_CAST_INT; }
".cast/real" { return K_CAST_REAL; }
".cast/real.s" { return K_CAST_REAL_S; }
".cmp/eeq" { return K_CMP_EEQ; }
".cmp/eq" { return K_CMP_EQ; }
".cmp/eq.r" { return K_CMP_EQ_R; }
@ -124,8 +127,11 @@
".dff" { return K_DFF; }
".event" { return K_EVENT; }
".event/or" { return K_EVENT_OR; }
".export" { return K_EXPORT; }
".extend/s" { return K_EXTEND_S; }
".functor" { return K_FUNCTOR; }
".import" { return K_IMPORT; }
".island" { return K_ISLAND; }
".modpath" { return K_MODPATH; }
".net" { return K_NET; }
".net8" { return K_NET8; }
@ -138,6 +144,7 @@
".part" { return K_PART; }
".part/pv" { return K_PART_PV; }
".part/v" { return K_PART_V; }
".port" { return K_PORT; }
".reduce/and" { return K_REDUCE_AND; }
".reduce/or" { return K_REDUCE_OR; }
".reduce/xor" { return K_REDUCE_XOR; }
@ -153,6 +160,10 @@
".shift/rs" { return K_SHIFTRS; }
".thread" { return K_THREAD; }
".timescale" { return K_TIMESCALE; }
".tran" { return K_TRAN; }
".tranif0" { return K_TRANIF0; }
".tranif1" { return K_TRANIF1; }
".tranvp" { return K_TRANVP; }
".ufunc" { return K_UFUNC; }
".var" { return K_VAR; }
".var/real" { return K_VAR_R; }
@ -173,22 +184,24 @@
"%disable" { return K_disable; }
"%fork" { return K_fork; }
/* Handle the specialized variable access functions. */
"&A" { return K_A; }
"&PV" { return K_PV; }
"%"[.$_/a-zA-Z0-9]+ {
yylval.text = strdup(yytext);
assert(yylval.text);
return T_INSTR; }
[0-9][0-9]* {
yylval.numb = strtol(yytext, 0, 0);
yylval.numb = strtoul(yytext, 0, 0);
return T_NUMBER; }
"0x"[0-9a-fA-F]+ {
yylval.numb = strtol(yytext, 0, 0);
yylval.numb = strtoul(yytext, 0, 0);
return T_NUMBER; }
"&A" { return K_A; }
/* Handle some specialized constant/literals as symbols. */
"C4<"[01xz]*">" {
@ -218,7 +231,7 @@
/* Symbols are pretty much what is left. They are used to refer to
labels so the rule must match a string that a label would match. */
[.$_a-zA-Z\\][.$_a-zA-Z\\0-9<>/]* {
[.$_a-zA-Z\\]([.$_a-zA-Z\\0-9/]|(\\.))* {
yylval.text = strdup(yytext);
assert(yylval.text);
return T_SYMBOL; }

View File

@ -176,7 +176,7 @@ int main(int argc, char*argv[])
" -M path VPI module directory\n"
" -M - Clear VPI module path\n"
" -m module Load vpi module.\n"
" -n Non-interctive ($stop = $finish).\n"
" -n Non-interactive ($stop = $finish).\n"
" -s $stop right away.\n"
" -v Verbose progress messages.\n" );
exit(0);
@ -274,15 +274,25 @@ int main(int argc, char*argv[])
}
if (verbose_flag) {
vpi_mcd_printf(1, " ... %8lu functors\n", count_functors);
vpi_mcd_printf(1, " ... %8lu functors (net_fun pool=%zu bytes)\n",
count_functors, size_vvp_net_funs);
vpi_mcd_printf(1, " %8lu logic\n", count_functors_logic);
vpi_mcd_printf(1, " %8lu bufif\n", count_functors_bufif);
vpi_mcd_printf(1, " %8lu resolv\n",count_functors_resolv);
vpi_mcd_printf(1, " %8lu signals\n", count_functors_sig);
vpi_mcd_printf(1, " ... %8lu opcodes (%lu bytes)\n",
count_opcodes, (unsigned long)size_opcodes);
vpi_mcd_printf(1, " ... %8lu opcodes (%zu bytes)\n",
count_opcodes, size_opcodes);
vpi_mcd_printf(1, " ... %8lu nets\n", count_vpi_nets);
vpi_mcd_printf(1, " ... %8lu memories\n", count_vpi_memories);
vpi_mcd_printf(1, " ... %8lu vvp_nets (%zu bytes)\n",
count_vvp_nets, size_vvp_nets);
vpi_mcd_printf(1, " ... %8lu arrays (%lu words)\n",
count_net_arrays, count_net_array_words);
vpi_mcd_printf(1, " ... %8lu memories\n",
count_var_arrays+count_real_arrays);
vpi_mcd_printf(1, " %8lu logic (%lu words)\n",
count_var_arrays, count_var_array_words);
vpi_mcd_printf(1, " %8lu real (%lu words)\n",
count_real_arrays, count_real_array_words);
vpi_mcd_printf(1, " ... %8lu scopes\n", count_vpi_scopes);
}
@ -299,16 +309,23 @@ int main(int argc, char*argv[])
my_getrusage(cycles+2);
print_rusage(cycles+2, cycles+1);
vpi_mcd_printf(1, "Event counts: (event pool = %lu)\n",
count_event_pool);
vpi_mcd_printf(1, "Event counts:\n");
vpi_mcd_printf(1, " %8lu time steps (pool=%lu)\n",
count_time_events, count_time_pool());
vpi_mcd_printf(1, " %8lu thread schedule events\n",
count_thread_events);
vpi_mcd_printf(1, " %8lu propagation events\n",
count_prop_events);
vpi_mcd_printf(1, " %8lu assign events\n",
count_assign_events);
vpi_mcd_printf(1, " %8lu other events\n",
count_gen_events);
vpi_mcd_printf(1, " ...assign(vec4) pool=%lu\n",
count_assign4_pool());
vpi_mcd_printf(1, " ...assign(vec8) pool=%lu\n",
count_assign8_pool());
vpi_mcd_printf(1, " ...assign(real) pool=%lu\n",
count_assign_real_pool());
vpi_mcd_printf(1, " ...assign(word) pool=%lu\n",
count_assign_aword_pool());
vpi_mcd_printf(1, " %8lu other events (pool=%lu)\n",
count_gen_events, count_gen_pool());
}
return vvp_return_value;

Some files were not shown because too many files have changed in this diff Show More