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() << ">";
|
||||
}
|
||||
|
||||
void NetELast::dump(ostream&fd) const
|
||||
{
|
||||
fd << "<last of " << sig_->name() << ">";
|
||||
}
|
||||
|
||||
void NetENetenum::dump(ostream&o) const
|
||||
{
|
||||
o << "<netenum=" << netenum_ << ">";
|
||||
|
|
|
|||
|
|
@ -182,6 +182,14 @@ NetEEvent* NetEEvent::dup_expr() const
|
|||
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
|
||||
{
|
||||
ivl_assert(*this, 0);
|
||||
|
|
|
|||
22
elab_expr.cc
22
elab_expr.cc
|
|
@ -4768,15 +4768,27 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
|||
return ss;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*des, NetScope*scope,
|
||||
NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*, NetScope*,
|
||||
NetESignal*net,
|
||||
NetScope*found_in,
|
||||
NetScope* /* found_in */,
|
||||
bool need_const) const
|
||||
{
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Don't yet know how to elaborate net expresion [$]" << endl;
|
||||
des->errors += 1;
|
||||
if (need_const) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Expression with \"[$]\" is not constant." << endl;
|
||||
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,
|
||||
|
|
|
|||
5
emit.cc
5
emit.cc
|
|
@ -610,6 +610,11 @@ void NetEEvent::expr_scan(struct expr_scan_t*tgt) const
|
|||
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
|
||||
{
|
||||
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)
|
||||
: netenum_(s)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -106,6 +106,11 @@ NexusSet* NetEEvent::nex_input(bool)
|
|||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetELast::nex_input(bool)
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetENetenum::nex_input(bool)
|
||||
{
|
||||
return new NexusSet;
|
||||
|
|
|
|||
25
netlist.h
25
netlist.h
|
|
@ -3613,6 +3613,31 @@ class NetTaskDef : public NetBaseDef {
|
|||
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
|
||||
* 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();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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_const(const NetEConst*);
|
||||
void expr_creal(const NetECReal*);
|
||||
void expr_last(const NetELast*);
|
||||
void expr_new(const NetENew*);
|
||||
void expr_null(const NetENull*);
|
||||
void expr_param(const NetEConstParam*);
|
||||
|
|
|
|||
|
|
@ -471,6 +471,12 @@ void expr_scan_t::expr_const(const NetEConst*)
|
|||
"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*)
|
||||
{
|
||||
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_array_pattern(const NetEArrayPattern*);
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_last(const NetELast*);
|
||||
virtual void expr_new(const NetENew*);
|
||||
virtual void expr_null(const NetENull*);
|
||||
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_wid, lab_x, lab_end;
|
||||
|
||||
/* Special case: the sub expression is a DARRAY variable, so
|
||||
do a dynamic array word load. */
|
||||
if (ivl_signal_data_type(sig) == IVL_VT_DARRAY) {
|
||||
/* Special case: the sub expression is a DARRAY or QUEUE
|
||||
variable, so do a dynamic array word load. */
|
||||
if ((ivl_signal_data_type(sig) == IVL_VT_DARRAY)
|
||||
|| (ivl_signal_data_type(sig) == IVL_VT_QUEUE)) {
|
||||
res.base = allocate_vector(wid);
|
||||
res.wid = wid;
|
||||
draw_eval_expr_into_integer(bit_idx, 3);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -16,7 +17,38 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
|
|
@ -29,6 +61,59 @@ static PLI_INT32 func_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name
|
|||
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)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
|
@ -66,13 +151,15 @@ void v2009_array_register(void)
|
|||
res = vpi_register_systf(&tf_data);
|
||||
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.user_data = "$increment";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
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;
|
||||
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->bits4.set_vec(bit, word);
|
||||
|
|
|
|||
Loading…
Reference in New Issue