From c9ff48bd4ec0bae9dbc665221063d9095b12a60d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 16 Aug 2014 16:11:40 -0700 Subject: [PATCH] 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. --- design_dump.cc | 5 +++ dup_expr.cc | 8 ++++ elab_expr.cc | 24 ++++++++--- emit.cc | 5 +++ net_expr.cc | 14 +++++++ net_nex_input.cc | 5 +++ netlist.h | 25 ++++++++++++ t-dll-expr.cc | 32 +++++++++++++++ t-dll.h | 1 + target.cc | 6 +++ target.h | 1 + tgt-vvp/eval_expr.c | 7 ++-- vpi/v2009_array.c | 99 ++++++++++++++++++++++++++++++++++++++++++--- vvp/vthread.cc | 8 +++- 14 files changed, 224 insertions(+), 16 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 5fa1209df..08327f491 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1704,6 +1704,11 @@ void NetEEvent::dump(ostream&o) const o << "name() << ">"; } +void NetELast::dump(ostream&fd) const +{ + fd << "name() << ">"; +} + void NetENetenum::dump(ostream&o) const { o << ""; diff --git a/dup_expr.cc b/dup_expr.cc index 08da1bb27..c1ec0ce0d 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -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); diff --git a/elab_expr.cc b/elab_expr.cc index e9579582c..bde26d975 100644 --- a/elab_expr.cc +++ b/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; - return 0; + 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, diff --git a/emit.cc b/emit.cc index edf90ef04..df661b909 100644 --- a/emit.cc +++ b/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); diff --git a/net_expr.cc b/net_expr.cc index c0e92ed4d..7cea59716 100644 --- a/net_expr.cc +++ b/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) { diff --git a/net_nex_input.cc b/net_nex_input.cc index c30f52368..aff41f281 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -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; diff --git a/netlist.h b/netlist.h index f277f5840..93b6482a6 100644 --- a/netlist.h +++ b/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 diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 30c73122e..9b748d955 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -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; diff --git a/t-dll.h b/t-dll.h index b588d2a8b..e7d092fd1 100644 --- a/t-dll.h +++ b/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*); diff --git a/target.cc b/target.cc index 4b9f4171b..a4fe8b44a 100644 --- a/target.cc +++ b/target.cc @@ -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() << "): " diff --git a/target.h b/target.h index 9361b6431..ec834418d 100644 --- a/target.h +++ b/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*); diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index ef99cedaf..ee6ada5bd 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -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); diff --git a/vpi/v2009_array.c b/vpi/v2009_array.c index fd760cea6..08cf79fbc 100644 --- a/vpi/v2009_array.c +++ b/vpi/v2009_array.c @@ -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 + +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); } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 8319df364..ae0a19b50 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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);