Add structures for VPI support, and all the %vpi_call

instruction. Get linking of VPI modules to work.
This commit is contained in:
steve 2001-03-16 01:44:34 +00:00
parent 32f3881344
commit f2c1902984
19 changed files with 1021 additions and 23 deletions

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.3 2001/03/14 19:26:01 steve Exp $"
#ident "$Id: Makefile.in,v 1.4 2001/03/16 01:44:34 steve Exp $"
#
#
SHELL = /bin/sh
@ -43,6 +43,9 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@ -I. -I$(srcdir)
LDFLAGS = @LDFLAGS@
dllib=@DLLIB@
rdynamic=@rdynamic@
all: vvp
clean:
@ -51,11 +54,13 @@ clean:
distclean: clean
rm -f config.h Makefile config.cache config.log config.status
V = vpi_modules.o vpi_iter.o vpi_mcd.o vpi_priv.o vpi_tasks.o
O = main.o parse.o parse_misc.o lexor.o compile.o functor.o symbols.o \
codes.o vthread.o schedule.o tables.o
codes.o vthread.o schedule.o tables.o $V
vvp: $O
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o vvp $O
$(CXX) $(rdynamic) $(CXXFLAGS) $(LDFLAGS) -o vvp $O $(dllib)
%.o: %.cc

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.2 2001/03/11 23:06:49 steve Exp $"
#ident "$Id: codes.h,v 1.3 2001/03/16 01:44:34 steve Exp $"
#endif
@ -40,6 +40,7 @@ extern bool of_DELAY(vthread_t thr, vvp_code_t code);
extern bool of_END(vthread_t thr, vvp_code_t code);
extern bool of_SET(vthread_t thr, vvp_code_t code);
extern bool of_NOOP(vthread_t thr, vvp_code_t code);
extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code);
/*
* This is the format of a machine code instruction.
@ -51,6 +52,7 @@ struct vvp_code_s {
unsigned number;
vvp_ipoint_t iptr;
vvp_cpoint_t cptr;
struct __vpiHandle*handle;
};
unsigned short bit_idx1;
@ -83,6 +85,10 @@ extern void codespace_dump(FILE*fd);
/*
* $Log: codes.h,v $
* Revision 1.3 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.2 2001/03/11 23:06:49 steve
* Compact the vvp_code_s structure.
*

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.3 2001/03/11 23:06:49 steve Exp $"
#ident "$Id: compile.cc,v 1.4 2001/03/16 01:44:34 steve Exp $"
#endif
# include "compile.h"
@ -25,6 +25,7 @@
# include "symbols.h"
# include "codes.h"
# include "schedule.h"
# include "vpi_priv.h"
# include "vthread.h"
# include "parse_misc.h"
# include <malloc.h>
@ -297,6 +298,30 @@ void compile_code(char*label, char*mnem, comp_operands_t opa)
free(mnem);
}
void compile_vpi_call(char*label, char*name)
{
vvp_cpoint_t ptr = codespace_allocate();
/* First, I can give the label a value that is the current
codespace pointer. Don't need the text of the label after
this is done. */
if (label) {
sym_set_value(sym_codespace, label, ptr);
free(label);
}
/* Create an instruction in the code space. */
vvp_code_t code = codespace_index(ptr);
code->opcode = &of_VPI_CALL;
/* Create a vpiHandle that bundles the call information, and
store that handle in the instruction. */
code->handle = vpip_build_vpi_call(name);
/* Done with the lexor-allocated name string. */
free(name);
}
/*
* When the parser finds a thread statement, I create a new thread
* with the start address referenced by the program symbol passed to
@ -391,6 +416,10 @@ void compile_dump(FILE*fd)
/*
* $Log: compile.cc,v $
* Revision 1.4 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.3 2001/03/11 23:06:49 steve
* Compact the vvp_code_s structure.
*

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.2 2001/03/11 22:42:11 steve Exp $"
#ident "$Id: compile.h,v 1.3 2001/03/16 01:44:34 steve Exp $"
#endif
# include <stdio.h>
@ -77,6 +77,7 @@ struct comp_operands_s {
typedef struct comp_operands_s*comp_operands_t;
extern void compile_code(char*label, char*mnem, comp_operands_t opa);
extern void compile_vpi_call(char*label, char*name);
/*
* The parser uses this function to declare a thread. The start_sym is
@ -97,6 +98,10 @@ extern void compile_dump(FILE*fd);
/*
* $Log: compile.h,v $
* Revision 1.3 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.2 2001/03/11 22:42:11 steve
* Functor values and propagation.
*

View File

@ -19,15 +19,24 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: config.h.in,v 1.1 2001/03/11 00:29:38 steve Exp $"
#ident "$Id: config.h.in,v 1.2 2001/03/16 01:44:34 steve Exp $"
#endif
# define SIZEOF_UNSIGNED_LONG 0
# define SIZEOF_UNSIGNED 0
# undef HAVE_DLFCN_H
# undef HAVE_DL_H
# define LU ""
# define TU ""
/*
* $Log: config.h.in,v $
* Revision 1.2 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.1 2001/03/11 00:29:38 steve
* Add the vvp engine to cvs.
*

View File

@ -10,4 +10,45 @@ AC_PROG_INSTALL
AC_CHECK_SIZEOF(unsigned long)
AC_CHECK_SIZEOF(unsigned)
# --
# Look for a dl library to use. First look for the standard dlopen
# functions, and failing that look for the HP specific shl_load function.
AC_CHECK_HEADERS(dlfcn.h dl.h, break)
DLLIB=''
AC_CHECK_LIB(dl,dlopen,[DLLIB=-ldl])
if test -z "$DLLIB" ; then
AC_CHECK_LIB(dld,shl_load,[DLLIB=-ldld])
fi
AC_SUBST(DLLIB)
# The -rdynamic flag is used by iverilog when compiling the target,
# to know how to export symbols of the main program to loadable modules
# that are brought in by -ldl. VPI support requires this.
AC_MSG_CHECKING("for -rdynamic compiler flag")
rdynamic=-rdynamic
case "${host}" in
*-*-netbsd*)
rdynamic="-Wl,--export-dynamic"
;;
*-*-solaris*)
rdynamic=""
;;
*-*-cygwin*)
rdynamic=""
;;
*-*-hpux*)
rdynamic="-E"
;;
esac
AC_SUBST(rdynamic)
AC_MSG_RESULT($rdynamic)
AC_OUTPUT(Makefile)

71
vvp/ivl_dlfcn.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef __ivl_dlfcn_H
#define __ivl_dlfcn_H
/*
* Copyright (c) 2001 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) && !defined(macintosh)
#ident "$Id: ivl_dlfcn.h,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
#if defined(HAVE_DLFCN_H)
# include <dlfcn.h>
typedef void* ivl_dll_t;
#elif defined(HAVE_DL_H)
# include <dl.h>
typedef shl_t ivl_dll_t;
#endif
#if defined(HAVE_DLFCN_H)
inline ivl_dll_t ivl_dlopen(const char*name)
{ return dlopen(name,RTLD_NOW); }
inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
{ return dlsym(dll, nm); }
inline void ivl_dlclose(ivl_dll_t dll)
{ dlclose(dll); }
#elif defined(HAVE_DL_H)
inline ivl_dll_t ivl_dlopen(const char*name)
{ return shl_load(name, BIND_IMMEDIATE, 0); }
inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
{
void*sym;
int rc = shl_findsym(&dll, nm, TYPE_PROCEDURE, &sym);
return (rc == 0) ? sym : 0;
}
inline void ivl_dlclose(ivl_dll_t dll)
{ shl_unload(dll); }
inline const char*dlerror(void)
{ return strerror( errno ); }
#endif
/*
* $Log: ivl_dlfcn.h,v $
* Revision 1.1 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.1 2001/01/14 17:12:59 steve
* possible HP/UX portability support.
*
*/
#endif

View File

@ -13,6 +13,13 @@
yylval.text = strdup(yytext);
return T_LABEL; }
/* String tokens are parsed here. Return as the token value the
contents of the string without the enclosing quotes. */
\"[^\"]*\" {
yytext[strlen(yytext)-1] = 0;
yylval.text = strdup(yytext+1);
return T_STRING; }
/* These are some keywords that are recognized. */
".functor" { return K_FUNCTOR; }
@ -21,7 +28,12 @@
/* instructions start with a % character. The compiler decides what
kind of instruction this really is. */
kind of instruction this really is. The few exceptions (that have
exceptional parameter requirements) are listed first. */
"%vpi_call" {
return K_vpi_call; }
"%"[.$_/a-zA-Z0-9]+ {
yylval.text = strdup(yytext);
return T_INSTR; }

View File

@ -17,17 +17,22 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.cc,v 1.1 2001/03/11 00:29:38 steve Exp $"
#ident "$Id: main.cc,v 1.2 2001/03/16 01:44:34 steve Exp $"
#endif
# include "config.h"
# include "parse_misc.h"
# include "compile.h"
# include "schedule.h"
# include "vpi_priv.h"
# include <stdio.h>
# include <getopt.h>
const char*module_path = ".";
unsigned module_cnt = 0;
const char*module_tab[64];
int main(int argc, char*argv[])
{
int opt;
@ -35,10 +40,16 @@ int main(int argc, char*argv[])
const char*dump_path = 0;
const char*design_path = 0;
while ((opt = getopt(argc, argv, "D:")) != EOF) switch (opt) {
while ((opt = getopt(argc, argv, "D:M:m:")) != EOF) switch (opt) {
case 'D':
dump_path = optarg;
break;
case 'M':
module_path = optarg;
break;
case 'm':
module_tab[module_cnt++] = optarg;
break;
default:
flag_errors += 1;
}
@ -54,6 +65,7 @@ int main(int argc, char*argv[])
design_path = argv[optind];
compile_init();
vpip_load_modules(module_cnt, module_tab, module_path);
compile_design(design_path);
compile_cleanup();
@ -69,6 +81,10 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.2 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.1 2001/03/11 00:29:38 steve
* Add the vvp engine to cvs.
*

View File

@ -34,6 +34,16 @@ value. Once the set completes, the value is immediately available to
be read out of the variable. The <bit> is the address of the thread
register that contains the bit value to assign.
* %vpi_call <name> [, ...]
This instruction makes a call to a system task or function that was
declared using VPI. The name is given in the source as a string. It is
not yet defined how arguments are to be passed.
* %waitfor <functor-label>
XXXX
When a thread executes this instruction, it places itself in the
sensitive list for the addressed functor. The functor holds all the
threads that await the functor. When the defined sort of event occurs
on the functor, a thread schedule event is created for all the threads
in its list and the list is cleared.

View File

@ -21,11 +21,12 @@ extern FILE*yyin;
};
%token K_FUNCTOR K_THREAD K_VAR
%token K_FUNCTOR K_THREAD K_VAR K_vpi_call
%token <text> T_INSTR
%token <text> T_LABEL
%token <numb> T_NUMBER
%token <text> T_STRING
%token <text> T_SYMBOL
%type <textv> symbols
@ -69,6 +70,15 @@ statement
{ compile_code(0, $1, $2);
}
/* %vpi_call statements are instructions that have unusual operand
requirements so are handled by their own rules. */
| T_LABEL K_vpi_call T_STRING ';'
{ compile_vpi_call($1, $3); }
| K_vpi_call T_STRING ';'
{ compile_vpi_call(0, $2); }
/* Thread statements declare a thread with its starting address. The
starting address must already be defined. */

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* $Id: vpi.txt,v 1.1 2001/03/14 19:26:58 steve Exp $
* $Id: vpi.txt,v 1.2 2001/03/16 01:44:34 steve Exp $
*/
@ -47,16 +47,43 @@ access to the system task call by calling back the VPI requesting the
handle. It uses the handle, in turn, to get hold of the operands for
the task.
In VPI Land, there is a vpiHandle for each system task call. However,
since only one is accessible at a time, there is no need for more then
the one that is active. Therefore, vvp will construct the vpiHande for
the task call at the time the call is made.
All that vvp needs to know about a system task call is the handle of
the system task (created by the vpi_register_systf function) and the
arguments of the actual call. The arguments are tricky because the
list has no bound, even though each particular call in the Verilog
source has a specific set of parameters.
the system task definitions (created by the vpi_register_systf
function) and the arguments of the actual call. The arguments are
tricky because the list has no bound, even though each particular call
in the Verilog source has a specific set of parameters.
Since each call takes a fixed number of parameters, the input source
can include in the statement the list of arguments. The argument list
will not fit in a single generated instruction, but a vpiHandle that
refers to a vpiSysTfCall does. Therefore, the compiler can take the
long argument list and form a vpiSysTaskCall object. The generated
instruction then only needs to be a %vpi_call with the single parameter
that is the vpiHandle for the call.
SYSTEM FUNCTION CALLS
System function calls are similar to system tasks. The only
differences are that all the arguments are input only, and there is a
single magic output that is the return value. The same %vpi_call can
even be used to call a function.
System functions, like system tasks, can only be called from thread
code. However, they can appear in expressions, even when that
expression is entirely structural. The desired effect is achieved by
writing a wrapper thread that calls the function when inputs change,
and that writes the output into the containing expression.
SYSTEM TASK/FUNCTION ARGUMENTS
The arguments to each system task or call are not stored in the
instruction op-code, but in the vpiSysTfCall object that the compiler
creates and that the %vpi_call instruction ultimately refers to. All
the arguments must be some sort of object that can be represented by a
vpiHandle at compile time.
/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)

77
vvp/vpi_iter.cc Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 1999-2001 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) && !defined(macintosh)
#ident "$Id: vpi_iter.cc,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
/*
* Find here the methods functions in support of iterator objects.
*/
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static const struct __vpirt vpip_iterator_rt = {
vpiIterator,
0,
0,
0,
0,
0,
0
};
vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args)
{
struct __vpiIterator*res = (struct __vpiIterator*)
calloc(1, sizeof(struct __vpiIterator));
res->base.vpi_type = &vpip_iterator_rt;
res->args = args;
res->nargs = nargs;
res->next = 0;
return &(res->base);
}
/*
* The vpi_scan function only applies to iterators. It returns the
* next vpiHandle in the iterated list.
*/
vpiHandle vpi_scan(vpiHandle ref)
{
struct __vpiIterator*hp = (struct __vpiIterator*)ref;
assert(ref->vpi_type->type_code == vpiIterator);
if (hp->next == hp->nargs) {
vpi_free_object(ref);
return 0;
}
return hp->args[hp->next++];
}
/*
* $Log: vpi_iter.cc,v $
* Revision 1.1 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
*/

123
vvp/vpi_mcd.cc Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2000 Stephen G. Tell <steve@telltronics.org>
*
* 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) && !defined(macintosh)
#ident "$Id: vpi_mcd.cc,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
struct mcd_entry {
FILE *fp;
char *filename;
};
static struct mcd_entry mcd_table[32];
/* Initialize mcd portion of vpi. Must be called before
* any vpi_mcd routines can be used.
*/
void vpi_mcd_init(void)
{
mcd_table[0].fp = stdout;
mcd_table[0].filename = "<stdout>";
mcd_table[1].fp = stderr;
mcd_table[1].filename = "<stderr>";
mcd_table[2].fp = stdout; /* TODO: initialize this to log file */
mcd_table[2].filename = "<stdlog>";
}
/*
* close one or more channels. we silently refuse to close the preopened ones.
*/
unsigned int vpi_mcd_close(unsigned int mcd)
{
int i;
int rc;
rc = 0;
for(i = 3; i < 31; i++) {
if( ((mcd>>i) & 1) && mcd_table[i].filename) {
if(fclose(mcd_table[i].fp) != 0)
rc |= 1<<i;
free(mcd_table[i].filename);
mcd_table[i].fp = NULL;
mcd_table[i].filename = NULL;
} else {
rc |= 1<<i;
}
}
return rc;
}
char *vpi_mcd_name(unsigned int mcd)
{
int i;
for(i = 0; i < 31; i++) {
if( (mcd>>i) & 1)
return mcd_table[i].filename;
}
return NULL;
}
unsigned int vpi_mcd_open(char *name)
{
int i;
for(i = 0; i < 31; i++) {
if(mcd_table[i].filename == NULL)
goto got_entry;
}
return 0; /* too many open mcd's */
got_entry:
mcd_table[i].fp = fopen(name, "w");
if(mcd_table[i].fp == NULL)
return 0;
mcd_table[i].filename = strdup(name);
return 1<<i;
}
int vpi_mcd_printf(unsigned int mcd, const char*fmt, ...)
{
int i;
int len;
int rc;
va_list ap;
rc = len = 0;
va_start(ap, fmt);
for(i = 0; i < 31; i++) {
if( (mcd>>i) & 1) {
if(mcd_table[i].fp)
len = vfprintf(mcd_table[i].fp, fmt, ap);
else
rc = EOF;
}
}
va_end(ap);
if(rc)
return rc;
else
return len;
}

64
vvp/vpi_modules.cc Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2001 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: vpi_modules.cc,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
# include "config.h"
# include "vpi_priv.h"
# include "ivl_dlfcn.h"
# include <stdio.h>
typedef void (*vlog_startup_routines_t)(void);
void vpip_load_modules(unsigned cnt, const char*mod[], const char*path)
{
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
char buf[4096];
sprintf(buf, "%s/%s.vpi", path, mod[idx]);
printf("Load %s...\n", buf);
ivl_dll_t dll = ivl_dlopen(buf);
if (dll == 0) {
fprintf(stderr, "%s: %s\n", mod[idx], dlerror());
continue;
}
void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU);
if (table == 0) {
fprintf(stderr, "%s: no vlog_startup_routines\n", mod[idx]);
ivl_dlclose(dll);
continue;
}
vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
for (unsigned tmp = 0 ; routines[tmp] ; tmp += 1)
(routines[tmp])();
}
}
/*
* $Log: vpi_modules.cc,v $
* Revision 1.1 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
*/

161
vvp/vpi_priv.cc Normal file
View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2001 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: vpi_priv.cc,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdio.h>
# include <stdarg.h>
# include <assert.h>
# include <malloc.h>
/*
* When a task is called, this value is set so that vpi_handle can
* fathom the vpi_handle(vpiSysTfCall,0) function.
*/
struct __vpiSysTaskCall*vpip_cur_task = 0;
int vpi_free_object(vpiHandle ref)
{
free(ref);
return 0;
}
static int vpip_get_global(int property)
{
switch (property) {
default:
assert(0);
return -1;
}
}
int vpi_get(int property, vpiHandle ref)
{
if (property == vpiType)
return ref->vpi_type->type_code;
if (ref == 0)
return vpip_get_global(property);
if (ref->vpi_type->vpi_get_ == 0)
return -1;
return (ref->vpi_type->vpi_get_)(property, ref);
}
char* vpi_get_str(int property, vpiHandle ref)
{
if (ref->vpi_type->vpi_get_str_ == 0)
return 0;
return (ref->vpi_type->vpi_get_str_)(property, ref);
}
void vpi_get_time(vpiHandle obj, s_vpi_time*t)
{
assert(0);
}
void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
{
if (expr->vpi_type->vpi_get_value_) {
(expr->vpi_type->vpi_get_value_)(expr, vp);
return;
}
vp->format = vpiSuppressVal;
}
vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
s_vpi_time*tp, int flags)
{
if (obj->vpi_type->vpi_put_value_)
return (obj->vpi_type->vpi_put_value_)(obj, vp, tp, flags);
else
return 0;
}
vpiHandle vpi_handle(int type, vpiHandle ref)
{
if (type == vpiSysTfCall) {
assert(ref == 0);
return &vpip_cur_task->base;
}
assert(ref->vpi_type->handle_);
return (ref->vpi_type->handle_)(type, ref);
}
/*
* This function asks the object to return an iterator for
* the specified reference. It is up to the iterate_ method to
* allocate a properly formed iterator.
*/
vpiHandle vpi_iterate(int type, vpiHandle ref)
{
assert(ref->vpi_type->iterate_);
return (ref->vpi_type->iterate_)(type, ref);
}
vpiHandle vpi_handle_by_index(vpiHandle ref, int idx)
{
assert(ref->vpi_type->index_);
return (ref->vpi_type->index_)(ref, idx);
}
void vpi_printf(const char*fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
/* STUBS */
vpiHandle vpi_register_cb(p_cb_data data)
{
assert(0);
return 0;
}
int vpi_remove_cb(vpiHandle ref)
{
assert(0);
return 0;
}
void vpi_sim_control(int operation, ...)
{
assert(0);
}
/*
* $Log: vpi_priv.cc,v $
* Revision 1.1 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
*/

129
vvp/vpi_priv.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef __vpi_priv_H
#define __vpi_priv_H
/*
* Copyright (c) 2001 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: vpi_priv.h,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
# include "vpi_user.h"
/*
* This header file contains the internal definitions that the vvp
* program uses to implement the public interface in the vpi_user.h
* header file elsewhere.
*/
/*
* This structure is the very base of a vpiHandle. Every handle
* structure starts with this structure, so that the library can
* internally pass the derived types as pointers to one of these.
*/
struct __vpiHandle {
const struct __vpirt *vpi_type;
};
/*
* Objects with this structure are used to represent a type of
* vpiHandle. A specific object becomes of this type by holding a
* pointer to an instance of this structure.
*/
struct __vpirt {
int type_code;
/* These methods extract information from the handle. */
int (*vpi_get_)(int, vpiHandle);
char* (*vpi_get_str_)(int, vpiHandle);
void (*vpi_get_value_)(vpiHandle, p_vpi_value);
vpiHandle (*vpi_put_value_)(vpiHandle, p_vpi_value, p_vpi_time, int);
/* These methods follow references. */
vpiHandle (*handle_)(int, vpiHandle);
vpiHandle (*iterate_)(int, vpiHandle);
vpiHandle (*index_)(vpiHandle, int);
};
/*
* The vpiHandle for an iterator has this structure. The definition of
* the methods lives in vpi_iter.c
*/
struct __vpiIterator {
struct __vpiHandle base;
vpiHandle *args;
unsigned nargs;
unsigned next;
};
/*
* When a loaded VPI module announces a system task/function, one
* __vpiUserSystf object is created to hold the definition of that
* task/function.
*
* When the compiler encounters a %vpi_call statement, it creates a
* __vpiSysTaskCall to represent that particular call. The call refers
* to the definition handle so that when the %vpi_call instruction is
* encountered at run-time, the definition can be located and used.
*/
struct __vpiUserSystf {
struct __vpiHandle base;
s_vpi_systf_data info;
};
struct __vpiSysTaskCall {
struct __vpiHandle base;
struct __vpiUserSystf*defn;
unsigned nargs;
vpiHandle*args;
};
extern struct __vpiSysTaskCall*vpip_cur_task;
/*
* This function is called before any compilation to load VPI
* modules. This gives the modules a chance to announce their
* contained functions before compilation commences. It is called only
* once.
*/
extern void vpip_load_modules(unsigned cnt, const char*tab[], const char*path);
/*
* The vpip_build_vpi_call function creates a __vpiSysTaskCall object
* and returns the handle. The compiler uses this function when it
* encounters a %vpi_call statement.
*
* The %vpi_call instruction has as its only parameter the handle that
* is returned by the vpip_build_vpi_call. This includes all the
* information needed by vpip_execute_vpi_call to actually execute the
* call.
*/
extern vpiHandle vpip_build_vpi_call(const char*name);
extern void vpip_execute_vpi_call(vpiHandle obj);
/*
* $Log: vpi_priv.h,v $
* Revision 1.1 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
*/
#endif

190
vvp/vpi_tasks.cc Normal file
View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2001 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: vpi_tasks.cc,v 1.1 2001/03/16 01:44:34 steve Exp $"
#endif
/*
* This file keeps the table of system/task definitions. This table is
* built up before the input source file is parsed, and is used by the
* compiler when %vpi_call statements are encountered.
*/
# include "vpi_priv.h"
# include <stdio.h>
# include <malloc.h>
# include <string.h>
# include <assert.h>
static vpiHandle systask_handle(int type, vpiHandle ref)
{
return 0;
}
/*
* the iter function only supports getting an iterator of the
* arguments. This works equally well for tasks and functions.
*/
static vpiHandle systask_iter(int type, vpiHandle ref)
{
struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref;
assert((ref->vpi_type->type_code == vpiSysTaskCall)
|| (ref->vpi_type->type_code == vpiSysFuncCall));
if (rfp->nargs == 0)
return 0;
#if 0
return vpip_make_iterator(rfp->nargs, rfp->args);
#else
return 0;
#endif
}
static const struct __vpirt vpip_systask_rt = {
vpiSysTaskCall,
0,
0,
0,
0,
systask_handle,
systask_iter
};
/*
* A value *can* be put to a vpiSysFuncCall object. This is how the
* return value is set. The value that is given should be converted to
* bits and set into the return value bit array.
*/
static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value val,
p_vpi_time t, int flag)
{
assert(0);
return 0;
}
static const struct __vpirt vpip_sysfunc_rt = {
vpiSysFuncCall,
0,
0,
0,
sysfunc_put_value,
0,
systask_iter
};
/* **** Manipulate the internal datastructures. **** */
static struct __vpiUserSystf**def_table = 0;
static unsigned def_count = 0;
static struct __vpiUserSystf* allocate_def(void)
{
if (def_table == 0) {
def_table = (struct __vpiUserSystf**)
malloc(sizeof (struct __vpiUserSystf*));
def_table[0] = (struct __vpiUserSystf*)
calloc(1, sizeof(struct __vpiUserSystf));
def_count = 1;
return def_table[0];
}
def_table = (struct __vpiUserSystf**)
realloc(def_table, (def_count+1)*sizeof (struct __vpiUserSystf*));
def_table[def_count] = (struct __vpiUserSystf*)
calloc(1, sizeof(struct __vpiUserSystf));
return def_table[def_count++];
}
static 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)
return def_table[idx];
return 0;
}
/*
* A vpi_call is actually built up into a vpiSysTaskCall VPI object
* that refers back to the vpiUserSystf VPI object that is the
* definition. So this function is called by the compiler when a
* %vpi_call statement is encountered. Create here a vpiHandle that
* describes the call, and return it. The %vpi_call instruction will
* store this handle for when it is executed.
*/
vpiHandle vpip_build_vpi_call(const char*name)
{
struct __vpiSysTaskCall*obj = (struct __vpiSysTaskCall*)
calloc(1, sizeof (struct __vpiSysTaskCall));
obj->base.vpi_type = &vpip_systask_rt;
obj->defn = vpip_find_systf(name);
obj->nargs = 0;
obj->args = 0;
/* If there is a compiletf function, call it here. */
if (obj->defn->info.compiletf)
obj->defn->info.compiletf (obj->defn->info.user_data);
return &obj->base;
}
/*
* This function is used by the %vpi_call instruction to actually
* place the call to the system task/function. For now, only support
* calls to system tasks.
*/
void vpip_execute_vpi_call(vpiHandle ref)
{
assert(ref->vpi_type->type_code == vpiSysTaskCall);
vpip_cur_task = (struct __vpiSysTaskCall*)ref;
assert(vpip_cur_task->defn->info.calltf);
vpip_cur_task->defn->info.calltf (vpip_cur_task->defn->info.user_data);
}
/*
* This is the entry function that a VPI module uses to hook a new
* task/function into the simulator. The function creates a new
* __vpi_userSystf to represent the definition for the calls that come
* to pass later.
*/
void vpi_register_systf(const struct t_vpi_systf_data*ss)
{
struct __vpiUserSystf*cur = allocate_def();
cur->info = *ss;
cur->info.tfname = strdup(ss->tfname);
}
/*
* $Log: vpi_tasks.cc,v $
* Revision 1.1 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
*/

View File

@ -17,13 +17,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vthread.cc,v 1.3 2001/03/11 23:06:49 steve Exp $"
#ident "$Id: vthread.cc,v 1.4 2001/03/16 01:44:34 steve Exp $"
#endif
# include "vthread.h"
# include "codes.h"
# include "schedule.h"
# include "functor.h"
# include "vpi_priv.h"
# include <assert.h>
struct vthread_s {
@ -53,6 +54,7 @@ void vthread_run(vthread_t thr)
vvp_code_t cp = codespace_index(thr->pc);
thr->pc += 1;
assert(cp->opcode);
bool rc = (cp->opcode)(thr, cp);
if (rc == false)
return;
@ -110,8 +112,19 @@ bool of_SET(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
{
printf("thread %p: %%vpi_call\n", thr);
vpip_execute_vpi_call(cp->handle);
return true;
}
/*
* $Log: vthread.cc,v $
* Revision 1.4 2001/03/16 01:44:34 steve
* Add structures for VPI support, and all the %vpi_call
* instruction. Get linking of VPI modules to work.
*
* Revision 1.3 2001/03/11 23:06:49 steve
* Compact the vvp_code_s structure.
*