Merge branch 'x-mil3'

Conflicts:
	vpi/Makefile.in
	vpi/sys_table.c
This commit is contained in:
Stephen Williams 2012-07-30 17:02:57 -07:00
commit 813f548a4b
81 changed files with 3086 additions and 275 deletions

View File

@ -108,13 +108,13 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \
net_design.o \
net_design.o netdarray.o \
netenum.o netstruct.o net_event.o net_expr.o net_func.o net_func_eval.o \
net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \
pform_types.o \
pform_disciplines.o pform_dump.o pform_pclass.o pform_string_type.o \
pform_struct_type.o pform_types.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \

View File

@ -371,6 +371,16 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
return false;
}
PENew::PENew(PExpr*size_expr)
: size_(size_expr)
{
}
PENew::~PENew()
{
delete size_;
}
PENumber::PENumber(verinum*vp)
: value_(vp)
{

30
PExpr.h
View File

@ -367,6 +367,8 @@ class PEIdent : public PExpr {
bool elaborate_lval_net_packed_member_(Design*, NetScope*,
NetAssign_*,
const perm_string&) const;
bool elaborate_lval_darray_bit_(Design*, NetScope*,
NetAssign_*) const;
private:
NetExpr*elaborate_expr_param_(Design*des,
@ -439,6 +441,23 @@ class PEIdent : public PExpr {
long&midx, long&lidx) const;
};
class PENew : public PExpr {
public:
explicit PENew (PExpr*s);
~PENew();
virtual void dump(ostream&) const;
virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode);
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid,
unsigned flags) const;
private:
PExpr*size_;
};
class PENumber : public PExpr {
public:
@ -717,8 +736,17 @@ class PECallFunction : public PExpr {
bool check_call_matches_definition_(Design*des, NetScope*dscope) const;
NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const;
NetExpr*elaborate_expr_method_(Design*des, NetScope*scope,
unsigned expr_wid) const;
#if 0
NetExpr*elaborate_expr_string_method_(Design*des, NetScope*scope) const;
NetExpr*elaborate_expr_enum_method_(Design*des, NetScope*scope,
unsigned expr_wid) const;
#endif
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope,
unsigned expr_wid,
unsigned flags) const;
@ -726,6 +754,8 @@ class PECallFunction : public PExpr {
unsigned expr_wid) const;
unsigned test_width_sfunc_(Design*des, NetScope*scope,
width_mode_t&mode);
unsigned test_width_method_(Design*des, NetScope*scope,
width_mode_t&mode);
};
/*

View File

@ -33,6 +33,7 @@ class ostream;
class PExpr;
class Design;
class netdarray_t;
/*
* The different type of PWire::set_range() calls.

View File

@ -107,6 +107,9 @@ class PAssign_ : public Statement {
NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width,
ivl_variable_type_t type) const;
NetExpr* elaborate_rval_obj_(Design*, NetScope*,
ivl_variable_type_t type) const;
PExpr* delay_;
PEventStatement*event_;
PExpr* count_;
@ -207,6 +210,8 @@ class PCallTask : public Statement {
NetProc* elaborate_sys(Design*des, NetScope*scope) const;
NetProc* elaborate_usr(Design*des, NetScope*scope) const;
NetProc*elaborate_method_(Design*des, NetScope*scope) const;
pform_name_t path_;
vector<PExpr*> parms_;
};

View File

@ -28,6 +28,7 @@
# include "netlist.h"
# include "compiler.h"
# include "discipline.h"
# include "netdarray.h"
# include "ivl_assert.h"
# include "PExpr.h"
@ -104,6 +105,9 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
case IVL_VT_STRING:
o << "string";
break;
case IVL_VT_DARRAY:
o << "darray";
break;
}
return o;
}
@ -193,11 +197,21 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const
dump_node_pins(o, ind+4);
}
static inline ostream&operator<<(ostream&out, const netrange_t&that)
{
if (that.defined())
out << "[" << that.get_msb() << ":" << that.get_lsb() << "]";
else
out << "[]";
return out;
}
ostream&operator<<(ostream&out, const list<netrange_t>&rlist)
{
for (list<netrange_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
out << "[" << cur->msb << ":" << cur->lsb << "]";
out << *cur;
}
return out;
}
@ -206,7 +220,7 @@ ostream&operator<<(ostream&out, const vector<netrange_t>&rlist)
{
for (vector<netrange_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
out << "[" << cur->msb << ":" << cur->lsb << "]";
out << *cur;
}
return out;
}
@ -244,7 +258,11 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
if (ivl_discipline_t dis = get_discipline())
o << " discipline=" << dis->name();
o << " packed dims: " << packed_dims_;
if (netdarray_t*darray = darray_type())
o << " dynamic array of " << darray->data_type();
if (!packed_dims_.empty())
o << " packed dims: " << packed_dims_;
o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")";
if (scope())
@ -1287,12 +1305,12 @@ void NetSTask::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << name_;
if (parms_.count() > 0) {
if (parms_.size() > 0) {
o << "(";
if (parms_[0])
parms_[0]->dump(o);
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
o << ", ";
if (parms_[idx])
parms_[idx]->dump(o);
@ -1422,7 +1440,7 @@ void NetEConcat::dump(ostream&o) const
else
o << "{";
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx])
o << ", " << *parms_[idx];
else

View File

@ -110,10 +110,10 @@ NetEBShift* NetEBShift::dup_expr() const
NetEConcat* NetEConcat::dup_expr() const
{
NetEConcat*dup = new NetEConcat(parms_.count(), repeat_);
NetEConcat*dup = new NetEConcat(parms_.size(), repeat_, expr_type_);
ivl_assert(*this, dup);
dup->set_line(*this);
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1)
if (parms_[idx]) {
NetExpr*tmp = parms_[idx]->dup_expr();
ivl_assert(*this, tmp);

View File

@ -29,6 +29,7 @@
# include "netenum.h"
# include "discipline.h"
# include "netmisc.h"
# include "netdarray.h"
# include "netstruct.h"
# include "util.h"
# include "ivl_assert.h"
@ -89,6 +90,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
switch (lv_type) {
case IVL_VT_REAL:
case IVL_VT_STRING:
case IVL_VT_DARRAY:
break;
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
@ -1021,6 +1023,15 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
return expr_width_;
}
if (test_width_method_(des, scope, mode)) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width "
<< "of method returns width " << expr_width_
<< ", type=" << expr_type_
<< "." << endl;
return expr_width_;
}
if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width "
<< "cannot find definition of " << path_
@ -1050,6 +1061,46 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
return 0;
}
unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
width_mode_t&mode)
{
if (!gn_system_verilog())
return 0;
// This is only useful if the path is at least 2 elements. For
// example, foo.bar() is a method, bar() is not.
if (path_.size() < 2)
return 0;
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
NetNet *net;
const NetExpr *par;
NetEvent *eve;
const NetExpr *ex1, *ex2;
symbol_search(this, des, scope, use_path,
net, par, eve, ex1, ex2);
if (net == 0)
return 0;
netdarray_t*darray = net->darray_type();
// function int size()
if (darray && method_name == "size") {
expr_type_ = IVL_VT_BOOL;
expr_width_ = 32;
min_width_ = expr_width_;
signed_flag_= true;
return expr_width_;
}
return 0;
}
NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
{
/* If the expression is a const, then replace it with a new
@ -1582,43 +1633,11 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
return elaborate_access_func_(des, scope, access_nature,
expr_wid);
// Maybe this is a method attached to an enumeration name? If
// this is system verilog, then test to see if the name is
// really a method attached to an object.
if (gn_system_verilog() && path_.size() >= 2) {
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
NetNet *net;
const NetExpr *par;
NetEvent *eve;
const NetExpr *ex1, *ex2;
symbol_search(this, des, scope, use_path,
net, par, eve, ex1, ex2);
// Check to see if we have a net and if so is it an
// enumeration? If so then check to see if this is an
// enumeration method call.
if (net != 0) {
if (netenum_t*netenum = net->enumeration()) {
// We may need the net expression for the
// enumeration variable so get it.
NetESignal*expr = new NetESignal(net);
expr->set_line(*this);
// This expression cannot be a select!
assert(use_path.back().index.empty());
PExpr*tmp = parms_.size() ? parms_[0] : 0;
return check_for_enum_methods(this, des, scope,
netenum, use_path,
method_name, expr,
expr_wid, tmp,
parms_.size());
}
}
// Maybe this is a method attached to a signal? If this
// is SystemVerilog then try that possibility.
if (gn_system_verilog()) {
NetExpr*tmp = elaborate_expr_method_(des, scope, expr_wid);
if (tmp) return tmp;
}
// Nothing was found so report this as an error.
@ -1759,6 +1778,64 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
unsigned expr_wid) const
{
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
NetNet *net;
const NetExpr *par;
NetEvent *eve;
const NetExpr *ex1, *ex2;
symbol_search(this, des, scope, use_path,
net, par, eve, ex1, ex2);
if (net == 0)
return 0;
if (net->data_type() == IVL_VT_STRING) {
if (method_name == "len") {
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$len",
IVL_VT_BOOL, 32, 1);
sys_expr->parm(0, new NetESignal(net));
return sys_expr;
}
}
if (netenum_t*netenum = net->enumeration()) {
// We may need the net expression for the
// enumeration variable so get it.
NetESignal*expr = new NetESignal(net);
expr->set_line(*this);
// This expression cannot be a select!
assert(use_path.back().index.empty());
PExpr*tmp = parms_.size() ? parms_[0] : 0;
return check_for_enum_methods(this, des, scope,
netenum, use_path,
method_name, expr,
expr_wid, tmp,
parms_.size());
}
if (net->darray_type()) {
if (method_name == "size") {
NetESFunc*sys_expr = new NetESFunc("$ivl_darray_method$size",
IVL_VT_BOOL, 32, 1);
sys_expr->parm(0, new NetESignal(net));
sys_expr->set_line(*this);
return sys_expr;
}
}
return 0;
}
unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&)
{
expr_width_ = size_;
@ -1782,15 +1859,36 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&)
{
expr_width_ = 0;
enum {NO, MAYBE, YES} expr_is_string = MAYBE;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
// Add in the width of this sub-expression.
expr_width_ += parms_[idx]->test_width(des, scope, width_modes_[idx]);
// If we already know this is not a string, then move on.
if (expr_is_string == NO)
continue;
// If this expression is a string, then the
// concatenation is a string until we find a reason to
// deny it.
if (parms_[idx]->expr_type()==IVL_VT_STRING) {
expr_is_string = YES;
continue;
}
// If this is a string literal, then this may yet be a string.
if (dynamic_cast<PEString*> (parms_[idx]))
continue;
// Failed to allow a string result.
expr_is_string = NO;
}
expr_type_ = IVL_VT_LOGIC;
expr_type_ = (expr_is_string==YES)? IVL_VT_STRING : IVL_VT_LOGIC;
signed_flag_ = false;
/* If there is a repeat expression, then evaluate the constant
value and set the repeat count. */
// If there is a repeat expression, then evaluate the constant
// value and set the repeat count.
if (repeat_ && (scope != tested_scope_)) {
NetExpr*tmp = elab_and_eval(des, scope, repeat_, -1, true);
if (tmp == 0) return 0;
@ -1919,7 +2017,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
}
/* Make the empty concat expression. */
NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_);
NetEConcat*concat = new NetEConcat(parm_cnt, repeat_count_, expr_type_);
concat->set_line(*this);
/* Remove any zero width constants. */
@ -2214,6 +2312,21 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
ivl_assert(*this, 0);
}
if (netdarray_t*darray = net? net->darray_type() : 0) {
if (use_sel == index_component_t::SEL_BIT) {
expr_type_ = darray->data_type();
expr_width_ = darray->vector_width();
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
} else {
expr_type_ = net->data_type();
expr_width_ = net->vector_width();
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
}
return expr_width_;
}
if (use_width != UINT_MAX) {
expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic
expr_width_ = use_width;
@ -2228,8 +2341,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
expr_type_ = net->data_type();
expr_width_ = net->vector_width();
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
signed_flag_ = net->get_signed();
return expr_width_;
}
@ -3386,7 +3498,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
// We want the last range, which is where we work.
const netrange_t&rng = packed.back();
if (rng.msb < rng.lsb) {
if (rng.get_msb() < rng.get_lsb()) {
offset = -wid + 1;
}
@ -3566,6 +3678,20 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
if (netdarray_t*darray = net->sig()->darray_type()) {
// Special case: This is a select of a dynamic
// array. Generate a NetESelect and attach it to
// the NetESignal. This should be interpreted as
// an array word select downstream.
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Bit select of a dynamic array becomes NetESelect." << endl;
}
NetESelect*res = new NetESelect(net, mux, darray->vector_width());
res->set_line(*net);
return res;
}
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
@ -3618,6 +3744,32 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
return res;
}
if (net->sig()->data_type()==IVL_VT_STRING && (msv < 0)) {
// Special case: This is a constant bit select of
// a string, and the index is < 0. For example:
// string foo;
// ... foo[-1] ...
// This is known to be 8'h00.
NetEConst*tmp = make_const_0(8);
tmp->set_line(*this);
delete mux;
return tmp;
}
if (net->sig()->data_type()==IVL_VT_STRING) {
// Special case: This is a select of a string
// variable. Generate a NetESelect and attach it
// to the NetESignal. This should be interpreted
// as a character select downstream.
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Bit select of string becomes NetESelect." << endl;
}
NetESelect*res = new NetESelect(net, mux, 8);
res->set_line(*net);
return res;
}
long idx = net->sig()->sb_to_idx(prefix_indices,msv);
if (idx >= (long)net->vector_width() || idx < 0) {
@ -3756,6 +3908,28 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
return node;
}
unsigned PENew::test_width(Design*des, NetScope*, width_mode_t&)
{
expr_type_ = IVL_VT_DARRAY;
expr_width_ = 1;
min_width_ = 1;
signed_flag_= false;
return 1;
}
NetExpr* PENew::elaborate_expr(Design*des, NetScope*scope,
unsigned, unsigned flags) const
{
width_mode_t mode = LOSSLESS;
unsigned use_wid = size_->test_width(des, scope, mode);
NetExpr*size = size_->elaborate_expr(des, scope, use_wid, flags);
NetESFunc*tmp = new NetESFunc("$ivl_darray_method$new",
IVL_VT_DARRAY, 1, 1);
tmp->set_line(*this);
tmp->parm(0, size);
return tmp;
}
unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode)
{
expr_type_ = IVL_VT_LOGIC;

View File

@ -257,9 +257,15 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
if (use_sel == index_component_t::SEL_BIT) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_bit_(des, scope, lv);
return lv;
if (reg->darray_type()) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_darray_bit_(des, scope, lv);
return lv;
} else {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_bit_(des, scope, lv);
return lv;
}
}
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
@ -413,6 +419,22 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
lv->set_part(mux, lwid);
}
} else if (reg->data_type() == IVL_VT_STRING) {
// Special case: This is a select of a string
// variable. The target of the assignment is a character
// select of a string. Force the r-value to be an 8bit
// vector and set the "part" to be the character select
// expression. The code generator knows what to do with
// this.
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Bit select of string becomes character select." << endl;
}
if (mux)
lv->set_part(mux, 8);
else
lv->set_part(new NetEConst(verinum(lsb)), 8);
} else if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select
@ -442,6 +464,26 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
return true;
}
bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*lv)const
{
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
// For now, only support single-dimension dynamic arrays.
ivl_assert(*this, name_tail.index.size() == 1);
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
// Evaluate the select expression...
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
lv->set_word(mux);
return true;
}
bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
@ -558,9 +600,9 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
// We want the last range, which is where we work.
const netrange_t&rng = packed.back();
if (((rng.msb < rng.lsb) &&
if (((rng.get_msb() < rng.get_lsb()) &&
use_sel == index_component_t::SEL_IDX_UP) ||
((rng.msb > rng.lsb) &&
((rng.get_msb() > rng.get_lsb()) &&
use_sel == index_component_t::SEL_IDX_DO)) {
offset = -wid + 1;
}

View File

@ -32,7 +32,9 @@
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "netenum.h"
# include "netstruct.h"
# include "netdarray.h"
# include "util.h"
# include "ivl_assert.h"
@ -821,10 +823,10 @@ static bool evaluate_ranges(Design*des, NetScope*scope,
for (list<pform_range_t>::const_iterator cur = rlist.begin()
; cur != rlist.end() ; ++cur) {
netrange_t lrng;
long use_msb, use_lsb;
NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true);
if (! eval_as_long(lrng.msb, texpr)) {
if (! eval_as_long(use_msb, texpr)) {
cerr << cur->first->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << cur->first->get_fileline() << " : "
@ -837,7 +839,7 @@ static bool evaluate_ranges(Design*des, NetScope*scope,
delete texpr;
texpr = elab_and_eval(des, scope, cur->second, -1, true);
if (! eval_as_long(lrng.lsb, texpr)) {
if (! eval_as_long(use_lsb, texpr)) {
cerr << cur->second->get_fileline() << ": error: "
"Range expressions must be constant." << endl;
cerr << cur->second->get_fileline() << " : "
@ -849,7 +851,7 @@ static bool evaluate_ranges(Design*des, NetScope*scope,
delete texpr;
llist.push_back(lrng);
llist.push_back(netrange_t(use_msb, use_lsb));
}
return bad_msb | bad_lsb;
@ -899,9 +901,9 @@ bool test_ranges_eeq(const list<netrange_t>&lef, const list<netrange_t>&rig)
list<netrange_t>::const_iterator lcur = lef.begin();
list<netrange_t>::const_iterator rcur = rig.begin();
while (lcur != lef.end()) {
if (lcur->msb != rcur->msb)
if (lcur->get_msb() != rcur->get_msb())
return false;
if (lcur->lsb != rcur->lsb)
if (lcur->get_lsb() != rcur->get_lsb())
return false;
++ lcur;
@ -1049,12 +1051,26 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
list<netrange_t>unpacked_dimensions;
netdarray_t*netarray = 0;
for (list<pform_range_t>::const_iterator cur = unpacked_.begin()
; cur != unpacked_.end() ; ++cur) {
PExpr*use_lidx = cur->first;
PExpr*use_ridx = cur->second;
assert(use_lidx && use_ridx);
// Special case: If we encounter an undefined
// dimensions, then turn this into a dynamic array and
// put all the packed dimensions there.
if (use_lidx==0 && use_ridx==0) {
ivl_assert(*this, netarray==0);
netarray = new netdarray_t(packed_dimensions, data_type_, wid);
packed_dimensions.clear();
continue;
}
// Cannot handle dynamic arrays of arrays yet.
ivl_assert(*this, netarray==0);
ivl_assert(*this, use_lidx && use_ridx);
NetExpr*lexp = elab_and_eval(des, scope, use_lidx, -1, true);
NetExpr*rexp = elab_and_eval(des, scope, use_ridx, -1, true);
@ -1157,6 +1173,34 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
sig = new NetNet(scope, name_, wtype, use_type);
} else if (enum_type_) {
ivl_assert(*this, struct_type_ == 0);
ivl_assert(*this, ! enum_type_->names->empty());
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype
<< " enumeration "
<< name_ << " in scope " << scope_path(scope) << endl;
}
sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions, use_enum);
} else if (netarray) {
ivl_assert(*this, struct_type_==0);
ivl_assert(*this, enum_type_==0);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype
<< " dynamic array "
<< name_ << " in scope " << scope_path(scope) << endl;
}
ivl_assert(*this, packed_dimensions.empty());
ivl_assert(*this, unpacked_dimensions.empty());
sig = new NetNet(scope, name_, wtype, netarray);
} else {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Create signal " << wtype;
@ -1170,16 +1214,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
sig = new NetNet(scope, name_, wtype, packed_dimensions, unpacked_dimensions);
}
// If this is an enumeration, then set the enumeration set for
// the new signal. This turns it into an enumeration.
if (enum_type_) {
ivl_assert(*this, struct_type_ == 0);
ivl_assert(*this, ! enum_type_->names->empty());
list<named_pexpr_t>::const_iterator sample_name = enum_type_->names->begin();
netenum_t*use_enum = scope->enumeration_for_name(sample_name->name);
sig->set_enumeration(use_enum);
}
if (wtype == NetNet::WIRE) sig->devirtualize_pins();
ivl_variable_type_t use_data_type = data_type_;

View File

@ -2908,7 +2908,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
if ((parm_count== 1) && (parms_[0] == 0))
parm_count = 0;
svector<NetExpr*>eparms (parm_count);
vector<NetExpr*>eparms (parm_count);
perm_string name = peek_tail_name(path_);
@ -2987,6 +2987,12 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
NetScope*task = des->find_task(scope, path_);
if (task == 0) {
// Maybe this is a method attached to a signal?
if (gn_system_verilog()) {
NetProc*tmp = elaborate_method_(des, scope);
if (tmp) return tmp;
}
cerr << get_fileline() << ": error: Enable of unknown task "
<< "``" << path_ << "''." << endl;
des->errors += 1;
@ -3169,6 +3175,39 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
return block;
}
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
{
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
NetNet *net;
const NetExpr *par;
NetEvent *eve;
const NetExpr *ex1, *ex2;
symbol_search(this, des, scope, use_path,
net, par, eve, ex1, ex2);
if (net == 0)
return 0;
// Is this a delete method for dynamic arrays?
if (net->darray_type() && method_name=="delete") {
NetESignal*sig = new NetESignal(net);
vector<NetExpr*> argv (1);
argv[0] = sig;
NetSTask*sys = new NetSTask("$ivl_darray_method$delete",
IVL_SFUNC_AS_TASK_IGNORE, argv);
sys->set_line(*this);
return sys;
}
return 0;
}
/*
* Elaborate a procedural continuous assign. This really looks very
* much like other procedural assignments, at this point, but there

View File

@ -1127,7 +1127,7 @@ NetEConst* NetEConcat::eval_tree()
}
unsigned gap = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
// Parameter not here? This is an error, but presumably
// already caught and we are here just to catch more.
@ -1178,7 +1178,7 @@ NetEConst* NetEConcat::eval_tree()
unsigned cur = 0;
bool is_string_flag = true;
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
for (unsigned idx = parms_.size() ; idx > 0 ; idx -= 1) {
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
if (expr == 0)
return 0;

View File

@ -702,11 +702,11 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, NetExpr*root)
NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
{
/* First, synthesize the operands. */
unsigned num_parms = parms_.count();
NetNet**tmp = new NetNet*[parms_.count()];
unsigned num_parms = parms_.size();
NetNet**tmp = new NetNet*[parms_.size()];
bool flag = true;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx]->expr_width() == 0) {
/* We need to synthesize a replication of zero. */
tmp[idx] = parms_[idx]->synthesize(des, scope, root);
@ -754,8 +754,8 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root)
unsigned count_input_width = 0;
unsigned cur_pin = 1;
for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
unsigned concat_item = parms_.count()-idx-1;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
unsigned concat_item = parms_.size()-idx-1;
if (tmp[concat_item] == 0) continue;
connect(concat->pin(cur_pin), tmp[concat_item]->pin(0));
cur_pin += 1;

View File

@ -435,6 +435,7 @@ typedef enum ivl_variable_type_e {
IVL_VT_BOOL = 3,
IVL_VT_LOGIC = 4,
IVL_VT_STRING = 5,
IVL_VT_DARRAY = 6, /* Array (esp. dynamic array) */
IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */
} ivl_variable_type_t;
@ -813,6 +814,14 @@ extern unsigned ivl_event_lineno(ivl_event_t net);
* conversion from signal units to vector units, so the result of
* ivl_expr_oper1 should range from 0 to ivl_expr_width().
*
* This exprsesion is also used to implement string substrings. If the
* sub-expression (oper1) is IVL_VT_STRING, then the base expression
* (oper2) is a charaster address, with 0 the first address of the
* string, 1 the second, and so on. This is OPPOSITE how a part select
* of a string cast to a vector works, to be aware. The size of the
* expression is an even multiple of 8, and is 8 times the number of
* characters to pick.
*
* - IVL_EX_SIGNAL
* This expression references a signal vector. The ivl_expr_signal
* function gets a handle for the signal that is referenced. The

View File

@ -20,6 +20,7 @@
# include "config.h"
# include "netlist.h"
# include "netdarray.h"
/*
* NetAssign
@ -84,11 +85,25 @@ ivl_select_type_t NetAssign_::select_type() const
unsigned NetAssign_::lwidth() const
{
if (netdarray_t*darray = sig_->darray_type()) {
if (word_ == 0)
return 1;
else
return darray->vector_width();
}
return lwid_;
}
ivl_variable_type_t NetAssign_::expr_type() const
{
if (netdarray_t*darray = sig_->darray_type()) {
if (word_ == 0)
return IVL_VT_DARRAY;
else
return darray->data_type();
}
return sig_->data_type();
}

View File

@ -184,18 +184,23 @@ bool NetEBShift::has_width() const
return left_->has_width();
}
NetEConcat::NetEConcat(unsigned cnt, unsigned r)
: parms_(cnt), repeat_(r)
NetEConcat::NetEConcat(unsigned cnt, unsigned r, ivl_variable_type_t vt)
: parms_(cnt), repeat_(r), expr_type_(vt)
{
expr_width(0);
}
NetEConcat::~NetEConcat()
{
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1)
delete parms_[idx];
}
ivl_variable_type_t NetEConcat::expr_type() const
{
return expr_type_;
}
bool NetEConcat::has_width() const
{
return true;
@ -203,7 +208,7 @@ bool NetEConcat::has_width() const
void NetEConcat::set(unsigned idx, NetExpr*e)
{
assert(idx < parms_.count());
assert(idx < parms_.size());
assert(parms_[idx] == 0);
parms_[idx] = e;
expr_width( expr_width() + repeat_ * e->expr_width() );

View File

@ -56,7 +56,7 @@ NexusSet* NetEConcat::nex_input(bool rem_out)
{
if (parms_[0] == NULL) return NULL;
NexusSet*result = parms_[0]->nex_input(rem_out);
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx] == NULL) {
delete result;
return NULL;
@ -397,13 +397,13 @@ NexusSet* NetRepeat::nex_input(bool rem_out)
*/
NexusSet* NetSTask::nex_input(bool rem_out)
{
if (parms_.count() == 0)
if (parms_.size() == 0)
return new NexusSet;
NexusSet*result;
if (parms_[0]) result = parms_[0]->nex_input(rem_out);
else result = new NexusSet;
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx]) {
NexusSet*tmp = parms_[idx]->nex_input(rem_out);
result->add(*tmp);

48
netarray.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef __netarray_H
#define __netarray_H
/*
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / 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 "LineInfo.h"
# include <vector>
class netarray_t : public LineInfo {
public:
explicit netarray_t(const std::list<netrange_t>&packed);
~netarray_t();
unsigned packed_width() const;
private:
std::list<netrange_t> packed_dims_;
};
inline netarray_t::netarray_t(const std::list<netrange_t>&packed)
: packed_dims_(packed)
{
}
netarray_t::~netarray_t()
{
}
#endif

32
netdarray.cc Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2012 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 "netdarray.h"
using namespace std;
netdarray_t::netdarray_t(const std::list<netrange_t>&packed,
ivl_variable_type_t type, unsigned long wid)
: packed_dims_(packed), type_(type), width_(wid)
{
}
netdarray_t::~netdarray_t()
{
}

43
netdarray.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef __netdarray_H
#define __netdarray_H
/*
* Copyright (c) 2012 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 "nettypes.h"
# include "ivl_target.h"
# include <list>
class netdarray_t : public nettype_base_t {
public:
explicit netdarray_t(const std::list<netrange_t>&packed,
ivl_variable_type_t type,
unsigned long wid);
~netdarray_t();
inline ivl_variable_type_t data_type() const { return type_; }
inline unsigned long vector_width(void) const { return width_; }
private:
std::list<netrange_t> packed_dims_;
ivl_variable_type_t type_;
unsigned long width_;
};
#endif

View File

@ -20,6 +20,7 @@
*/
# include "ivl_target.h"
# include "nettypes.h"
# include "verinum.h"
# include "StringHeap.h"
# include "LineInfo.h"
@ -28,7 +29,7 @@
class NetScope;
class netenum_t : public LineInfo {
class netenum_t : public LineInfo, public nettype_base_t {
public:
explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag,

View File

@ -27,6 +27,8 @@
# include "compiler.h"
# include "netlist.h"
# include "netmisc.h"
# include "netdarray.h"
# include "netenum.h"
# include "netstruct.h"
# include "ivl_assert.h"
@ -465,7 +467,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0),
net_type_(0), discipline_(0),
eref_count_(0), lref_count_(0),
port_index_(-1)
{
@ -515,7 +517,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
: NetObj(s, n, 1), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), struct_type_(0), discipline_(0),
net_type_(0), discipline_(0),
eref_count_(0), lref_count_(0)
{
packed_dims_ = packed;
@ -548,6 +550,11 @@ static unsigned calculate_count(const list<netrange_t>&unpacked)
unsigned long sum = 1;
for (list<netrange_t>::const_iterator cur = unpacked.begin()
; cur != unpacked.end() ; ++cur) {
// Special case: If there are any undefined dimensions,
// then give up on trying to create pins for the net.
if (! cur->defined())
return 0;
sum *= cur->width();
}
@ -559,11 +566,12 @@ static unsigned calculate_count(const list<netrange_t>&unpacked)
NetNet::NetNet(NetScope*s, perm_string n, Type t,
const list<netrange_t>&packed,
const list<netrange_t>&unpacked)
const list<netrange_t>&unpacked,
nettype_base_t*net_type)
: NetObj(s, n, calculate_count(unpacked)),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0),
is_scalar_(false), local_flag_(false), net_type_(net_type),
discipline_(0), unpacked_dims_(unpacked.size()),
eref_count_(0), lref_count_(0)
{
@ -577,7 +585,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
ivl_assert(*this, s);
if (pin_count() == 0) {
cerr << "Array too big " << unpacked << endl;
cerr << "Invalid array dimensions: " << unpacked << endl;
ivl_assert(*this, 0);
}
@ -621,7 +629,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty),
is_scalar_(false), local_flag_(false), net_type_(ty),
discipline_(0),
eref_count_(0), lref_count_(0)
{
@ -648,6 +656,36 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
s->add_signal(this);
}
NetNet::NetNet(NetScope*s, perm_string n, Type t, netdarray_t*ty)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), net_type_(ty),
discipline_(0),
eref_count_(0), lref_count_(0)
{
Link::DIR dir = Link::PASSIVE;
switch (t) {
case REG:
case IMPLICIT_REG:
dir = Link::OUTPUT;
break;
case SUPPLY0:
dir = Link::OUTPUT;
break;
case SUPPLY1:
dir = Link::OUTPUT;
break;
default:
break;
}
initialize_dir_(dir);
s->add_signal(this);
}
NetNet::~NetNet()
{
if (eref_count_ > 0) {
@ -769,19 +807,17 @@ void NetNet::set_scalar(bool flag)
netenum_t*NetNet::enumeration(void) const
{
return enumeration_;
}
void NetNet::set_enumeration(netenum_t*es)
{
ivl_assert(*this, struct_type_ == 0);
ivl_assert(*this, enumeration_ == 0);
enumeration_ = es;
return dynamic_cast<netenum_t*> (net_type_);
}
netstruct_t*NetNet::struct_type(void) const
{
return struct_type_;
return dynamic_cast<netstruct_t*> (net_type_);
}
netdarray_t* NetNet::darray_type(void) const
{
return dynamic_cast<netdarray_t*> (net_type_);
}
ivl_discipline_t NetNet::get_discipline() const
@ -800,10 +836,10 @@ bool NetNet::sb_is_valid(const list<long>&indices, long sb) const
ivl_assert(*this, indices.size()+1 == packed_dims_.size());
assert(packed_dims_.size() == 1);
const netrange_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
return (sb <= rng.msb) && (sb >= rng.lsb);
if (rng.get_msb() >= rng.get_lsb())
return (sb <= rng.get_msb()) && (sb >= rng.get_lsb());
else
return (sb <= rng.lsb) && (sb >= rng.msb);
return (sb <= rng.get_lsb()) && (sb >= rng.get_msb());
}
long NetNet::sb_to_idx(const list<long>&indices, long sb) const
@ -815,10 +851,10 @@ long NetNet::sb_to_idx(const list<long>&indices, long sb) const
long acc_off;
long acc_wid = pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off = sb - pcur->lsb;
if (pcur->get_msb() >= pcur->get_lsb())
acc_off = sb - pcur->get_lsb();
else
acc_off = pcur->lsb - sb;
acc_off = pcur->get_lsb() - sb;
// The acc_off is the possition within the innermost
// dimension. If this is a multi-dimension packed array then
@ -830,10 +866,10 @@ long NetNet::sb_to_idx(const list<long>&indices, long sb) const
-- pcur;
long tmp_off;
if (pcur->msb >= pcur->lsb)
tmp_off = *icur - pcur->lsb;
if (pcur->get_msb() >= pcur->get_lsb())
tmp_off = *icur - pcur->get_lsb();
else
tmp_off = pcur->lsb - *icur;
tmp_off = pcur->get_lsb() - *icur;
acc_off += tmp_off * acc_wid;
acc_wid *= pcur->width();
@ -2053,7 +2089,7 @@ const NetNet* NetFuncDef::return_sig() const
}
NetSTask::NetSTask(const char*na, ivl_sfunc_as_task_t sfat,
const svector<NetExpr*>&pa)
const vector<NetExpr*>&pa)
: name_(0), sfunc_as_task_(sfat), parms_(pa)
{
name_ = lex_strings.add(na);
@ -2062,7 +2098,7 @@ NetSTask::NetSTask(const char*na, ivl_sfunc_as_task_t sfat,
NetSTask::~NetSTask()
{
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1)
delete parms_[idx];
/* The name_ string is perm-allocated in lex_strings. */
@ -2080,7 +2116,7 @@ ivl_sfunc_as_task_t NetSTask::sfunc_as_task() const
unsigned NetSTask::nparms() const
{
return parms_.count();
return parms_.size();
}
const NetExpr* NetSTask::parm(unsigned idx) const
@ -2399,19 +2435,22 @@ long NetESignal::lsi() const
{
const list<netrange_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().lsb;
return packed.back().get_lsb();
}
long NetESignal::msi() const
{
const list<netrange_t>&packed = net_->packed_dims();
ivl_assert(*this, packed.size() == 1);
return packed.back().msb;
return packed.back().get_msb();
}
ivl_variable_type_t NetESignal::expr_type() const
{
return net_->data_type();
if (net_->darray_type())
return IVL_VT_DARRAY;
else
return net_->data_type();
}
/*

View File

@ -76,6 +76,7 @@ class NetEvTrig;
class NetEvWait;
class PExpr;
class PFunction;
class netdarray_t;
class netenum_t;
class netstruct_t;
@ -607,10 +608,12 @@ class NetNet : public NetObj, public PortType {
const std::list<netrange_t>&packed);
explicit NetNet(NetScope*s, perm_string n, Type t,
const std::list<netrange_t>&packed,
const std::list<netrange_t>&unpacked);
const std::list<netrange_t>&unpacked,
nettype_base_t*type =0);
// This form builds a NetNet from its record definition.
// This form builds a NetNet from its record/enum definition.
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_t*type);
virtual ~NetNet();
@ -641,10 +644,9 @@ class NetNet : public NetObj, public PortType {
bool get_scalar() const;
void set_scalar(bool);
void set_enumeration(netenum_t*enum_set);
netenum_t*enumeration(void) const;
netstruct_t*struct_type(void) const;
netdarray_t*darray_type(void) const;
/* Attach a discipline to the net. */
ivl_discipline_t get_discipline() const;
@ -730,8 +732,7 @@ class NetNet : public NetObj, public PortType {
bool isint_ : 1; // original type of integer
bool is_scalar_ : 1;
bool local_flag_: 1;
netenum_t*enumeration_;
netstruct_t*struct_type_;
nettype_base_t*net_type_;
ivl_discipline_t discipline_;
std::list<netrange_t> packed_dims_;
@ -3190,7 +3191,7 @@ class NetSTask : public NetProc {
public:
NetSTask(const char*na, ivl_sfunc_as_task_t sfat,
const svector<NetExpr*>&);
const std::vector<NetExpr*>&);
~NetSTask();
const char* name() const;
@ -3208,7 +3209,7 @@ class NetSTask : public NetProc {
private:
const char* name_;
ivl_sfunc_as_task_t sfunc_as_task_;
svector<NetExpr*>parms_;
std::vector<NetExpr*>parms_;
};
/*
@ -3747,16 +3748,17 @@ class NetEBShift : public NetEBinary {
class NetEConcat : public NetExpr {
public:
NetEConcat(unsigned cnt, unsigned repeat =1);
NetEConcat(unsigned cnt, unsigned repeat, ivl_variable_type_t vt);
~NetEConcat();
// Manipulate the parameters.
void set(unsigned idx, NetExpr*e);
unsigned repeat() const { return repeat_; }
unsigned nparms() const { return parms_.count() ; }
unsigned nparms() const { return parms_.size() ; }
NetExpr* parm(unsigned idx) const { return parms_[idx]; }
virtual ivl_variable_type_t expr_type() const;
virtual NexusSet* nex_input(bool rem_out = true);
virtual bool has_width() const;
virtual NetEConcat* dup_expr() const;
@ -3766,8 +3768,9 @@ class NetEConcat : public NetExpr {
virtual void dump(ostream&) const;
private:
svector<NetExpr*>parms_;
std::vector<NetExpr*>parms_;
unsigned repeat_;
ivl_variable_type_t expr_type_;
};

View File

@ -325,7 +325,7 @@ NetExpr *normalize_variable_base(NetExpr *base,
{
ivl_assert(*base, dims.size() == 1);
const netrange_t&rng = dims.back();
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up);
return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), wid, is_up);
}
NetExpr *normalize_variable_bit_base(const list<long>&indices, NetExpr*base,
@ -338,9 +338,9 @@ NetExpr *normalize_variable_bit_base(const list<long>&indices, NetExpr*base,
// addressing. We need that address as a slice offset to
// calculate the proper complete address
const netrange_t&rng = packed_dims.back();
long slice_off = reg->sb_to_idx(indices, rng.lsb);
long slice_off = reg->sb_to_idx(indices, rng.get_lsb());
return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off);
return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), 1, true, slice_off);
}
NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*base,
@ -354,9 +354,9 @@ NetExpr *normalize_variable_part_base(const list<long>&indices, NetExpr*base,
// addressing. We need that address as a slice offset to
// calculate the proper complete address
const netrange_t&rng = packed_dims.back();
long slice_off = reg->sb_to_idx(indices, rng.lsb);
long slice_off = reg->sb_to_idx(indices, rng.get_lsb());
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off);
return normalize_variable_base(base, rng.get_msb(), rng.get_lsb(), wid, is_up, slice_off);
}
NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
@ -371,10 +371,10 @@ NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
}
long sb;
if (pcur->msb >= pcur->lsb)
sb = pcur->lsb;
if (pcur->get_msb() >= pcur->get_lsb())
sb = pcur->get_lsb();
else
sb = pcur->msb;
sb = pcur->get_msb();
long loff;
reg->sb_to_slice(indices, sb, loff, lwid);
@ -492,10 +492,10 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<long>&indices)
; cur != indices.end() ; ++cur, ++idx) {
long tmp = *cur;
if (dims[idx].lsb <= dims[idx].msb)
tmp -= dims[idx].lsb;
if (dims[idx].get_lsb() <= dims[idx].get_msb())
tmp -= dims[idx].get_lsb();
else
tmp -= dims[idx].msb;
tmp -= dims[idx].get_msb();
// Notice of this index is out of range.
if (tmp < 0 || tmp >= (long)dims[idx].width()) {
@ -531,15 +531,17 @@ NetExpr* normalize_variable_unpacked(const NetNet*net, list<NetExpr*>&indices)
return 0;
int64_t use_base;
if (dims[idx].lsb <= dims[idx].msb)
use_base = dims[idx].lsb;
if (! dims[idx].defined())
use_base = 0;
else if (dims[idx].get_lsb() <= dims[idx].get_msb())
use_base = dims[idx].get_lsb();
else
use_base = dims[idx].msb;
use_base = dims[idx].get_msb();
int64_t use_stride = stride[idx];
// Account for that we are doing arithmatic and should
// have a proper width to make sure there ar no
// have a proper width to make sure there are no
// losses. So calculate a min_wid width.
unsigned tmp_wid;
unsigned min_wid = tmp->expr_width();

View File

@ -24,7 +24,7 @@
# include "ivl_target.h"
# include "nettypes.h"
class netstruct_t : public LineInfo {
class netstruct_t : public LineInfo, public nettype_base_t {
public:
struct member_t {

View File

@ -22,16 +22,16 @@
using namespace std;
nettype_base_t::~nettype_base_t()
{
}
unsigned long netrange_width(const list<netrange_t>&packed)
{
unsigned wid = 1;
for (list<netrange_t>::const_iterator cur = packed.begin()
; cur != packed.end() ; ++cur) {
unsigned use_wid;
if (cur->msb >= cur->lsb)
use_wid = cur->msb - cur->lsb + 1;
else
use_wid = cur->lsb - cur->msb + 1;
unsigned use_wid = cur->width();
wid *= use_wid;
}
@ -60,16 +60,16 @@ bool prefix_to_slice(const std::list<netrange_t>&dims,
lwid = acc_wid;
-- pcur;
if (sb < pcur->msb && sb < pcur->lsb)
if (sb < pcur->get_msb() && sb < pcur->get_lsb())
return false;
if (sb > pcur->msb && sb > pcur->lsb)
if (sb > pcur->get_msb() && sb > pcur->get_lsb())
return false;
long acc_off = 0;
if (pcur->msb >= pcur->lsb)
acc_off += (sb - pcur->lsb) * acc_wid;
if (pcur->get_msb() >= pcur->get_lsb())
acc_off += (sb - pcur->get_lsb()) * acc_wid;
else
acc_off += (sb - pcur->msb) * acc_wid;
acc_off += (sb - pcur->get_msb()) * acc_wid;
if (prefix.size() == 0) {
loff = acc_off;
@ -83,10 +83,10 @@ bool prefix_to_slice(const std::list<netrange_t>&dims,
-- pcur;
-- icur;
acc_wid *= pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off += (*icur - pcur->lsb) * acc_wid;
if (pcur->get_msb() >= pcur->get_lsb())
acc_off += (*icur - pcur->get_lsb()) * acc_wid;
else
acc_off += (*icur - pcur->msb) * acc_wid;
acc_off += (*icur - pcur->get_msb()) * acc_wid;
} while (icur != prefix.begin());

View File

@ -20,25 +20,48 @@
*/
# include <list>
# include <climits>
# include <cassert>
/*
* This is a fully abstract type that is a type that can be attached
* to a NetNet object.
*/
class nettype_base_t {
public:
virtual ~nettype_base_t() =0;
};
class netrange_t {
public:
inline netrange_t() : msb(0), lsb(0) { }
inline netrange_t(long m, long l) : msb(m), lsb(l) { }
// Create an undefined range. An undefined range is a range
// used to declare dynamic arrays, etc.
inline netrange_t() : msb_(LONG_MAX), lsb_(LONG_MAX) { }
// Create a properly defined netrange
inline netrange_t(long m, long l) : msb_(m), lsb_(l) { }
// Copy constructure.
inline netrange_t(const netrange_t&that)
: msb(that.msb), lsb(that.lsb) { }
: msb_(that.msb_), lsb_(that.lsb_) { }
inline netrange_t& operator = (const netrange_t&that)
{ msb = that.msb; lsb = that.lsb; return *this; }
{ msb_ = that.msb_; lsb_ = that.lsb_; return *this; }
public:
long msb;
long lsb;
inline bool defined() const
{ return msb_!=LONG_MAX || msb_!= LONG_MAX; }
inline unsigned long width()const
{ if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; }
{ if (!defined()) return 0;
else if (msb_ >= lsb_) return msb_-lsb_+1;
else return lsb_-msb_+1;
}
inline long get_msb() const { assert(defined()); return msb_; }
inline long get_lsb() const { assert(defined()); return lsb_; }
private:
long msb_;
long lsb_;
};
extern unsigned long netrange_width(const std::list<netrange_t>&dims);

16
parse.y
View File

@ -898,8 +898,9 @@ data_type /* IEEE1800-2005: A.2.2.1 */
else $$ = $1;
}
| K_string
{ yyerror(@1, "sorry: String data type not supported.");
$$ = 0;
{ string_type_t*tmp = new string_type_t;
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
@ -937,12 +938,14 @@ endnew_opt : ':' K_new | ;
dynamic_array_new /* IEEE1800-2005: A.2.4 */
: K_new '[' expression ']'
{ yyerror(@1, "sorry: Dynamic array new expression not supported.");
$$ = 0;
{ $$ = new PENew($3);
FILE_NAME($$, @1);
}
| K_new '[' expression ']' '(' expression ')'
{ yyerror(@1, "sorry: Dynamic array new expression not supported.");
$$ = 0;
{ yyerror(@1, "sorry: Dynamic array new expression with initializer not supported.");
delete $6;
$$ = new PENew($3);
FILE_NAME($$, @1);
}
;
@ -1741,7 +1744,6 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
| '[' ']'
{ list<pform_range_t> *tmp = new list<pform_range_t>;
pform_range_t index (0,0);
yyerror("sorry: Dynamic array ranges not supported.");
tmp->push_back(index);
$$ = tmp;
}

View File

@ -2829,6 +2829,11 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list<pe
return;
}
if (string_type_t*string_type = dynamic_cast<string_type_t*> (data_type)) {
pform_set_string_type(string_type, names, attr);
return;
}
assert(0);
}

View File

@ -310,6 +310,8 @@ extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, std::list<named_pexpr_t>*attr);
extern void pform_set_string_type(string_type_t*string_type, std::list<perm_string>*names, std::list<named_pexpr_t>*attr);
/* pform_set_attrib and pform_set_type_attrib exist to support the
$attribute syntax, which can only set string values to
attributes. The functions keep the value strings that are

View File

@ -233,6 +233,11 @@ void PEFNumber::dump(ostream &out) const
out << value();
}
void PENew::dump(ostream&out) const
{
out << "new [" << *size_ << "]";
}
void PENumber::dump(ostream&out) const
{
out << value();

37
pform_string_type.cc Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2012 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 "pform.h"
# include "parse_misc.h"
# include "ivl_assert.h"
static void pform_set_string_type(string_type_t*string_type, perm_string name, list<named_pexpr_t>*attr)
{
PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_STRING);
pform_bind_attributes(net->attributes, attr, true);
}
void pform_set_string_type(string_type_t*string_type, list<perm_string>*names, list<named_pexpr_t>*attr)
{
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur) {
pform_set_string_type(string_type, *cur, attr);
}
}

View File

@ -23,3 +23,7 @@
data_type_t::~data_type_t()
{
}
string_type_t::~string_type_t()
{
}

View File

@ -156,6 +156,11 @@ struct real_type_t : public data_type_t {
type_t type_code;
};
struct string_type_t : public data_type_t {
inline explicit string_type_t() { }
~string_type_t();
};
struct class_type_t : public data_type_t {
inline explicit class_type_t(perm_string n)
: name(n) { }

View File

@ -48,7 +48,9 @@ EXTERN_C_START
#define vpiIntVar 612
#define vpiByteVar 614
#define vpiLogicVar vpiReg
#define vpiStringVar 616
#define vpiBitVar 620
#define vpiArrayVar vpiRegArray
/********* TYPESPECS *************/
#define vpiEnumTypespec 633

View File

@ -2049,13 +2049,13 @@ extern "C" ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx)
extern "C" unsigned ivl_scope_sigs(ivl_scope_t net)
{
assert(net);
return net->nsigs_;
return net->sigs_.size();
}
extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
{
assert(net);
assert(idx < net->nsigs_);
assert(idx < net->sigs_.size());
return net->sigs_[idx];
}
@ -2196,13 +2196,13 @@ extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net)
extern "C" int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim)
{
assert(dim < net->packed_dims.size());
return net->packed_dims[dim].msb;
return net->packed_dims[dim].get_msb();
}
extern "C" int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim)
{
assert(dim < net->packed_dims.size());
return net->packed_dims[dim].lsb;
return net->packed_dims[dim].get_lsb();
}
extern "C" int ivl_signal_msb(ivl_signal_t net)
@ -2211,7 +2211,7 @@ extern "C" int ivl_signal_msb(ivl_signal_t net)
return 0;
assert(net->packed_dims.size() == 1);
return net->packed_dims[0].msb;
return net->packed_dims[0].get_msb();
}
extern "C" int ivl_signal_lsb(ivl_signal_t net)
@ -2220,7 +2220,7 @@ extern "C" int ivl_signal_lsb(ivl_signal_t net)
return 0;
assert(net->packed_dims.size() == 1);
return net->packed_dims[0].lsb;
return net->packed_dims[0].get_lsb();
}
extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net)

View File

@ -200,7 +200,7 @@ void dll_target::expr_concat(const NetEConcat*net)
assert(cur);
cur->type_ = IVL_EX_CONCAT;
cur->value_ = IVL_VT_VECTOR;
cur->value_ = net->expr_type();
cur->width_ = net->expr_width();
cur->signed_ = net->has_sign() ? 1 : 0;
cur->sized_ = 1;

View File

@ -257,7 +257,7 @@ ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net)
perm_string nname = net->name();
for (unsigned idx = 0 ; idx < scope->nsigs_ ; idx += 1) {
for (unsigned idx = 0 ; idx < scope->sigs_.size() ; idx += 1) {
if (strcmp(scope->sigs_[idx]->name_, nname) == 0)
return scope->sigs_[idx];
}
@ -533,8 +533,6 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s)
root_->name_ = name;
FILE_NAME(root_, s);
root_->parent = 0;
root_->nsigs_ = 0;
root_->sigs_ = 0;
root_->nlog_ = 0;
root_->log_ = 0;
root_->nevent_ = 0;
@ -2280,8 +2278,6 @@ void dll_target::scope(const NetScope*net)
scop->parent = find_scope(des_, net->parent());
assert(scop->parent);
scop->parent->children[net->fullname()] = scop;
scop->nsigs_ = 0;
scop->sigs_ = 0;
scop->nlog_ = 0;
scop->log_ = 0;
scop->nevent_ = 0;
@ -2371,20 +2367,7 @@ void dll_target::signal(const NetNet*net)
assert(obj->scope_);
FILE_NAME(obj, net);
if (obj->scope_->nsigs_ == 0) {
assert(obj->scope_->sigs_ == 0);
obj->scope_->nsigs_ = 1;
obj->scope_->sigs_ = (ivl_signal_t*)malloc(sizeof(ivl_signal_t));
} else {
assert(obj->scope_->sigs_);
obj->scope_->nsigs_ += 1;
obj->scope_->sigs_ = (ivl_signal_t*)
realloc(obj->scope_->sigs_,
obj->scope_->nsigs_*sizeof(ivl_signal_t));
}
obj->scope_->sigs_[obj->scope_->nsigs_-1] = obj;
obj->scope_->sigs_.push_back(obj);
/* Save the primitive properties of the signal in the
@ -2490,6 +2473,10 @@ void dll_target::signal(const NetNet*net)
obj->nattr = net->attr_cnt();
obj->attr = fill_in_attributes(net);
/* If this is a dynamic array, then set the type to DARRAY. */
if (net->darray_type()) {
obj->data_type = IVL_VT_DARRAY;
}
/* Get the nexus objects for all the pins of the signal. If
the signal has only one pin, then write the single
@ -2502,11 +2489,11 @@ void dll_target::signal(const NetNet*net)
if (obj->array_dimensions_ == 1) {
const vector<netrange_t>& dims = net->unpacked_dims();
if (dims[0].msb < dims[0].lsb) {
obj->array_base = dims[0].msb;
if (dims[0].get_msb() < dims[0].get_lsb()) {
obj->array_base = dims[0].get_msb();
obj->array_addr_swapped = false;
} else {
obj->array_base = dims[0].lsb;
obj->array_base = dims[0].get_lsb();
obj->array_addr_swapped = true;
}
obj->array_words = net->unpacked_count();

View File

@ -627,8 +627,7 @@ struct ivl_scope_s {
std::vector<ivl_enumtype_t> enumerations_;
unsigned nsigs_;
ivl_signal_t*sigs_;
std::vector<ivl_signal_t> sigs_;
unsigned nlog_;
ivl_net_logic_t*log_;

View File

@ -165,6 +165,42 @@ static void show_memory_expression(ivl_expr_t net, unsigned ind)
width);
}
static void show_select_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
ivl_expr_t oper1 = ivl_expr_oper1(net);
ivl_expr_t oper2 = ivl_expr_oper2(net);
if (ivl_expr_value(oper1) == IVL_VT_STRING) {
/* If the sub-expression is a STRING, then this is a
substring and the code generator will handle it
differently. */
fprintf(out, "%*s<substring: width=%u bits, %u bytes>\n", ind, "", width, width/8);
if (width%8 != 0)
fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, "");
show_expression(oper1, ind+3);
show_expression(oper2, ind+3);
} else if (oper2) {
/* If oper2 is present, then it is the base of a part
select. The width of the expression defines the range
of the part select. */
fprintf(out, "%*s<select: width=%u, %s>\n", ind, "",
width, sign);
show_expression(oper1, ind+3);
show_expression(oper2, ind+3);
} else {
/* There is no base expression so this is a pad
operation. The sub-expression is padded (signed or
unsigned as appropriate) to the expression width. */
fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "",
width, sign);
show_expression(oper1, ind+3);
}
}
static void show_signal_expression(ivl_expr_t net, unsigned ind)
{
unsigned width = ivl_expr_width(net);
@ -173,6 +209,7 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind)
ivl_expr_t word = ivl_expr_oper1(net);
ivl_signal_t sig = ivl_expr_signal(net);
const char*vt_sig = data_type_string(ivl_signal_data_type(sig));
unsigned dimensions = ivl_signal_dimensions(sig);
unsigned word_count = ivl_signal_array_count(sig);
@ -182,8 +219,8 @@ static void show_signal_expression(ivl_expr_t net, unsigned ind)
stub_errors += 1;
}
fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s>\n", ind, "",
ivl_expr_name(net), word_count, width, sign, vt);
fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s (%s)>\n", ind, "",
ivl_expr_name(net), word_count, width, sign, vt, vt_sig);
/* If the expression refers to a signal array, then there must
also be a word select expression, and if the signal is not an
@ -312,18 +349,7 @@ void show_expression(ivl_expr_t net, unsigned ind)
}
case IVL_EX_SELECT:
/* The SELECT expression can be used to express part
select, or if the base is null vector extension. */
if (ivl_expr_oper2(net)) {
fprintf(out, "%*s<select: width=%u, %s>\n", ind, "",
width, sign);
show_expression(ivl_expr_oper1(net), ind+3);
show_expression(ivl_expr_oper2(net), ind+3);
} else {
fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "",
width, sign);
show_expression(ivl_expr_oper1(net), ind+3);
}
show_select_expression(net, ind);
break;
case IVL_EX_STRING:

View File

@ -21,10 +21,36 @@
# include "priv.h"
# include <assert.h>
/*
* If the l-value signal is a darray object, then the ivl_lval_mux()
* gets you the array index expression.
*/
static unsigned show_assign_lval_darray(ivl_lval_t lval, unsigned ind)
{
ivl_signal_t sig = ivl_lval_sig(lval);
assert(sig);
if (ivl_lval_idx(lval)) {
fprintf(out, "%*sAddress-0 select of dynamic array:\n", ind+4, "");
show_expression(ivl_lval_idx(lval), ind+6);
}
if (ivl_lval_mux(lval)) {
fprintf(out, "%*sERROR: unexpected ivl_lval_mux() expression:\n", ind+4, "");
stub_errors += 1;
show_expression(ivl_lval_mux(lval), ind+6);
}
if (ivl_lval_part_off(lval)) {
fprintf(out, "%*sERROR: unexpected Part select expression:\n", ind+4, "");
stub_errors += 1;
show_expression(ivl_lval_part_off(lval), ind+8);
}
return ivl_lval_width(lval);
}
static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind)
{
unsigned wid = 0;
ivl_signal_t sig = ivl_lval_sig(lval);
assert(sig);
@ -34,6 +60,10 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind)
ivl_signal_width(sig),
ivl_lval_width(lval));
/* Special case: target signal is a darray. */
if (ivl_signal_data_type(sig) == IVL_VT_DARRAY)
return show_assign_lval_darray(lval, ind);
if (ivl_lval_idx(lval)) {
fprintf(out, "%*sAddress-0 select expression:\n", ind+4, "");
show_expression(ivl_lval_idx(lval), ind+6);
@ -59,9 +89,7 @@ static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind)
show_expression(ivl_lval_part_off(lval), ind+8);
}
wid = ivl_lval_width(lval);
return wid;
return ivl_lval_width(lval);
}
static void show_stmt_cassign(ivl_statement_t net, unsigned ind)

View File

@ -169,6 +169,9 @@ const char*data_type_string(ivl_variable_type_t vtype)
case IVL_VT_STRING:
vt = "string";
break;
case IVL_VT_DARRAY:
vt = "darray";
break;
}
return vt;
@ -1260,22 +1263,29 @@ static void show_signal(ivl_signal_t net)
break;
}
data_type = "?data?";
switch (ivl_signal_data_type(net)) {
case IVL_VT_NO_TYPE:
data_type = "<no-type>";
break;
case IVL_VT_BOOL:
data_type = "bool";
break;
case IVL_VT_LOGIC:
data_type = "logic";
break;
case IVL_VT_REAL:
data_type = "real";
break;
default:
data_type = "?data?";
case IVL_VT_STRING:
data_type = "string";
break;
case IVL_VT_DARRAY:
data_type = "darray";
break;
case IVL_VT_VOID:
data_type = "void";
break;
}
@ -1358,6 +1368,15 @@ static void show_signal(ivl_signal_t net)
}
}
switch (ivl_signal_data_type(net)) {
case IVL_VT_NO_TYPE:
case IVL_VT_VOID:
fprintf(out, " ERROR: Invalid type for signal: %s\n", data_type);
stub_errors += 1;
break;
default:
break;
}
}
void test_expr_is_delay(ivl_expr_t expr)

View File

@ -49,7 +49,8 @@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@
LDFLAGS = @LDFLAGS@
O = vvp.o draw_enum.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 stmt_assign.o vector.o \
eval_bool.o eval_expr.o eval_object.o eval_real.o eval_string.o \
modpath.o stmt_assign.o vector.o \
vvp_process.o vvp_scope.o
all: dep vvp.tgt vvp.conf vvp-s.conf

View File

@ -31,6 +31,9 @@ struct args_info {
char*text;
int vec_flag; /* True if the vec must be released. */
struct vector_info vec;
/* String Stack position if this argument is a calculated string. */
int str_flag;
unsigned str_stack;
struct args_info *child; /* Arguments can be nested. */
};
@ -178,6 +181,18 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL &&
ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0;
/* If the expression is a substring expression, then
the xPV method of passing the argument will not work
and we have to resort to the default method. */
if (ivl_expr_value(vexpr) == IVL_VT_STRING)
return 0;
/* If the sub-expression is a DARRAY, then this select
is a dynamic-array word select. Handle that
elsewhere. */
if (ivl_expr_value(vexpr) == IVL_VT_DARRAY)
return 0;
/* The signal is part of an array. */
/* Add &APV<> code here when it is finished. */
bexpr = ivl_expr_oper2(expr);
@ -265,6 +280,11 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_parameter_t par;
/* Keep track of how much string stack this function call is
going to need. We'll need this for making stack references,
and also to clean out the stack when done. */
unsigned str_stack_need = 0;
/* Figure out how many expressions are going to be evaluated
for this task call. I won't need to evaluate expressions
for items that are VPI objects directly. */
@ -376,7 +396,17 @@ static void draw_vpi_taskfunc_args(const char*call_string,
"W<%u,r>", args[idx].vec.base);
break;
case IVL_VT_STRING:
/* STRING expressions not supported yet. */
/* Eval the string into the stack, and tell VPI
about the stack position. */
draw_eval_string(expr);
args[idx].vec_flag = 0;
args[idx].vec.base = 0;
args[idx].vec.wid = 0;
args[idx].str_flag = 1;
args[idx].str_stack = str_stack_need;
str_stack_need += 1;
buffer[0] = 0;
break;
default:
assert(0);
}
@ -388,7 +418,16 @@ static void draw_vpi_taskfunc_args(const char*call_string,
for (idx = 0 ; idx < parm_count ; idx += 1) {
struct args_info*ptr;
fprintf(vvp_out, ", %s", args[idx].text);
if (args[idx].str_flag) {
/* If this is a string stack reference, then
calculate the stack depth and use that to
generate the completed string. */
unsigned pos = str_stack_need - args[idx].str_stack - 1;
fprintf(vvp_out, ", S<%u,str>",pos);
} else {
fprintf(vvp_out, ", %s", args[idx].text);
}
free(args[idx].text);
/* Clear the nested children vectors. */
for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) {
@ -409,6 +448,9 @@ static void draw_vpi_taskfunc_args(const char*call_string,
free(args);
fprintf(vvp_out, ";\n");
if (str_stack_need > 0)
fprintf(vvp_out, " %%pop/str %u;\n", str_stack_need);
}
void draw_vpi_task_call(ivl_statement_t tnet)

View File

@ -459,6 +459,39 @@ static struct vector_info draw_binary_expr_eq_real(ivl_expr_t expr)
return res;
}
static struct vector_info draw_binary_expr_eq_string(ivl_expr_t expr)
{
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
struct vector_info res;
res.base = allocate_vector(1);
res.wid = 1;
assert(res.base);
draw_eval_string(le);
draw_eval_string(re);
fprintf(vvp_out, " %%cmp/str;\n");
switch (ivl_expr_opcode(expr)) {
case 'e': /* == */
fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base);
break;
case 'n': /* != */
fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base);
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
break;
default:
assert(0);
}
return res;
}
static struct vector_info draw_binary_expr_eq(ivl_expr_t expr,
unsigned ewid,
int stuff_ok_flag)
@ -476,13 +509,30 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr,
return draw_binary_expr_eq_real(expr);
}
if ((ivl_expr_value(le) == IVL_VT_STRING)
&& (ivl_expr_value(re) == IVL_VT_STRING)) {
return draw_binary_expr_eq_string(expr);
}
if ((ivl_expr_value(le) == IVL_VT_STRING)
&& (ivl_expr_type(re) == IVL_EX_STRING)) {
return draw_binary_expr_eq_string(expr);
}
if ((ivl_expr_type(le) == IVL_EX_STRING)
&& (ivl_expr_value(re) == IVL_VT_STRING)) {
return draw_binary_expr_eq_string(expr);
}
if (number_is_immediate(re,16,0) && !number_is_unknown(re))
return draw_eq_immediate(expr, ewid, le, re, stuff_ok_flag);
assert(ivl_expr_value(le) == IVL_VT_LOGIC
|| ivl_expr_value(le) == IVL_VT_BOOL);
|| ivl_expr_value(le) == IVL_VT_BOOL
|| ivl_expr_value(le) == IVL_VT_STRING);
assert(ivl_expr_value(re) == IVL_VT_LOGIC
|| ivl_expr_value(re) == IVL_VT_BOOL);
|| ivl_expr_value(re) == IVL_VT_BOOL
|| ivl_expr_value(re) == IVL_VT_STRING);
wid = ivl_expr_width(le);
if (ivl_expr_width(re) > wid)
@ -825,6 +875,57 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t expr)
return res;
}
static struct vector_info draw_binary_expr_le_string(ivl_expr_t expr)
{
struct vector_info res;
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
res.base = allocate_vector(1);
res.wid = 1;
assert(res.base);
/* The %cmp/str function implements < and <= operands. To get
the > and >= results, simply switch the order of the
operands. */
switch (ivl_expr_opcode(expr)) {
case '<':
case 'L':
draw_eval_string(le);
draw_eval_string(re);
break;
case '>':
case 'G':
draw_eval_string(re);
draw_eval_string(le);
break;
default:
assert(0);
}
switch (ivl_expr_opcode(expr)) {
case '<':
case '>':
fprintf(vvp_out, " %%cmp/str;\n");
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
break;
case 'L': /* <= */
case 'G': /* >= */
fprintf(vvp_out, " %%cmp/str;\n");
fprintf(vvp_out, " %%or 5, 4, 1;\n");
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
break;
default:
assert(0);
}
return res;
}
static struct vector_info draw_binary_expr_le_bool(ivl_expr_t expr,
unsigned wid)
{
@ -919,6 +1020,21 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
return draw_binary_expr_le_bool(expr, wid);
}
if ((ivl_expr_value(le) == IVL_VT_STRING)
&& (ivl_expr_value(re) == IVL_VT_STRING)) {
return draw_binary_expr_le_string(expr);
}
if ((ivl_expr_value(le) == IVL_VT_STRING)
&& (ivl_expr_type(re) == IVL_EX_STRING)) {
return draw_binary_expr_le_string(expr);
}
if ((ivl_expr_type(le) == IVL_EX_STRING)
&& (ivl_expr_value(re) == IVL_VT_STRING)) {
return draw_binary_expr_eq_string(expr);
}
assert(ivl_expr_value(le) == IVL_VT_LOGIC
|| ivl_expr_value(le) == IVL_VT_BOOL);
assert(ivl_expr_value(re) == IVL_VT_LOGIC
@ -2646,6 +2762,25 @@ static struct vector_info draw_select_unsized_literal(ivl_expr_t expr,
return res;
}
static void draw_select_string_dest(ivl_expr_t expr, struct vector_info res)
{
ivl_expr_t sube = ivl_expr_oper1(expr);
ivl_expr_t shift = ivl_expr_oper2(expr);
int shift_i;
draw_eval_string(sube);
shift_i = allocate_word();
draw_eval_expr_into_integer(shift, shift_i);
assert(res.wid % 8 == 0);
clr_word(shift_i);
fprintf(vvp_out, " %%substr/v %u, %d, %u;\n", res.base, shift_i, res.wid);
fprintf(vvp_out, " %%pop/str 1;\n");
}
static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid,
int stuff_ok_flag)
{
@ -2668,6 +2803,28 @@ static struct vector_info draw_select_expr(ivl_expr_t expr, unsigned wid,
return res;
}
/* Special case: The sub expression is a string, so do a
string select then a part select from that. */
if (ivl_expr_value(sube) == IVL_VT_STRING) {
res.base = allocate_vector(wid);
res.wid = wid;
draw_select_string_dest(expr, res);
return res;
}
/* Special case: The sub-expression is a DARRAY variable, so
do a dynamic array word load. */
if (ivl_expr_value(sube) == IVL_VT_DARRAY) {
ivl_signal_t sig = ivl_expr_signal(sube);
assert(sig);
res.base = allocate_vector(wid);
res.wid = wid;
draw_eval_expr_into_integer(shift, 3);
fprintf(vvp_out, " %%load/dar %u, v%p_0, %u;\n",
res.base, sig, res.wid);
return res;
}
if (ivl_expr_type(sube) == IVL_EX_SIGNAL) {
res = draw_select_signal(expr, sube, shift, ivl_expr_width(expr),
wid);
@ -2770,6 +2927,13 @@ static void draw_select_expr_dest(ivl_expr_t expr, struct vector_info dest,
ivl_expr_t sube = ivl_expr_oper1(expr);
ivl_expr_t shift= ivl_expr_oper2(expr);
/* Special case: The sub expression is a string, so do a
string select then a part select from that. */
if (ivl_expr_value(sube) == IVL_VT_STRING) {
draw_select_string_dest(expr, dest);
return;
}
/* If the shift expression is not present, then this is really
a pad expression, and that can be handled pretty
easily. Evaluate the subexpression into the destination,
@ -2897,7 +3061,6 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid)
unsigned parm_count = ivl_expr_parms(expr);
struct vector_info res;
/* If the function has no parameters, then use this short-form
to draw the statement. */
if (parm_count == 0) {

59
tgt-vvp/eval_object.c Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2012 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 <string.h>
# include <assert.h>
static int eval_darray_new(ivl_expr_t ex)
{
unsigned size_reg = allocate_word();
ivl_expr_t size_expr = ivl_expr_parm(ex, 0);
draw_eval_expr_into_integer(size_expr, size_reg);
clr_word(size_reg);
// XXXX: Assume elements are 32bit integers.
fprintf(vvp_out, " %%new/darray %u, \"sb32\";\n", size_reg);
return 0;
}
static int draw_eval_object_sfunc(ivl_expr_t ex)
{
const char*name = ivl_expr_name(ex);
if (strcmp(name, "$ivl_darray_method$new") == 0)
return eval_darray_new(ex);
fprintf(vvp_out, "; ERROR: Invalid system function %s for darray\n", name);
return 1;
}
int draw_eval_object(ivl_expr_t ex)
{
switch (ivl_expr_type(ex)) {
case IVL_EX_SFUNC:
return draw_eval_object_sfunc(ex);
default:
fprintf(vvp_out, "; ERROR: Invalid expression type %u\n", ivl_expr_type(ex));
return 1;
}
}

94
tgt-vvp/eval_string.c Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2012 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>
static void fallback_eval(ivl_expr_t expr)
{
struct vector_info res = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%pushv/str %u, %u; Cast BOOL/LOGIC to string\n",
res.base, res.wid);
if (res.base > 0)
clr_vector(res);
}
static void string_ex_concat(ivl_expr_t expr)
{
unsigned repeat;
assert(ivl_expr_parms(expr) != 0);
assert(ivl_expr_repeat(expr) != 0);
/* Push the first string onto the stack, no matter what. */
draw_eval_string(ivl_expr_parm(expr,0));
for (repeat = 0 ; repeat < ivl_expr_repeat(expr) ; repeat += 1) {
unsigned idx;
for (idx = (repeat==0)? 1 : 0 ; idx < ivl_expr_parms(expr) ; idx += 1) {
ivl_expr_t sub = ivl_expr_parm(expr,idx);
/* Special case: If operand is a string literal,
then concat it using the %concati/str
instruction. */
if (ivl_expr_type(sub) == IVL_EX_STRING) {
fprintf(vvp_out, " %%concati/str \"%s\";\n",
ivl_expr_string(sub));
continue;
}
draw_eval_string(sub);
fprintf(vvp_out, " %%concat/str;\n");
}
}
}
static void string_ex_signal(ivl_expr_t expr)
{
ivl_signal_t sig = ivl_expr_signal(expr);
if (ivl_signal_data_type(sig) == IVL_VT_STRING) {
fprintf(vvp_out, " %%load/str v%p_0;\n", sig);
return;
}
fallback_eval(expr);
}
void draw_eval_string(ivl_expr_t expr)
{
switch (ivl_expr_type(expr)) {
case IVL_EX_STRING:
fprintf(vvp_out, " %%pushi/str \"%s\";\n", ivl_expr_string(expr));
break;
case IVL_EX_SIGNAL:
string_ex_signal(expr);
break;
case IVL_EX_CONCAT:
string_ex_concat(expr);
break;
default:
fallback_eval(expr);
break;
}
}

View File

@ -731,6 +731,74 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
return 0;
}
static int show_stmt_assign_sig_string(ivl_statement_t net)
{
ivl_lval_t lval = ivl_stmt_lval(net, 0);
ivl_expr_t rval = ivl_stmt_rval(net);
ivl_expr_t part = ivl_lval_part_off(lval);
ivl_signal_t var= ivl_lval_sig(lval);
assert(ivl_stmt_lvals(net) == 1);
assert(ivl_stmt_opcode(net) == 0);
assert(ivl_lval_mux(lval) == 0);
/* Simplest case: no mux. Evaluate the r-value as a string and
store the result into the variable. Note that the
%store/str opcode pops the string result. */
if (part == 0) {
draw_eval_string(rval);
fprintf(vvp_out, " %%store/str v%p_0;\n", var);
return 0;
}
/* Calculate the character select for the word. */
int mux_word = allocate_word();
draw_eval_expr_into_integer(part, mux_word);
/* Evaluate the r-value as a vector. */
struct vector_info rvec = draw_eval_expr_wid(rval, 8, STUFF_OK_XZ);
assert(rvec.wid == 8);
fprintf(vvp_out, " %%putc/str/v v%p_0, %d, %u;\n", var, mux_word, rvec.base);
clr_vector(rvec);
clr_word(mux_word);
return 0;
}
static int show_stmt_assign_sig_darray(ivl_statement_t net)
{
int errors = 0;
ivl_lval_t lval = ivl_stmt_lval(net, 0);
ivl_expr_t rval = ivl_stmt_rval(net);
ivl_expr_t part = ivl_lval_part_off(lval);
ivl_signal_t var= ivl_lval_sig(lval);
ivl_expr_t mux = ivl_lval_idx(lval);
assert(ivl_stmt_lvals(net) == 1);
assert(ivl_stmt_opcode(net) == 0);
assert(ivl_lval_mux(lval) == 0);
assert(part == 0);
if (mux) {
struct vector_info rvec = draw_eval_expr_wid(rval, ivl_lval_width(lval),
STUFF_OK_XZ);
/* The %set/dar expects the array index to be in index
register 3. Calculate the index in place. */
draw_eval_expr_into_integer(mux, 3);
fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n",
var, rvec.base, rvec.wid);
if (rvec.base >= 4) clr_vector(rvec);
} else {
errors += draw_eval_object(rval);
fprintf(vvp_out, " %%store/obj v%p_0;\n", var);
}
return errors;
}
int show_stmt_assign(ivl_statement_t net)
{
@ -746,5 +814,13 @@ int show_stmt_assign(ivl_statement_t net)
return show_stmt_assign_sig_real(net);
}
if (sig && (ivl_signal_data_type(sig) == IVL_VT_STRING)) {
return show_stmt_assign_sig_string(net);
}
if (sig && (ivl_signal_data_type(sig) == IVL_VT_DARRAY)) {
return show_stmt_assign_sig_darray(net);
}
return show_stmt_assign_vector(net);
}

View File

@ -313,6 +313,18 @@ extern int draw_eval_real(ivl_expr_t ex);
*/
extern int draw_eval_bool64(ivl_expr_t ex);
/*
* The draw_eval_string functio evaluates the expression as a string,
* and pushes the string onto the string stack.
*/
extern void draw_eval_string(ivl_expr_t ex);
/*
* The draw_eval_string functio evaluates the expression as an object,
* and pushes the object onto the object stack.
*/
extern int draw_eval_object(ivl_expr_t ex);
extern int show_stmt_assign(ivl_statement_t net);
extern void show_stmt_file_line(ivl_statement_t net, const char*desc);

View File

@ -1646,8 +1646,29 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
return rc;
}
static int show_delete_method(ivl_statement_t net)
{
show_stmt_file_line(net, "Delete object");
unsigned parm_count = ivl_stmt_parm_count(net);
if (parm_count < 1)
return 1;
ivl_expr_t parm = ivl_stmt_parm(net, 0);
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
ivl_signal_t var = ivl_expr_signal(parm);
fprintf(vvp_out, " %%delete/obj v%p_0;\n", var);
return 0;
}
static int show_system_task_call(ivl_statement_t net)
{
const char*stmt_name = ivl_stmt_name(net);
if (strcmp(stmt_name,"$ivl_darray_method$delete") == 0)
return show_delete_method(net);
show_stmt_file_line(net, "System task call.");
draw_vpi_task_call(net);

View File

@ -502,6 +502,16 @@ static void draw_reg_in_scope(ivl_signal_t sig)
vvp_mangle_name(ivl_signal_basename(sig)),
swapped ? first: last, swapped ? last : first, msb, lsb);
} else if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) {
fprintf(vvp_out, "v%p_0 .var/darray \"%s\";%s\n", sig,
vvp_mangle_name(ivl_signal_basename(sig)),
ivl_signal_local(sig)? " Local signal" : "");
} else if (ivl_signal_data_type(sig) == IVL_VT_STRING) {
fprintf(vvp_out, "v%p_0 .var/str \"%s\";%s\n", sig,
vvp_mangle_name(ivl_signal_basename(sig)),
ivl_signal_local(sig)? " Local signal" : "");
} else {
fprintf(vvp_out, "v%p_0 .var%s %s\"%s\", %d %d;%s\n",

View File

@ -52,10 +52,10 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
LDFLAGS = @LDFLAGS@
# Object files for system.vpi
O = sys_table.o sys_convert.o sys_countdrivers.o sys_deposit.o sys_display.o \
O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o sys_display.o \
sys_fileio.o sys_finish.o sys_icarus.o sys_plusargs.o sys_queue.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 \
sys_sdf.o sys_string.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o \
sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o vams_simparam.o \
table_mod.o table_mod_lexor.o table_mod_parse.o
OPP = vcd_priv2.o

91
vpi/sys_darray.c Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2012 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 "sys_priv.h"
# include <assert.h>
static PLI_INT32 one_darray_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
vpiHandle arg;
argv = vpi_iterate(vpiArgument, callh);
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if (arg == 0) return 0;
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s has too many arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
static PLI_INT32 size_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
vpiHandle arg;
argv = vpi_iterate(vpiArgument, callh);
assert(argv);
arg = vpi_scan(argv);
assert(arg);
vpi_free_object(argv);
int res = vpi_get(vpiSize, arg);
s_vpi_value value;
value.format = vpiIntVal;
value.value.integer = res;
vpi_put_value(callh, &value, 0, vpiNoDelay);
return 0;
}
void sys_darray_register(void)
{
s_vpi_systf_data tf_data;
vpiHandle res;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.tfname = "$ivl_darray_method$size";
tf_data.calltf = size_calltf;
tf_data.compiletf = one_darray_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$ivl_darray_method$size";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
}

View File

@ -964,6 +964,18 @@ static char *get_display(unsigned int *rtnsz, const struct strobe_cb_info *info)
memcpy(rtn+size-1, buf, width);
break;
/* Process string variables like string constants: interpret
the contained strings like format strings. */
case vpiStringVar:
value.format = vpiStringVal;
vpi_get_value(item, &value);
fmt = strdup(value.value.str);
width = get_format(&result, fmt, info, &idx);
free(fmt);
rtn = realloc(rtn, (size+width)*sizeof(char));
memcpy(rtn+size-1, result, width);
break;
case vpiSysFuncCall:
func_name = vpi_get_str(vpiName, item);
if (strcmp(func_name, "$time") == 0) {
@ -1071,6 +1083,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name,
case vpiLongIntVar:
case vpiTimeVar:
case vpiRealVar:
case vpiStringVar:
case vpiSysFuncCall:
break;

90
vpi/sys_string.c Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2012 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 "sys_priv.h"
# include <assert.h>
static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
vpiHandle arg;
argv = vpi_iterate(vpiArgument, callh);
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a string argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if (arg == 0) return 0;
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s has too many arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
return 0;
}
static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
vpiHandle arg;
argv = vpi_iterate(vpiArgument, callh);
assert(argv);
arg = vpi_scan(argv);
assert(arg);
vpi_free_object(argv);
int res = vpi_get(vpiSize, arg);
s_vpi_value value;
value.format = vpiIntVal;
value.value.integer = res;
vpi_put_value(callh, &value, 0, vpiNoDelay);
return 0;
}
void sys_string_register(void)
{
s_vpi_systf_data tf_data;
vpiHandle res;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiIntFunc;
tf_data.tfname = "$ivl_string_method$len";
tf_data.calltf = len_calltf;
tf_data.compiletf = one_string_arg_compiletf;
tf_data.sizetf = 0;
tf_data.user_data = "$ivl_string_method$len";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
}

View File

@ -25,6 +25,7 @@
extern void sys_convert_register();
extern void sys_countdrivers_register();
extern void sys_darray_register();
extern void sys_fileio_register();
extern void sys_finish_register();
extern void sys_deposit_register();
@ -34,6 +35,7 @@ extern void sys_queue_register();
extern void sys_random_register();
extern void sys_random_mti_register();
extern void sys_readmem_register();
extern void sys_string_register();
extern void sys_scanf_register();
extern void sys_sdf_register();
extern void sys_time_register();
@ -197,6 +199,7 @@ static void sys_lxt_or_vcd_register()
void (*vlog_startup_routines[])() = {
sys_convert_register,
sys_countdrivers_register,
sys_darray_register,
sys_fileio_register,
sys_finish_register,
sys_deposit_register,
@ -207,6 +210,7 @@ void (*vlog_startup_routines[])() = {
sys_random_mti_register,
sys_readmem_register,
sys_scanf_register,
sys_string_register,
sys_time_register,
sys_lxt_or_vcd_register,
sys_sdf_register,

View File

@ -21,3 +21,5 @@ $abstime vpiSysFuncReal
$simparam vpiSysFuncReal
$simparam$str vpiSysFuncSized 1024 unsigned
$table_model vpiSysFuncReal
$ivl_string_method$len vpiSysFuncInt

View File

@ -310,6 +310,12 @@ typedef struct t_vpi_delay {
#define vpiVariables 100
#define vpiExpr 102
/********************** object types added with 1364-2001 *********************/
# define vpiRegArray 116
/********************** object types added with 1364-2005 *********************/
#define vpiCallback 1000
/* PROPERTIES */

View File

@ -66,8 +66,8 @@ dllib=@DLLIB@
MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"'
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \
V = vpi_modules.o vpi_callback.o vpi_const.o vpi_darray.o vpi_event.o vpi_iter.o vpi_mcd.o \
vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \
vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \
vpip_to_dec.o vpip_format.o vvp_vpi.o
@ -76,7 +76,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
permaheap.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_island.o vvp_net.o vvp_net_sig.o \
event.o logic.o delay.o words.o island_tran.o $V
vvp_object.o event.o logic.o delay.o words.o island_tran.o $V
all: dep vvp@EXEEXT@ libvpi.a vvp.man

View File

@ -284,6 +284,7 @@ general syntax of a variable is:
<label> .var/2s "name", <msb> <lsb>; Signed bool/bit variable
<label> .var/real "name", <msb>, <lsb>; real variable
<label> .var/i "name", <msb>, <lsb>; vpiIntegerVar variable
<label> .var/str "name"; vpiStringVar variable
The "name" is the declared base name of the original variable, for the
sake of VPI code that might access it. The variable is placed in the

View File

@ -68,12 +68,15 @@ extern bool of_CAST2(vthread_t thr, vvp_code_t code);
extern bool of_CMPIS(vthread_t thr, vvp_code_t code);
extern bool of_CMPIU(vthread_t thr, vvp_code_t code);
extern bool of_CMPS(vthread_t thr, vvp_code_t code);
extern bool of_CMPSTR(vthread_t thr, vvp_code_t code);
extern bool of_CMPU(vthread_t thr, vvp_code_t code);
extern bool of_CMPWR(vthread_t thr, vvp_code_t code);
extern bool of_CMPWS(vthread_t thr, vvp_code_t code);
extern bool of_CMPWU(vthread_t thr, vvp_code_t code);
extern bool of_CMPX(vthread_t thr, vvp_code_t code);
extern bool of_CMPZ(vthread_t thr, vvp_code_t code);
extern bool of_CONCAT_STR(vthread_t thr, vvp_code_t code);
extern bool of_CONCATI_STR(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RS(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RU(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RV(vthread_t thr, vvp_code_t code);
@ -85,6 +88,7 @@ extern bool of_DEASSIGN(vthread_t thr, vvp_code_t code);
extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code);
extern bool of_DELAY(vthread_t thr, vvp_code_t code);
extern bool of_DELAYX(vthread_t thr, vvp_code_t code);
extern bool of_DELETE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
extern bool of_DIV(vthread_t thr, vvp_code_t code);
extern bool of_DIV_S(vthread_t thr, vvp_code_t code);
@ -121,6 +125,8 @@ 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_DAR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_STR(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);
@ -139,20 +145,26 @@ extern bool of_MUL_WR(vthread_t thr, vvp_code_t code);
extern bool of_MULI(vthread_t thr, vvp_code_t code);
extern bool of_NAND(vthread_t thr, vvp_code_t code);
extern bool of_NANDR(vthread_t thr, vvp_code_t code);
extern bool of_NEW_DARRAY(vthread_t thr, vvp_code_t code);
extern bool of_NOOP(vthread_t thr, vvp_code_t code);
extern bool of_NOR(vthread_t thr, vvp_code_t code);
extern bool of_NORR(vthread_t thr, vvp_code_t code);
extern bool of_OR(vthread_t thr, vvp_code_t code);
extern bool of_ORR(vthread_t thr, vvp_code_t code);
extern bool of_PAD(vthread_t thr, vvp_code_t code);
extern bool of_POP_STR(vthread_t thr, vvp_code_t code);
extern bool of_POW(vthread_t thr, vvp_code_t code);
extern bool of_POW_S(vthread_t thr, vvp_code_t code);
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
extern bool of_PUSHI_STR(vthread_t thr, vvp_code_t code);
extern bool of_PUSHV_STR(vthread_t thr, vvp_code_t code);
extern bool of_PUTC_STR_V(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
extern bool of_SET_DAR(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
@ -160,9 +172,12 @@ extern bool of_SET_X0_X(vthread_t thr, vvp_code_t code);
extern bool of_SHIFTL_I0(vthread_t thr, vvp_code_t code);
extern bool of_SHIFTR_I0(vthread_t thr, vvp_code_t code);
extern bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t code);
extern bool of_STORE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_STORE_STR(vthread_t thr, vvp_code_t code);
extern bool of_SUB(vthread_t thr, vvp_code_t code);
extern bool of_SUB_WR(vthread_t thr, vvp_code_t code);
extern bool of_SUBI(vthread_t thr, vvp_code_t code);
extern bool of_SUBSTR_V(vthread_t thr, vvp_code_t code);
extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code);
extern bool of_WAIT(vthread_t thr, vvp_code_t code);
extern bool of_XNOR(vthread_t thr, vvp_code_t code);
@ -189,6 +204,7 @@ struct vvp_code_s {
vvp_array_t array;
class __vpiHandle*handle;
struct __vpiScope*scope;
const char*text;
};
union {

View File

@ -70,7 +70,9 @@ enum operand_e {
/* The operand is a second functor pointer */
OA_FUNC_PTR2,
/* The operand is a VPI handle */
OA_VPI_PTR
OA_VPI_PTR,
/* String */
OA_STRING
};
struct opcode_table_s {
@ -115,6 +117,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%cast2", of_CAST2, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/str",of_CMPSTR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/ws", of_CMPWS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
@ -123,6 +126,8 @@ static const struct opcode_table_s opcode_table[] = {
{ "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/s", of_CMPIS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%concat/str",of_CONCAT_STR,0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%concati/str",of_CONCATI_STR,1,{OA_STRING,OA_NONE, OA_NONE} },
{ "%cvt/rs", of_CVT_RS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/ru", of_CVT_RU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/rv", of_CVT_RV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@ -134,6 +139,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%deassign/wr",of_DEASSIGN_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%delay", of_DELAY, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%div/s", of_DIV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%div/wr", of_DIV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
@ -167,6 +173,8 @@ static const struct opcode_table_s opcode_table[] = {
{ "%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/dar",of_LOAD_DAR,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/str",of_LOAD_STR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%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} },
@ -185,29 +193,38 @@ static const struct opcode_table_s opcode_table[] = {
{ "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%nand", of_NAND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%nand/r", of_NANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%new/darray",of_NEW_DARRAY,2,{OA_BIT1, OA_STRING, OA_NONE} },
{ "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%nor", of_NOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pad", of_PAD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pop/str",of_POP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/s", of_POW_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%pushi/str",of_PUSHI_STR,1,{OA_STRING, OA_NONE, OA_NONE} },
{ "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} },
{ "%putc/str/v",of_PUTC_STR_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%set/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/dar",of_SET_DAR,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%store/obj",of_STORE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/str",of_STORE_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%sub", of_SUB, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%sub/wr", of_SUB_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%xnor", of_XNOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%xnor/r", of_XNORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@ -310,11 +327,21 @@ vvp_net_t* vvp_net_lookup(const char*label)
return sig->net;
}
case vpiStringVar: {
__vpiStringVar*sig = dynamic_cast<__vpiStringVar*>(vpi);
return sig->get_net();
}
case vpiNamedEvent: {
__vpiNamedEvent*tmp = dynamic_cast<__vpiNamedEvent*>(vpi);
return tmp->funct;
}
case vpiArrayVar: {
__vpiDarrayVar*tmp = dynamic_cast<__vpiDarrayVar*>(vpi);
return tmp->get_net();
}
default:
fprintf(stderr, "Unsupported type %d.\n",
vpi->get_type_code());
@ -492,6 +519,12 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
val.ptr = vpip_make_vthr_word(base, ss);
sym_set_value(sym_vpi, label(), val);
} else if (1 == sscanf(label(), "S<%u,str>%n", &base, &n)
&& n == strlen(label())) {
val.ptr = vpip_make_vthr_str_stack(base);
sym_set_value(sym_vpi, label(), val);
}
}
@ -1671,6 +1704,15 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
compile_vpi_lookup(&code->handle, opa->argv[idx].symb.text);
break;
case OA_STRING:
if (opa->argv[idx].ltype != L_STRING) {
yyerror("operand format");
break;
}
code->text = opa->argv[idx].text;
break;
}
}

View File

@ -388,7 +388,7 @@ extern void compile_named_event(char*label, char*type);
*/
#define OPERAND_MAX 3
enum ltype_e { L_NUMB, L_SYMB };
enum ltype_e { L_NUMB, L_SYMB, L_STRING };
struct comp_operands_s {
unsigned argc;
@ -397,6 +397,7 @@ struct comp_operands_s {
union {
unsigned long numb;
struct symb_s symb;
const char *text;
};
} argv[OPERAND_MAX];
};
@ -455,8 +456,9 @@ extern void compile_variable(char*label, char*name,
int msb, int lsb, int vpi_type_code,
bool signed_flag, bool local_flag);
extern void compile_var_real(char*label, char*name,
int msb, int lsb);
extern void compile_var_real(char*label, char*name);
extern void compile_var_string(char*label, char*name);
extern void compile_var_darray(char*label, char*name);
/*
* This function is used to create a scope port

View File

@ -195,8 +195,10 @@ static char* strdupnew(char const *str)
".ufunc" { return K_UFUNC; }
".ufunc/e" { return K_UFUNC_E; }
".var" { return K_VAR; }
".var/darray" { return K_VAR_DARRAY; }
".var/real" { return K_VAR_R; }
".var/s" { return K_VAR_S; }
".var/str" { return K_VAR_STR; }
".var/i" { return K_VAR_I; /* integer */ }
".var/2s" { return K_VAR_2S; /* byte/shortint/int/longint signed */ }
".var/2u" { return K_VAR_2U; /* byte/shortint/int/longint unsigned */ }
@ -254,6 +256,11 @@ static char* strdupnew(char const *str)
assert(yylval.text);
return T_SYMBOL; }
"S<"[0-9]*",str>" {
yylval.text = strdup(yytext);
assert(yylval.text);
return T_SYMBOL; }
"T<"[0-9]*","[0-9]*","[us]">" {
yylval.text = strdup(yytext);
assert(yylval.text);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com)
*
*/
@ -12,13 +12,26 @@ operands. In no case are there more than 3 operands. This chapter
describes the specific behavior of each opcode, in enough detail
(I hope) that its complete effect can be predicted.
General principles of Arithmetic:
General Principles of Arithmetic (current plan):
The binary arithmetic instruction in general takes three parameters,
the left operand, the right operand, and the base. The left operand is
replaced with the result, which is the same width as the left and
right operands.
General Principles of Arithmetic (new plan):
For strings, all arithmetic is stack based. That is, there is an
abstract stack of strings from which operations pull their operands
and push their results. This is somewhat like FORTH (or an HP calculator
RPN notation) and spares the need to keep register addresses in
operands. I may find this leads to a more compact form of instruction
code, and may lead to more efficient operators overall, and in
particular I may find improved efficiency overall; so after the
experience of implementing it for strings, I'll want to change other
types around to using this method as well. Keep this in mind whenever
considering adding new instructions to vvp.
* %abs/wr <bit-o>, <bit-i>
This instruction calculates the absolute value of a real value. It uses
@ -280,6 +293,25 @@ instruction will also treat x values in either operand as don't care.
Only bit 4 is set by these instructions.
* %cmp/str
This instruction pops the top two strings from the string stack and
compares them. The results of the comparison go into bits 4 and 5:
4: eq (equal)
5: lt (less than)
For the purposes of calculating the lt bit, the top string is the
right operand and the string underneath is the left operand. This
instruction removes two strings from the stack.
* %concat/str
* %concati/str <string>
Pop the top string, and concatenate it to the new top string. Or think
of it as possing the tail, then the head, concatenating them, and
pushing the result. The stack starts with two strings in the stack,
and ends with one string in the stack.
* %cvt/sr <bit-l>, <bit-r>
* %cvt/rs <bit-l>, <bit-r>
@ -343,6 +375,11 @@ This is similar to the %delay opcode, except that the parameter
selects an index register, which contains the actual delay. This
supports run-time calculated delays.
* %delete/obj <var-label>
Arrange for the dynamic object at the target label to be deleted.
This has no effect on the object or string stack.
* %disable <scope-label>
This instruction terminates threads that are part of a specific
@ -560,6 +597,15 @@ bit, and the <index> is the selector for the bit to use. If <index> is
out of range, then x is loaded. The index value is incremented by one
if it is defined (bit 4 is not 1).
* %load/dar <bit>, <functor-label>, <wid>
This instruction loads an array word from a dynamic array. The
<label> refers to the variable object, and the <bit>/<wid> are the
location in local vector space where the extracted word goes. The
index is implicitly extracted from index register 3.
(See also %set/dar)
* %load/v <bit>, <functor-label>, <wid>
This instruction loads a vector value from the given functor node into
@ -684,6 +730,17 @@ means the following:
otherwise x
* %new/darray <idx>, "<type>"
Create a new array (of int objects) with a size. the <idx> is the
address of an index variable that contains the computed array size to
use. The <type> is a string that expresses the type of the elements of
the array. See also %delete/obj
The supported types are:
"sb32" - signed bool 32bits
* %nor <dst>, <src>, <wid>
Perform the bitwise nor of the vectors. Each bit in the <dst> is
@ -734,6 +791,12 @@ destination vector in register space. The destination may overlap
the source bit. The <dst> may not be 0-3. This is useful for zero
or sign extending a vector.
* %pop/str <num>
Pop this many items from the string stack. This is the opposite of the
%pushX/str opcode which pushes a string to the stack. The %pop/str is
not normally needed because the %store/str includes an implicit pop,
but sometimes it is necessary to pop explicitly.
* %pow <bit-l>, <bit-r>, <wid>
* %pow/s <bit-l>, <bit-r>, <wid>
@ -750,6 +813,13 @@ replaces the left operand.
This opcode raises <bit-l> (real) to the power of <bit-r> (real). The
result replaces the left operand.
* %pushi/str <text>
Push a literal string to the string stack.
* %pushv/str <src>, <wid>
Convert a vector to a string and push the string to the string stack.
* %release/net <functor-label>, <base>, <width>
* %release/reg <functor-label>, <base>, <width>
@ -774,6 +844,12 @@ Release the force on the real signal that is represented by the functor
statement. The <type> is 0 for nets and 1 for registers. See the other
%release commands above.
* %set/dar <var-label>, <bit>, <wid>
This sets a vector to a word of the dynamic array. Index register 3
contains the word address within the dynamic array, and <bit>,<wid>
specifies the thread vector to be written.
* %set/v <var-label>, <bit>, <wid>
This sets a vector to a variable, and is used to implement blocking
@ -849,6 +925,16 @@ top bits. %shiftr/s/i0 is a signed shift, so the value is sign-extended.
For a negative shift %shiftr/i0 will pad the value with 'bx.
* %store/obj <var-label>
This pops the top of the object stack and writes it to the object
variable given by the label.
* %store/str <var-label>
This pops the top of the string stack and writes it to the string
varible.
* %sub <bit-l>, <bit-r>, <wid>
This instruction arithmetically subtracts the right vector out of the
@ -876,6 +962,16 @@ indexed value is subtracted from the left indexed value, and the
result placed in the left index.
* %substr/v <bit-l>, <sel>, <wid>
This instruction extracts the substring of the top string in the string
stack and delivers the result to vector space. The <bit>,<wid> part is
the location where the result goes, and <sel> is the index register
that holds the index. This is the general method for getting string
values into the vector space. The string value is NOT popped.
* %vpi_call <name> [, ...]
This instruction makes a call to a system task that was declared using

View File

@ -91,7 +91,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_RESOLV K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP
%token K_UFUNC K_UFUNC_E K_UDP K_UDP_C K_UDP_S
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
%token K_VAR K_VAR_DARRAY K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
%token K_vpi_call K_vpi_call_w K_vpi_call_i
%token K_vpi_func K_vpi_func_r
%token K_disable K_fork
@ -697,7 +697,13 @@ statement
{ compile_variable($1, $4, $6, $7, vpiIntVar, false, $3); }
| T_LABEL K_VAR_R T_STRING ',' signed_t_number signed_t_number ';'
{ compile_var_real($1, $3, $5, $6); }
{ compile_var_real($1, $3); }
| T_LABEL K_VAR_STR T_STRING ';'
{ compile_var_string($1, $3); }
| T_LABEL K_VAR_DARRAY T_STRING ';'
{ compile_var_darray($1, $3); }
/* Net statements are similar to .var statements, except that they
declare nets, and they have an input list. */
@ -880,23 +886,31 @@ operands
;
operand
: symbol
{ comp_operands_t opa = (comp_operands_t)
calloc(1, sizeof(struct comp_operands_s));
opa->argc = 1;
opa->argv[0].ltype = L_SYMB;
opa->argv[0].symb = $1;
$$ = opa;
}
| T_NUMBER
{ comp_operands_t opa = (comp_operands_t)
calloc(1, sizeof(struct comp_operands_s));
opa->argc = 1;
opa->argv[0].ltype = L_NUMB;
opa->argv[0].numb = $1;
$$ = opa;
}
;
: symbol
{ comp_operands_t opa = (comp_operands_t)
calloc(1, sizeof(struct comp_operands_s));
opa->argc = 1;
opa->argv[0].ltype = L_SYMB;
opa->argv[0].symb = $1;
$$ = opa;
}
| T_NUMBER
{ comp_operands_t opa = (comp_operands_t)
calloc(1, sizeof(struct comp_operands_s));
opa->argc = 1;
opa->argv[0].ltype = L_NUMB;
opa->argv[0].numb = $1;
$$ = opa;
}
| T_STRING
{ comp_operands_t opa = (comp_operands_t)
calloc(1, sizeof(struct comp_operands_s));
opa->argc = 1;
opa->argv[0].ltype = L_STRING;
opa->argv[0].text = $1;
$$ = opa;
}
;
/* The argument_list is a list of vpiHandle objects that can be

View File

@ -794,6 +794,16 @@ void vvp_wire_real::get_signal_value(struct t_vpi_value*vp)
real_signal_value(vp, real_value());
}
void vvp_fun_signal_string_aa::get_signal_value(struct t_vpi_value*vp)
{
assert(0);
}
#if 0
void vvp_wire_string::get_signal_value(struct t_vpi_value*vp)
{
assert(0);
}
#endif
void vvp_wire_vec4::get_value(struct t_vpi_value*val)
{
get_signal_value(val);
@ -808,3 +818,9 @@ void vvp_wire_real::get_value(struct t_vpi_value*val)
{
get_signal_value(val);
}
#if 0
void vvp_wire_string::get_value(struct t_vpi_value*val)
{
assert(0);
}
#endif

77
vvp/vpi_darray.cc Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2012 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 "compile.h"
# include "vpi_priv.h"
# include "vvp_net_sig.h"
# include "schedule.h"
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
#endif
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <cassert>
# include "ivl_alloc.h"
using namespace std;
__vpiDarrayVar::__vpiDarrayVar(__vpiScope*sc, const char*na, vvp_net_t*ne)
: scope_(sc), name_(na), net_(ne)
{
}
int __vpiDarrayVar::get_type_code(void) const
{ return vpiArrayVar; }
int __vpiDarrayVar::vpi_get(int code)
{
vvp_fun_signal_object*fun = dynamic_cast<vvp_fun_signal_object*> (net_->fun);
assert(fun);
vvp_object_t val = fun->get_object();
vvp_darray*aval = dynamic_cast<vvp_darray*> (val);
switch (code) {
case vpiSize:
if (aval == 0)
return 0;
else
return aval->get_size();
default:
return 0;
}
}
void __vpiDarrayVar::vpi_get_value(p_vpi_value val)
{
val->format = vpiSuppressVal;
}
vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net)
{
struct __vpiScope*scope = vpip_peek_current_scope();
const char*use_name = name ? vpip_name_string(name) : 0;
struct __vpiDarrayVar*obj = new __vpiDarrayVar(scope, use_name, net);
return obj;
}

View File

@ -902,6 +902,11 @@ void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
assert(expr);
assert(vp);
// Never bother with suppressed values. All the derived
// classes can ignore this type.
if (vp->format == vpiSuppressVal)
return;
expr->vpi_get_value(vp);
if (vpi_trace) switch (vp->format) {

View File

@ -24,6 +24,7 @@
# include "config.h"
# include <set>
# include <string>
/*
* Added to use some "vvp_fun_modpath_src"
@ -477,6 +478,43 @@ struct __vpiRealVar : public __vpiHandle {
extern struct __vpiScope* vpip_scope(__vpiRealVar*sig);
extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net);
class __vpiStringVar : public __vpiHandle {
public:
__vpiStringVar(__vpiScope*scope, const char*name, vvp_net_t*net);
int get_type_code(void) const;
int vpi_get(int code);
void vpi_get_value(p_vpi_value val);
inline vvp_net_t* get_net() const { return net_; }
private:
struct __vpiScope* scope_;
const char*name_;
vvp_net_t*net_;
};
extern vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net);
class __vpiDarrayVar : public __vpiHandle {
public:
__vpiDarrayVar(__vpiScope*scope, const char*name, vvp_net_t*net);
int get_type_code(void) const;
int vpi_get(int code);
void vpi_get_value(p_vpi_value val);
inline vvp_net_t* get_net() const { return net_; }
private:
struct __vpiScope* scope_;
const char*name_;
vvp_net_t*net_;
};
extern vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net);
/*
* When a loaded VPI module announces a system task/function, one
@ -592,6 +630,7 @@ vpiHandle vpip_make_real_param(char*name, double value, bool local_flag,
vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag);
vpiHandle vpip_make_vthr_word(unsigned base, const char*type);
vpiHandle vpip_make_vthr_str_stack(unsigned depth);
vpiHandle vpip_make_vthr_A(char*label, unsigned index);
vpiHandle vpip_make_vthr_A(char*label, char*symbol);

84
vvp/vpi_string.cc Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2012 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 "compile.h"
# include "vpi_priv.h"
# include "vvp_net_sig.h"
# include "schedule.h"
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
#endif
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <cassert>
# include "ivl_alloc.h"
using namespace std;
__vpiStringVar::__vpiStringVar(__vpiScope*sc, const char*na, vvp_net_t*ne)
: scope_(sc), name_(na), net_(ne)
{
}
int __vpiStringVar::get_type_code(void) const
{ return vpiStringVar; }
int __vpiStringVar::vpi_get(int code)
{
vvp_fun_signal_string*fun = dynamic_cast<vvp_fun_signal_string*> (net_->fun);
assert(fun);
string str = fun->get_string();
switch (code) {
case vpiSize:
// The vpiSize of a string variable is the number of
// bytes (characters) in that string.
return str.size();
default:
return 0;
}
}
void __vpiStringVar::vpi_get_value(p_vpi_value val)
{
vvp_fun_signal_string*fun = dynamic_cast<vvp_fun_signal_string*> (net_->fun);
assert(fun);
string str = fun->get_string();
if (val->format == vpiStringVal || val->format == vpiObjTypeVal) {
char*rbuf = need_result_buf(str.size()+1, RBUF_VAL);
strcpy(rbuf, str.c_str());
val->format = vpiStringVal;
val->value.str = rbuf;
return;
}
val->format = vpiSuppressVal;
}
vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net)
{
struct __vpiScope*scope = vpip_peek_current_scope();
const char*use_name = name ? vpip_name_string(name) : 0;
struct __vpiStringVar*obj = new __vpiStringVar(scope, use_name, net);
return obj;
}

View File

@ -635,3 +635,66 @@ void vpi_handle_delete()
}
}
#endif
class __vpiVThrStrStack : public __vpiHandle {
public:
__vpiVThrStrStack(unsigned depth);
int get_type_code(void) const;
int vpi_get(int code);
void vpi_get_value(p_vpi_value val);
private:
const char* name;
unsigned depth_;
};
__vpiVThrStrStack::__vpiVThrStrStack(unsigned d)
: depth_(d)
{
}
int __vpiVThrStrStack::get_type_code(void) const
{ return vpiConstant; }
int __vpiVThrStrStack::vpi_get(int code)
{
switch (code) {
case vpiConstType:
return vpiStringConst;
default:
return 0;
}
}
void __vpiVThrStrStack::vpi_get_value(p_vpi_value vp)
{
string val;
char*rbuf = 0;
if (vpip_current_vthread)
val = vthread_get_str_stack(vpip_current_vthread, depth_);
switch (vp->format) {
case vpiObjTypeVal:
vp->format = vpiStringVal;
case vpiStringVal:
rbuf = need_result_buf(val.size()+1, RBUF_VAL);
strcpy(rbuf, val.c_str());
vp->value.str = rbuf;
break;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiConstant (String)\n", (int)vp->format);
vp->format = vpiSuppressVal;
break;
}
}
vpiHandle vpip_make_vthr_str_stack(unsigned depth)
{
struct __vpiVThrStrStack*obj = new __vpiVThrStrStack(depth);
return obj;
}

View File

@ -99,6 +99,16 @@ struct vthread_s {
double w_real;
} words[16];
/* Strings are operated on using a forth-like operator
set. Items at the top of the stack (back()) are the objects
operated on except for special cases. New objects are
pushed onto the top (back()) and pulled from the top
(back()) only. */
vector<string> stack_str;
/* Objects are also operated on in a stack. */
vector<vvp_object_t> stack_obj;
/* My parent sets this when it wants me to wake it up. */
unsigned i_am_joining :1;
unsigned i_have_ended :1;
@ -182,6 +192,13 @@ void vthread_put_real(struct vthread_s*thr, unsigned addr, double val)
thr->words[addr].w_real = val;
}
string vthread_get_str_stack(struct vthread_s*thr, unsigned depth)
{
assert(depth < thr->stack_str.size());
unsigned use_index = thr->stack_str.size()-1-depth;
return thr->stack_str[use_index];
}
template <class T> T coerce_to_width(const T&that, unsigned width)
{
if (that.size() == width)
@ -1484,6 +1501,36 @@ bool of_CMPS(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_CMPSTR(vthread_t thr, vvp_code_t)
{
assert(thr->stack_str.size() >= 2);
string re = thr->stack_str.back();
thr->stack_str.pop_back();
string le = thr->stack_str.back();
thr->stack_str.pop_back();
int rc = strcmp(le.c_str(), re.c_str());
vvp_bit4_t eq;
vvp_bit4_t lt;
if (rc == 0) {
eq = BIT4_1;
lt = BIT4_0;
} else if (rc < 0) {
eq = BIT4_0;
lt = BIT4_1;
} else {
eq = BIT4_0;
lt = BIT4_0;
}
thr_put_bit(thr, 4, eq);
thr_put_bit(thr, 5, lt);
return true;
}
bool of_CMPIS(vthread_t thr, vvp_code_t cp)
{
vvp_bit4_t eq = BIT4_1;
@ -1780,6 +1827,29 @@ bool of_CMPZ(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %concat/str;
*/
bool of_CONCAT_STR(vthread_t thr, vvp_code_t)
{
assert(thr->stack_str.size() >= 1);
string text = thr->stack_str.back();
thr->stack_str.pop_back();
thr->stack_str.back().append(text);
return true;
}
/*
* %concati/str <string>;
*/
bool of_CONCATI_STR(vthread_t thr, vvp_code_t cp)
{
const char*text = cp->text;
assert(thr->stack_str.size() >= 1);
thr->stack_str.back().append(text);
return true;
}
bool of_CVT_RS(vthread_t thr, vvp_code_t cp)
{
int64_t r = thr->words[cp->bit_idx[1]].w_int;
@ -1941,6 +2011,21 @@ bool of_DELAYX(vthread_t thr, vvp_code_t cp)
return false;
}
/* %delete/obj <label>
*
* This operator works by assigning a nil to the target object. This
* causes any value that might be there to be garbage collected, thus
* deleting the object.
*/
bool of_DELETE_OBJ(vthread_t thr, vvp_code_t cp)
{
/* set the value into port 0 of the destination. */
vvp_net_ptr_t ptr (cp->net, 0);
vvp_send_object(ptr, 0, thr->wt_context);
return true;
}
static bool do_disable(vthread_t thr, vthread_t match)
{
bool flag = false;
@ -3013,6 +3098,32 @@ bool of_LOAD_AV(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %load/dar <bit>, <array-label>, <index>;
*/
bool of_LOAD_DAR(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
unsigned adr = thr->words[3].w_int;
vvp_net_t*net = cp->net;
assert(net);
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*> (net->fun);
assert(obj);
vvp_darray*darray = dynamic_cast<vvp_darray*>(obj->get_object());
assert(darray);
vvp_vector4_t word;
darray->get_word(adr, word);
assert(word.size() == wid);
thr->bits4.set_vec(bit, word);
return true;
}
/*
* %load/vp0, %load/vp0/s, %load/avp0 and %load/avp0/s share this function.
*/
@ -3146,6 +3257,20 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_LOAD_STR(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
vvp_fun_signal_string*fun = dynamic_cast<vvp_fun_signal_string*> (net->fun);
assert(fun);
const string&val = fun->get_string();
thr->stack_str.push_back(val);
return true;
}
/* %load/v <bit>, <label>, <wid>
*
* Implement the %load/v instruction. Load the vector value of the
@ -3170,7 +3295,7 @@ static void load_base(vvp_code_t cp, vvp_vector4_t&dst)
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
if (sig == 0) {
cerr << "%%load/v error: Net arg not a signal? "
<< typeid(*net->fil).name() << endl;
<< (net->fil ? typeid(*net->fil).name() : typeid(*net->fun).name()) << endl;
assert(sig);
}
@ -3826,6 +3951,23 @@ bool of_NAND(vthread_t thr, vvp_code_t cp)
}
bool of_NEW_DARRAY(vthread_t thr, vvp_code_t cp)
{
const char*text = cp->text;
size_t size = thr->words[cp->bit_idx[0]].w_int;
vvp_object_t obj;
if (strcmp(text,"sb32") == 0) {
obj = new vvp_darray_atom<int32_t>(size);
} else {
obj = new vvp_darray (size);
}
thr->stack_obj.push_back(obj);
return true;
}
bool of_NOOP(vthread_t, vvp_code_t)
{
return true;
@ -4061,6 +4203,21 @@ bool of_NOR(vthread_t thr, vvp_code_t cp)
return cp->opcode(thr, cp);
}
/*
* %pop/str <number>
*/
bool of_POP_STR(vthread_t thr, vvp_code_t cp)
{
unsigned cnt = cp->number;
assert(cnt <= thr->stack_str.size());
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
thr->stack_str.pop_back();
}
return true;
}
bool of_POW(vthread_t thr, vvp_code_t cp)
{
assert(cp->bit_idx[0] >= 4);
@ -4141,6 +4298,97 @@ bool of_POW_WR(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_PUSHI_STR(vthread_t thr, vvp_code_t cp)
{
const char*text = cp->text;
thr->stack_str.push_back(string(text));
return true;
}
bool of_PUSHV_STR(vthread_t thr, vvp_code_t cp)
{
unsigned src = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
vvp_vector4_t vec = vthread_bits_to_vector(thr, src, wid);
size_t slen = (vec.size() + 7)/8;
vector<char>buf;
buf.reserve(slen);
for (size_t idx = 0 ; idx < vec.size() ; idx += 8) {
char tmp = 0;
size_t trans = 8;
if (idx+trans > vec.size())
trans = vec.size() - idx;
for (size_t bdx = 0 ; bdx < trans ; bdx += 1) {
if (vec.value(idx+bdx) == BIT4_1)
tmp |= 1 << bdx;
}
if (tmp != 0)
buf.push_back(tmp);
}
string val;
for (vector<char>::reverse_iterator cur = buf.rbegin()
; cur != buf.rend() ; ++cur) {
val.push_back(*cur);
}
thr->stack_str.push_back(val);
return true;
}
/*
* %putc/str/v <var>, <muxr>, <base>
*/
bool of_PUTC_STR_V(vthread_t thr, vvp_code_t cp)
{
unsigned muxr = cp->bit_idx[0];
unsigned base = cp->bit_idx[1];
/* The mux is the index into the string. If it is <0, then
this operation cannot possible effect the string, so we are
done. */
assert(muxr < 16);
int32_t mux = thr->words[muxr].w_int;
if (mux < 0)
return true;
/* Extract the character from the vector space. If that byte
is null (8'hh00) then there is nothing more to do. */
unsigned long*tmp = vector_to_array(thr, base, 8);
if (tmp == 0)
return true;
if (tmp[0] == 0)
return true;
char tmp_val = tmp[0]&0xff;
/* Get the existing value of the string. If we find that the
index is too big for the string, then give up. */
vvp_net_t*net = cp->net;
vvp_fun_signal_string*fun = dynamic_cast<vvp_fun_signal_string*> (net->fun);
assert(fun);
string val = fun->get_string();
if (val.size() <= (size_t)mux)
return true;
/* If the value to write is the same as the destination, then
stop now. */
if (val[mux] == tmp_val)
return true;
/* Finally, modify the string and write the new string to the
variable so that the new value propagates. */
val[mux] = tmp_val;
vvp_send_string(vvp_net_ptr_t(cp->net, 0), val, thr->wt_context);
return true;
}
/*
* These implement the %release/net and %release/reg instructions. The
* %release/net instruction applies to a net kind of functor by
@ -4241,6 +4489,28 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %set/dar <label>, <bit>, <wid>
*/
bool of_SET_DAR(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
unsigned adr = thr->words[3].w_int;
/* Make a vector of the desired width. */
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
vvp_net_t*net = cp->net;
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*> (net->fun);
assert(obj);
vvp_darray*darray = dynamic_cast<vvp_darray*>(obj->get_object());
assert(darray);
darray->set_word(adr, value);
return true;
}
/*
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
@ -4478,6 +4748,38 @@ bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_STORE_OBJ(vthread_t thr, vvp_code_t cp)
{
/* set the value into port 0 of the destination. */
vvp_net_ptr_t ptr (cp->net, 0);
assert(!thr->stack_obj.empty());
vvp_object_t val= thr->stack_obj.back();
thr->stack_obj.pop_back();
vvp_send_object(ptr, val, thr->wt_context);
return true;
}
bool of_STORE_STR(vthread_t thr, vvp_code_t cp)
{
/* set the value into port 0 of the destination. */
vvp_net_ptr_t ptr (cp->net, 0);
assert(!thr->stack_str.empty());
string val= thr->stack_str.back();
thr->stack_str.pop_back();
vvp_send_string(ptr, val, thr->wt_context);
return true;
}
bool of_SUB(vthread_t thr, vvp_code_t cp)
{
assert(cp->bit_idx[0] >= 4);
@ -4557,6 +4859,40 @@ bool of_SUBI(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %substr/v <bitl>, <index>, <wid>
*/
bool of_SUBSTR_V(vthread_t thr, vvp_code_t cp)
{
string&val = thr->stack_str.back();
uint32_t bitl = cp->bit_idx[0];
uint32_t sel = cp->bit_idx[1];
unsigned wid = cp->number;
thr_check_addr(thr, bitl+wid);
assert(bitl >= 4);
int32_t use_sel = thr->words[sel].w_int;
vvp_vector4_t tmp (8);
unsigned char_count = wid/8;
for (unsigned idx = 0 ; idx < char_count ; idx += 1) {
unsigned long byte;
if (use_sel < 0)
byte = 0x00;
else if ((size_t)use_sel >= val.size())
byte = 0x00;
else
byte = val[use_sel];
thr->bits4.setarray(bitl, 8, &byte);
bitl += 8;
use_sel += 1;
}
return true;
}
bool of_FILE_LINE(vthread_t, vvp_code_t cp)
{
if (show_file_line) {

View File

@ -21,6 +21,8 @@
# include "vvp_net.h"
# include <string>
/*
* A vthread is a simulation thread that executes instructions when
* they are scheduled. This structure contains all the thread specific
@ -117,6 +119,11 @@ extern void vthread_put_bit(struct vthread_s*thr, unsigned addr, vvp_bit4_t bit)
extern double vthread_get_real(struct vthread_s*thr, unsigned addr);
extern void vthread_put_real(struct vthread_s*thr, unsigned addr, double val);
/* Get the string from the requested position in the vthread string
stack. The top of the stack is depth==0, and items below are
depth==1, etc. */
extern std::string vthread_get_str_stack(struct vthread_s*thr, unsigned depth);
/* This is used to actually delete a thread once we are done with it. */
extern void vthread_delete(vthread_t thr);

View File

@ -1465,7 +1465,7 @@ void vvp_vector4_t::set_to_x()
}
}
char* vvp_vector4_t::as_string(char*buf, size_t buf_len)
char* vvp_vector4_t::as_string(char*buf, size_t buf_len) const
{
char*res = buf;
*buf++ = 'C';
@ -2989,6 +2989,20 @@ void vvp_net_fun_t::recv_long_pv(vvp_net_ptr_t, long, unsigned, unsigned)
assert(0);
}
void vvp_net_fun_t::recv_string(vvp_net_ptr_t, const std::string&bit, vvp_context_t)
{
fprintf(stderr, "internal error: %s: recv_string(%s) not implemented\n",
typeid(*this).name(), bit.c_str());
assert(0);
}
void vvp_net_fun_t::recv_object(vvp_net_ptr_t, vvp_object_t, vvp_context_t)
{
fprintf(stderr, "internal error: %s: recv_object(...) not implemented\n",
typeid(*this).name());
assert(0);
}
void vvp_net_fun_t::force_flag(void)
{
}

View File

@ -23,6 +23,7 @@
# include "vpi_user.h"
# include "vvp_vpi_callback.h"
# include "permaheap.h"
# include "vvp_object.h"
# include <cstddef>
# include <cstdlib>
# include <cstring>
@ -279,7 +280,7 @@ class vvp_vector4_t {
void set_to_x();
// Display the value into the buf as a string.
char*as_string(char*buf, size_t buf_len);
char*as_string(char*buf, size_t buf_len) const;
void invert();
vvp_vector4_t& operator &= (const vvp_vector4_t&that);
@ -1100,6 +1101,8 @@ class vvp_net_t {
void send_vec8(const vvp_vector8_t&val);
void send_real(double val, vvp_context_t context);
void send_long(long val);
void send_string(const std::string&val, vvp_context_t context);
void send_object(vvp_object_t val, vvp_context_t context);
void send_vec4_pv(const vvp_vector4_t&val,
unsigned base, unsigned wid, unsigned vwid,
@ -1177,6 +1180,10 @@ class vvp_net_fun_t {
virtual void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t context);
virtual void recv_long(vvp_net_ptr_t port, long bit);
virtual void recv_string(vvp_net_ptr_t port, const std::string&bit,
vvp_context_t context);
virtual void recv_object(vvp_net_ptr_t port, vvp_object_t bit,
vvp_context_t context);
// Part select variants of above
virtual void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit,
@ -1535,6 +1542,30 @@ extern void vvp_send_long(vvp_net_ptr_t ptr, long val);
extern void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
unsigned base, unsigned width);
inline void vvp_send_string(vvp_net_ptr_t ptr, const std::string&val, vvp_context_t context)
{
while (vvp_net_t*cur = ptr.ptr()) {
vvp_net_ptr_t next = cur->port[ptr.port()];
if (cur->fun)
cur->fun->recv_string(ptr, val, context);
ptr = next;
}
}
inline void vvp_send_object(vvp_net_ptr_t ptr, vvp_object_t val, vvp_context_t context)
{
while (vvp_net_t*cur = ptr.ptr()) {
vvp_net_ptr_t next = cur->port[ptr.port()];
if (cur->fun)
cur->fun->recv_object(ptr, val, context);
ptr = next;
}
}
/*
* Part-vector versions of above functions. This function uses the
* corresponding recv_vec4_pv method in the vvp_net_fun_t functor to
@ -1675,6 +1706,20 @@ inline void vvp_net_t::send_real(double val, vvp_context_t context)
}
inline void vvp_net_t::send_string(const std::string&val, vvp_context_t context)
{
assert(!fil);
vvp_send_string(out_, val, context);
}
inline void vvp_net_t::send_object(vvp_object_t val, vvp_context_t context)
{
assert(!fil);
vvp_send_object(out_, val, context);
}
inline bool vvp_net_fil_t::test_force_mask(unsigned bit) const
{
if (bit >= force_mask_.size())

View File

@ -22,6 +22,7 @@
# include "vvp_net_sig.h"
# include "statistics.h"
# include "vpi_priv.h"
# include <vector>
# include <cassert>
#ifdef CHECK_WITH_VALGRIND
# include <valgrind/memcheck.h>
@ -30,6 +31,8 @@
# include <iostream>
using namespace std;
/*
* The filter_mask_ method takes as an input the value to propagate,
* the mask of what is being forced, and returns a propagation
@ -585,6 +588,158 @@ void vvp_fun_signal_real_aa::operator delete(void*)
assert(0);
}
vvp_fun_signal_string_sa::vvp_fun_signal_string_sa()
{
}
void vvp_fun_signal_string_sa::recv_string(vvp_net_ptr_t ptr, const std::string&bit,
vvp_context_t)
{
assert(ptr.port() == 0);
if (needs_init_ || value_ != bit) {
value_ = bit;
needs_init_ = false;
ptr.ptr()->send_string(bit, 0);
}
}
vvp_fun_signal_string_aa::vvp_fun_signal_string_aa()
{
context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope());
}
vvp_fun_signal_string_aa::~vvp_fun_signal_string_aa()
{
assert(0);
}
void vvp_fun_signal_string_aa::alloc_instance(vvp_context_t)
{
assert(0);
}
void vvp_fun_signal_string_aa::reset_instance(vvp_context_t)
{
assert(0);
}
unsigned vvp_fun_signal_string_aa::value_size() const
{
assert(0);
return 1;
}
vvp_bit4_t vvp_fun_signal_string_aa::value(unsigned) const
{
assert(0);
return BIT4_X;
}
vvp_scalar_t vvp_fun_signal_string_aa::scalar_value(unsigned) const
{
assert(0);
return vvp_scalar_t();
}
void vvp_fun_signal_string_aa::vec4_value(vvp_vector4_t&) const
{
assert(0);
}
double vvp_fun_signal_string_aa::real_value() const
{
assert(0);
return 0.0;
}
void* vvp_fun_signal_string_aa::operator new(std::size_t size)
{
return vvp_net_fun_t::heap_.alloc(size);
}
void vvp_fun_signal_string_aa::operator delete(void*)
{
assert(0);
}
/* OBJECT signals */
vvp_fun_signal_object_sa::vvp_fun_signal_object_sa()
{
}
void vvp_fun_signal_object_sa::recv_object(vvp_net_ptr_t ptr, vvp_object_t bit,
vvp_context_t)
{
assert(ptr.port() == 0);
if (needs_init_ || value_ != bit) {
if (value_) delete value_;
value_ = bit;
needs_init_ = false;
ptr.ptr()->send_object(bit, 0);
}
}
vvp_fun_signal_object_aa::vvp_fun_signal_object_aa()
{
context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope());
}
vvp_fun_signal_object_aa::~vvp_fun_signal_object_aa()
{
assert(0);
}
void vvp_fun_signal_object_aa::alloc_instance(vvp_context_t)
{
assert(0);
}
void vvp_fun_signal_object_aa::reset_instance(vvp_context_t)
{
assert(0);
}
unsigned vvp_fun_signal_object_aa::value_size() const
{
assert(0);
return 1;
}
vvp_bit4_t vvp_fun_signal_object_aa::value(unsigned) const
{
assert(0);
return BIT4_X;
}
vvp_scalar_t vvp_fun_signal_object_aa::scalar_value(unsigned) const
{
assert(0);
return vvp_scalar_t();
}
void vvp_fun_signal_object_aa::vec4_value(vvp_vector4_t&) const
{
assert(0);
}
void* vvp_fun_signal_object_aa::operator new(std::size_t size)
{
return vvp_net_fun_t::heap_.alloc(size);
}
void vvp_fun_signal_object_aa::operator delete(void*)
{
assert(0);
}
/* **** */
vvp_fun_force::vvp_fun_force()
{
}
@ -1090,3 +1245,67 @@ double vvp_wire_real::real_value() const
else
return bit_;
}
#if 0
vvp_wire_string::vvp_wire_string()
{
}
unsigned vvp_wire_string::filter_size() const
{
assert(0);
return 0;
}
void vvp_wire_string::force_fil_vec4(const vvp_vector4_t&, vvp_vector2_t)
{
assert(0);
}
void vvp_wire_string::force_fil_vec8(const vvp_vector8_t&, vvp_vector2_t)
{
assert(0);
}
void vvp_wire_string::force_fil_real(double, vvp_vector2_t)
{
assert(0);
}
void vvp_wire_string::release(vvp_net_ptr_t ptr, bool net_flag)
{
assert(0);
}
void vvp_wire_string::release_pv(vvp_net_ptr_t, unsigned, unsigned, bool)
{
assert(0);
}
unsigned vvp_wire_string::value_size() const
{
assert(0);
return 1;
}
vvp_bit4_t vvp_wire_string::value(unsigned) const
{
assert(0);
return BIT4_X;
}
vvp_scalar_t vvp_wire_string::scalar_value(unsigned) const
{
assert(0);
return vvp_scalar_t();
}
void vvp_wire_string::vec4_value(vvp_vector4_t&) const
{
assert(0);
}
double vvp_wire_string::real_value() const
{
assert(0);
return 0.0;
}
#endif

View File

@ -22,6 +22,8 @@
# include "config.h"
# include "vpi_user.h"
# include "vvp_net.h"
# include "vvp_object.h"
# include <string>
# include <cstddef>
# include <cstdlib>
# include <cstring>
@ -261,6 +263,119 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_sign
};
class vvp_fun_signal_string : public vvp_fun_signal_base {
public:
explicit vvp_fun_signal_string() {};
unsigned size() const { return 1; }
inline const std::string& get_string() const { return value_; }
protected:
std::string value_;
};
/*
* Statically allocated vvp_fun_signal_string.
*/
class vvp_fun_signal_string_sa : public vvp_fun_signal_string {
public:
explicit vvp_fun_signal_string_sa();
void recv_string(vvp_net_ptr_t port, const std::string&bit,
vvp_context_t context);
};
/*
* Automatically allocated vvp_fun_signal_real.
*/
class vvp_fun_signal_string_aa : public vvp_fun_signal_string, public automatic_signal_base, public automatic_hooks_s {
public:
explicit vvp_fun_signal_string_aa();
~vvp_fun_signal_string_aa();
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
// Get information about the vector value.
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
void vec4_value(vvp_vector4_t&) const;
double real_value() const;
void get_signal_value(struct t_vpi_value*vp);
public: // These objects are only permallocated.
static void* operator new(std::size_t size);
static void operator delete(void*obj);
private:
unsigned context_idx_;
};
class vvp_fun_signal_object : public vvp_fun_signal_base {
public:
explicit vvp_fun_signal_object() {};
unsigned size() const { return 1; }
inline vvp_object_t get_object() const { return value_; }
protected:
vvp_object_t value_;
};
/*
* Statically allocated vvp_fun_signal_string.
*/
class vvp_fun_signal_object_sa : public vvp_fun_signal_object {
public:
explicit vvp_fun_signal_object_sa();
void recv_object(vvp_net_ptr_t port, vvp_object_t bit,
vvp_context_t context);
};
/*
* Automatically allocated vvp_fun_signal_real.
*/
class vvp_fun_signal_object_aa : public vvp_fun_signal_object, public automatic_signal_base, public automatic_hooks_s {
public:
explicit vvp_fun_signal_object_aa();
~vvp_fun_signal_object_aa();
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
// Get information about the vector value.
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
void vec4_value(vvp_vector4_t&) const;
//double real_value() const;
//void get_signal_value(struct t_vpi_value*vp);
public: // These objects are only permallocated.
static void* operator new(std::size_t size);
static void operator delete(void*obj);
private:
unsigned context_idx_;
};
/* vvp_wire
* The vvp_wire is different from vvp_variable objects in that it
* exists only as a filter. The vvp_wire class tree is for
@ -400,4 +515,34 @@ class vvp_wire_real : public vvp_wire_base {
double force_;
};
#if 0
class vvp_wire_string : public vvp_wire_base {
public:
explicit vvp_wire_string(void);
// Abstract methods from vvp_vpi_callback
void get_value(struct t_vpi_value*value);
// Abstract methods from vvp_net_fil_t
unsigned filter_size() const;
void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
void force_fil_real(double val, vvp_vector2_t mask);
void release(vvp_net_ptr_t ptr, bool net_flag);
void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag);
// Implementation of vvp_signal_value methods
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
void vec4_value(vvp_vector4_t&) const;
double real_value() const;
void get_signal_value(struct t_vpi_value*vp);
private:
std::string value_;
};
#endif
#endif

70
vvp/vvp_object.cc Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2012 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_object.h"
# include "vvp_net.h"
# include <iostream>
# include <typeinfo>
using namespace std;
vvp_object::~vvp_object()
{
}
vvp_darray::~vvp_darray()
{
}
void vvp_darray::set_word(unsigned adr, const vvp_vector4_t&)
{
cerr << "XXXX set_word not implemented for " << typeid(*this).name() << endl;
}
void vvp_darray::get_word(unsigned, vvp_vector4_t&)
{
cerr << "XXXX get_word not implemented for " << typeid(*this).name() << endl;
}
template <> vvp_darray_atom<int32_t>::~vvp_darray_atom()
{
}
template <> void vvp_darray_atom<int32_t>::set_word(unsigned adr, const vvp_vector4_t&value)
{
if (adr >= array_.size())
return;
vector4_to_value(value, array_[adr], true, false);
}
template <> void vvp_darray_atom<int32_t>::get_word(unsigned adr, vvp_vector4_t&value)
{
if (adr >= array_.size()) {
value = vvp_vector4_t(32, BIT4_X);
return;
}
uint32_t word = array_[adr];
vvp_vector4_t tmp (32, BIT4_0);
for (unsigned idx = 0 ; idx < 32 ; idx += 1) {
if (word&1) tmp.set_bit(idx, BIT4_1);
word >>= 1;
}
value = tmp;
}

64
vvp/vvp_object.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef __vvp_object_H
#define __vvp_object_H
/*
* Copyright (c) 2012 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 <stdlib.h>
# include <vector>
typedef class vvp_object*vvp_object_t;
class vvp_vector4_t;
class vvp_object {
public:
inline vvp_object() { }
virtual ~vvp_object() =0;
};
class vvp_darray : public vvp_object {
public:
inline vvp_darray(size_t siz) : size_(siz) { }
virtual ~vvp_darray();
inline size_t get_size(void) const { return size_; }
virtual void set_word(unsigned adr, const vvp_vector4_t&value);
virtual void get_word(unsigned adr, vvp_vector4_t&value);
private:
size_t size_;
};
template <class TYPE> class vvp_darray_atom : public vvp_darray {
public:
inline vvp_darray_atom(size_t siz) : vvp_darray(siz), array_(siz) { }
~vvp_darray_atom();
void set_word(unsigned adr, const vvp_vector4_t&value);
void get_word(unsigned adr, vvp_vector4_t&value);
private:
std::vector<TYPE> array_;
};
#endif

View File

@ -65,9 +65,8 @@ static void __compile_var_real(char*label, char*name,
delete[] name;
}
void compile_var_real(char*label, char*name, int msb, int lsb)
void compile_var_real(char*label, char*name)
{
assert(msb == 0 && lsb == 0);
__compile_var_real(label, name, 0, 0);
}
@ -79,6 +78,78 @@ void compile_varw_real(char*label, vvp_array_t array,
__compile_var_real(label, 0, array, addr);
}
static void __compile_var_string(char*label, char*name,
vvp_array_t array, unsigned long array_addr)
{
vvp_net_t*net = new vvp_net_t;
if (vpip_peek_current_scope()->is_automatic) {
vvp_fun_signal_string_aa*tmp = new vvp_fun_signal_string_aa;
net->fil = tmp;
net->fun = tmp;
} else {
net->fil = 0;
net->fun = new vvp_fun_signal_string_sa;
}
define_functor_symbol(label, net);
vpiHandle obj = vpip_make_string_var(name, net);
compile_vpi_symbol(label, obj);
if (name) {
assert(!array);
vpip_attach_to_current_scope(obj);
}
if (array) {
assert(!name);
array_attach_word(array, array_addr, obj);
}
delete[]label;
delete[] name;
}
void compile_var_string(char*label, char*name)
{
__compile_var_string(label, name, 0, 0);
}
static void __compile_var_darray(char*label, char*name,
vvp_array_t array, unsigned long array_addr)
{
vvp_net_t*net = new vvp_net_t;
if (vpip_peek_current_scope()->is_automatic) {
vvp_fun_signal_object_aa*tmp = new vvp_fun_signal_object_aa;
net->fil = tmp;
net->fun = tmp;
} else {
net->fil = 0;
net->fun = new vvp_fun_signal_object_sa;
}
define_functor_symbol(label, net);
vpiHandle obj = vpip_make_darray_var(name, net);
compile_vpi_symbol(label, obj);
if (name) {
assert(!array);
vpip_attach_to_current_scope(obj);
}
if (array) {
assert(!name);
array_attach_word(array, array_addr, obj);
}
delete[]label;
delete[] name;
}
void compile_var_darray(char*label, char*name)
{
__compile_var_darray(label, name, 0, 0);
}
/*
* A variable is a special functor, so we allocate that functor and
* write the label into the symbol table.