Add support for LPM_UFUNC user defined functions.

This commit is contained in:
steve
2005-03-18 02:56:03 +00:00
parent 0f914bf35a
commit 53da6e9a33
16 changed files with 375 additions and 302 deletions
+20 -2
View File
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams ([email protected])
*
* $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:
+10 -4
View File
@@ -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.
*
+6 -3
View File
@@ -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.
*
+107 -122
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2003 Stephen Williams ([email protected])
* Copyright (c) 2002-2005 Stephen Williams ([email protected])
*
* 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
+63 -39
View File
@@ -1,7 +1,7 @@
#ifndef __ufunc_H
#define __ufunc_H
/*
* Copyright (c) 2002 Stephen Williams ([email protected])
* Copyright (c) 2002-2005 Stephen Williams ([email protected])
*
* 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_s --+
* ufunc_input_functor --+--> ufunc_core --> ...
* |
* 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
+15 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004 Stephen Williams ([email protected])
* Copyright (c) 2004-2005 Stephen Williams ([email protected])
*
* 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,
+5 -1
View File
@@ -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,