Add the va_math module and constants.vams include file.

The va_math.vpi module implements systen-function versions of the
Verilog-A math functions. This library was contributed by Cary R.

Also add the constants.vams include file. This is pretty much
direct from the Verilog-AMS LRM.
This commit is contained in:
Stephen Williams 2008-04-29 21:20:39 -07:00
parent f95a6fed14
commit f5263c9447
7 changed files with 475 additions and 33 deletions

View File

@ -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

43
constants.vams Normal file
View File

@ -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

View File

@ -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)

View File

@ -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

367
vpi/va_math.c Normal file
View File

@ -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 <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <vpi_user.h>
/*
* 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
};

31
vpi/va_math.sft Normal file
View File

@ -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

View File

@ -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