Add the .ufunc statement.

This commit is contained in:
steve 2002-03-18 00:19:34 +00:00
parent 7349a6beaf
commit de252965ac
10 changed files with 413 additions and 72 deletions

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.35 2002/02/03 01:01:51 steve Exp $"
#ident "$Id: Makefile.in,v 1.36 2002/03/18 00:19:34 steve Exp $"
#
#
SHELL = /bin/sh
@ -66,8 +66,8 @@ vpi_priv.o vpi_scope.o vpi_signal.o vpi_tasks.o vpi_time.o vpi_memory.o \
vpi_vthr_vector.o vpip_to_dec.o vvp_vpi.o
O = main.o parse.o parse_misc.o lexor.o arith.o bufif.o compile.o debug.o \
functor.o fvectors.o npmos.o resolv.o symbols.o codes.o vthread.o schedule.o \
tables.o udp.o memory.o force.o event.o logic.o delay.o $V
functor.o fvectors.o npmos.o resolv.o symbols.o ufunc.o codes.o vthread.o \
schedule.o tables.o udp.o memory.o force.o event.o logic.o delay.o $V
vvp: $O
$(CXX) $(rdynamic) $(CXXFLAGS) $(LDFLAGS) -o vvp $O $(LIBS) $(dllib)

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: README.txt,v 1.39 2002/01/03 04:19:01 steve Exp $
* $Id: README.txt,v 1.40 2002/03/18 00:19:34 steve Exp $
*/
VVP SIMULATION ENGINE
@ -476,6 +476,13 @@ number of data inputs. The first <wid> symbols in the <symbols_list>
gives the input data. The remaining hold the shift value, lsb first.
STRUCTURAL FUNCTION CALLS:
The .ufunc statement defines a call to a user defined function.
<label> .ufunc ;
THREAD STATEMENTS:
Thread statements create the initial threads for a simulation. These

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: codes.h,v 1.37 2001/11/07 03:34:42 steve Exp $"
#ident "$Id: codes.h,v 1.38 2002/03/18 00:19:34 steve Exp $"
#endif
@ -93,6 +93,8 @@ extern bool of_XORR(vthread_t thr, vvp_code_t code);
extern bool of_ZOMBIE(vthread_t thr, vvp_code_t code);
extern bool of_CALL_UFUNC(vthread_t thr, vvp_code_t code);
/*
* This is the format of a machine code instruction.
*/
@ -113,6 +115,7 @@ struct vvp_code_s {
unsigned short bit_idx[2];
vvp_ipoint_t iptr2;
vvp_cpoint_t cptr2;
struct ufunc_core*ufunc_core_ptr;
};
};
@ -148,6 +151,9 @@ extern vvp_code_t codespace_index(vvp_cpoint_t ptr);
/*
* $Log: codes.h,v $
* Revision 1.38 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
* Revision 1.37 2001/11/07 03:34:42 steve
* Use functor pointers where vvp_ipoint_t is unneeded.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: compile.cc,v 1.121 2002/03/08 05:41:45 steve Exp $"
#ident "$Id: compile.cc,v 1.122 2002/03/18 00:19:34 steve Exp $"
#endif
# include "arith.h"
@ -325,7 +325,6 @@ bool functor_gen_resolv_list_s::resolve(bool mes)
return false;
}
inline static
void functor_ref_lookup(vvp_ipoint_t *ref, char*lab, unsigned idx)
{
struct functor_gen_resolv_list_s*res =
@ -418,7 +417,6 @@ bool code_label_resolv_list_s::resolve(bool mes)
return false;
}
inline static
void code_label_lookup(struct vvp_code_s *code, char *label)
{
struct code_label_resolv_list_s *res
@ -578,8 +576,8 @@ void const_functor_s::set(vvp_ipoint_t p, bool, unsigned val, unsigned)
fprintf(stderr, " : Value is %u, trying to set %u\n",
oval, val);
debug_print(p);
#if defined(WITH_DEBUG)
debug_print(p);
breakpoint();
#else
fprintf(stderr, " : I'm driving functor 0x%x\n", out);
@ -1389,6 +1387,9 @@ vvp_ipoint_t debug_lookup_functor(const char*name)
/*
* $Log: compile.cc,v $
* Revision 1.122 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
* Revision 1.121 2002/03/08 05:41:45 steve
* Debug code for write to constants.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: compile.h,v 1.40 2002/01/03 04:19:02 steve Exp $"
#ident "$Id: compile.h,v 1.41 2002/03/18 00:19:34 steve Exp $"
#endif
# include <stdio.h>
@ -118,6 +118,22 @@ extern void compile_shiftr(char*label, long width,
extern void compile_vpi_symbol(const char*label, vpiHandle obj);
extern void compile_vpi_lookup(vpiHandle *objref, char*label);
/*
* This function schedules a lookup of an indexed label. The ref
* points to the vvp_ipoint_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.
*/
extern void functor_ref_lookup(vvp_ipoint_t *ref, char*lab, unsigned idx);
/*
* This function schedules a lookup of the labeled instruction. The
* code points to a code structure that points to the instruction
* field that receives the result, and the label is the name to
* lookup. The lookup will free the label text when it is done.
*/
extern void code_label_lookup(struct vvp_code_s *code, char *label);
/*
* The `compile_udp_def' function creates a UDP. The `table' is a
* NULL terminated array of char*, as assembled by `compile_udp_table'.
@ -151,6 +167,13 @@ extern void compile_memory_port(char *label, char *memid,
extern void compile_memory_init(char *memid, unsigned idx, unsigned char val);
/*
* Compile the .ufunc statement.
*/
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);
/*
* The compile_event function takes the parts of the event statement
@ -225,6 +248,9 @@ extern void compile_net(char*label, char*name,
/*
* $Log: compile.h,v $
* Revision 1.41 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
* Revision 1.40 2002/01/03 04:19:02 steve
* Add structural modulus support down to vvp.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.31 2002/03/01 05:42:50 steve Exp $"
#ident "$Id: lexor.lex,v 1.32 2002/03/18 00:19:34 steve Exp $"
#endif
# include "parse_misc.h"
@ -87,6 +87,7 @@
".shift/l" { return K_SHIFTL; }
".shift/r" { return K_SHIFTR; }
".thread" { return K_THREAD; }
".ufunc" { return K_UFUNC; }
".var" { return K_VAR; }
".var/s" { return K_VAR_S; }
".udp" { return K_UDP; }
@ -158,6 +159,9 @@ int yywrap()
/*
* $Log: lexor.lex,v $
* Revision 1.32 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
* Revision 1.31 2002/03/01 05:42:50 steve
* out-of-memory asserts.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.43 2002/01/03 04:19:02 steve Exp $"
#ident "$Id: parse.y,v 1.44 2002/03/18 00:19:34 steve Exp $"
#endif
# include "parse_misc.h"
@ -60,7 +60,7 @@ extern FILE*yyin;
%token K_ARITH_DIV K_ARITH_MOD K_ARITH_MULT K_ARITH_SUB K_ARITH_SUM
%token K_CMP_GE K_CMP_GT
%token K_EVENT K_EVENT_OR K_FUNCTOR K_NET K_NET_S
%token K_RESOLV K_SCOPE K_SHIFTL K_SHIFTR K_THREAD
%token K_RESOLV K_SCOPE K_SHIFTL K_SHIFTR K_THREAD K_UFUNC
%token K_UDP K_UDP_C K_UDP_S
%token K_MEM K_MEM_P K_MEM_I
%token K_FORCE
@ -159,6 +159,17 @@ statement
| mem_init_stmt
/* The .ufunc functor is for implementing user defined functions, or
other thread code that is automatically invoked if any of the
bits in the symbols list change. */
| T_LABEL K_UFUNC T_SYMBOL ',' T_NUMBER ',' symbols
'(' symbols ')' symbols ';'
{ compile_ufunc($1, $3, $5,
$7.cnt, $7.vect,
$9.cnt, $9.vect,
$11.cnt, $11.vect); }
/* Resolver statements are very much like functors. They are
compiled to functors of a different mode. */
@ -538,6 +549,9 @@ int compile_design(const char*path)
/*
* $Log: parse.y,v $
* Revision 1.44 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
* Revision 1.43 2002/01/03 04:19:02 steve
* Add structural modulus support down to vvp.
*

222
vvp/ufunc.cc Normal file
View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2002 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
*/
#if !defined(WINNT)
#ident "$Id: ufunc.cc,v 1.1 2002/03/18 00:19:34 steve Exp $"
#endif
# include "compile.h"
# include "symbols.h"
# include "codes.h"
# include "functor.h"
# include "ufunc.h"
# include "vthread.h"
# include "schedule.h"
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <stdlib.h>
# include <string.h>
# include <assert.h>
#ifdef __MINGW32__
#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_cpoint_t start_address,
struct __vpiScope*run_scope)
: owid_(ow), obase_(ob), oports_(op), nports_(np), ports_(p)
{
thread_ = 0;
scope_ = run_scope;
code_ = start_address;
ibits_ = new unsigned char[(nports_+3) / 4];
memset(ibits_, 0xaa, (nports_+3) / 4);
}
ufunc_core::~ufunc_core()
{
delete[] ports_;
}
void ufunc_core::set_bit(unsigned port_idx, unsigned val)
{
unsigned idx = port_idx / 4;
unsigned pp = port_idx % 4;
static const unsigned char mask[4] = {0xfc, 0xf3, 0xcf, 0x3f};
ibits_[idx] &= mask[pp];
ibits_[idx] |= (val&3) << pp*2;
if (thread_ == 0) {
thread_ = vthread_new(code_, scope_);
schedule_vthread(thread_, 0);
}
}
static const unsigned char strong_values[4] = {St0, St1, StX, HiZ};
void ufunc_core::assign_bits_to_ports(void)
{
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)
{
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)
{
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);
}
/*
* 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.
*/
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)
{
/* 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. */
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);
/* Construct some phantom code that is the thread of the
function call. The first instruction, at the start_address
of the function, loads the points and calls the function.
The last instruction is the usual %end. */
vvp_cpoint_t start_address = codespace_allocate();
vvp_code_t start_code = codespace_index(start_address);
start_code->opcode = of_CALL_UFUNC;
code_label_lookup(start_code, code);
{ vvp_cpoint_t cur = codespace_allocate();
vvp_code_t codep = codespace_index(cur);
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_address,
vpip_peek_current_scope());
start_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);
}
inputs_connect(ibase, argc, argv);
}
/*
* $Log: ufunc.cc,v $
* Revision 1.1 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
*/

85
vvp/ufunc.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef __ufunc_H
#define __ufunc_H
/*
* Copyright (c) 2002 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
*/
#if !defined(WINNT)
#ident "$Id: ufunc.h,v 1.1 2002/03/18 00:19:34 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:
*
* ufunc_input_functor_s --+--> ufunc_core --+--> ufunc_output_functor_s
* | |
* ufunc_input_functor_s --+ +--> ufunc_output_functor_s
* |
* ufunc_input_functor_s --+
*/
class ufunc_core {
public:
ufunc_core(unsigned ow, vvp_ipoint_t ob, vvp_ipoint_t*op,
unsigned np, vvp_ipoint_t*p,
vvp_cpoint_t start_address,
struct __vpiScope*run_scope);
~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_; }
private:
// The owid_ and obase_ point to the functor vector that makes
// up the output of the function.
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.
unsigned nports_;
vvp_ipoint_t*ports_;
// This is a thread to execute the behavioral portion of the
// function.
vthread_t thread_;
struct __vpiScope*scope_;
vvp_cpoint_t code_;
// Save the input bits as I receive them.
unsigned char*ibits_;
};
/*
* $Log: ufunc.h,v $
* Revision 1.1 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
*/
#endif

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vthread.cc,v 1.66 2002/01/26 02:08:07 steve Exp $"
#ident "$Id: vthread.cc,v 1.67 2002/03/18 00:19:34 steve Exp $"
#endif
# include "vthread.h"
@ -25,6 +25,7 @@
# include "debug.h"
# include "schedule.h"
# include "functor.h"
# include "ufunc.h"
# include "event.h"
# include "vpi_priv.h"
#ifdef HAVE_MALLOC_H
@ -1716,8 +1717,41 @@ bool of_ZOMBIE(vthread_t thr, vvp_code_t)
return false;
}
/*
* This is a phantom opcode used to call user defined functions. It is
* used in code generated by the .ufunc statement. This instruction
* contains a pointer to executable code of the function, and to a
* ufunc_core object that has all the port information about the
* function.
*/
bool of_CALL_UFUNC(vthread_t thr, vvp_code_t cp)
{
/* Copy all the inputs to the ufunc object to the port
variables of the function. This copies all the values
atomically. */
cp->ufunc_core_ptr->assign_bits_to_ports();
/* Create a temporary thread, and execute it manually. This is
necessary so that the previous step (assign_bits_to_ports)
and the execution of the function itself are an atomic
unit. If it were not, then the inputs might change between
setup and execution, causing really bad things to happen. */
vthread_t child = vthread_new(cp->cptr, cp->ufunc_core_ptr->scope());
vthread_mark_scheduled(child);
vthread_run(child);
/* Now copy the output from the result variable to the output
ports of the .ufunc device. */
cp->ufunc_core_ptr->finish_thread(thr);
return true;
}
/*
* $Log: vthread.cc,v $
* Revision 1.67 2002/03/18 00:19:34 steve
* Add the .ufunc statement.
*
* Revision 1.66 2002/01/26 02:08:07 steve
* Handle x in l-value of set/x
*
@ -1825,63 +1859,5 @@ bool of_ZOMBIE(vthread_t thr, vvp_code_t)
* Add strengths to functors at compile time,
* and Make functors pass their strengths as they
* propagate their output.
*
* Revision 1.36 2001/05/06 17:42:22 steve
* Add the %ix/get instruction. (Stephan Boettcher)
*
* Revision 1.35 2001/05/05 23:55:46 steve
* Add the beginnings of an interactive debugger.
*
* Revision 1.34 2001/05/02 23:16:50 steve
* Document memory related opcodes,
* parser uses numbv_s structures instead of the
* symbv_s and a mess of unions,
* Add the %is/sub instruction.
* (Stephan Boettcher)
*
* Revision 1.33 2001/05/02 01:57:26 steve
* Support behavioral subtraction.
*
* Revision 1.32 2001/05/02 01:37:38 steve
* initialize is_schedule.
*
* Revision 1.31 2001/05/01 05:00:02 steve
* Implement %ix/load.
*
* Revision 1.30 2001/05/01 01:09:39 steve
* Add support for memory objects. (Stephan Boettcher)
*
* Revision 1.29 2001/04/21 00:34:39 steve
* Working %disable and reap handling references from scheduler.
*
* Revision 1.28 2001/04/18 05:04:19 steve
* %end complete the %join for the parent.
*
* Revision 1.27 2001/04/18 04:21:23 steve
* Put threads into scopes.
*
* Revision 1.26 2001/04/15 16:37:48 steve
* add XOR support.
*
* Revision 1.25 2001/04/15 04:07:56 steve
* Add support for behavioral xnor.
*
* Revision 1.24 2001/04/14 05:10:05 steve
* Initialize the waiting_for_event member.
*
* Revision 1.23 2001/04/13 03:55:18 steve
* More complete reap of all threads.
*
* Revision 1.22 2001/04/05 01:12:28 steve
* Get signed compares working correctly in vvp.
*
* Revision 1.21 2001/04/03 03:18:34 steve
* support functor_set push for blocking assignment.
*
* Revision 1.20 2001/04/01 22:25:33 steve
* Add the reduction nor instruction.
*
* Revision 1.19 2001/04/01 07:22:08 steve
* Implement the less-then and %or instructions.
*/