Add support for dynamic array/queue "last" index ($)
Internally, treat the "$" as a special expression type that takes as an argument the signal that is being indexed. In the vvp target, use the $last system function to implement this.
This commit is contained in:
parent
9b4681918b
commit
c9ff48bd4e
|
|
@ -1704,6 +1704,11 @@ void NetEEvent::dump(ostream&o) const
|
||||||
o << "<event=" << event_->name() << ">";
|
o << "<event=" << event_->name() << ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetELast::dump(ostream&fd) const
|
||||||
|
{
|
||||||
|
fd << "<last of " << sig_->name() << ">";
|
||||||
|
}
|
||||||
|
|
||||||
void NetENetenum::dump(ostream&o) const
|
void NetENetenum::dump(ostream&o) const
|
||||||
{
|
{
|
||||||
o << "<netenum=" << netenum_ << ">";
|
o << "<netenum=" << netenum_ << ">";
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,14 @@ NetEEvent* NetEEvent::dup_expr() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetELast* NetELast::dup_expr() const
|
||||||
|
{
|
||||||
|
NetELast*tmp = new NetELast(sig_);
|
||||||
|
ivl_assert(*this, tmp);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
NetENetenum* NetENetenum::dup_expr() const
|
NetENetenum* NetENetenum::dup_expr() const
|
||||||
{
|
{
|
||||||
ivl_assert(*this, 0);
|
ivl_assert(*this, 0);
|
||||||
|
|
|
||||||
22
elab_expr.cc
22
elab_expr.cc
|
|
@ -4768,17 +4768,29 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*des, NetScope*scope,
|
NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*, NetScope*,
|
||||||
NetESignal*net,
|
NetESignal*net,
|
||||||
NetScope*found_in,
|
NetScope* /* found_in */,
|
||||||
bool need_const) const
|
bool need_const) const
|
||||||
{
|
{
|
||||||
cerr << get_fileline() << ": sorry: "
|
if (need_const) {
|
||||||
<< "Don't yet know how to elaborate net expresion [$]" << endl;
|
cerr << get_fileline() << ": error: "
|
||||||
des->errors += 1;
|
<< "Expression with \"[$]\" is not constant." << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned use_width = 1;
|
||||||
|
if (const netdarray_t*darray = net->sig()->darray_type()) {
|
||||||
|
use_width = darray->element_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
NetELast*mux = new NetELast(net->sig());
|
||||||
|
mux->set_line(*this);
|
||||||
|
NetESelect*ss = new NetESelect(net, mux, use_width);
|
||||||
|
ss->set_line(*this);
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
|
NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
|
||||||
NetNet*net, NetScope*found_in,
|
NetNet*net, NetScope*found_in,
|
||||||
unsigned expr_wid,
|
unsigned expr_wid,
|
||||||
|
|
|
||||||
5
emit.cc
5
emit.cc
|
|
@ -610,6 +610,11 @@ void NetEEvent::expr_scan(struct expr_scan_t*tgt) const
|
||||||
tgt->expr_event(this);
|
tgt->expr_event(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetELast::expr_scan(struct expr_scan_t*tgt) const
|
||||||
|
{
|
||||||
|
tgt->expr_last(this);
|
||||||
|
}
|
||||||
|
|
||||||
void NetENetenum::expr_scan(struct expr_scan_t*tgt) const
|
void NetENetenum::expr_scan(struct expr_scan_t*tgt) const
|
||||||
{
|
{
|
||||||
tgt->expr_netenum(this);
|
tgt->expr_netenum(this);
|
||||||
|
|
|
||||||
14
net_expr.cc
14
net_expr.cc
|
|
@ -321,6 +321,20 @@ const NetScope* NetECRealParam::scope() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NetELast::NetELast(NetNet*s)
|
||||||
|
: sig_(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetELast::~NetELast()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ivl_variable_type_t NetELast::expr_type() const
|
||||||
|
{
|
||||||
|
return IVL_VT_BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
NetENetenum::NetENetenum(const netenum_t*s)
|
NetENetenum::NetENetenum(const netenum_t*s)
|
||||||
: netenum_(s)
|
: netenum_(s)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,11 @@ NexusSet* NetEEvent::nex_input(bool)
|
||||||
return new NexusSet;
|
return new NexusSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NexusSet* NetELast::nex_input(bool)
|
||||||
|
{
|
||||||
|
return new NexusSet;
|
||||||
|
}
|
||||||
|
|
||||||
NexusSet* NetENetenum::nex_input(bool)
|
NexusSet* NetENetenum::nex_input(bool)
|
||||||
{
|
{
|
||||||
return new NexusSet;
|
return new NexusSet;
|
||||||
|
|
|
||||||
25
netlist.h
25
netlist.h
|
|
@ -3613,6 +3613,31 @@ class NetTaskDef : public NetBaseDef {
|
||||||
NetTaskDef& operator= (const NetTaskDef&);
|
NetTaskDef& operator= (const NetTaskDef&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The NetELast expression node takes as an argument a net, that is
|
||||||
|
* intended to be a queue or dynamic array object. The return value is
|
||||||
|
* the index of the last item in the node. This is intended to
|
||||||
|
* implement the '$' is the expression "foo[$]".
|
||||||
|
*/
|
||||||
|
class NetELast : public NetExpr {
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NetELast(NetNet*sig);
|
||||||
|
~NetELast();
|
||||||
|
|
||||||
|
inline const NetNet*sig() const { return sig_; }
|
||||||
|
|
||||||
|
virtual ivl_variable_type_t expr_type() const;
|
||||||
|
virtual void dump(std::ostream&) const;
|
||||||
|
|
||||||
|
virtual void expr_scan(struct expr_scan_t*) const;
|
||||||
|
virtual NetELast*dup_expr() const;
|
||||||
|
virtual NexusSet* nex_input(bool rem_out = true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetNet*sig_;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This node represents a function call in an expression. The object
|
* This node represents a function call in an expression. The object
|
||||||
* contains a pointer to the function definition, which is used to
|
* contains a pointer to the function definition, which is used to
|
||||||
|
|
|
||||||
|
|
@ -343,6 +343,38 @@ void dll_target::expr_creal(const NetECReal*net)
|
||||||
expr_->u_.real_.value = net->value().as_double();
|
expr_->u_.real_.value = net->value().as_double();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dll_target::expr_last(const NetELast*net)
|
||||||
|
{
|
||||||
|
assert(expr_ == 0);
|
||||||
|
ivl_expr_t expr = new struct ivl_expr_s;
|
||||||
|
expr->type_ = IVL_EX_SFUNC;
|
||||||
|
expr->value_ = IVL_VT_LOGIC;
|
||||||
|
expr->width_ = 32;
|
||||||
|
expr->signed_ = 1;
|
||||||
|
expr->sized_ = 1;
|
||||||
|
expr->net_type = 0;
|
||||||
|
FILE_NAME(expr, net);
|
||||||
|
|
||||||
|
expr->u_.sfunc_.name_ = "$high";
|
||||||
|
|
||||||
|
ivl_signal_t sig = find_signal(des_, net->sig());
|
||||||
|
|
||||||
|
ivl_expr_t esig = new struct ivl_expr_s;
|
||||||
|
esig->type_ = IVL_EX_SIGNAL;
|
||||||
|
esig->value_ = IVL_VT_DARRAY;
|
||||||
|
esig->net_type= sig->net_type;
|
||||||
|
esig->width_ = 1;
|
||||||
|
FILE_NAME(esig, net);
|
||||||
|
esig->u_.signal_.word = 0;
|
||||||
|
esig->u_.signal_.sig = sig;
|
||||||
|
|
||||||
|
expr->u_.sfunc_.parms = 1;
|
||||||
|
expr->u_.sfunc_.parm = new ivl_expr_t[1];
|
||||||
|
expr->u_.sfunc_.parm[0] = esig;
|
||||||
|
|
||||||
|
expr_ = expr;
|
||||||
|
}
|
||||||
|
|
||||||
void dll_target::expr_new(const NetENew*net)
|
void dll_target::expr_new(const NetENew*net)
|
||||||
{
|
{
|
||||||
ivl_expr_t size = 0;
|
ivl_expr_t size = 0;
|
||||||
|
|
|
||||||
1
t-dll.h
1
t-dll.h
|
|
@ -141,6 +141,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||||
void expr_concat(const NetEConcat*);
|
void expr_concat(const NetEConcat*);
|
||||||
void expr_const(const NetEConst*);
|
void expr_const(const NetEConst*);
|
||||||
void expr_creal(const NetECReal*);
|
void expr_creal(const NetECReal*);
|
||||||
|
void expr_last(const NetELast*);
|
||||||
void expr_new(const NetENew*);
|
void expr_new(const NetENew*);
|
||||||
void expr_null(const NetENull*);
|
void expr_null(const NetENull*);
|
||||||
void expr_param(const NetEConstParam*);
|
void expr_param(const NetEConstParam*);
|
||||||
|
|
|
||||||
|
|
@ -471,6 +471,12 @@ void expr_scan_t::expr_const(const NetEConst*)
|
||||||
"unhandled expr_const." << endl;
|
"unhandled expr_const." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expr_scan_t::expr_last(const NetELast*exp)
|
||||||
|
{
|
||||||
|
cerr << exp->get_fileline() << ": expr_scan_t(" << typeid(*this).name() << "): "
|
||||||
|
<< "unhandled expr_last." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
void expr_scan_t::expr_new(const NetENew*)
|
void expr_scan_t::expr_new(const NetENew*)
|
||||||
{
|
{
|
||||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||||
|
|
|
||||||
1
target.h
1
target.h
|
|
@ -159,6 +159,7 @@ struct expr_scan_t {
|
||||||
virtual void expr_access_func(const NetEAccess*);
|
virtual void expr_access_func(const NetEAccess*);
|
||||||
virtual void expr_array_pattern(const NetEArrayPattern*);
|
virtual void expr_array_pattern(const NetEArrayPattern*);
|
||||||
virtual void expr_const(const NetEConst*);
|
virtual void expr_const(const NetEConst*);
|
||||||
|
virtual void expr_last(const NetELast*);
|
||||||
virtual void expr_new(const NetENew*);
|
virtual void expr_new(const NetENew*);
|
||||||
virtual void expr_null(const NetENull*);
|
virtual void expr_null(const NetENull*);
|
||||||
virtual void expr_param(const NetEConstParam*);
|
virtual void expr_param(const NetEConstParam*);
|
||||||
|
|
|
||||||
|
|
@ -2533,9 +2533,10 @@ static struct vector_info draw_select_signal(ivl_expr_t expr,
|
||||||
unsigned use_word = 0;
|
unsigned use_word = 0;
|
||||||
unsigned use_wid, lab_x, lab_end;
|
unsigned use_wid, lab_x, lab_end;
|
||||||
|
|
||||||
/* Special case: the sub expression is a DARRAY variable, so
|
/* Special case: the sub expression is a DARRAY or QUEUE
|
||||||
do a dynamic array word load. */
|
variable, so do a dynamic array word load. */
|
||||||
if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) {
|
if ((ivl_signal_data_type(sig) == IVL_VT_DARRAY)
|
||||||
|
|| (ivl_signal_data_type(sig) == IVL_VT_QUEUE)) {
|
||||||
res.base = allocate_vector(wid);
|
res.base = allocate_vector(wid);
|
||||||
res.wid = wid;
|
res.wid = wid;
|
||||||
draw_eval_expr_into_integer(bit_idx, 3);
|
draw_eval_expr_into_integer(bit_idx, 3);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Cary R. (cygcary@yahoo.com)
|
* Copyright (C) 2013 Cary R. (cygcary@yahoo.com)
|
||||||
|
* Copyright (C) 2014 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -17,6 +18,37 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# include "sys_priv.h"
|
# include "sys_priv.h"
|
||||||
|
# include <assert.h>
|
||||||
|
|
||||||
|
static PLI_INT32 one_array_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 an array 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 func_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name)
|
static PLI_INT32 func_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name)
|
||||||
{
|
{
|
||||||
|
|
@ -29,6 +61,59 @@ static PLI_INT32 func_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void high_array(const char*name, vpiHandle callh, vpiHandle arg)
|
||||||
|
{
|
||||||
|
s_vpi_value value;
|
||||||
|
int array_type;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
switch ( (array_type = vpi_get(vpiArrayType, arg)) ) {
|
||||||
|
case vpiDynamicArray:
|
||||||
|
case vpiQueueArray:
|
||||||
|
size = vpi_get(vpiSize, arg);
|
||||||
|
value.format = vpiIntVal;
|
||||||
|
value.value.integer = size - 1;
|
||||||
|
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vpi_printf("SORRY: %s:%d: function %s() argument object code is %d\n",
|
||||||
|
vpi_get_str(vpiFile,callh), (int)vpi_get(vpiLineNo, callh),
|
||||||
|
name, array_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 high_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv;
|
||||||
|
vpiHandle arg;
|
||||||
|
int object_code;
|
||||||
|
|
||||||
|
(void)name; /* Parameter is not used. */
|
||||||
|
|
||||||
|
argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
assert(argv);
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
assert(arg);
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
switch ( (object_code = vpi_get(vpiType, arg)) ) {
|
||||||
|
case vpiArrayVar:
|
||||||
|
high_array(name, callh, arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vpi_printf("SORRY: %s:%d: function %s() argument object code is %d\n",
|
||||||
|
vpi_get_str(vpiFile,callh), (int)vpi_get(vpiLineNo, callh),
|
||||||
|
name, object_code);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void v2009_array_register(void)
|
void v2009_array_register(void)
|
||||||
{
|
{
|
||||||
s_vpi_systf_data tf_data;
|
s_vpi_systf_data tf_data;
|
||||||
|
|
@ -66,13 +151,15 @@ void v2009_array_register(void)
|
||||||
res = vpi_register_systf(&tf_data);
|
res = vpi_register_systf(&tf_data);
|
||||||
vpip_make_systf_system_defined(res);
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
tf_data.tfname = "$high";
|
|
||||||
tf_data.user_data = "$high";
|
|
||||||
res = vpi_register_systf(&tf_data);
|
|
||||||
vpip_make_systf_system_defined(res);
|
|
||||||
|
|
||||||
tf_data.tfname = "$increment";
|
tf_data.tfname = "$increment";
|
||||||
tf_data.user_data = "$increment";
|
tf_data.user_data = "$increment";
|
||||||
res = vpi_register_systf(&tf_data);
|
res = vpi_register_systf(&tf_data);
|
||||||
vpip_make_systf_system_defined(res);
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
|
tf_data.tfname = "$high";
|
||||||
|
tf_data.user_data = "$high";
|
||||||
|
tf_data.compiletf = one_array_arg_compiletf;
|
||||||
|
tf_data.calltf = high_calltf;
|
||||||
|
res = vpi_register_systf(&tf_data);
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3328,7 +3328,13 @@ bool of_LOAD_DAR(vthread_t thr, vvp_code_t cp)
|
||||||
|
|
||||||
vvp_vector4_t word;
|
vvp_vector4_t word;
|
||||||
darray->get_word(adr, word);
|
darray->get_word(adr, word);
|
||||||
assert(word.size() == wid);
|
|
||||||
|
if (word.size() != wid) {
|
||||||
|
cerr << __FILE__ << ":" << __LINE__
|
||||||
|
<< ": %load/dar element word.size()=" << word.size()
|
||||||
|
<< ", expecting wid=" << wid << "." << endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
thr_check_addr(thr, bit+word.size());
|
thr_check_addr(thr, bit+word.size());
|
||||||
thr->bits4.set_vec(bit, word);
|
thr->bits4.set_vec(bit, word);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue