Merge branch 'x-mil3'
Conflicts: vpi/Makefile.in vpi/sys_table.c
This commit is contained in:
commit
813f548a4b
|
|
@ -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 \
|
||||
|
|
|
|||
10
PExpr.cc
10
PExpr.cc
|
|
@ -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
30
PExpr.h
|
|
@ -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);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
1
PWire.h
1
PWire.h
|
|
@ -33,6 +33,7 @@ class ostream;
|
|||
|
||||
class PExpr;
|
||||
class Design;
|
||||
class netdarray_t;
|
||||
|
||||
/*
|
||||
* The different type of PWire::set_range() calls.
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
262
elab_expr.cc
262
elab_expr.cc
|
|
@ -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;
|
||||
|
|
|
|||
52
elab_lval.cc
52
elab_lval.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
68
elab_sig.cc
68
elab_sig.cc
|
|
@ -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_;
|
||||
|
|
|
|||
41
elaborate.cc
41
elaborate.cc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
13
net_expr.cc
13
net_expr.cc
|
|
@ -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() );
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
99
netlist.cc
99
netlist.cc
|
|
@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
25
netlist.h
25
netlist.h
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
32
netmisc.cc
32
netmisc.cc
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
26
nettypes.cc
26
nettypes.cc
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
41
nettypes.h
41
nettypes.h
|
|
@ -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
16
parse.y
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
5
pform.cc
5
pform.cc
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,3 +23,7 @@
|
|||
data_type_t::~data_type_t()
|
||||
{
|
||||
}
|
||||
|
||||
string_type_t::~string_type_t()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) { }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
12
t-dll-api.cc
12
t-dll-api.cc
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
31
t-dll.cc
31
t-dll.cc
|
|
@ -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();
|
||||
|
|
|
|||
3
t-dll.h
3
t-dll.h
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -21,3 +21,5 @@ $abstime vpiSysFuncReal
|
|||
$simparam vpiSysFuncReal
|
||||
$simparam$str vpiSysFuncSized 1024 unsigned
|
||||
$table_model vpiSysFuncReal
|
||||
|
||||
$ivl_string_method$len vpiSysFuncInt
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
16
vvp/codes.h
16
vvp/codes.h
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
100
vvp/opcodes.txt
100
vvp/opcodes.txt
|
|
@ -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
|
||||
|
|
|
|||
52
vvp/parse.y
52
vvp/parse.y
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
338
vvp/vthread.cc
338
vvp/vthread.cc
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
75
vvp/words.cc
75
vvp/words.cc
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue