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:
Stephen Williams 2014-08-16 16:11:40 -07:00
parent 9b4681918b
commit c9ff48bd4e
14 changed files with 224 additions and 16 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() << "): "

View File

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

View File

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

View File

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

View File

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