Add support for LPM_UFUNC user defined functions.
This commit is contained in:
parent
0f914bf35a
commit
53da6e9a33
17
elab_net.cc
17
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.155 2005/03/13 01:26:48 steve Exp $"
|
||||
#ident "$Id: elab_net.cc,v 1.156 2005/03/18 02:56:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -1227,7 +1227,7 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope,
|
|||
for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) {
|
||||
const NetNet* port_reg = def->port(idx);
|
||||
NetNet*tmp = parms_[idx]->elaborate_net(des, scope,
|
||||
port_reg->pin_count(),
|
||||
port_reg->vector_width(),
|
||||
0, 0, 0,
|
||||
Link::STRONG,
|
||||
Link::STRONG);
|
||||
|
|
@ -1256,21 +1256,19 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope,
|
|||
of the function net. */
|
||||
NetNet*osig = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE,
|
||||
def->return_sig()->pin_count());
|
||||
def->return_sig()->vector_width());
|
||||
osig->local_flag(true);
|
||||
|
||||
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
|
||||
connect(net->port_pin(0, idx), osig->pin(idx));
|
||||
connect(net->pin(0), osig->pin(0));
|
||||
|
||||
/* Connect the parameter pins to the parameter expressions. */
|
||||
for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) {
|
||||
const NetNet* port = def->port(idx);
|
||||
NetNet*cur = eparms[idx];
|
||||
|
||||
NetNet*tmp = pad_to_width(des, cur, port->pin_count());
|
||||
NetNet*tmp = pad_to_width(des, cur, port->vector_width());
|
||||
|
||||
for (unsigned pin = 0 ; pin < port->pin_count() ; pin += 1)
|
||||
connect(net->port_pin(idx+1, pin), tmp->pin(pin));
|
||||
connect(net->pin(idx+1), tmp->pin(0));
|
||||
}
|
||||
|
||||
return osig;
|
||||
|
|
@ -2492,6 +2490,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
|||
|
||||
/*
|
||||
* $Log: elab_net.cc,v $
|
||||
* Revision 1.156 2005/03/18 02:56:03 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.155 2005/03/13 01:26:48 steve
|
||||
* UPdate elabrate continuous assighn of string to net.
|
||||
*
|
||||
|
|
|
|||
33
ivl_target.h
33
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.146 2005/03/09 04:53:40 steve Exp $"
|
||||
#ident "$Id: ivl_target.h,v 1.147 2005/03/18 02:56:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -866,6 +866,25 @@ extern const char* ivl_udp_name(ivl_udp_t net);
|
|||
* ivl_lpm_data(0) nexus is the vector input, and the ivl_lpm_data(1)
|
||||
* the shift distance. The vector input is the same width as the
|
||||
* output, but the distance has its own width.
|
||||
*
|
||||
* - 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
|
||||
* function are connected to the net, as is the output.
|
||||
*
|
||||
* The function definition is associated with a scope, and the
|
||||
* ivl_lpm_define fuction returns the scope that is that definition.
|
||||
* See the ivl_scope_* fuctions for how to get at the actual
|
||||
* definition.
|
||||
*
|
||||
* As with many LPM nodes, the ivl_lpm_q function returns the nexus
|
||||
* for the signal function return value. The width of this nexus must
|
||||
* exactly match the width of the device from ivl_lpm_width.
|
||||
*
|
||||
* The ivl_lpm_data function retrives the nexa for all the input
|
||||
* ports. The ivl_lpm_size function returns the number of inputs for
|
||||
* the device, and the ivl_lpm_data() function index argument selects
|
||||
* the port to retrieve. Each port is sized independently.
|
||||
*/
|
||||
|
||||
extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */
|
||||
|
|
@ -891,14 +910,19 @@ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
|
|||
/* IVL_LPM_FF IVL_LPM_RAM */
|
||||
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
|
||||
/* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT
|
||||
IVL_LPM_MUX IVL_LPM_RAM IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB */
|
||||
IVL_LPM_MUX IVL_LPM_RAM IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB
|
||||
IVL_LPM_UFUNC */
|
||||
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);
|
||||
|
|
@ -906,7 +930,7 @@ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx);
|
|||
extern unsigned ivl_lpm_selects(ivl_lpm_t net);
|
||||
/* IVL_LPM_MUX IVL_LPM_RAM */
|
||||
extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx);
|
||||
/* IVL_LPM_CONCAT IVL_LPM_MUX IVL_LPM_REPEAT */
|
||||
/* IVL_LPM_CONCAT IVL_LPM_MUX IVL_LPM_REPEAT IVL_LPM_UFUNC */
|
||||
extern unsigned ivl_lpm_size(ivl_lpm_t net);
|
||||
/* IVL_LPM_RAM */
|
||||
extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
|
||||
|
|
@ -1556,6 +1580,9 @@ _END_DECL
|
|||
|
||||
/*
|
||||
* $Log: ivl_target.h,v $
|
||||
* Revision 1.147 2005/03/18 02:56:03 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.146 2005/03/09 04:53:40 steve
|
||||
* Generate code for new form of memory ports.
|
||||
*
|
||||
|
|
|
|||
87
net_func.cc
87
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.6 2004/05/31 23:34:37 steve Exp $"
|
||||
#ident "$Id: net_func.cc,v 1.7 2005/03/18 02:56:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -26,42 +26,25 @@
|
|||
# include "PExpr.h"
|
||||
# include <iostream>
|
||||
|
||||
static unsigned count_def_pins(const NetFuncDef*def)
|
||||
{
|
||||
assert(def->return_sig());
|
||||
|
||||
unsigned sum = def->return_sig()->pin_count();
|
||||
for (unsigned idx = 0 ; idx < def->port_count() ; idx += 1)
|
||||
sum += def->port(idx)->pin_count();
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*
|
||||
* To make a NetUserFunc device, make as many pins as there are ports
|
||||
* in the function. Get the port count from the function definition,
|
||||
* which accounts for all the inputs, plus one for the phantom output
|
||||
* that is the result.
|
||||
*/
|
||||
NetUserFunc::NetUserFunc(NetScope*s, perm_string n, NetScope*d)
|
||||
: NetNode(s, n, count_def_pins(d->func_def())),
|
||||
: NetNode(s, n, d->func_def()->port_count()+1),
|
||||
def_(d)
|
||||
{
|
||||
NetFuncDef*def = def_->func_def();
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(0).set_name(def_->basename(), 0);
|
||||
|
||||
unsigned port_wid = port_width(0);
|
||||
for (unsigned idx = 0 ; idx < port_wid ; idx += 1) {
|
||||
pin(idx).set_dir(Link::OUTPUT);
|
||||
pin(idx).set_name(def_->basename(), idx);
|
||||
}
|
||||
for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) {
|
||||
|
||||
unsigned pin_base = port_wid;
|
||||
for (unsigned idx = 1 ; idx < port_count() ; idx += 1) {
|
||||
|
||||
const NetNet*port_sig = def->port(idx-1);
|
||||
unsigned bits = port_width(idx);
|
||||
for (unsigned bit = 0; bit < bits; bit += 1) {
|
||||
pin(pin_base+bit).set_dir(Link::INPUT);
|
||||
pin(pin_base+bit).set_name(port_sig->name(), bit);
|
||||
pin(pin_base+bit).drive0(Link::HIGHZ);
|
||||
pin(pin_base+bit).drive1(Link::HIGHZ);
|
||||
}
|
||||
|
||||
pin_base += bits;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,11 +52,6 @@ NetUserFunc::~NetUserFunc()
|
|||
{
|
||||
}
|
||||
|
||||
unsigned NetUserFunc::port_count() const
|
||||
{
|
||||
return def_->func_def()->port_count() + 1;
|
||||
}
|
||||
|
||||
unsigned NetUserFunc::port_width(unsigned port) const
|
||||
{
|
||||
NetFuncDef*def = def_->func_def();
|
||||
|
|
@ -82,44 +60,16 @@ unsigned NetUserFunc::port_width(unsigned port) const
|
|||
if (port == 0) {
|
||||
const NetNet*sig = def->return_sig();
|
||||
assert(sig);
|
||||
return sig->pin_count();
|
||||
return sig->vector_width();
|
||||
}
|
||||
|
||||
port -= 1;
|
||||
assert(port < def->port_count());
|
||||
const NetNet*port_sig = def->port(port);
|
||||
|
||||
return port_sig->pin_count();
|
||||
return port_sig->vector_width();
|
||||
}
|
||||
|
||||
Link& NetUserFunc::port_pin(unsigned port, unsigned idx)
|
||||
{
|
||||
NetFuncDef*def = def_->func_def();
|
||||
unsigned pin_base = 0;
|
||||
const NetNet*port_sig;
|
||||
|
||||
if (port == 0)
|
||||
return pin(idx);
|
||||
|
||||
port_sig = def->return_sig();
|
||||
pin_base += port_sig->pin_count();
|
||||
port -= 1;
|
||||
|
||||
assert(port < def->port_count());
|
||||
|
||||
for (unsigned port_idx = 0 ; port_idx < port ; port_idx += 1) {
|
||||
port_sig = def->port(port_idx);
|
||||
pin_base += port_sig->pin_count();
|
||||
}
|
||||
|
||||
port_sig = def->port(port);
|
||||
assert(idx < port_sig->pin_count());
|
||||
assert((pin_base+idx) < pin_count());
|
||||
|
||||
return pin(pin_base+idx);
|
||||
}
|
||||
|
||||
|
||||
const NetScope* NetUserFunc::def() const
|
||||
{
|
||||
return def_;
|
||||
|
|
@ -164,6 +114,9 @@ bool PECallFunction::check_call_matches_definition_(Design*des, NetScope*dscope)
|
|||
|
||||
/*
|
||||
* $Log: net_func.cc,v $
|
||||
* Revision 1.7 2005/03/18 02:56:03 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.6 2004/05/31 23:34:37 steve
|
||||
* Rewire/generalize parsing an elaboration of
|
||||
* function return values to allow for better
|
||||
|
|
|
|||
10
netlist.h
10
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.337 2005/03/12 06:43:36 steve Exp $"
|
||||
#ident "$Id: netlist.h,v 1.338 2005/03/18 02:56:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -960,7 +960,8 @@ class NetReplicate : public NetNode {
|
|||
|
||||
/*
|
||||
* This node represents the call of a user defined function in a
|
||||
* structural context.
|
||||
* structural context. The pin count is the same as the port count,
|
||||
* with pin0 the return value.
|
||||
*/
|
||||
class NetUserFunc : public NetNode {
|
||||
|
||||
|
|
@ -968,9 +969,7 @@ class NetUserFunc : public NetNode {
|
|||
NetUserFunc(NetScope*s, perm_string n, NetScope*def);
|
||||
~NetUserFunc();
|
||||
|
||||
unsigned port_count() const;
|
||||
unsigned port_width(unsigned port) const;
|
||||
Link& port_pin(unsigned port, unsigned idx);
|
||||
|
||||
const NetScope* def() const;
|
||||
|
||||
|
|
@ -3417,6 +3416,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
|||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.338 2005/03/18 02:56:03 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.337 2005/03/12 06:43:36 steve
|
||||
* Update support for LPM_MOD.
|
||||
*
|
||||
|
|
|
|||
22
t-dll-api.cc
22
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.120 2005/03/09 05:52:04 steve Exp $"
|
||||
#ident "$Id: t-dll-api.cc,v 1.121 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -798,6 +798,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_UFUNC:
|
||||
// Skip the return port.
|
||||
assert(idx < (net->u_.ufunc.ports-1));
|
||||
return net->u_.ufunc.pins[idx+1];
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
|
|
@ -828,8 +833,10 @@ extern "C" ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
extern "C" ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx)
|
||||
{
|
||||
cerr << "ANACHRONISM: Call to anachronistic ivl_lpm_data2." << endl;
|
||||
assert(net);
|
||||
switch (net->type) {
|
||||
|
||||
|
|
@ -848,7 +855,8 @@ extern "C" ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
extern "C" unsigned ivl_lpm_data2_width(ivl_lpm_t net, unsigned sdx)
|
||||
{
|
||||
assert(net);
|
||||
|
|
@ -862,6 +870,7 @@ extern "C" unsigned ivl_lpm_data2_width(ivl_lpm_t net, unsigned sdx)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function returns the hierarchical name for the LPM device. The
|
||||
|
|
@ -942,8 +951,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
|||
return net->u_.shift.q;
|
||||
|
||||
case IVL_LPM_UFUNC:
|
||||
assert(idx < net->u_.ufunc.port_wid[0]);
|
||||
return net->u_.ufunc.pins[idx];
|
||||
assert(idx == 0);
|
||||
return net->u_.ufunc.pins[0];
|
||||
|
||||
case IVL_LPM_CONCAT:
|
||||
return net->u_.concat.pins[0];
|
||||
|
|
@ -1101,7 +1110,7 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
|
|||
case IVL_LPM_SHIFTR:
|
||||
return net->u_.shift.width;
|
||||
case IVL_LPM_UFUNC:
|
||||
return net->u_.ufunc.port_wid[0];
|
||||
return net->u_.ufunc.width;
|
||||
case IVL_LPM_CONCAT:
|
||||
return net->u_.concat.width;
|
||||
case IVL_LPM_PART_VP:
|
||||
|
|
@ -1991,6 +2000,9 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net)
|
|||
|
||||
/*
|
||||
* $Log: t-dll-api.cc,v $
|
||||
* Revision 1.121 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.120 2005/03/09 05:52:04 steve
|
||||
* Handle case inequality in netlists.
|
||||
*
|
||||
|
|
|
|||
22
t-dll.cc
22
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.144 2005/03/12 06:43:36 steve Exp $"
|
||||
#ident "$Id: t-dll.cc,v 1.145 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -1012,28 +1012,25 @@ bool dll_target::net_function(const NetUserFunc*net)
|
|||
|
||||
/* Save information about the ports in the ivl_lpm_s
|
||||
structure. Note that port 0 is the return value. */
|
||||
obj->u_.ufunc.ports = net->port_count();
|
||||
obj->u_.ufunc.port_wid = new unsigned[net->port_count()];
|
||||
for (unsigned idx = 0 ; idx < obj->u_.ufunc.ports ; idx += 1)
|
||||
obj->u_.ufunc.port_wid[idx] = net->port_width(idx);
|
||||
obj->u_.ufunc.ports = net->pin_count();
|
||||
|
||||
assert(net->pin_count() >= 1);
|
||||
obj->u_.ufunc.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
|
||||
remaining input pins are HiZ. */
|
||||
|
||||
unsigned pin_count = net->pin_count();
|
||||
obj->u_.ufunc.pins = new ivl_nexus_t[pin_count];
|
||||
obj->u_.ufunc.pins = new ivl_nexus_t[net->pin_count()];
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count ; idx += 1) {
|
||||
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
||||
const Nexus*nex = net->pin(idx).nexus();
|
||||
assert(nex->t_cookie());
|
||||
ivl_nexus_t nn = (ivl_nexus_t)nex->t_cookie();
|
||||
assert(nn);
|
||||
|
||||
obj->u_.ufunc.pins[idx] = nn;
|
||||
ivl_drive_t drive = idx < obj->u_.ufunc.port_wid[0]
|
||||
? IVL_DR_STRONG
|
||||
: IVL_DR_HiZ;
|
||||
ivl_drive_t drive = idx == 0 ? IVL_DR_STRONG : IVL_DR_HiZ;
|
||||
nexus_lpm_add(obj->u_.ufunc.pins[idx], obj, idx, drive, drive);
|
||||
}
|
||||
|
||||
|
|
@ -2136,6 +2133,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
|
|||
|
||||
/*
|
||||
* $Log: t-dll.cc,v $
|
||||
* Revision 1.145 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.144 2005/03/12 06:43:36 steve
|
||||
* Update support for LPM_MOD.
|
||||
*
|
||||
|
|
|
|||
7
t-dll.h
7
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.122 2005/02/19 02:43:39 steve Exp $"
|
||||
#ident "$Id: t-dll.h,v 1.123 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
|
|
@ -362,7 +362,7 @@ struct ivl_lpm_s {
|
|||
struct ivl_lpm_ufunc_s {
|
||||
ivl_scope_t def;
|
||||
unsigned ports;
|
||||
unsigned *port_wid;
|
||||
unsigned width;
|
||||
ivl_nexus_t*pins;
|
||||
} ufunc;
|
||||
} u_;
|
||||
|
|
@ -685,6 +685,9 @@ struct ivl_variable_s {
|
|||
|
||||
/*
|
||||
* $Log: t-dll.h,v $
|
||||
* Revision 1.123 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.122 2005/02/19 02:43:39 steve
|
||||
* Support shifts and divide.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.116 2005/03/12 06:43:36 steve Exp $"
|
||||
#ident "$Id: stub.c,v 1.117 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -604,6 +604,33 @@ static void show_lpm_sub(ivl_lpm_t net)
|
|||
show_lpm_arithmetic_pins(net);
|
||||
}
|
||||
|
||||
static void show_lpm_ufunc(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned ports = ivl_lpm_size(net);
|
||||
ivl_scope_t def = ivl_lpm_define(net);
|
||||
ivl_nexus_t nex;
|
||||
unsigned idx;
|
||||
|
||||
fprintf(out, " LPM_UFUNC %s: <call=%s, width=%u, ports=%u>\n",
|
||||
ivl_lpm_basename(net), ivl_scope_name(def), width, 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 <width=%u>\n", idx,
|
||||
ivl_nexus_name(nex), width_of_nexus(nex));
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm(ivl_lpm_t net)
|
||||
{
|
||||
unsigned idx;
|
||||
|
|
@ -736,6 +763,10 @@ static void show_lpm(ivl_lpm_t net)
|
|||
show_lpm_repeat(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_UFUNC:
|
||||
show_lpm_ufunc(net);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(out, " LPM(%d) %s: <width=%u, signed=%d>\n",
|
||||
ivl_lpm_type(net),
|
||||
|
|
@ -1185,6 +1216,9 @@ int target_design(ivl_design_t des)
|
|||
|
||||
/*
|
||||
* $Log: stub.c,v $
|
||||
* Revision 1.117 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.116 2005/03/12 06:43:36 steve
|
||||
* Update support for LPM_MOD.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.121 2005/03/09 05:52:04 steve Exp $"
|
||||
#ident "$Id: vvp_scope.c,v 1.122 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvp_priv.h"
|
||||
|
|
@ -1714,8 +1714,7 @@ static void draw_lpm_shiftl(ivl_lpm_t net)
|
|||
|
||||
static void draw_lpm_ufunc(ivl_lpm_t net)
|
||||
{
|
||||
unsigned idx, bit;
|
||||
char comma;
|
||||
unsigned idx;
|
||||
ivl_scope_t def = ivl_lpm_define(net);
|
||||
|
||||
fprintf(vvp_out, "L_%p .ufunc TD_%s, %u", net,
|
||||
|
|
@ -1723,15 +1722,10 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
|
|||
ivl_lpm_width(net));
|
||||
|
||||
/* Print all the net signals that connect to the input of the
|
||||
function. Print them one per line, for convenience. */
|
||||
function. */
|
||||
for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
|
||||
comma = ' ';
|
||||
fprintf(vvp_out, ",\n");
|
||||
for (bit = 0 ; bit < ivl_lpm_data2_width(net, idx) ; bit += 1) {
|
||||
fprintf(vvp_out, "%c ", comma);
|
||||
draw_input_from_net(ivl_lpm_data2(net, idx, bit));
|
||||
comma = ',';
|
||||
}
|
||||
fprintf(vvp_out, ", ");
|
||||
draw_input_from_net(ivl_lpm_data(net, idx));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1741,32 +1735,23 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
|
|||
receive the input values given in the previous list. */
|
||||
for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
|
||||
ivl_signal_t psig = ivl_scope_port(def, idx+1);
|
||||
comma = ' ';
|
||||
|
||||
if (idx == 0)
|
||||
fprintf(vvp_out, "\n(");
|
||||
fprintf(vvp_out, " (");
|
||||
else
|
||||
fprintf(vvp_out, ",\n");
|
||||
fprintf(vvp_out, ", ");
|
||||
|
||||
for (bit = 0 ; bit < ivl_signal_pins(psig) ; bit += 1) {
|
||||
fprintf(vvp_out, "%c V_%s[%u]", comma,
|
||||
vvp_signal_label(psig), bit);
|
||||
comma = ',';
|
||||
}
|
||||
fprintf(vvp_out, "V_%s", vvp_signal_label(psig));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ")\n");
|
||||
fprintf(vvp_out, ")");
|
||||
|
||||
/* Finally, print the reference to the signal from which the
|
||||
result is collected. */
|
||||
{ ivl_signal_t psig = ivl_scope_port(def, 0);
|
||||
assert(ivl_lpm_width(net) == ivl_signal_pins(psig));
|
||||
assert(ivl_lpm_width(net) == ivl_signal_width(psig));
|
||||
|
||||
comma = ' ';
|
||||
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
|
||||
fprintf(vvp_out, "%c V_%s[%u]", comma,
|
||||
vvp_signal_label(psig),
|
||||
idx);
|
||||
comma = ',';
|
||||
}
|
||||
fprintf(vvp_out, " V_%s", vvp_signal_label(psig));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
|
|
@ -2022,6 +2007,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
|
||||
/*
|
||||
* $Log: vvp_scope.c,v $
|
||||
* Revision 1.122 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.121 2005/03/09 05:52:04 steve
|
||||
* Handle case inequality in netlists.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* $Id: README.txt,v 1.60 2005/03/09 05:52:04 steve Exp $
|
||||
* $Id: README.txt,v 1.61 2005/03/18 02:56:04 steve Exp $
|
||||
*/
|
||||
|
||||
VVP SIMULATION ENGINE
|
||||
|
|
@ -609,8 +609,26 @@ STRUCTURAL FUNCTION CALLS:
|
|||
|
||||
The .ufunc statement defines a call to a user defined function.
|
||||
|
||||
<label> .ufunc ;
|
||||
<label> .ufunc <flabel>, <wid>, <isymbols> ( <psymbols> ) <rsymbol> ;
|
||||
|
||||
The <flabel> is the code label for the first instruction of the
|
||||
function implementation. This is code that the simulator will branch
|
||||
to.
|
||||
|
||||
The <wid> is the width of the output vector in bits.
|
||||
|
||||
The <isymbols> is a list of net symbols for each of the inputs to the
|
||||
function. These are points in the net, and the ufunc device watches
|
||||
these nets for input changes.
|
||||
|
||||
The <psymbols> list is exactly the same size as the <isymbols>
|
||||
list. The <psymbols> are variables that represent the input ports for
|
||||
the function. The ufunc performs an assignment to these variables
|
||||
before calling the function.
|
||||
|
||||
Finally, the <rsymbol> is the variable within the function where the
|
||||
result will be found when the function code ends. This value is picked
|
||||
up and propagated to the output of the functor.
|
||||
|
||||
THREAD STATEMENTS:
|
||||
|
||||
|
|
|
|||
|
|
@ -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.65 2005/03/09 05:52:04 steve Exp $"
|
||||
#ident "$Id: compile.h,v 1.66 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
|
@ -161,11 +161,14 @@ extern void compile_param_string(char*label, char*name,
|
|||
|
||||
/*
|
||||
* This function schedules a lookup of an indexed label. The ref
|
||||
* points to the vvp_ipoint_t that receives the result. The result may
|
||||
* points to the vvp_net_t that receives the result. The result may
|
||||
* be assigned later, if the symbol is defined later in the source
|
||||
* file, so the memory that ref points to must persist.
|
||||
*
|
||||
* The text for the label will be deleted by this function, or the
|
||||
* cleanup that completes the binding.
|
||||
*/
|
||||
extern void functor_ref_lookup(vvp_ipoint_t *ref, char*lab, unsigned idx);
|
||||
extern void functor_ref_lookup(vvp_net_t**ref, char*lab);
|
||||
|
||||
/*
|
||||
* This function schedules a lookup of the labeled instruction. The
|
||||
|
|
@ -212,7 +215,7 @@ extern void compile_memory_init(char *memid, unsigned idx, long val);
|
|||
extern void compile_ufunc(char*label, char*code, unsigned wid,
|
||||
unsigned argc, struct symb_s*argv,
|
||||
unsigned portc, struct symb_s*portv,
|
||||
unsigned retc, struct symb_s*retv);
|
||||
struct symb_s retv);
|
||||
|
||||
/*
|
||||
* The compile_event function takes the parts of the event statement
|
||||
|
|
@ -297,6 +300,9 @@ extern void compile_net(char*label, char*name,
|
|||
|
||||
/*
|
||||
* $Log: compile.h,v $
|
||||
* Revision 1.66 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.65 2005/03/09 05:52:04 steve
|
||||
* Handle case inequality in netlists.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.69 2005/03/09 05:52:04 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.70 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
|
|
@ -171,11 +171,11 @@ statement
|
|||
bits in the symbols list change. */
|
||||
|
||||
| T_LABEL K_UFUNC T_SYMBOL ',' T_NUMBER ',' symbols
|
||||
'(' symbols ')' symbols ';'
|
||||
'(' symbols ')' symbol ';'
|
||||
{ compile_ufunc($1, $3, $5,
|
||||
$7.cnt, $7.vect,
|
||||
$9.cnt, $9.vect,
|
||||
$11.cnt, $11.vect); }
|
||||
$11); }
|
||||
|
||||
/* Resolver statements are very much like functors. They are
|
||||
compiled to functors of a different mode. */
|
||||
|
|
@ -679,6 +679,9 @@ int compile_design(const char*path)
|
|||
|
||||
/*
|
||||
* $Log: parse.y,v $
|
||||
* Revision 1.70 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.69 2005/03/09 05:52:04 steve
|
||||
* Handle case inequality in netlists.
|
||||
*
|
||||
|
|
|
|||
229
vvp/ufunc.cc
229
vvp/ufunc.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2005 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
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: ufunc.cc,v 1.5 2004/12/11 02:31:30 steve Exp $"
|
||||
#ident "$Id: ufunc.cc,v 1.6 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compile.h"
|
||||
|
|
@ -39,34 +39,65 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
ufunc_core::ufunc_core(unsigned ow, vvp_ipoint_t ob, vvp_ipoint_t*op,
|
||||
unsigned np, vvp_ipoint_t*p,
|
||||
vvp_code_t start_address,
|
||||
struct __vpiScope*run_scope)
|
||||
: owid_(ow), obase_(ob), oports_(op), nports_(np), ports_(p)
|
||||
ufunc_core::ufunc_core(unsigned owid, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t sa, struct __vpiScope*run_scope,
|
||||
char*result_label)
|
||||
{
|
||||
owid_ = owid;
|
||||
onet_ = ptr;
|
||||
nports_ = nports;
|
||||
ports_ = ports;
|
||||
port_values_ = new vvp_vector4_t[nports];
|
||||
code_ = sa;
|
||||
thread_ = 0;
|
||||
scope_ = run_scope;
|
||||
code_ = start_address;
|
||||
|
||||
ibits_ = new unsigned char[(nports_+3) / 4];
|
||||
memset(ibits_, 0xaa, (nports_+3) / 4);
|
||||
functor_ref_lookup(&result_, result_label);
|
||||
}
|
||||
|
||||
ufunc_core::~ufunc_core()
|
||||
{
|
||||
delete[] ports_;
|
||||
delete[]port_values_;
|
||||
}
|
||||
|
||||
void ufunc_core::set_bit(unsigned port_idx, unsigned val)
|
||||
/*
|
||||
* This method is called by the %fork_ufunc function to prepare the
|
||||
* input variables of the function for execution. The method copies
|
||||
* the input values collected by the core to the variables.
|
||||
*/
|
||||
void ufunc_core::assign_bits_to_ports(void)
|
||||
{
|
||||
unsigned idx = port_idx / 4;
|
||||
unsigned pp = port_idx % 4;
|
||||
for (unsigned idx = 0 ; idx < nports_ ; idx += 1) {
|
||||
vvp_net_t*net = ports_[idx];
|
||||
vvp_net_ptr_t pp (net, 0);
|
||||
net->fun->recv_vec4(pp, port_values_[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char mask[4] = {0xfc, 0xf3, 0xcf, 0x3f};
|
||||
/*
|
||||
* This method is called by the %join_ufunc instruction to copy the
|
||||
* result from the return code variable and deliver it to the output
|
||||
* of the functor, back into the netlist.
|
||||
*/
|
||||
void ufunc_core::finish_thread(vthread_t thr)
|
||||
{
|
||||
thread_ = 0;
|
||||
|
||||
ibits_[idx] &= mask[pp];
|
||||
ibits_[idx] |= (val&3) << pp*2;
|
||||
vvp_fun_signal*sig = reinterpret_cast<vvp_fun_signal*>(result_->fun);
|
||||
|
||||
vvp_send_vec4(onet_->out, sig->vec4_value());
|
||||
}
|
||||
|
||||
/*
|
||||
* The recv_vec4 methods of the input functors call this to assign the
|
||||
* input value to the port of the functor. I save the input value and
|
||||
* arrange for the function to be called.
|
||||
*/
|
||||
void ufunc_core::recv_vec4_from_inputs(unsigned port, vvp_vector4_t bit)
|
||||
{
|
||||
assert(port < nports_);
|
||||
port_values_[port] = bit;
|
||||
|
||||
if (thread_ == 0) {
|
||||
thread_ = vthread_new(code_, scope_);
|
||||
|
|
@ -74,100 +105,43 @@ void ufunc_core::set_bit(unsigned port_idx, unsigned val)
|
|||
}
|
||||
}
|
||||
|
||||
static const unsigned char strong_values[4] = {St0, St1, StX, HiZ};
|
||||
|
||||
void ufunc_core::assign_bits_to_ports(void)
|
||||
ufunc_input_functor::ufunc_input_functor(ufunc_core*c, unsigned base)
|
||||
: core_(c), port_base_(base)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nports_ ; idx += 1) {
|
||||
unsigned bit_val = ibits_[idx/4] >> (idx%4)*2;
|
||||
bit_val &= 3;
|
||||
|
||||
functor_set(ports_[idx], bit_val, strong_values[bit_val], true);
|
||||
}
|
||||
}
|
||||
|
||||
void ufunc_core::finish_thread(vthread_t thr)
|
||||
ufunc_input_functor::~ufunc_input_functor()
|
||||
{
|
||||
assert(thread_ == thr);
|
||||
thread_ = 0;
|
||||
|
||||
for (unsigned idx = 0 ; idx < owid_ ; idx += 1) {
|
||||
unsigned val = functor_get(oports_[idx]);
|
||||
vvp_ipoint_t ptr = ipoint_index(obase_, idx);
|
||||
functor_set(ptr, val, strong_values[val], false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There is an instance of ufunc_output_functor_s for each output bit
|
||||
* of the function. This is the functor that passes the output bits to
|
||||
* the rest of the design. The functor simply puts its input to its
|
||||
* output.
|
||||
*/
|
||||
struct ufunc_output_functor_s : public functor_s {
|
||||
void set(vvp_ipoint_t, bool push, unsigned val, unsigned str = 0);
|
||||
};
|
||||
|
||||
void ufunc_output_functor_s::set(vvp_ipoint_t, bool push, unsigned
|
||||
val, unsigned str)
|
||||
void ufunc_input_functor::recv_vec4(vvp_net_ptr_t port, vvp_vector4_t bit)
|
||||
{
|
||||
put_oval(val, push);
|
||||
}
|
||||
|
||||
struct ufunc_input_functor_s : public functor_s {
|
||||
void set(vvp_ipoint_t, bool push, unsigned val, unsigned str = 0);
|
||||
|
||||
unsigned core_base_;
|
||||
ufunc_core*core_;
|
||||
};
|
||||
|
||||
void ufunc_input_functor_s::set(vvp_ipoint_t ptr, bool,
|
||||
unsigned val, unsigned str)
|
||||
{
|
||||
unsigned pp = ipoint_port(ptr);
|
||||
core_->set_bit(core_base_+pp, val);
|
||||
unsigned pidx = port_base_ + port.port();
|
||||
core_->recv_vec4_from_inputs(pidx, bit);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function compiles the .ufunc statement that is discovered in
|
||||
* the source file. Create all the functors and the thread, and
|
||||
* connect them all up.
|
||||
*
|
||||
* The argv list is a list of the inputs to the function.
|
||||
*
|
||||
* The portv list is a list of variables that the function reads as
|
||||
* inputs. The core assigns values to these nets as part of the startup.
|
||||
*/
|
||||
void compile_ufunc(char*label, char*code, unsigned wid,
|
||||
unsigned argc, struct symb_s*argv,
|
||||
unsigned portc, struct symb_s*portv,
|
||||
unsigned retc, struct symb_s*retv)
|
||||
struct symb_s retv)
|
||||
{
|
||||
#if 0
|
||||
/* Create an array of vvp_ipoint_t pointers, that point to the
|
||||
.var bits of the function ports. Do this for the input
|
||||
ports and the output port. */
|
||||
/* The input argument list and port list must have the same
|
||||
sizes, since internally we will be mapping the inputs list
|
||||
to the ports list. */
|
||||
assert(argc == portc);
|
||||
vvp_ipoint_t* ports = new vvp_ipoint_t [portc];
|
||||
|
||||
for (unsigned idx = 0 ; idx < portc ; idx += 1) {
|
||||
functor_ref_lookup(ports+idx, portv[idx].text, portv[idx].idx);
|
||||
}
|
||||
|
||||
assert(retc == wid);
|
||||
vvp_ipoint_t* rets = new vvp_ipoint_t [retc];
|
||||
|
||||
for (unsigned idx = 0 ; idx < retc ; idx += 1) {
|
||||
functor_ref_lookup(rets+idx, retv[idx].text, retv[idx].idx);
|
||||
}
|
||||
|
||||
/* Create enough output functors for the output bits of the
|
||||
function. */
|
||||
vvp_ipoint_t obase = functor_allocate(wid);
|
||||
struct ufunc_output_functor_s*fpa
|
||||
= new struct ufunc_output_functor_s[wid];
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
vvp_ipoint_t ptr = ipoint_index(obase,idx);
|
||||
functor_define(ptr, fpa+idx);
|
||||
}
|
||||
|
||||
define_functor_symbol(label, obase);
|
||||
struct __vpiScope*run_scope = vpip_peek_current_scope();
|
||||
assert(run_scope);
|
||||
|
||||
/* Construct some phantom code that is the thread of the
|
||||
function call. The first instruction, at the start_address
|
||||
|
|
@ -202,43 +176,54 @@ void compile_ufunc(char*label, char*code, unsigned wid,
|
|||
codep->opcode = &of_END;
|
||||
}
|
||||
|
||||
|
||||
/* Create the function core object that references the output
|
||||
functors and the function ports. The input functors will
|
||||
point to this core to deliver input. */
|
||||
ufunc_core*core = new ufunc_core(wid, obase, rets,
|
||||
portc, ports,
|
||||
start_code,
|
||||
vpip_peek_current_scope());
|
||||
start_code->ufunc_core_ptr = core;
|
||||
ujoin_code->ufunc_core_ptr = core;
|
||||
|
||||
/* create enough input functors to connect to all the input
|
||||
bits of the function. These are used to detect changes and
|
||||
trigger the function thread. */
|
||||
unsigned icnt = (argc + 3) / 4;
|
||||
vvp_ipoint_t ibase = functor_allocate(icnt);
|
||||
struct ufunc_input_functor_s*ifp
|
||||
= new struct ufunc_input_functor_s[icnt];
|
||||
|
||||
for (unsigned idx = 0 ; idx < icnt ; idx += 1) {
|
||||
vvp_ipoint_t ptr = ipoint_index(ibase,idx);
|
||||
struct ufunc_input_functor_s*cur = ifp+idx;
|
||||
|
||||
cur->core_base_ = idx*4;
|
||||
cur->core_ = core;
|
||||
|
||||
functor_define(ptr, ifp+idx);
|
||||
/* Run through the function ports (which are related to but
|
||||
not the same as the input ports) and arrange for their
|
||||
binding. */
|
||||
vvp_net_t**ports = new vvp_net_t*[portc];
|
||||
for (unsigned idx = 0 ; idx < portc ; idx += 1) {
|
||||
functor_ref_lookup(&ports[idx], portv[idx].text);
|
||||
}
|
||||
|
||||
inputs_connect(ibase, argc, argv);
|
||||
#else
|
||||
fprintf(stderr, "XXXX compile_ufunc not implemented.\n");
|
||||
#endif
|
||||
/* Create the output functor and attach it to the label. Tell
|
||||
it about the start address of the code stub, and the scope
|
||||
that will contain the execution. */
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
ufunc_core*fcore = new ufunc_core(wid, ptr, portc, ports,
|
||||
start_code, run_scope,
|
||||
retv.text);
|
||||
ptr->fun = fcore;
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
start_code->ufunc_core_ptr = fcore;
|
||||
ujoin_code->ufunc_core_ptr = fcore;
|
||||
|
||||
/* Create input functors to receive values from the
|
||||
network. These functors pass the data to the core. */
|
||||
unsigned input_functors = (argc+3) / 4;
|
||||
for (unsigned idx = 0 ; idx < input_functors ; idx += 1) {
|
||||
unsigned base = idx*4;
|
||||
unsigned trans = 4;
|
||||
if (base+trans > argc)
|
||||
trans = argc - base;
|
||||
|
||||
ufunc_input_functor*cur = new ufunc_input_functor(fcore, base);
|
||||
ptr = new vvp_net_t;
|
||||
ptr->fun = cur;
|
||||
|
||||
inputs_connect(ptr, trans, argv+base);
|
||||
}
|
||||
|
||||
free(argv);
|
||||
free(portv);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: ufunc.cc,v $
|
||||
* Revision 1.6 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.5 2004/12/11 02:31:30 steve
|
||||
* Rework of internals to carry vectors through nexus instead
|
||||
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
||||
|
|
|
|||
100
vvp/ufunc.h
100
vvp/ufunc.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __ufunc_H
|
||||
#define __ufunc_H
|
||||
/*
|
||||
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2005 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
|
||||
|
|
@ -19,73 +19,97 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: ufunc.h,v 1.3 2003/07/03 20:03:36 steve Exp $"
|
||||
#ident "$Id: ufunc.h,v 1.4 2005/03/18 02:56:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "pointers.h"
|
||||
|
||||
/*
|
||||
* The .ufunc statement creates functors to represent user defined
|
||||
* functions. The function device itself is implemented as a thread
|
||||
* with a bunch of functors for the output bits. This thread has a set
|
||||
* of outputs, represented by output_functors and a set of inputs
|
||||
* connected to input functors. The input functors detect that a
|
||||
* change has occurred, and invoke the thread to process the new
|
||||
* values. The relationships work like this:
|
||||
* functions within the netlist (as opposed to within behavioral
|
||||
* code.) The function device itself is implemented as a thread with a
|
||||
* bunch of functors to receive input and a functor to deliver the
|
||||
* output. (Functions have exactly one output.) The input functors
|
||||
* detect that a change has occurred, and invoke the thread to process
|
||||
* the new values. The thread then uses the output functor to deliver
|
||||
* the result. The relationships look like this:
|
||||
*
|
||||
* ufunc_input_functor_s --+--> ufunc_core --+--> ufunc_output_functor_s
|
||||
* | |
|
||||
* ufunc_input_functor_s --+ +--> ufunc_output_functor_s
|
||||
* ufunc_input_functor --+--> ufunc_core --> ...
|
||||
* |
|
||||
* ufunc_input_functor_s --+
|
||||
* ufunc_input_functor --+
|
||||
* |
|
||||
* ufunc_input_functor --+
|
||||
*
|
||||
* There are enough input functors to take all the function inputs, 4
|
||||
* per functor. These inputs deliver the changed input value to the
|
||||
* ufunc_core, which carries the infastructure for the thread. The
|
||||
* ufunc_core is also a functor whose output is connected to the rest
|
||||
* of the netlist. This is where the result is delivered back to the
|
||||
* netlist.
|
||||
*/
|
||||
|
||||
class ufunc_core {
|
||||
class ufunc_core : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
ufunc_core(unsigned ow, vvp_ipoint_t ob, vvp_ipoint_t*op,
|
||||
unsigned np, vvp_ipoint_t*p,
|
||||
ufunc_core(unsigned ow, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t start_address,
|
||||
struct __vpiScope*run_scope);
|
||||
struct __vpiScope*run_scope,
|
||||
char*result_label);
|
||||
~ufunc_core();
|
||||
|
||||
void set_bit(unsigned port_idx, unsigned val);
|
||||
|
||||
void assign_bits_to_ports();
|
||||
void finish_thread(vthread_t thr);
|
||||
|
||||
struct __vpiScope*scope() { return scope_; }
|
||||
|
||||
void assign_bits_to_ports(void);
|
||||
void finish_thread(vthread_t thr);
|
||||
|
||||
private:
|
||||
// The owid_ and obase_ point to the functor vector that makes
|
||||
// up the output of the function.
|
||||
friend class ufunc_input_functor;
|
||||
void recv_vec4_from_inputs(unsigned port, vvp_vector4_t bit);
|
||||
|
||||
private:
|
||||
// output width of the function node.
|
||||
unsigned owid_;
|
||||
vvp_ipoint_t obase_;
|
||||
vvp_ipoint_t*oports_;
|
||||
// Keep an array of vvp_ipoint_t pointers that point to .var
|
||||
// functors. These are the input ports of the function.
|
||||
// Pointer to the "self" vvp_net_t that points to this functor.
|
||||
vvp_net_t*onet_;
|
||||
// Structure to track the input values from the input functors.
|
||||
unsigned nports_;
|
||||
vvp_ipoint_t*ports_;
|
||||
vvp_net_t**ports_;
|
||||
vvp_vector4_t*port_values_;
|
||||
|
||||
// This is a thread to execute the behavioral portion of the
|
||||
// function.
|
||||
vthread_t thread_;
|
||||
struct __vpiScope*scope_;
|
||||
vvp_code_t code_;
|
||||
|
||||
// Save the input bits as I receive them.
|
||||
unsigned char*ibits_;
|
||||
// Where the result will be.
|
||||
vvp_net_t*result_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The job of the input functor is only to monitor inputs to the
|
||||
* function and pass them to the ufunc_core object. Each functor takes
|
||||
* up to 4 inputs, with the base the port number for the first
|
||||
* function input that this functor represents.
|
||||
*/
|
||||
class ufunc_input_functor : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
ufunc_input_functor(ufunc_core*c, unsigned base);
|
||||
~ufunc_input_functor();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, vvp_vector4_t bit);
|
||||
|
||||
private:
|
||||
ufunc_core*core_;
|
||||
unsigned port_base_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: ufunc.h,v $
|
||||
* Revision 1.3 2003/07/03 20:03:36 steve
|
||||
* Remove the vvp_cpoint_t indirect code pointer.
|
||||
*
|
||||
* Revision 1.2 2002/08/12 01:35:08 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.1 2002/03/18 00:19:34 steve
|
||||
* Add the .ufunc statement.
|
||||
* Revision 1.4 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2004 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2004-2005 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
|
||||
|
|
@ -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.18 2005/03/12 04:27:43 steve Exp $"
|
||||
#ident "$Id: vvp_net.cc,v 1.19 2005/03/18 02:56:04 steve Exp $"
|
||||
|
||||
# include "vvp_net.h"
|
||||
# include <stdio.h>
|
||||
|
|
@ -771,6 +771,16 @@ vvp_scalar_t vvp_fun_signal::scalar_value(unsigned idx) const
|
|||
return vvp_scalar_t(bits4_.value(idx), 6, 6);
|
||||
}
|
||||
|
||||
vvp_vector4_t vvp_fun_signal::vec4_value() const
|
||||
{
|
||||
if (force_active_)
|
||||
return force_;
|
||||
else if (type_is_vector8_())
|
||||
return reduce4(bits8_);
|
||||
else
|
||||
return bits4_;
|
||||
}
|
||||
|
||||
/* **** vvp_scalar_t methods **** */
|
||||
|
||||
/*
|
||||
|
|
@ -1168,6 +1178,9 @@ vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
|
|||
|
||||
/*
|
||||
* $Log: vvp_net.cc,v $
|
||||
* Revision 1.19 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.18 2005/03/12 04:27:43 steve
|
||||
* Implement VPI access to signal strengths,
|
||||
* Fix resolution of ambiguous drive pairs,
|
||||
|
|
|
|||
|
|
@ -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.18 2005/03/12 04:27:43 steve Exp $"
|
||||
#ident "$Id: vvp_net.h,v 1.19 2005/03/18 02:56:04 steve Exp $"
|
||||
|
||||
# include <stdio.h>
|
||||
# include <assert.h>
|
||||
|
|
@ -579,6 +579,7 @@ class vvp_fun_signal : public vvp_net_fun_t {
|
|||
unsigned size() const;
|
||||
vvp_bit4_t value(unsigned idx) const;
|
||||
vvp_scalar_t scalar_value(unsigned idx) const;
|
||||
vvp_vector4_t vec4_value() const;
|
||||
|
||||
// Commands
|
||||
void deassign();
|
||||
|
|
@ -603,6 +604,9 @@ class vvp_fun_signal : public vvp_net_fun_t {
|
|||
|
||||
/*
|
||||
* $Log: vvp_net.h,v $
|
||||
* Revision 1.19 2005/03/18 02:56:04 steve
|
||||
* Add support for LPM_UFUNC user defined functions.
|
||||
*
|
||||
* Revision 1.18 2005/03/12 04:27:43 steve
|
||||
* Implement VPI access to signal strengths,
|
||||
* Fix resolution of ambiguous drive pairs,
|
||||
|
|
|
|||
Loading…
Reference in New Issue