From 27cdd27889454fb9464360506143f92ce7d850ea Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 20 Jun 2008 18:11:11 -0700 Subject: [PATCH] Add .cast/int and update .cast/real. This patch adds .cast/int and updates .cast/real to act as a local (temporary) net and to support either a signed or unsigned input. The vvp_vector4_t class not can convert an arbitrarily sized double to a vector value. This removes the restriction of lround(). Also document the new statements. --- design_dump.cc | 8 +++ elaborate.cc | 30 +++++------ emit.cc | 5 ++ ivl_target.h | 1 + netlist.cc | 9 ++++ netlist.h | 18 +++++++ netmisc.cc | 21 ++++++++ netmisc.h | 1 + t-dll-api.cc | 3 ++ t-dll.cc | 32 ++++++++++++ t-dll.h | 1 + target.cc | 7 +++ target.h | 1 + tgt-stub/stub.c | 29 +++++++++++ tgt-vvp/draw_net_input.c | 1 + tgt-vvp/vvp_scope.c | 37 ++++++++------ vpi/vams_simparam.c | 2 +- vvp/README.txt | 20 +++++++- vvp/arith.cc | 16 +++++- vvp/arith.h | 11 ++++ vvp/compile.cc | 26 +++++++--- vvp/compile.h | 6 ++- vvp/lexor.lex | 2 + vvp/parse.y | 14 ++++- vvp/vvp_net.cc | 107 +++++++++++++++++++++++++++++---------- vvp/vvp_net.h | 6 ++- 26 files changed, 341 insertions(+), 73 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 53b625f3d..ac6748521 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -302,6 +302,14 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetCastInt::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "Cast to int. (NetCastInt): " << + name() << " width=" << width() << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetCastReal::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "Cast to real (NetCastReal): " << diff --git a/elaborate.cc b/elaborate.cc index 4331c8c0e..a0d8d73a0 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -113,14 +113,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const return; } - /* If either lval or rid are real then both must be real. */ - if ((lval->data_type() == IVL_VT_REAL || - rid->data_type() == IVL_VT_REAL) && - lval->data_type() != rid->data_type()) { - cerr << get_fileline() << ": sorry: Both the r-value and " - "the l-value must be real in this context." << endl; - des->errors += 1; - return; + /* Cast the right side when needed. */ + if ((lval->data_type() == IVL_VT_REAL && + rid->data_type() != IVL_VT_REAL)) { + rid = cast_to_real(des, scope, rid); + } else if ((lval->data_type() != IVL_VT_REAL && + rid->data_type() == IVL_VT_REAL)) { + rid = cast_to_int(des, scope, rid, lval->vector_width()); } ivl_assert(*this, rid); @@ -287,14 +286,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const assert(lval && rval); assert(rval->pin_count() == 1); - /* If either lval or rval are real then both must be real. */ - if ((lval->data_type() == IVL_VT_REAL || - rval->data_type() == IVL_VT_REAL) && - lval->data_type() != rval->data_type()) { - cerr << get_fileline() << ": sorry: Both the r-value and " - "the l-value must be real in this context." << endl; - des->errors += 1; - return; + /* Cast the right side when needed. */ + if ((lval->data_type() == IVL_VT_REAL && + rval->data_type() != IVL_VT_REAL)) { + rval = cast_to_real(des, scope, rval); + } else if ((lval->data_type() != IVL_VT_REAL && + rval->data_type() == IVL_VT_REAL)) { + rval = cast_to_int(des, scope, rval, lval->vector_width()); } /* If the r-value insists on being smaller then the l-value diff --git a/emit.cc b/emit.cc index 84c4d6a25..4e2b652b6 100644 --- a/emit.cc +++ b/emit.cc @@ -72,6 +72,11 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const return true; } +bool NetCastInt::emit_node(struct target_t*tgt) const +{ + return tgt->lpm_cast_int(this); +} + bool NetCastReal::emit_node(struct target_t*tgt) const { return tgt->lpm_cast_real(this); diff --git a/ivl_target.h b/ivl_target.h index 61069a6eb..13d4b68db 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -254,6 +254,7 @@ typedef enum ivl_lpm_type_e { IVL_LPM_ABS = 32, IVL_LPM_ADD = 0, IVL_LPM_ARRAY = 30, + IVL_LPM_CAST_INT = 34, IVL_LPM_CAST_REAL = 33, IVL_LPM_CONCAT = 16, IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */ diff --git a/netlist.cc b/netlist.cc index d1565aab0..51cf898f6 100644 --- a/netlist.cc +++ b/netlist.cc @@ -849,6 +849,15 @@ const NetScope* NetProcTop::scope() const return scope_; } +NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width) +: NetNode(scope, n, 2), width_(width) +{ + pin(0).set_dir(Link::OUTPUT); + pin(0).set_name(perm_string::literal("O"), 0); + pin(1).set_dir(Link::INPUT); + pin(1).set_name(perm_string::literal("I"), 0); +} + NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag) : NetNode(scope, n, 2), signed_flag_(signed_flag) { diff --git a/netlist.h b/netlist.h index 7c9186060..d8963aeea 100644 --- a/netlist.h +++ b/netlist.h @@ -916,6 +916,24 @@ class NetArrayDq : public NetNode { }; +/* + * Convert an IVL_VT_REAL input to a logical value with the + * given width. The input is pin(1) and the output is pin(0). + */ +class NetCastInt : public NetNode { + + public: + NetCastInt(NetScope*s, perm_string n, unsigned width); + + unsigned width() const { return width_; } + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + + private: + unsigned width_; +}; + /* * Convert an input to IVL_VT_REAL. The input is pin(1), which can be * any vector type (VT_BOOL or VT_LOGIC) and the output is pin(0), diff --git a/netmisc.cc b/netmisc.cc index eea23d1e2..2cab1dc8d 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -76,6 +76,26 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val) #endif } +NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid) +{ + if (src->data_type() != IVL_VT_REAL) + return src; + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + tmp->data_type(IVL_VT_LOGIC); + tmp->set_line(*src); + tmp->local_flag(true); + + NetCastInt*cast = new NetCastInt(scope, scope->local_symbol(), wid); + cast->set_line(*src); + des->add_node(cast); + + connect(cast->pin(0), tmp->pin(0)); + connect(cast->pin(1), src->pin(0)); + + return tmp; +} + NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) { if (src->data_type() == IVL_VT_REAL) @@ -84,6 +104,7 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); tmp->data_type(IVL_VT_REAL); tmp->set_line(*src); + tmp->local_flag(true); NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed()); cast->set_line(*src); diff --git a/netmisc.h b/netmisc.h index 3c8ce1ca9..20efe2d98 100644 --- a/netmisc.h +++ b/netmisc.h @@ -68,6 +68,7 @@ extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w); * Generate the nodes necessary to cast an expression (a net) to a * real value. */ +extern NetNet*cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid); extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src); /* diff --git a/t-dll-api.cc b/t-dll-api.cc index e5e275aad..cf3c9b83c 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -886,6 +886,7 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) assert(net); switch (net->type) { case IVL_LPM_ABS: + case IVL_LPM_CAST_INT: case IVL_LPM_CAST_REAL: assert(idx == 0); return net->u_.arith.a; @@ -1029,6 +1030,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) switch (net->type) { case IVL_LPM_ABS: case IVL_LPM_ADD: + case IVL_LPM_CAST_INT: case IVL_LPM_CAST_REAL: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: @@ -1166,6 +1168,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_SHIFTL: case IVL_LPM_SHIFTR: return net->u_.shift.signed_flag; + case IVL_LPM_CAST_INT: case IVL_LPM_SIGN_EXT: // Sign extend is always signed. return 1; case IVL_LPM_SFUNC: diff --git a/t-dll.cc b/t-dll.cc index edeb58a8c..5b6a22a52 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1550,6 +1550,38 @@ void dll_target::lpm_clshift(const NetCLShift*net) scope_add_lpm(obj->scope, obj); } +bool dll_target::lpm_cast_int(const NetCastInt*net) +{ + ivl_lpm_t obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_CAST_INT; + obj->name = net->name(); // NetCastInt names are permallocated + assert(net->scope()); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + + obj->width = net->width(); + + const Nexus*nex; + + nex = net->pin(0).nexus(); + assert(nex->t_cookie()); + + obj->u_.arith.q = nex->t_cookie(); + + nex = net->pin(1).nexus(); + assert(nex->t_cookie()); + obj->u_.arith.a = nex->t_cookie(); + + nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); + nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + make_lpm_delays_(obj, net); + + scope_add_lpm(obj->scope, obj); + + return true; +} + bool dll_target::lpm_cast_real(const NetCastReal*net) { ivl_lpm_t obj = new struct ivl_lpm_s; diff --git a/t-dll.h b/t-dll.h index 3b017bf83..5bc4c3fb4 100644 --- a/t-dll.h +++ b/t-dll.h @@ -76,6 +76,7 @@ struct dll_target : public target_t, public expr_scan_t { void lpm_abs(const NetAbs*); void lpm_add_sub(const NetAddSub*); bool lpm_array_dq(const NetArrayDq*); + bool lpm_cast_int(const NetCastInt*); bool lpm_cast_real(const NetCastReal*); void lpm_clshift(const NetCLShift*); void lpm_compare(const NetCompare*); diff --git a/target.cc b/target.cc index 0d71e0e26..10e900027 100644 --- a/target.cc +++ b/target.cc @@ -107,6 +107,13 @@ bool target_t::lpm_array_dq(const NetArrayDq*) return false; } +bool target_t::lpm_cast_int(const NetCastInt*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetCastInt." << endl; + return false; +} + bool target_t::lpm_cast_real(const NetCastReal*) { cerr << "target (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index 89c78c037..03fba0886 100644 --- a/target.h +++ b/target.h @@ -72,6 +72,7 @@ struct target_t { virtual void lpm_add_sub(const NetAddSub*); virtual bool lpm_array_dq(const NetArrayDq*); virtual void lpm_clshift(const NetCLShift*); + virtual bool lpm_cast_int(const NetCastInt*); virtual bool lpm_cast_real(const NetCastReal*); virtual void lpm_compare(const NetCompare*); virtual void lpm_divide(const NetDivide*); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 4238a4820..927312765 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -240,6 +240,31 @@ static void show_lpm_array(ivl_lpm_t net) } } +static void show_lpm_cast_int(ivl_lpm_t net) +{ + unsigned width = ivl_lpm_width(net); + + fprintf(out, " LPM_CAST_INT %s: \n", + ivl_lpm_basename(net), width); + + ivl_nexus_t q = ivl_lpm_q(net,0); + ivl_nexus_t a = ivl_lpm_data(net,0); + fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0))); + fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0))); + + if (type_of_nexus(q) == IVL_VT_REAL) { + fprintf(out, " ERROR: Data type of Q is %s, expecting !real\n", + data_type_string(type_of_nexus(q))); + stub_errors += 1; + } + + if (type_of_nexus(a) != IVL_VT_REAL) { + fprintf(out, " ERROR: Data type of A is %s, expecting real\n", + data_type_string(type_of_nexus(a))); + stub_errors += 1; + } +} + static void show_lpm_cast_real(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -827,6 +852,10 @@ static void show_lpm(ivl_lpm_t net) show_lpm_array(net); break; + case IVL_LPM_CAST_INT: + show_lpm_cast_int(net); + break; + case IVL_LPM_CAST_REAL: show_lpm_cast_real(net); break; diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index f7616ade0..87c13733d 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -387,6 +387,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_ARRAY: + case IVL_LPM_CAST_INT: case IVL_LPM_CAST_REAL: case IVL_LPM_CONCAT: case IVL_LPM_CMP_EEQ: diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 1f2cdeaec..c55bcb590 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1079,6 +1079,17 @@ static void draw_lpm_abs(ivl_lpm_t net) net, dly, src_table[0]); } +static void draw_lpm_cast_int(ivl_lpm_t net) +{ + const char*src_table[1]; + draw_lpm_data_inputs(net, 0, 1, src_table); + + const char*dly = draw_lpm_output_delay(net); + + fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n", + net, dly, ivl_lpm_width(net), src_table[0]); +} + static void draw_lpm_cast_real(ivl_lpm_t net) { const char*src_table[1]; @@ -1086,8 +1097,11 @@ static void draw_lpm_cast_real(ivl_lpm_t net) const char*dly = draw_lpm_output_delay(net); - fprintf(vvp_out, "L_%p%s .cast/real %s;\n", - net, dly, src_table[0]); + const char*is_signed = ""; + if (ivl_lpm_signed(net)) is_signed = ".s"; + + fprintf(vvp_out, "L_%p%s .cast/real%s %s;\n", + net, dly, is_signed, src_table[0]); } static void draw_lpm_add(ivl_lpm_t net) @@ -1140,20 +1154,9 @@ static void draw_lpm_add(ivl_lpm_t net) case IVL_LPM_POW: if (dto == IVL_VT_REAL) type = "pow.r"; - else if (ivl_lpm_signed(net)) { + else if (ivl_lpm_signed(net)) type = "pow.s"; - if (width > 8*sizeof(long)) { - fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power " -#ifdef __MINGW32__ /* MinGW does not know about z. */ - "result must be no more than %u bits.\n", -#else - "result must be no more than %zu bits.\n", -#endif - ivl_lpm_file(net), ivl_lpm_lineno(net), - 8*sizeof(long)); - exit(1); - } - } else + else type = "pow"; break; default: @@ -1655,6 +1658,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_abs(net); return; + case IVL_LPM_CAST_INT: + draw_lpm_cast_int(net); + return; + case IVL_LPM_CAST_REAL: draw_lpm_cast_real(net); return; diff --git a/vpi/vams_simparam.c b/vpi/vams_simparam.c index 169eade8e..90a73ced5 100644 --- a/vpi/vams_simparam.c +++ b/vpi/vams_simparam.c @@ -84,7 +84,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) } } - /* We can only have two argument. */ + /* We can have a maximum of two arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; snprintf(msg, 64, "ERROR: %s line %d:", diff --git a/vvp/README.txt b/vvp/README.txt index b96de8969..cdd51086f 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -345,6 +345,24 @@ The .alias statements do not create new nodes, but instead create net names that are aliases of an existing node. This handles special cases where a net has different names, possibly in different scopes. +CAST STATEMENTS: + +Sometimes nets need to be cast from a real valued net to a bit based +net or from a bit based net to a real valued net. These statements +are used to performa that operation: + +