diff --git a/PExpr.h b/PExpr.h index dfc3fe297..cdeac1ca4 100644 --- a/PExpr.h +++ b/PExpr.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: PExpr.h,v 1.82 2006/06/02 04:48:49 steve Exp $" +#ident "$Id: PExpr.h,v 1.83 2006/06/18 04:15:50 steve Exp $" #endif # include @@ -556,10 +556,20 @@ class PECallFunction : public PExpr { bool check_call_matches_definition_(Design*des, NetScope*dscope) const; NetExpr* elaborate_sfunc_(Design*des, NetScope*scope) const; + NetNet* elaborate_net_sfunc_(Design*des, NetScope*scope, + unsigned width, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) const; }; /* * $Log: PExpr.h,v $ + * Revision 1.83 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.82 2006/06/02 04:48:49 steve * Make elaborate_expr methods aware of the width that the context * requires of it. In the process, fix sizing of the width of unary diff --git a/design_dump.cc b/design_dump.cc index 353fbf18f..af7f680bd 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: design_dump.cc,v 1.165 2006/04/10 00:37:42 steve Exp $" +#ident "$Id: design_dump.cc,v 1.166 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -29,7 +29,7 @@ # include # include # include "netlist.h" - +# include "compiler.h" static ostream& operator<< (ostream&o, NetBlock::Type t) { @@ -462,6 +462,13 @@ void NetUReduce::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetSysFunc::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << def_->name << "(...)" << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetUserFunc::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << def_->name() << "("; @@ -1173,6 +1180,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.166 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.165 2006/04/10 00:37:42 steve * Add support for generate loops w/ wires and gates. * diff --git a/elab_net.cc b/elab_net.cc index b71fa0d7d..73f1dcaad 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_net.cc,v 1.186 2006/06/02 04:48:50 steve Exp $" +#ident "$Id: elab_net.cc,v 1.187 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -1209,39 +1209,11 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope, unsigned errors = 0; unsigned func_pins = 0; - /* Handle the special case that the function call is to - $signed. This takes a single expression argument, and - forces it to be a signed result. Otherwise, it is as if the - $signed did not exist. */ - if (strcmp(path_.peek_name(0), "$signed") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { - cerr << get_line() << ": error: The $signed() function " - << "takes exactly one(1) argument." << endl; - des->errors += 1; - return 0; - } + if (path_.peek_name(0)[0] == '$') + return elaborate_net_sfunc_(des, scope, + width, rise, fall, decay, + drive0, drive1); - PExpr*expr = parms_[0]; - NetNet*sub = expr->elaborate_net(des, scope, width, rise, - fall, decay, drive0, drive1); - sub->set_signed(true); - return sub; - } - /* handle $unsigned like $signed */ - if (strcmp(path_.peek_name(0), "$unsigned") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { - cerr << get_line() << ": error: The $unsigned() function " - << "takes exactly one(1) argument." << endl; - des->errors += 1; - return 0; - } - - PExpr*expr = parms_[0]; - NetNet*sub = expr->elaborate_net(des, scope, width, rise, - fall, decay, drive0, drive1); - sub->set_signed(false); - return sub; - } /* Look up the function definition. */ NetFuncDef*def = des->find_function(scope, path_); @@ -1319,6 +1291,87 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope, return osig; } +NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, + unsigned width, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) const +{ + /* Handle the special case that the function call is to + $signed. This takes a single expression argument, and + forces it to be a signed result. Otherwise, it is as if the + $signed did not exist. */ + if (strcmp(path_.peek_name(0), "$signed") == 0) { + if ((parms_.count() != 1) || (parms_[0] == 0)) { + cerr << get_line() << ": error: The $signed() function " + << "takes exactly one(1) argument." << endl; + des->errors += 1; + return 0; + } + + PExpr*expr = parms_[0]; + NetNet*sub = expr->elaborate_net(des, scope, width, rise, + fall, decay, drive0, drive1); + sub->set_signed(true); + return sub; + } + + /* handle $unsigned like $signed */ + if (strcmp(path_.peek_name(0), "$unsigned") == 0) { + if ((parms_.count() != 1) || (parms_[0] == 0)) { + cerr << get_line() << ": error: The $unsigned() function " + << "takes exactly one(1) argument." << endl; + des->errors += 1; + return 0; + } + + PExpr*expr = parms_[0]; + NetNet*sub = expr->elaborate_net(des, scope, width, rise, + fall, decay, drive0, drive1); + sub->set_signed(false); + return sub; + } + + const struct sfunc_return_type*def = lookup_sys_func(path_.peek_name(0)); + + if (def == 0) { + cerr << get_line() << ": error: System function " + << path_.peek_name(0) << " not defined." << endl; + des->errors += 1; + return 0; + } + + NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(), + def, 1+parms_.count()); + des->add_node(net); + net->set_line(*this); + + NetNet*osig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, def->wid); + osig->local_flag(true); + osig->data_type(def->type); + osig->set_line(*this); + + connect(net->pin(0), osig->pin(0)); + + for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + NetNet*tmp = parms_[idx]->elaborate_net(des, scope, 0, + 0, 0, 0, + Link::STRONG, Link::STRONG); + if (tmp == 0) { + cerr << get_line() << ": error: Unable to elaborate " + << "port " << idx << " of call to " << path_ << + "." << endl; + continue; + } + + connect(net->pin(1+idx), tmp->pin(0)); + } + return osig; +} + /* * The concatenation operator, as a net, is a wide signal that is @@ -2779,6 +2832,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, /* * $Log: elab_net.cc,v $ + * Revision 1.187 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.186 2006/06/02 04:48:50 steve * Make elaborate_expr methods aware of the width that the context * requires of it. In the process, fix sizing of the width of unary diff --git a/emit.cc b/emit.cc index ef6e93174..e3e3f82c8 100644 --- a/emit.cc +++ b/emit.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: emit.cc,v 1.86 2005/07/11 16:56:50 steve Exp $" +#ident "$Id: emit.cc,v 1.87 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -146,6 +146,10 @@ bool NetUReduce::emit_node(struct target_t*tgt) const return tgt->ureduce(this); } +bool NetSysFunc::emit_node(struct target_t*tgt) const +{ + return tgt->net_sysfunction(this); +} bool NetUserFunc::emit_node(struct target_t*tgt) const { @@ -525,6 +529,9 @@ int emit(const Design*des, const char*type) /* * $Log: emit.cc,v $ + * Revision 1.87 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.86 2005/07/11 16:56:50 steve * Remove NetVariable and ivl_variable_t structures. * diff --git a/ivl_target.h b/ivl_target.h index f650838e3..277685ac6 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: ivl_target.h,v 1.167 2006/04/16 00:15:43 steve Exp $" +#ident "$Id: ivl_target.h,v 1.168 2006/06/18 04:15:50 steve Exp $" #endif #ifdef __cplusplus @@ -244,6 +244,7 @@ typedef enum ivl_lpm_type_e { IVL_LPM_RE_XNOR= 24, IVL_LPM_RE_XOR = 25, IVL_LPM_REPEAT = 26, + IVL_LPM_SFUNC = 29, IVL_LPM_SHIFTL = 6, IVL_LPM_SHIFTR = 7, IVL_LPM_SIGN_EXT=27, @@ -991,6 +992,19 @@ extern const char* ivl_udp_name(ivl_udp_t net); * the shift distance. The vector input is the same width as the * output, but the distance has its own width. * + * - System function call (IVL_LPM_SFUNC) + * This device represents a netlist call to a system function. The + * inputs to the device are passed to a system function, and the + * result is sent via the output. The ivl_lpm_q function returns the + * output nexus. + * + * The ivl_lpm_size function returns the number of arguments, and the + * ivl_lpm_data(net,N) returns the nexa for the argument. + * + * The ivl_lpm_string(net) function returns the name of the system + * function (i.e. "$display") that was found in the source code. The + * compiler does little checking of that name. + * * - User Function Call (IVL_LPM_UFUNC) * This device is special as it represents a call to a user defined * function (behavioral code) within a netlist. The inputs to the @@ -1039,14 +1053,6 @@ extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_SUB */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); -#if 0 - /* IVL_LPM_UFUNC */ -extern ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx); -#endif -#if 0 - /* IVL_LPM_UFUNC */ -extern unsigned ivl_lpm_data2_width(ivl_lpm_t net, unsigned sdx); -#endif /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_RAM IVL_LPM_SUB IVL_LPM_UFUNC */ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx); @@ -1056,6 +1062,8 @@ extern unsigned ivl_lpm_selects(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net); /* IVL_LPM_CONCAT IVL_LPM_MUX IVL_LPM_REPEAT IVL_LPM_UFUNC */ extern unsigned ivl_lpm_size(ivl_lpm_t net); + /* IVL_LPM_SFUNC */ +extern const char*ivl_lpm_string(ivl_lpm_t net); /* IVL_LPM_RAM */ extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net); @@ -1706,6 +1714,9 @@ _END_DECL /* * $Log: ivl_target.h,v $ + * Revision 1.168 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.167 2006/04/16 00:15:43 steve * Fix part selects in l-values. * diff --git a/net_func.cc b/net_func.cc index 7fa4740a3..f68da4a54 100644 --- a/net_func.cc +++ b/net_func.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: net_func.cc,v 1.7 2005/03/18 02:56:03 steve Exp $" +#ident "$Id: net_func.cc,v 1.8 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -112,8 +112,46 @@ bool PECallFunction::check_call_matches_definition_(Design*des, NetScope*dscope) return true; } + +NetSysFunc::NetSysFunc(NetScope*s, perm_string n, + const struct sfunc_return_type*def, + unsigned ports) +: NetNode(s, n, ports) +{ + def_ = def; + + pin(0).set_dir(Link::OUTPUT); + pin(0).set_name(perm_string::literal("Q"), 0); + + for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { + + pin(idx).set_dir(Link::INPUT); + pin(idx).set_name(perm_string::literal("D"), idx-1); + pin(idx).drive0(Link::HIGHZ); + pin(idx).drive1(Link::HIGHZ); + } +} + +NetSysFunc::~NetSysFunc() +{ +} + +const char*NetSysFunc::func_name() const +{ + return def_->name; +} + +unsigned NetSysFunc::vector_width() const +{ + return def_->wid; +} + + /* * $Log: net_func.cc,v $ + * Revision 1.8 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.7 2005/03/18 02:56:03 steve * Add support for LPM_UFUNC user defined functions. * diff --git a/netlist.h b/netlist.h index 164779a54..7380be690 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: netlist.h,v 1.357 2006/04/10 00:37:42 steve Exp $" +#ident "$Id: netlist.h,v 1.358 2006/06/18 04:15:50 steve Exp $" #endif /* @@ -1020,6 +1020,28 @@ class NetUserFunc : public NetNode { NetScope*def_; }; +/* + * The number of ports includes the return value, so will always be at + * least 1. + */ +class NetSysFunc : public NetNode { + + public: + NetSysFunc(NetScope*s, perm_string n, + const struct sfunc_return_type*def, + unsigned ports); + ~NetSysFunc(); + + unsigned vector_width() const; + const char* func_name() const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + + private: + const struct sfunc_return_type*def_; +}; + /* ========= * There are cases where expressions need to be represented. The * NetExpr class is the root of a hierarchy that serves that purpose. @@ -3464,6 +3486,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.358 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.357 2006/04/10 00:37:42 steve * Add support for generate loops w/ wires and gates. * diff --git a/t-dll-api.cc b/t-dll-api.cc index 6759e772c..a04d206d9 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: t-dll-api.cc,v 1.133 2006/02/02 02:43:59 steve Exp $" +#ident "$Id: t-dll-api.cc,v 1.134 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -852,6 +852,11 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) assert(idx == 0); return net->u_.repeat.a; + case IVL_LPM_SFUNC: + // Skip the return port. + assert(idx < (net->u_.sfunc.ports-1)); + return net->u_.sfunc.pins[idx+1]; + case IVL_LPM_UFUNC: // Skip the return port. assert(idx < (net->u_.ufunc.ports-1)); @@ -1005,6 +1010,10 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) assert(idx == 0); return net->u_.shift.q; + case IVL_LPM_SFUNC: + assert(idx == 0); + return net->u_.sfunc.pins[0]; + case IVL_LPM_UFUNC: assert(idx == 0); return net->u_.ufunc.pins[0]; @@ -1096,6 +1105,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) return net->u_.shift.signed_flag; case IVL_LPM_SIGN_EXT: // Sign extend is always signed. return 1; + case IVL_LPM_SFUNC: + return 0; case IVL_LPM_UFUNC: return 0; case IVL_LPM_CONCAT: // Concatenations are always unsigned @@ -1117,6 +1128,8 @@ extern "C" unsigned ivl_lpm_size(ivl_lpm_t net) switch (net->type) { case IVL_LPM_MUX: return net->u_.mux.size; + case IVL_LPM_SFUNC: + return net->u_.sfunc.ports - 1; case IVL_LPM_UFUNC: return net->u_.ufunc.ports - 1; case IVL_LPM_REPEAT: @@ -1127,6 +1140,12 @@ extern "C" unsigned ivl_lpm_size(ivl_lpm_t net) } } +extern "C" const char* ivl_lpm_string(ivl_lpm_t net) +{ + assert(net->type == IVL_LPM_SFUNC); + return net->u_.sfunc.fun_name; +} + extern "C" ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net) { return net->type; @@ -1135,50 +1154,7 @@ extern "C" ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net) extern "C" unsigned ivl_lpm_width(ivl_lpm_t net) { assert(net); - switch (net->type) { - case IVL_LPM_FF: - case IVL_LPM_RAM: - return net->u_.ff.width; - case IVL_LPM_MUX: - return net->u_.mux.width; - case IVL_LPM_ADD: - case IVL_LPM_CMP_EEQ: - case IVL_LPM_CMP_EQ: - case IVL_LPM_CMP_GE: - case IVL_LPM_CMP_GT: - case IVL_LPM_CMP_NE: - case IVL_LPM_CMP_NEE: - case IVL_LPM_DIVIDE: - case IVL_LPM_MOD: - case IVL_LPM_MULT: - case IVL_LPM_SUB: - return net->u_.arith.width; - case IVL_LPM_RE_AND: - case IVL_LPM_RE_OR: - case IVL_LPM_RE_XOR: - case IVL_LPM_RE_NAND: - case IVL_LPM_RE_NOR: - case IVL_LPM_RE_XNOR: - case IVL_LPM_SIGN_EXT: - return net->u_.reduce.width; - case IVL_LPM_SHIFTL: - case IVL_LPM_SHIFTR: - return net->u_.shift.width; - case IVL_LPM_UFUNC: - return net->u_.ufunc.width; - case IVL_LPM_CONCAT: - return net->u_.concat.width; - case IVL_LPM_PART_VP: - case IVL_LPM_PART_PV: - return net->u_.part.width; - case IVL_LPM_PART_BI: - return net->u_.part.width; - case IVL_LPM_REPEAT: - return net->u_.repeat.width; - default: - assert(0); - return 0; - } + return net->width; } extern "C" ivl_memory_t ivl_lpm_memory(ivl_lpm_t net) @@ -2033,6 +2009,9 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net) /* * $Log: t-dll-api.cc,v $ + * Revision 1.134 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.133 2006/02/02 02:43:59 steve * Allow part selects of memory words in l-values. * diff --git a/t-dll.cc b/t-dll.cc index f90768a1e..71d7215b2 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: t-dll.cc,v 1.156 2006/04/10 00:37:42 steve Exp $" +#ident "$Id: t-dll.cc,v 1.157 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -904,7 +904,7 @@ bool dll_target::sign_extend(const NetSignExtend*net) { struct ivl_lpm_s*obj = new struct ivl_lpm_s; obj->type = IVL_LPM_SIGN_EXT; - obj->u_.reduce.width = net->width(); + obj->width = net->width(); obj->name = net->name(); obj->scope = find_scope(des_, net->scope()); assert(obj->scope); @@ -959,7 +959,7 @@ bool dll_target::ureduce(const NetUReduce*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->u_.reduce.width = net->width(); + obj->width = net->width(); const Nexus*nex; @@ -988,7 +988,7 @@ void dll_target::net_case_cmp(const NetCaseCmp*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->u_.arith.width = net->width(); + obj->width = net->width(); obj->u_.arith.signed_flag = 0; const Nexus*nex; @@ -1014,6 +1014,46 @@ void dll_target::net_case_cmp(const NetCaseCmp*net) scope_add_lpm(obj->scope, obj); } +bool dll_target::net_sysfunction(const NetSysFunc*net) +{ + unsigned idx; + const Nexus*nex; + + struct ivl_lpm_s*obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_SFUNC; + obj->name = net->name(); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + + obj->u_.sfunc.ports = net->pin_count(); + + assert(net->pin_count() >= 1); + obj->width = net->vector_width(); + + obj->u_.sfunc.fun_name = net->func_name(); + + obj->u_.sfunc.pins = new ivl_nexus_t[net->pin_count()]; + + nex = net->pin(0).nexus(); + assert(nex->t_cookie()); + + obj->u_.sfunc.pins[0] = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.sfunc.pins[0], obj, 0, + IVL_DR_STRONG, IVL_DR_STRONG); + + for (idx = 1 ; idx < net->pin_count() ; idx += 1) { + nex = net->pin(idx).nexus(); + assert(nex->t_cookie()); + + obj->u_.sfunc.pins[idx] = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.sfunc.pins[idx], obj, 0, + IVL_DR_HiZ, IVL_DR_HiZ); + } + + scope_add_lpm(obj->scope, obj); + return true; +} + /* * An IVL_LPM_UFUNC represents a node in a combinational expression * that calls a user defined function. I create an LPM object that has @@ -1039,7 +1079,7 @@ bool dll_target::net_function(const NetUserFunc*net) obj->u_.ufunc.ports = net->pin_count(); assert(net->pin_count() >= 1); - obj->u_.ufunc.width = net->port_width(0); + obj->width = net->port_width(0); /* Now collect all the pins and connect them to the nexa of the net. The output pins have strong drive, and the @@ -1177,9 +1217,9 @@ void dll_target::lpm_add_sub(const NetAddSub*net) /* Choose the width of the adder. If the carry bit is connected, then widen the adder by one and plan on leaving the fake inputs unconnected. */ - obj->u_.arith.width = net->width(); + obj->width = net->width(); if (net->pin_Cout().is_linked()) { - obj->u_.arith.width += 1; + obj->width += 1; } @@ -1235,7 +1275,7 @@ void dll_target::lpm_clshift(const NetCLShift*net) else obj->u_.shift.signed_flag = 0; - obj->u_.shift.width = net->width(); + obj->width = net->width(); obj->u_.shift.select = net->width_dist(); const Nexus*nex; @@ -1276,7 +1316,7 @@ void dll_target::lpm_compare(const NetCompare*net) bool swap_operands = false; - obj->u_.arith.width = net->width(); + obj->width = net->width(); obj->u_.arith.signed_flag = net->get_signed()? 1 : 0; const Nexus*nex; @@ -1377,7 +1417,7 @@ void dll_target::lpm_divide(const NetDivide*net) unsigned wid = net->width_r(); - obj->u_.arith.width = wid; + obj->width = wid; obj->u_.arith.signed_flag = net->get_signed()? 1 : 0; const Nexus*nex; @@ -1415,7 +1455,7 @@ void dll_target::lpm_modulo(const NetModulo*net) unsigned wid = net->width_r(); - obj->u_.arith.width = wid; + obj->width = wid; obj->u_.arith.signed_flag = 0; const Nexus*nex; @@ -1449,7 +1489,7 @@ void dll_target::lpm_ff(const NetFF*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->u_.ff.width = net->width(); + obj->width = net->width(); scope_add_lpm(obj->scope, obj); @@ -1548,7 +1588,7 @@ void dll_target::lpm_ram_dq(const NetRamDq*net) obj->scope = find_scope(des_, net->mem()->scope()); assert(obj->scope); - obj->u_.ff.width = net->width(); + obj->width = net->width(); obj->u_.ff.swid = net->awidth(); scope_add_lpm(obj->scope, obj); @@ -1619,7 +1659,7 @@ void dll_target::lpm_mult(const NetMult*net) unsigned wid = net->width_r(); - obj->u_.arith.width = wid; + obj->width = wid; const Nexus*nex; @@ -1657,7 +1697,7 @@ void dll_target::lpm_mux(const NetMux*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->u_.mux.width = net->width(); + obj->width = net->width(); obj->u_.mux.size = net->size(); obj->u_.mux.swid = net->sel_width(); @@ -1701,7 +1741,7 @@ bool dll_target::concat(const NetConcat*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->u_.concat.width = net->width(); + obj->width = net->width(); obj->u_.concat.inputs = net->pin_count() - 1; obj->u_.concat.pins = new ivl_nexus_t[obj->u_.concat.inputs+1]; @@ -1743,7 +1783,7 @@ bool dll_target::part_select(const NetPartSelect*net) obj->u_.part.signed_flag = 0; /* Choose the width of the part select. */ - obj->u_.part.width = net->width(); + obj->width = net->width(); obj->u_.part.base = net->base(); obj->u_.part.s = 0; @@ -1834,7 +1874,7 @@ bool dll_target::replicate(const NetReplicate*net) obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->u_.repeat.width = net->width(); + obj->width = net->width(); obj->u_.repeat.count = net->repeat(); ivl_drive_t dr = IVL_DR_STRONG; @@ -2167,6 +2207,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj }; /* * $Log: t-dll.cc,v $ + * Revision 1.157 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.156 2006/04/10 00:37:42 steve * Add support for generate loops w/ wires and gates. * diff --git a/t-dll.h b/t-dll.h index 8331e5dc5..b751588df 100644 --- a/t-dll.h +++ b/t-dll.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: t-dll.h,v 1.130 2006/02/02 02:43:59 steve Exp $" +#ident "$Id: t-dll.h,v 1.131 2006/06/18 04:15:50 steve Exp $" #endif # include "target.h" @@ -86,6 +86,7 @@ struct dll_target : public target_t, public expr_scan_t { bool part_select(const NetPartSelect*); bool replicate(const NetReplicate*); void net_assign(const NetAssign_*); + bool net_sysfunction(const NetSysFunc*); bool net_function(const NetUserFunc*); bool net_const(const NetConst*); bool net_literal(const NetLiteral*); @@ -282,10 +283,11 @@ struct ivl_lpm_s { ivl_lpm_type_t type; ivl_scope_t scope; perm_string name; + // Value returned by ivl_lpm_width; + unsigned width; union { struct ivl_lpm_ff_s { - unsigned width; unsigned swid; // ram only ivl_nexus_t clk; ivl_nexus_t we; @@ -311,7 +313,6 @@ struct ivl_lpm_s { } ff; struct ivl_lpm_mux_s { - unsigned width; unsigned size; unsigned swid; ivl_nexus_t*d; @@ -319,26 +320,22 @@ struct ivl_lpm_s { } mux; struct ivl_lpm_shift_s { - unsigned width; unsigned select; unsigned signed_flag :1; ivl_nexus_t q, d, s; } shift; struct ivl_lpm_arith_s { - unsigned width; unsigned signed_flag :1; ivl_nexus_t q, a, b; } arith; struct ivl_concat_s { - unsigned width; unsigned inputs; ivl_nexus_t*pins; } concat; struct ivl_part_s { - unsigned width; unsigned base; unsigned signed_flag :1; ivl_nexus_t q, a, s; @@ -346,20 +343,23 @@ struct ivl_lpm_s { // IVL_LPM_RE_* and IVL_LPM_SIGN_EXT use this. struct ivl_lpm_reduce_s { - unsigned width; ivl_nexus_t q, a; } reduce; struct ivl_lpm_repeat_s { - unsigned width; unsigned count; ivl_nexus_t q, a; } repeat; + struct ivl_lpm_sfunc_s { + const char* fun_name; + unsigned ports; + ivl_nexus_t*pins; + } sfunc; + struct ivl_lpm_ufunc_s { ivl_scope_t def; unsigned ports; - unsigned width; ivl_nexus_t*pins; } ufunc; } u_; @@ -671,6 +671,9 @@ struct ivl_statement_s { /* * $Log: t-dll.h,v $ + * Revision 1.131 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.130 2006/02/02 02:43:59 steve * Allow part selects of memory words in l-values. * diff --git a/target.cc b/target.cc index 0efbcb4b2..fe5c35ed5 100644 --- a/target.cc +++ b/target.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: target.cc,v 1.77 2005/07/11 16:56:51 steve Exp $" +#ident "$Id: target.cc,v 1.78 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -174,6 +174,13 @@ bool target_t::net_const(const NetConst*) return false; } +bool target_t::net_sysfunction(const NetSysFunc*net) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetSysFunc node." << endl; + return false; +} + bool target_t::net_function(const NetUserFunc*net) { cerr << "target (" << typeid(*this).name() << "): " @@ -431,6 +438,9 @@ void expr_scan_t::expr_binary(const NetEBinary*ex) /* * $Log: target.cc,v $ + * Revision 1.78 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.77 2005/07/11 16:56:51 steve * Remove NetVariable and ivl_variable_t structures. * diff --git a/target.h b/target.h index cb4f62774..3ff97eb1d 100644 --- a/target.h +++ b/target.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: target.h,v 1.74 2005/07/11 16:56:51 steve Exp $" +#ident "$Id: target.h,v 1.75 2006/06/18 04:15:50 steve Exp $" #endif # include "netlist.h" @@ -94,6 +94,7 @@ struct target_t { virtual void udp(const NetUDP*); virtual void net_case_cmp(const NetCaseCmp*); virtual bool net_const(const NetConst*); + virtual bool net_sysfunction(const NetSysFunc*); virtual bool net_function(const NetUserFunc*); virtual bool net_literal(const NetLiteral*); virtual void net_probe(const NetEvProbe*); @@ -170,6 +171,9 @@ extern const struct target *target_table[]; /* * $Log: target.h,v $ + * Revision 1.75 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.74 2005/07/11 16:56:51 steve * Remove NetVariable and ivl_variable_t structures. * diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 756fb13e6..62ef85a4b 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: stub.c,v 1.138 2006/04/30 05:16:53 steve Exp $" +#ident "$Id: stub.c,v 1.139 2006/06/18 04:15:50 steve Exp $" #endif # include "config.h" @@ -83,11 +83,29 @@ unsigned width_of_nexus(ivl_nexus_t nex) return 0; } -const char*vt_type_string(ivl_expr_t net) +ivl_variable_type_t type_of_nexus(ivl_nexus_t net) +{ + unsigned idx; + + for (idx = 0 ; idx < ivl_nexus_ptrs(net); idx += 1) { + ivl_nexus_ptr_t ptr = ivl_nexus_ptr(net, idx); + ivl_signal_t sig = ivl_nexus_ptr_sig(ptr); + + if (sig != 0) { + return ivl_signal_data_type(sig); + } + } + + /* ERROR: A nexus should have at least one signal to carry + properties like the data type. */ + return IVL_VT_NO_TYPE; +} + +const char*data_type_string(ivl_variable_type_t vtype) { const char*vt = "??"; - switch (ivl_expr_value(net)) { + switch (vtype) { case IVL_VT_NO_TYPE: vt = "NO_TYPE"; break; @@ -108,6 +126,11 @@ const char*vt_type_string(ivl_expr_t net) return vt; } +const char*vt_type_string(ivl_expr_t net) +{ + return data_type_string(ivl_expr_value(net)); +} + void show_binary_expression(ivl_expr_t net, unsigned ind) { unsigned width = ivl_expr_width(net); @@ -894,6 +917,34 @@ static void show_lpm_sub(ivl_lpm_t net) show_lpm_arithmetic_pins(net); } +static void show_lpm_sfunc(ivl_lpm_t net) +{ + unsigned width = ivl_lpm_width(net); + unsigned ports = ivl_lpm_size(net); + ivl_variable_type_t data_type = type_of_nexus(ivl_lpm_q(net,0)); + ivl_nexus_t nex; + unsigned idx; + + fprintf(out, " LPM_SFUNC %s: \n", + ivl_lpm_basename(net), ivl_lpm_string(net), + width, data_type_string(data_type), ports); + + nex = ivl_lpm_q(net, 0); + if (width != width_of_nexus(nex)) { + fprintf(out, " ERROR: Q output nexus width=%u " + " does not match part width\n", width_of_nexus(nex)); + stub_errors += 1; + } + + fprintf(out, " Q: %s\n", ivl_nexus_name(nex)); + for (idx = 0 ; idx < ports ; idx += 1) { + nex = ivl_lpm_data(net, idx); + fprintf(out, " D%u: %s \n", idx, + ivl_nexus_name(nex), width_of_nexus(nex), + data_type_string(type_of_nexus(nex))); + } +} + static void show_lpm_ufunc(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -1014,6 +1065,10 @@ static void show_lpm(ivl_lpm_t net) show_lpm_repeat(net); break; + case IVL_LPM_SFUNC: + show_lpm_sfunc(net); + break; + case IVL_LPM_UFUNC: show_lpm_ufunc(net); break; @@ -1591,6 +1646,9 @@ int target_design(ivl_design_t des) /* * $Log: stub.c,v $ + * Revision 1.139 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.138 2006/04/30 05:16:53 steve * Dump *all* the reduction operator gates. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 2fcd7327a..efd817c4a 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vvp_scope.c,v 1.144 2006/04/22 04:27:36 steve Exp $" +#ident "$Id: vvp_scope.c,v 1.145 2006/06/18 04:15:50 steve Exp $" #endif # include "vvp_priv.h" @@ -611,6 +611,7 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) case IVL_LPM_RE_NAND: case IVL_LPM_RE_NOR: case IVL_LPM_RE_XNOR: + case IVL_LPM_SFUNC: case IVL_LPM_SHIFTL: case IVL_LPM_SHIFTR: case IVL_LPM_SIGN_EXT: @@ -1801,6 +1802,43 @@ static void draw_lpm_shiftl(ivl_lpm_t net) fprintf(vvp_out, ";\n"); } +static void draw_type_string_of_nex(ivl_nexus_t nex) +{ + switch (data_type_of_nexus(nex)) { + case IVL_VT_REAL: + fprintf(vvp_out, "r"); + break; + case IVL_VT_LOGIC: + fprintf(vvp_out, "v%d", width_of_nexus(nex)); + break; + default: + assert(0); + break; + } +} + +static void draw_lpm_sfunc(ivl_lpm_t net) +{ + unsigned idx; + fprintf(vvp_out, "L_%p .sfunc \"%s\"", net, ivl_lpm_string(net)); + + /* Print the function type descriptor string. */ + fprintf(vvp_out, ", \""); + + draw_type_string_of_nex(ivl_lpm_q(net,0)); + + for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) + draw_type_string_of_nex(ivl_lpm_data(net,idx)); + + fprintf(vvp_out, "\""); + + for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) { + fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx))); + } + + fprintf(vvp_out, ";\n"); +} + static void draw_lpm_ufunc(ivl_lpm_t net) { unsigned idx; @@ -2078,6 +2116,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_sign_ext(net); return; + case IVL_LPM_SFUNC: + draw_lpm_sfunc(net); + return; + case IVL_LPM_UFUNC: draw_lpm_ufunc(net); return; @@ -2209,6 +2251,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) /* * $Log: vvp_scope.c,v $ + * Revision 1.145 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.144 2006/04/22 04:27:36 steve * Get tail counts right in nested concatenations. * diff --git a/vvp/Makefile.in b/vvp/Makefile.in index fbb50b3f8..318519dd6 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.69 2005/06/12 01:42:20 steve Exp $" +#ident "$Id: Makefile.in,v 1.70 2006/06/18 04:15:50 steve Exp $" # # SHELL = /bin/sh @@ -82,7 +82,7 @@ vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o O = main.o parse.o parse_misc.o lexor.o arith.o bufif.o compile.o concat.o \ -dff.o extend.o npmos.o part.o reduce.o resolv.o stop.o symbols.o \ +dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \ ufunc.o codes.o \ vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \ event.o logic.o delay.o words.o $V diff --git a/vvp/compile.cc b/vvp/compile.cc index 298f7728c..658013df8 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: compile.cc,v 1.219 2006/03/18 22:51:10 steve Exp $" +#ident "$Id: compile.cc,v 1.220 2006/06/18 04:15:50 steve Exp $" #endif # include "arith.h" @@ -1417,7 +1417,7 @@ void compile_vpi_call(char*label, char*name, unsigned argc, vpiHandle*argv) /* Create a vpiHandle that bundles the call information, and store that handle in the instruction. */ - code->handle = vpip_build_vpi_call(name, 0, 0, argc, argv); + code->handle = vpip_build_vpi_call(name, 0, 0, 0, argc, argv); if (code->handle == 0) compile_errors += 1; @@ -1438,7 +1438,7 @@ void compile_vpi_func_call(char*label, char*name, /* Create a vpiHandle that bundles the call information, and store that handle in the instruction. */ - code->handle = vpip_build_vpi_call(name, vbit, vwid, argc, argv); + code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, argc, argv); if (code->handle == 0) compile_errors += 1; @@ -1495,6 +1495,9 @@ void compile_param_string(char*label, char*name, char*value) /* * $Log: compile.cc,v $ + * Revision 1.220 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.219 2006/03/18 22:51:10 steve * Syntax for carrying sign with parameter. * diff --git a/vvp/compile.h b/vvp/compile.h index 0247a35e0..53df3073a 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: compile.h,v 1.80 2006/03/18 22:51:10 steve Exp $" +#ident "$Id: compile.h,v 1.81 2006/06/18 04:15:50 steve Exp $" #endif # include @@ -169,6 +169,8 @@ extern void compile_reduce_xnor(char*label, struct symb_s arg); extern void compile_extend_signed(char*label, long width, struct symb_s arg); +extern void compile_sfunc(char*label, char*name, char*format_string, + unsigned argc, struct symb_s*argv); extern void compile_repeat(char*label, long width, long repeat, struct symb_s arg); @@ -343,6 +345,9 @@ extern void compile_alias_real(char*label, char*name, /* * $Log: compile.h,v $ + * Revision 1.81 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.80 2006/03/18 22:51:10 steve * Syntax for carrying sign with parameter. * diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 70d2bb78d..1a080e335 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -21,7 +21,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: lexor.lex,v 1.60 2006/05/17 04:15:25 steve Exp $" +#ident "$Id: lexor.lex,v 1.61 2006/06/18 04:15:50 steve Exp $" #endif # include "parse_misc.h" @@ -130,6 +130,7 @@ ".repeat" { return K_REPEAT; } ".resolv" { return K_RESOLV; } ".scope" { return K_SCOPE; } +".sfunc" { return K_SFUNC; } ".shift/l" { return K_SHIFTL; } ".shift/r" { return K_SHIFTR; } ".thread" { return K_THREAD; } @@ -208,6 +209,9 @@ int yywrap() /* * $Log: lexor.lex,v $ + * Revision 1.61 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.60 2006/05/17 04:15:25 steve * Lexor os never interactive. * diff --git a/vvp/parse.y b/vvp/parse.y index ad7f8f852..85b4ffabb 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: parse.y,v 1.82 2006/03/18 22:51:10 steve Exp $" +#ident "$Id: parse.y,v 1.83 2006/06/18 04:15:50 steve Exp $" #endif # include "parse_misc.h" @@ -67,7 +67,7 @@ extern FILE*yyin; %token K_PARAM_STR K_PARAM_L K_PART K_PART_PV %token K_PART_V K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR %token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT -%token K_RESOLV K_SCOPE K_SHIFTL K_SHIFTR K_THREAD K_TIMESCALE K_UFUNC +%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_THREAD K_TIMESCALE K_UFUNC %token K_UDP K_UDP_C K_UDP_S %token K_MEM K_MEM_P K_MEM_I %token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r @@ -329,6 +329,10 @@ statement | T_LABEL K_EXTEND_S T_NUMBER ',' symbol ';' { compile_extend_signed($1, $3, $5); } + /* System function call */ + | T_LABEL K_SFUNC T_STRING ',' T_STRING ',' symbols ';' + { compile_sfunc($1, $3, $5, $7.cnt, $7.vect); } + /* Shift nodes. */ | T_LABEL K_SHIFTL T_NUMBER ',' symbols ';' @@ -739,6 +743,9 @@ int compile_design(const char*path) /* * $Log: parse.y,v $ + * Revision 1.83 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.82 2006/03/18 22:51:10 steve * Syntax for carrying sign with parameter. * diff --git a/vvp/sfunc.cc b/vvp/sfunc.cc new file mode 100644 index 000000000..285a12a8a --- /dev/null +++ b/vvp/sfunc.cc @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2006 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: sfunc.cc,v 1.1 2006/06/18 04:15:50 steve Exp $" +#endif + +# include "compile.h" +# include "sfunc.h" +#ifdef HAVE_MALLOC_H +# include +#endif +# include +# include +# include +# include + + +sfunc_core::sfunc_core(vvp_net_t*net, vpiHandle sys, + unsigned argc, vpiHandle*argv) +: vvp_wide_fun_core(net, argc) +{ + sys_ = sys; + argc_ = argc; + argv_ = argv; +} + +sfunc_core::~sfunc_core() +{ +} + +void sfunc_core::recv_vec4_from_inputs(unsigned port) +{ + vpiHandle vpi = argv_[port]; + assert(vpi_get(vpiConstType,vpi) == vpiBinaryConst); + + struct __vpiBinaryConst*obj + = (struct __vpiBinaryConst*)vpi; + + obj->bits = value(port); + + invoke_function_(); +} + +void sfunc_core::recv_real_from_inputs(unsigned port) +{ + vpiHandle vpi = argv_[port]; + assert(vpi_get(vpiConstType,vpi) == vpiRealConst); + + struct __vpiRealConst*obj + = (struct __vpiRealConst*)vpi; + + obj->value = value_r(port); + + invoke_function_(); +} + +void sfunc_core::invoke_function_() +{ + vpip_execute_vpi_call(0, sys_); +} + +static int make_vpi_argv(unsigned argc, vpiHandle*vpi_argv, + const char*arg_string) +{ + unsigned idx = 0; + const char*cp = arg_string; + int return_type = 0; + + switch (*cp) { + case 'r': // real result + cp += 1; + return_type = -vpiRealConst; + break; + + case 'v': // vector4_t + cp += 1; + return_type = strtoul(cp, 0, 10); + cp += strspn(cp, "0123456789"); + break; + + default: + assert(0); + break; + } + + while (*cp) { + assert(idx < argc); + + switch (*cp) { + case 'r': // real + cp += 1; + vpi_argv[idx] = vpip_make_real_const(0.0); + break; + + case 'v': { // vector4_t (v) + cp += 1; + unsigned wid = strtoul(cp, 0, 10); + cp += strspn(cp, "0123456789"); + vpi_argv[idx] = vpip_make_binary_const(wid, "x"); + break; + } + + default: + assert(0); + } + idx += 1; + } + + assert(idx == argc); + return return_type; +} + + +void compile_sfunc(char*label, char*name, char*format_string, + unsigned argc, struct symb_s*argv) +{ + vpiHandle*vpi_argv = new vpiHandle[argc]; + int width_code = make_vpi_argv(argc, vpi_argv, format_string); + free(format_string); + + vvp_net_t*ptr = new vvp_net_t; + + vpiHandle sys = vpip_build_vpi_call(name, 0, width_code, ptr, + argc, vpi_argv); + assert(sys); + + /* Create and connect the functor to the label. */ + sfunc_core*score = new sfunc_core(ptr, sys, argc, vpi_argv); + ptr->fun = score; + define_functor_symbol(label, ptr); + free(label); + + /* Link the inputs to the functor. */ + wide_inputs_connect(score, argc, argv); + free(argv); +} + + +/* + * $Log: sfunc.cc,v $ + * Revision 1.1 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * + */ diff --git a/vvp/sfunc.h b/vvp/sfunc.h new file mode 100644 index 000000000..a3b203cb3 --- /dev/null +++ b/vvp/sfunc.h @@ -0,0 +1,51 @@ +#ifndef __sfunc_H +#define __sfunc_H +/* + * Copyright (c) 2006 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: sfunc.h,v 1.1 2006/06/18 04:15:50 steve Exp $" +#endif + +# include "pointers.h" + +class sfunc_core : public vvp_wide_fun_core { + + public: + sfunc_core(vvp_net_t*ptr, vpiHandle sys, unsigned argc, vpiHandle*argv); + ~sfunc_core(); + + private: + void recv_vec4_from_inputs(unsigned port); + void recv_real_from_inputs(unsigned port); + + void invoke_function_(); + + private: + vpiHandle sys_; + unsigned argc_; + vpiHandle*argv_; +}; + +/* + * $Log: sfunc.h,v $ + * Revision 1.1 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * + */ +#endif diff --git a/vvp/stop.cc b/vvp/stop.cc index a21a5858b..c1fdb3125 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: stop.cc,v 1.15 2005/11/25 18:35:38 steve Exp $" +#ident "$Id: stop.cc,v 1.16 2006/06/18 04:15:50 steve Exp $" #endif /* @@ -174,7 +174,7 @@ static void cmd_call(unsigned argc, char*argv[]) vpi task and execute that call. Free the call structure when we finish. */ if (errors == 0) { - vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, + vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0, vpi_argc, vpi_argv); if (call_handle == 0) goto out; @@ -505,6 +505,9 @@ void stop_handler(int rc) /* * $Log: stop.cc,v $ + * Revision 1.16 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.15 2005/11/25 18:35:38 steve * stop/continue messages go through MCD for logging. * diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index e5342e3f6..1ae9719f4 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vpi_const.cc,v 1.35 2006/03/18 22:51:10 steve Exp $" +#ident "$Id: vpi_const.cc,v 1.36 2006/06/18 04:15:50 steve Exp $" #endif # include "vpi_priv.h" @@ -529,8 +529,69 @@ vpiHandle vpip_make_dec_const(int value) } +static int real_get(int code, vpiHandle ref) +{ + + switch (code) { + case vpiConstType: + return vpiRealConst; + + case vpiSigned: + return 1; + + default: + fprintf(stderr, "vvp error: get %d not supported " + "by vpiDecConst\n", code); + assert(0); + return 0; + } +} + +static void real_value(vpiHandle ref, p_vpi_value vp) +{ + struct __vpiRealConst*rfp = (struct __vpiRealConst*)ref; + assert(ref->vpi_type->type_code == vpiConstant); + + switch (vp->format) { + case vpiObjTypeVal: + vp->format = vpiRealVal; + case vpiRealVal: + vp->value.real = rfp->value; + break; + default: + assert(0); + } +} + +static const struct __vpirt vpip_real_rt = { + vpiConstant, + real_get, + 0, + real_value, + 0, + 0, + 0 +}; + +vpiHandle vpip_make_real_const(struct __vpiRealConst*obj, double value) +{ + obj->base.vpi_type = &vpip_real_rt; + obj->value = value; + return &(obj->base); +} + +vpiHandle vpip_make_real_const(double value) +{ + struct __vpiRealConst*obj; + obj =(struct __vpiRealConst*) malloc(sizeof (struct __vpiRealConst)); + return vpip_make_real_const(obj, value); +} + /* * $Log: vpi_const.cc,v $ + * Revision 1.36 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.35 2006/03/18 22:51:10 steve * Syntax for carrying sign with parameter. * diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index d636f7414..123556091 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vpi_priv.h,v 1.70 2006/03/18 22:51:10 steve Exp $" +#ident "$Id: vpi_priv.h,v 1.71 2006/06/18 04:15:50 steve Exp $" #endif # include "vpi_user.h" @@ -257,6 +257,9 @@ struct __vpiUserSystf { s_vpi_systf_data info; }; +extern struct __vpiUserSystf* vpip_find_systf(const char*name); + + struct __vpiSysTaskCall { struct __vpiHandle base; struct __vpiScope* scope; @@ -268,6 +271,7 @@ struct __vpiSysTaskCall { /* These represent where in the vthread to put the return value. */ unsigned vbit; signed vwid; + class vvp_net_t*fnet; }; extern struct __vpiSysTaskCall*vpip_cur_task; @@ -309,6 +313,13 @@ struct __vpiDecConst { vpiHandle vpip_make_dec_const(int value); vpiHandle vpip_make_dec_const(struct __vpiDecConst*obj, int value); +struct __vpiRealConst { + struct __vpiHandle base; + double value; +}; + +vpiHandle vpip_make_real_const(double value); + /* * This one looks like a constant, but really is a vector in the current * thread. @@ -350,6 +361,7 @@ extern unsigned vpip_module_path_cnt; */ extern vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, + class vvp_net_t*fnet, unsigned argc, vpiHandle*argv); @@ -432,6 +444,9 @@ extern char *need_result_buf(unsigned cnt, vpi_rbuf_t type); /* * $Log: vpi_priv.h,v $ + * Revision 1.71 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.70 2006/03/18 22:51:10 steve * Syntax for carrying sign with parameter. * diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index a4cdac4f8..0d99a5667 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vpi_tasks.cc,v 1.31 2005/09/20 18:34:02 steve Exp $" +#ident "$Id: vpi_tasks.cc,v 1.32 2006/06/18 04:15:50 steve Exp $" #endif /* @@ -266,6 +266,92 @@ static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp) return 0; } +static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp) +{ + assert(ref->vpi_type->type_code == vpiSysFuncCall); + + struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + + unsigned vwid = (unsigned) rfp->vwid; + vvp_vector4_t val (vwid); + + switch (vp->format) { + + case vpiIntVal: { + long tmp = vp->value.integer; + for (unsigned idx = 0 ; idx < vwid ; idx += 1) { + val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0); + tmp >>= 1; + } + break; + } + + case vpiVectorVal: + + for (unsigned wdx = 0 ; wdx < vwid ; wdx += 32) { + unsigned word = wdx / 32; + unsigned long aval = vp->value.vector[word].aval; + unsigned long bval = vp->value.vector[word].bval; + + for (unsigned idx = 0 ; (wdx+idx) < vwid ; idx += 1) { + int bit = (aval&1) | ((bval<<1)&2); + vvp_bit4_t bit4; + + switch (bit) { + case 0: + bit4 = BIT4_0; + break; + case 1: + bit4 = BIT4_1; + break; + case 2: + bit4 = BIT4_Z; + break; + case 3: + bit4 = BIT4_X; + break; + default: + assert(0); + } + val.set_bit(wdx+idx, bit4); + + aval >>= 1; + bval >>= 1; + } + } + break; + + default: + fprintf(stderr, "XXXX format=%d, vwid=%u\n", vp->format, rfp->vwid); + assert(0); + } + + vvp_send_vec4(rfp->fnet->out, val); + return 0; +} + +static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp) +{ + assert(ref->vpi_type->type_code == vpiSysFuncCall); + + struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + double val; + + switch (vp->format) { + + case vpiRealVal: + val = vp->value.real; + break; + + default: + assert(0); + } + + vvp_send_real(rfp->fnet->out, val); + + return 0; +} + static const struct __vpirt vpip_sysfunc_rt = { vpiSysFuncCall, @@ -287,6 +373,26 @@ static const struct __vpirt vpip_sysfunc_real_rt = { systask_iter }; +static const struct __vpirt vpip_sysfunc_4net_rt = { + vpiSysFuncCall, + 0, + systask_get_str, + 0, + sysfunc_put_4net_value, + systask_handle, + systask_iter +}; + +static const struct __vpirt vpip_sysfunc_rnet_rt = { + vpiSysFuncCall, + 0, + systask_get_str, + 0, + sysfunc_put_rnet_value, + systask_handle, + systask_iter +}; + /* **** Manipulate the internal datastructures. **** */ static struct __vpiUserSystf**def_table = 0; @@ -315,7 +421,7 @@ static struct __vpiUserSystf* allocate_def(void) } -static struct __vpiUserSystf* vpip_find_systf(const char*name) +struct __vpiUserSystf* vpip_find_systf(const char*name) { for (unsigned idx = 0 ; idx < def_count ; idx += 1) if (strcmp(def_table[idx]->info.tfname, name) == 0) @@ -337,6 +443,7 @@ static struct __vpiUserSystf* vpip_find_systf(const char*name) * vbit is also a non-zero value, the address in thread space of the result. */ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, + class vvp_net_t*fnet, unsigned argc, vpiHandle*argv) { struct __vpiUserSystf*defn = vpip_find_systf(name); @@ -348,7 +455,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, switch (defn->info.type) { case vpiSysTask: - if (vwid != 0) { + if (vwid != 0 || fnet != 0) { fprintf(stderr, "%s: This is a system Task, " "you cannot call it as a Function\n", name); return 0; @@ -357,7 +464,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, break; case vpiSysFunc: - if (vwid == 0) { + if (vwid == 0 && fnet == 0) { fprintf(stderr, "%s: This is a system Function, " "you cannot call it as a Task\n", name); return 0; @@ -376,18 +483,20 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, break; case vpiSysFunc: - if (vwid > 0) { - obj->base.vpi_type = &vpip_sysfunc_rt; + if (fnet && vwid == -vpiRealConst) { + obj->base.vpi_type = &vpip_sysfunc_rnet_rt; - } else switch (vwid) { + } else if (fnet && vwid > 0) { + obj->base.vpi_type = &vpip_sysfunc_4net_rt; - case -vpiRealConst: + } else if (vwid == -vpiRealConst) { obj->base.vpi_type = &vpip_sysfunc_real_rt; - break; - default: - assert(0); + } else if (vwid > 0) { obj->base.vpi_type = &vpip_sysfunc_rt; + + } else { + assert(0); } break; } @@ -398,6 +507,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, obj->args = argv; obj->vbit = vbit; obj->vwid = vwid; + obj->fnet = fnet; obj->userdata = 0; /* If there is a compiletf function, call it here. */ @@ -487,6 +597,9 @@ void* vpi_get_userdata(vpiHandle ref) /* * $Log: vpi_tasks.cc,v $ + * Revision 1.32 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.31 2005/09/20 18:34:02 steve * Clean up compiler warnings. * diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 8f639abf4..44739409c 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ident "$Id: vvp_net.cc,v 1.52 2006/03/15 19:15:34 steve Exp $" +#ident "$Id: vvp_net.cc,v 1.53 2006/06/18 04:15:50 steve Exp $" # include "config.h" # include "vvp_net.h" @@ -1709,12 +1709,14 @@ vvp_wide_fun_core::vvp_wide_fun_core(vvp_net_t*net, unsigned nports) { ptr_ = net; nports_ = nports; - port_values_ = new vvp_vector4_t [nports_]; + port_values_ = 0; + port_rvalues_ = 0; } vvp_wide_fun_core::~vvp_wide_fun_core() { - delete[]port_values_; + if (port_values_) delete[]port_values_; + if (port_rvalues_) delete[]port_rvalues_; } void vvp_wide_fun_core::propagate_vec4(const vvp_vector4_t&bit, @@ -1735,17 +1737,39 @@ unsigned vvp_wide_fun_core::port_count() const vvp_vector4_t& vvp_wide_fun_core::value(unsigned idx) { assert(idx < nports_); + assert(port_values_); return port_values_[idx]; } +double vvp_wide_fun_core::value_r(unsigned idx) +{ + assert(idx < nports_); + return port_rvalues_? port_rvalues_[idx] : 0.0; +} + +void vvp_wide_fun_core::recv_real_from_inputs(unsigned p) +{ + assert(0); +} + void vvp_wide_fun_core::dispatch_vec4_from_input_(unsigned port, vvp_vector4_t bit) { assert(port < nports_); + if (port_values_ == 0) port_values_ = new vvp_vector4_t [nports_]; port_values_[port] = bit; recv_vec4_from_inputs(port); } +void vvp_wide_fun_core::dispatch_real_from_input_(unsigned port, + double bit) +{ + assert(port < nports_); + if (port_rvalues_ == 0) port_rvalues_ = new double[nports_]; + port_rvalues_[port] = bit; + recv_real_from_inputs(port); +} + vvp_wide_fun_t::vvp_wide_fun_t(vvp_wide_fun_core*c, unsigned base) : core_(c), port_base_(base) { @@ -1761,6 +1785,12 @@ void vvp_wide_fun_t::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit) core_->dispatch_vec4_from_input_(pidx, bit); } +void vvp_wide_fun_t::recv_real(vvp_net_ptr_t port, double bit) +{ + unsigned pidx = port_base_ + port.port(); + core_->dispatch_real_from_input_(pidx, bit); +} + /* **** vvp_scalar_t methods **** */ @@ -2163,6 +2193,9 @@ vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a, /* * $Log: vvp_net.cc,v $ + * Revision 1.53 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.52 2006/03/15 19:15:34 steve * const/non-const clash. * diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 30f2388fa..aef0b78c1 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -18,7 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ident "$Id: vvp_net.h,v 1.50 2006/03/08 05:29:42 steve Exp $" +#ident "$Id: vvp_net.h,v 1.51 2006/06/18 04:15:50 steve Exp $" # include "config.h" # include @@ -918,15 +918,19 @@ class vvp_wide_fun_core : public vvp_net_fun_t { protected: void propagate_vec4(const vvp_vector4_t&bit, vvp_time64_t delay =0); unsigned port_count() const; + vvp_vector4_t& value(unsigned); + double value_r(unsigned); private: // the derived class implements this to receive an indication // that one of the port input values changed. virtual void recv_vec4_from_inputs(unsigned port) =0; + virtual void recv_real_from_inputs(unsigned port); friend class vvp_wide_fun_t; void dispatch_vec4_from_input_(unsigned port, vvp_vector4_t bit); + void dispatch_real_from_input_(unsigned port, double bit); private: // Back-point to the vvp_net_t that points to me. @@ -934,7 +938,7 @@ class vvp_wide_fun_core : public vvp_net_fun_t { // Structure to track the input values from the input functors. unsigned nports_; vvp_vector4_t*port_values_; - + double*port_rvalues_; }; /* @@ -950,6 +954,7 @@ class vvp_wide_fun_t : public vvp_net_fun_t { ~vvp_wide_fun_t(); void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit); + void recv_real(vvp_net_ptr_t port, double bit); private: vvp_wide_fun_core*core_; @@ -1008,6 +1013,9 @@ inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val, /* * $Log: vvp_net.h,v $ + * Revision 1.51 2006/06/18 04:15:50 steve + * Add support for system functions in continuous assignments. + * * Revision 1.50 2006/03/08 05:29:42 steve * Add support for logic parameters. *