diff --git a/Makefile.in b/Makefile.in index 36aa3dd6d..6a5e3fd90 100644 --- a/Makefile.in +++ b/Makefile.in @@ -217,7 +217,7 @@ endif XNF_INSTALL = $(libdir)/ivl/xnf.conf $(libdir)/ivl/xnf-s.conf -install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC) +install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC) for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done for dir in vpi ivlpp driver; \ do (cd $$dir ; $(MAKE) $@); done @@ -228,6 +228,9 @@ $(bindir)/iverilog-vpi: ./iverilog-vpi $(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@ $(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(libdir)/ivl/ivl@EXEEXT@ +$(libdir)/ivl/include/constants.vams: $(srcdir)/constants.vams + $(INSTALL_DATA) $(srcdir)/constants.vams $@ + $(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf $(INSTALL_DATA) $(srcdir)/xnf-s.conf $(libdir)/ivl/xnf-s.conf @@ -283,7 +286,7 @@ uninstall: for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done for dir in vpi ivlpp driver; \ do (cd $$dir ; $(MAKE) $@); done - for f in xnf.conf xnf-s.conf ivl@EXEEXT@; \ + for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams; \ do rm -f $(libdir)/ivl/$$f; done -rmdir $(libdir)/ivl/include -rmdir $(libdir)/ivl diff --git a/constants.vams b/constants.vams new file mode 100644 index 000000000..356d97c9f --- /dev/null +++ b/constants.vams @@ -0,0 +1,43 @@ +// Mathematical and physical constants + +`ifdef CONSTANTS_VAMS +`else +`define CONSTANTS_VAMS 1 + +// M_ is a mathematical constant +`define M_E 2.7182818284590452354 +`define M_LOG2E 1.4426950408889634074 +`define M_LOG10E 0.43429448190325182765 +`define M_LN2 0.69314718055994530942 +`define M_LN10 2.30258509299404568402 +`define M_PI 3.14159265358979323846 +`define M_TWO_PI 6.28318530717958647693 +`define M_PI_2 1.57079632679489661923 +`define M_PI_4 0.78539816339744830962 +`define M_1_PI 0.31830988618379067154 +`define M_2_PI 0.63661977236758134308 +`define M_2_SQRTPI 1.12837916709551257390 +`define M_SQRT2 1.41421356237309504880 +`define M_SQRT1_2 0.70710678118654752440 + +/* + * Do we need these? For now they are not available. + * +// The following constants have been taken from http://physics.nist.gov +// P_ is a physical constant +// charge of electron in coulombs +`define P_Q 1.602176462e-19 +// speed of light in vacuum in meters/sec +`define P_C 2.99792458e8 +// Boltzmann's constant in joules/kelvin +`define P_K 1.3806503e-23 +// Planck's constant in joules*sec +`define P_H 6.62606876e-34 +// permittivity of vacuum in farads/meter +`define P_EPS0 8.854187817e-12 +// permeability of vacuum in henrys/meter +`define P_U0 (4.0e-7 * `M_PI) +// zero celsius in kelvin +`define P_CELSIUS0 273.15 +*/ +`endif diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 1c335e1bb..6119b939c 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -46,7 +46,7 @@ CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -I$(srcdir) -I.. @file64_support@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ -all: dep system.vpi $(ALL32) +all: dep system.vpi va_math.vpi $(ALL32) dep: mkdir dep @@ -55,6 +55,7 @@ dep: $(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o mv $*.d dep +# Object files for system.vpi O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \ sys_finish.o sys_plusargs.o sys_random.o sys_random_mti.o \ sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \ @@ -68,10 +69,15 @@ endif O += sys_lxt2.o lxt2_write.o endif +# Object files for va_math.vpi +V = va_math.o + LIBS = @LIBS@ SYSTEM_VPI_LDFLAGS = $(LIBS) +VA_MATH_LDFLAGS = ifeq (@MING32@,yes) SYSTEM_VPI_LDFLAGS += @EXTRALIBS@ + VA_MATH_LDFLAGS += @EXTRALIBS@ endif system.vpi: $O ../vvp/libvpi.a @@ -88,8 +94,11 @@ sdf_lexor.c: sdf_lexor.lex sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y $(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y +va_math.vpi: $V ../vvp/libvpi.a + $(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) + clean: - rm -rf *.o sys_readmem_lex.c dep system.vpi bin32 + rm -rf *.o sys_readmem_lex.c dep system.vpi va_math.vpi bin32 rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h distclean: clean @@ -97,7 +106,10 @@ distclean: clean check: all -install: all installdirs $(vpidir)/system.vpi $(libdir)/ivl/system.sft +install: all installdirs \ + $(vpidir)/system.vpi $(libdir)/ivl/system.sft \ + $(vpidir)/va_math.vpi $(libdir)/ivl/va_math.sft \ + $(vpidir)/include/ $(vpidir)/system.vpi: ./system.vpi $(INSTALL_PROGRAM) ./system.vpi $(vpidir)/system.vpi @@ -105,12 +117,20 @@ $(vpidir)/system.vpi: ./system.vpi $(libdir)/ivl/system.sft: system.sft $(INSTALL_DATA) $< $@ +$(vpidir)/va_math.vpi: ./va_math.vpi + $(INSTALL_PROGRAM) ./va_math.vpi $(vpidir)/va_math.vpi + +$(libdir)/ivl/va_math.sft: va_math.sft + $(INSTALL_DATA) $< $@ + installdirs: ../mkinstalldirs $(srcdir)/../mkinstalldirs $(vpidir) uninstall: rm -f $(vpidir)/system.vpi rm -f $(libdir)/ivl/system.sft + rm -f $(vpidir)/va_math.vpi + rm -f $(libdir)/ivl/va_math.sft -include $(patsubst %.o, dep/%.d, $O) diff --git a/vpi/configure.in b/vpi/configure.in index e96764497..331c77684 100644 --- a/vpi/configure.in +++ b/vpi/configure.in @@ -45,18 +45,8 @@ AC_CHECK_LIB(bz2, BZ2_bzdopen, HAVE_LIBBZ2=yes, HAVE_LIBBZ2=no) fi AC_SUBST(HAVE_LIBBZ2) -# -- -# 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) +# fmin and fmax are needed by va_math.vpi +AC_CHECK_FUNCS_ONCE(fmin fmax) AC_PROG_INSTALL diff --git a/vpi/va_math.c b/vpi/va_math.c new file mode 100644 index 000000000..602d4a1e7 --- /dev/null +++ b/vpi/va_math.c @@ -0,0 +1,367 @@ +/* + * Verilog-A math library for Icarus Verilog + * http://www.icarus.com/eda/verilog/ + * + * Copyright (C) 2007-2008 Cary R. (cygcary@yahoo.com) + * + * This program is free software; you can redistribute it and/or modify + * it 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "vpi_config.h" +#include +#include +#include +#include +#include + +/* + * Compile time options: (set in the Makefile.) + * + * The functions fmax() and fmin() may not be available in pre-c99 + * libraries, so if they are not available you need to uncomment the + * -DUSE_MY_FMAX_AND_FMIN in the Makefile. + */ + + +/* + * These are functionally equivalent fmax() and fmin() implementations + * that can be used when needed. + */ +#ifndef HAVE_FMIN +static double va_fmin(const double x, const double y) +{ + if (x != x) {return y;} /* x is NaN so return y. */ + if (y != y) {return x;} /* y is NaN so return x. */ + + return (x < y) ? x : y; +} +#endif +#ifndef HAVE_FMAX +static double va_fmax(const double x, const double y) +{ + if (x != x) {return y;} /* x is NaN so return y. */ + if (y != y) {return x;} /* y is NaN so return x. */ + + return (x > y) ? x : y; +} +#endif + + +/* Single argument functions. */ +typedef struct s_single_data { + const char *name; + double (*func)(double); +} t_single_data; + +static t_single_data va_single_data[]= { + {"$sqrt", sqrt}, + {"$ln", log}, + {"$log", log10}, + {"$exp", exp}, + {"$abs", fabs}, + {"$ceil", ceil}, + {"$floor", floor}, + {"$sin", sin}, + {"$cos", cos}, + {"$tan", tan}, + {"$asin", asin}, + {"$acos", acos}, + {"$atan", atan}, + {"$sinh", sinh}, + {"$cosh", cosh}, + {"$tanh", tanh}, + {"$asinh", asinh}, + {"$acosh", acosh}, + {"$atanh", atanh}, + {0, 0} /* Must be NULL terminated! */ +}; + + +/* Double argument functions. */ +typedef struct s_double_data { + const char *name; + double (*func)(double, double); +} t_double_data; + +static t_double_data va_double_data[]= { +#ifdef HAVE_FMAX + {"$max", fmax}, +#else + {"$max", va_fmax}, +#endif +#ifdef HAVE_FMIN + {"$min", fmin}, +#else + {"$min", va_fmin}, +#endif + {"$pow", pow}, + {"$atan2", atan2}, + {"$hypot", hypot}, + {0, 0} /* Must be NULL terminated! */ +}; + + +/* + * This structure holds the single argument information. + */ +typedef struct { + vpiHandle arg; + double (*func)(double); +} va_single_t; + + +/* + * This structure holds the double argument information. + */ +typedef struct { + vpiHandle arg1; + vpiHandle arg2; + double (*func)(double, double); +} va_double_t; + + +/* + * Standard error message routine. The format string must take one + * string argument (the name of the function). + */ +static void va_error_message(vpiHandle callh, const char* format, + const char* name) { + vpi_printf("%s:%d: error: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf(format, name); + vpi_control(vpiFinish, 1); +} + + +/* + * Process an argument. + */ +vpiHandle va_process_argument(vpiHandle callh, const char* name, + vpiHandle arg, const char* post) { + PLI_INT32 type; + + if (arg == NULL) return 0; + type = vpi_get(vpiType, arg); + /* Math function cannot do anything with a string. */ + if ((type == vpiConstant || type == vpiParameter) && + (vpi_get(vpiConstType, arg) == vpiStringConst)) { + const char* basemsg = "%s cannot process strings"; + char* msg = malloc(strlen(basemsg)+strlen(post)+3); + strcpy(msg, basemsg); + strcat(msg, post); + strcat(msg, ".\n"); + va_error_message(callh, msg, name); + free(msg); + return 0; + } + return arg; +} + + +/* + * Routine to check all the single argument math functions. + */ +static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8* ud) +{ + assert(ud != 0); + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + assert(callh != 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + t_single_data *data = (t_single_data *) ud; + const char *name = data->name; + + va_single_t* fun_data = malloc(sizeof(va_single_t)); + + /* Check that malloc gave use some memory. */ + if (fun_data == 0) { + va_error_message(callh, "%s failed to allocate memory.\n", name); + return 0; + } + + /* Check that there are arguments. */ + if (argv == 0) { + va_error_message(callh, "%s requires one argument.\n", name); + return 0; + } + + /* In Icarus if we have an argv we have at least one argument. */ + arg = vpi_scan(argv); + fun_data->arg = va_process_argument(callh, name, arg, ""); + + /* These functions only take one argument. */ + arg = vpi_scan(argv); + if (arg != 0) { + va_error_message(callh, "%s takes only one argument.\n", name); + } + + /* Get the function that is to be used by the calltf routine. */ + fun_data->func = data->func; + + vpi_put_userdata(callh, fun_data); + + /* vpi_scan() returning 0 (NULL) has already freed argv. */ + return 0; +} + + +/* + * Routine to implement the single argument math functions. + */ +static PLI_INT32 va_single_argument_calltf(PLI_BYTE8* ud) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + s_vpi_value val; + (void) ud; /* Not used! */ + + /* Retrieve the function and argument data. */ + va_single_t* fun_data = vpi_get_userdata(callh); + + /* Calculate the result */ + val.format = vpiRealVal; + vpi_get_value(fun_data->arg, &val); + val.value.real = (fun_data->func)(val.value.real); + + /* Return the result */ + vpi_put_value(callh, &val, 0, vpiNoDelay); + + return 0; +} + + +/* + * Routine to check all the double argument math functions. + */ +static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8* ud) +{ + assert(ud != 0); + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + assert(callh != 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + t_double_data *data = (t_double_data *) ud; + const char *name = data->name; + + va_double_t* fun_data = malloc(sizeof(va_double_t)); + + /* Check that malloc gave use some memory. */ + if (fun_data == 0) { + va_error_message(callh, "%s failed to allocate memory.\n", name); + return 0; + } + + /* Check that there are arguments. */ + if (argv == 0) { + va_error_message(callh, "%s requires two arguments.\n", name); + return 0; + } + + /* In Icarus if we have an argv we have at least one argument. */ + arg = vpi_scan(argv); + fun_data->arg1 = va_process_argument(callh, name, arg, " (arg1)"); + + /* Check that there are at least two arguments. */ + arg = vpi_scan(argv); + if (arg == 0) { + va_error_message(callh, "%s requires two arguments.\n", name); + } + fun_data->arg2 = va_process_argument(callh, name, arg, " (arg2)"); + + /* These functions only take two arguments. */ + arg = vpi_scan(argv); + if (arg != 0) { + va_error_message(callh, "%s takes only two arguments.\n", name); + } + + /* Get the function that is to be used by the calltf routine. */ + fun_data->func = data->func; + + vpi_put_userdata(callh, fun_data); + + /* vpi_scan() returning 0 (NULL) has already freed argv. */ + return 0; +} + + +/* + * Routine to implement the double argument math functions. + */ +static PLI_INT32 va_double_argument_calltf(PLI_BYTE8 *ud) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + s_vpi_value val; + double first_arg; + (void) ud; /* Not used! */ + + /* Retrieve the function and argument data. */ + va_double_t* fun_data = vpi_get_userdata(callh); + + /* Calculate the result */ + val.format = vpiRealVal; + vpi_get_value(fun_data->arg1, &val); + first_arg = val.value.real; + vpi_get_value(fun_data->arg2, &val); + val.value.real = (fun_data->func)(first_arg, val.value.real); + + /* Return the result */ + vpi_put_value(callh, &val, 0, vpiNoDelay); + + return 0; +} + + +/* + * Register all the functions with Verilog. + */ +static void va_math_register(void) +{ + s_vpi_systf_data tf_data; + unsigned idx; + + /* Register the single argument functions. */ + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiRealFunc; + tf_data.calltf = va_single_argument_calltf; + tf_data.compiletf = va_single_argument_compiletf; + tf_data.sizetf = 0; + + for (idx=0; va_single_data[idx].name != 0; idx++) { + tf_data.tfname = va_single_data[idx].name; + tf_data.user_data = (PLI_BYTE8 *) &va_single_data[idx]; + vpi_register_systf(&tf_data); + } + + /* Register the double argument functions. */ + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiRealFunc; + tf_data.calltf = va_double_argument_calltf; + tf_data.compiletf = va_double_argument_compiletf; + tf_data.sizetf = 0; + + for (idx=0; va_double_data[idx].name != 0; idx++) { + tf_data.tfname = va_double_data[idx].name; + tf_data.user_data = (PLI_BYTE8 *) &va_double_data[idx]; + vpi_register_systf(&tf_data); + } +} + + +/* + * Hook to get Icarus Verilog to find the registration function. + */ +void (*vlog_startup_routines[])(void) = { + va_math_register, + 0 +}; diff --git a/vpi/va_math.sft b/vpi/va_math.sft new file mode 100644 index 000000000..3d85358a8 --- /dev/null +++ b/vpi/va_math.sft @@ -0,0 +1,31 @@ +# +# This is the system function descriptor table for the +# Verilog-A math functions. +# + +# Single argument functions. +$sqrt vpiSysFuncReal +$ln vpiSysFuncReal +$log vpiSysFuncReal +$exp vpiSysFuncReal +$abs vpiSysFuncReal +$ceil vpiSysFuncReal +$floor vpiSysFuncReal +$sin vpiSysFuncReal +$cos vpiSysFuncReal +$tan vpiSysFuncReal +$asin vpiSysFuncReal +$acos vpiSysFuncReal +$atan vpiSysFuncReal +$sinh vpiSysFuncReal +$cosh vpiSysFuncReal +$tanh vpiSysFuncReal +$asinh vpiSysFuncReal +$acosh vpiSysFuncReal +$atanh vpiSysFuncReal +# Double argument functions. +$min vpiSysFuncReal +$max vpiSysFuncReal +$pow vpiSysFuncReal +$atan2 vpiSysFuncReal +$hypot vpiSysFuncReal diff --git a/vpi/vpi_config.h.in b/vpi/vpi_config.h.in index acb51216a..59a8d13b8 100644 --- a/vpi/vpi_config.h.in +++ b/vpi/vpi_config.h.in @@ -1,7 +1,7 @@ #ifndef __vpi_config_H -#define __config_H +#define __vpi_config_H /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2008 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 @@ -18,16 +18,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: vpi_config.h.in,v 1.2 2004/01/26 21:52:46 steve Exp $" -#endif # undef HAVE_LIBIBERTY_H # undef HAVE_MALLOC_H -# undef HAVE_DLFCN_H -# undef HAVE_DL_H # undef HAVE_LIBZ # undef HAVE_LIBBZ2 +# undef HAVE_FMIN +# undef HAVE_FMAX # undef WORDS_BIGENDIAN # undef _LARGEFILE_SOURCE @@ -35,13 +32,4 @@ # define _FILE_OFFSET_BITS 64 #endif -/* - * $Log: vpi_config.h.in,v $ - * Revision 1.2 2004/01/26 21:52:46 steve - * Make sure file64 support is on cc -D flags. - * - * Revision 1.1 2004/01/21 01:22:53 steve - * Give the vip directory its own configure and vpi_config.h - * - */ #endif // __config_H