First batch of added file.
This commit is contained in:
parent
8362dec274
commit
9317355c0c
|
|
@ -0,0 +1,20 @@
|
|||
# Process this file with automake
|
||||
CFLAGS = -g -O2 -Wall
|
||||
CC = gcc
|
||||
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
|
||||
EXTRA_DIST = README
|
||||
|
||||
## This is removed because icm relies upon the existance of all other
|
||||
## libs. It is currently compiled manually, last.
|
||||
##SUBDIRS = mif cm enh evt ipc idn icm
|
||||
|
||||
SUBDIRS = mif cm enh evt ipc idn cmpp
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
all: xspice.o
|
||||
xspice.o:
|
||||
$(COMPILE) -c xspice.c
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Spice Opus / XSpice code model support.
|
||||
--------------------------------------
|
||||
|
||||
Use configure flag --enable-xspice to compile the support in,
|
||||
when you run the ./configure script.
|
||||
This creates a new command, "codemodel", which you can
|
||||
use to load a codemodel.
|
||||
|
||||
Some codemodels are included in the xspice/lib directory
|
||||
with some examples in xspice/examples, compiled for linux glibc.
|
||||
|
||||
Make sure the the library dir, xspice/lib, is in your LD_LIBRARY_PATH
|
||||
enviromental variable, otherwise the libs will not be found!
|
||||
|
||||
To create codemodels go to http://www.fe.uni-lj.si/spice/welcome.html
|
||||
and download their trial version of spice opus for the codemodel toolkit!
|
||||
|
||||
TODO:
|
||||
Intergrate the ipc stuff from XSpice.
|
||||
Create ng-spice capacity to create codemodels (a perl script)
|
||||
Ngspice crashes when you try to plot a digital node
|
||||
|
||||
Stefan Jones
|
||||
19/2/2002
|
||||
|
||||
-----------------------------------------
|
||||
SPICE2 POLY codemodel support.
|
||||
|
||||
SPICE2 POLY attributes are now available for controlled sources. To
|
||||
use POLY attributes, configure tclspice/ngspice with the
|
||||
--enable-xspice flag set as described above. After compilation of
|
||||
ngspice, cd into $(top_srcdir)/src/xspice/icm and read the README file
|
||||
there for instructions about how to get POLY support. (Hint: you have
|
||||
to download some stuff from http://www.fe.uni-lj.si/ and edit the
|
||||
Makefiles before you can do "make && make install" of the codemodel
|
||||
stuff.)
|
||||
|
||||
Please direct questions/comments/complaints to mailto:sdb@cloud9.net.
|
||||
|
||||
6.22.2003 -- SDB.
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LIBRARIES = libcmxsp.a
|
||||
|
||||
libcmxsp_a_SOURCES = \
|
||||
cm.c \
|
||||
cmevt.c \
|
||||
cmmeters.c \
|
||||
cmutil.c
|
||||
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,701 @@
|
|||
/* ===========================================================================
|
||||
FILE CM.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from user code models.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_analog_alloc()
|
||||
cm_analog_get_ptr()
|
||||
cm_analog_integrate()
|
||||
cm_analog_converge()
|
||||
cm_analog_set_temp_bkpt()
|
||||
cm_analog_set_perm_bkpt()
|
||||
cm_analog_ramp_factor()
|
||||
cm_analog_not_converged()
|
||||
cm_analog_auto_partial()
|
||||
|
||||
cm_message_get_errmsg()
|
||||
cm_message_send()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
#include "ngspice.h"
|
||||
#include "cm.h"
|
||||
#include "mif.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void cm_static_integrate(int byte_index,
|
||||
double integrand,
|
||||
double *integral,
|
||||
double *partial);
|
||||
|
||||
/*
|
||||
|
||||
cm_analog_alloc()
|
||||
|
||||
This function is called from code model C functions to allocate
|
||||
state storage for a particular instance. It computes the number
|
||||
of doubles that need to be allocated in SPICE's state storage
|
||||
vectors from the number of bytes specified in it's argument and
|
||||
then allocates space for the states. An index into the SPICE
|
||||
state-vectors is stored in the instance's data structure along
|
||||
with a ``tag'' variable supplied by the caller so that the location
|
||||
of the state storage area can be found by cm_analog_get_ptr().
|
||||
|
||||
*/
|
||||
|
||||
void *cm_analog_alloc(
|
||||
int tag, /* The user-specified tag for this block of memory */
|
||||
int bytes) /* The number of bytes to allocate */
|
||||
{
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_State_t *state;
|
||||
|
||||
int doubles_needed;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Scan states in instance struct and see if tag has already been used */
|
||||
for(i = 0; i < here->num_state; i++) {
|
||||
if(tag == here->state[i].tag) {
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_alloc() - Tag already used in previous call\n";
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute number of doubles needed and allocate space in ckt->CKTstates[i] */
|
||||
doubles_needed = bytes / sizeof(double) + 1;
|
||||
|
||||
/* Allocate space in instance struct for this state descriptor */
|
||||
if(here->num_state == 0) {
|
||||
here->num_state = 1;
|
||||
here->state = (void *) MALLOC(sizeof(Mif_State_t));
|
||||
}
|
||||
else {
|
||||
here->num_state++;
|
||||
here->state = (void *) REALLOC(here->state,
|
||||
here->num_state * sizeof(Mif_State_t));
|
||||
}
|
||||
|
||||
/* Fill in the members of the state descriptor struct */
|
||||
state = &(here->state[here->num_state - 1]);
|
||||
state->tag = tag;
|
||||
state->index = ckt->CKTnumStates;
|
||||
state->doubles = doubles_needed;
|
||||
state->bytes = bytes;
|
||||
|
||||
|
||||
/* Add the states to the ckt->CKTstates vectors */
|
||||
ckt->CKTnumStates += doubles_needed;
|
||||
for(i=0;i<=ckt->CKTmaxOrder+1;i++) {
|
||||
if(ckt->CKTnumStates == doubles_needed)
|
||||
ckt->CKTstates[i] = (double *) MALLOC(ckt->CKTnumStates * sizeof(double));
|
||||
else
|
||||
ckt->CKTstates[i] = (double *) REALLOC(ckt->CKTstates[i],
|
||||
ckt->CKTnumStates * sizeof(double));
|
||||
}
|
||||
|
||||
/* Return pointer to the allocated space in state 0 */
|
||||
return( (void *) (ckt->CKTstates[0] + (ckt->CKTnumStates - doubles_needed)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_get_ptr()
|
||||
|
||||
This function is called from code model C functions to return a
|
||||
pointer to state storage allocated with cm_analog_alloc(). A tag
|
||||
specified in its argument list is used to locate the state in
|
||||
question. A second argument specifies whether the desired state
|
||||
is for the current timestep or from a preceding timestep. The
|
||||
location of the state in memory is then computed and returned.
|
||||
*/
|
||||
|
||||
void *cm_analog_get_ptr(
|
||||
int tag, /* The user-specified tag for this block of memory */
|
||||
int timepoint) /* The timepoint of interest - 0=current 1=previous */
|
||||
{
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_State_t *state=NULL;
|
||||
|
||||
Mif_Boolean_t got_tag;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Scan states in instance struct and see if tag exists */
|
||||
for(got_tag = MIF_FALSE, i = 0; i < here->num_state; i++) {
|
||||
if(tag == here->state[i].tag) {
|
||||
state = &(here->state[i]);
|
||||
got_tag = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return error if tag not found */
|
||||
if(! got_tag) {
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_get_ptr() - Bad tag\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Return error if timepoint is not 0 or 1 */
|
||||
if((timepoint < 0) || (timepoint > 1)) {
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_get_ptr() - Bad timepoint\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Return address of requested state in ckt->CKTstates[timepoint] vector */
|
||||
return( (void *) (ckt->CKTstates[timepoint] + state->index) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_integrate()
|
||||
|
||||
This function performs a numerical integration on the state
|
||||
supplied in its argument list according to the integrand also
|
||||
supplied in the argument list. The next value of the integral
|
||||
and the partial derivative with respect to the integrand input is
|
||||
returned. The integral argument must be a pointer to memory
|
||||
previously allocated through a call to cm_analog_alloc(). If this is
|
||||
the first call to cm_analog_integrate(), information is entered into the
|
||||
instance structure to mark that the integral should be processed
|
||||
by MIFtrunc and MIFconvTest.
|
||||
*/
|
||||
|
||||
int cm_analog_integrate(
|
||||
double integrand, /* The integrand */
|
||||
double *integral, /* The current and returned value of integral */
|
||||
double *partial) /* The partial derivative of integral wrt integrand */
|
||||
{
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_Intgr_t *intgr;
|
||||
Mif_Boolean_t got_index;
|
||||
|
||||
char *char_state0;
|
||||
char *char_state;
|
||||
|
||||
int byte_index;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Check to be sure we're in transient analysis */
|
||||
if(g_mif_info.circuit.anal_type != MIF_TRAN) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - Called in non-transient analysis\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Preliminary check to be sure argument was allocated by cm_analog_alloc() */
|
||||
if(ckt->CKTnumStates <= 0) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - Integral must be memory allocated by cm_analog_alloc()\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Compute byte offset from start of state0 vector */
|
||||
char_state0 = (char *) ckt->CKTstate0;
|
||||
char_state = (char *) integral;
|
||||
byte_index = char_state - char_state0;
|
||||
|
||||
/* Check to be sure argument address is in range of state0 vector */
|
||||
if((byte_index < 0) ||
|
||||
(byte_index > ((ckt->CKTnumStates - 1) * sizeof(double)) ) ) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - Argument must be in state vector 0\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Scan the intgr array in the instance struct to see if already exists */
|
||||
for(got_index = MIF_FALSE, i = 0; i < here->num_intgr; i++) {
|
||||
if(here->intgr[i].byte_index == byte_index) {
|
||||
got_index = MIF_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report error if not found and this is not the first load pass in tran analysis */
|
||||
if((! got_index) && (! g_mif_info.circuit.anal_init)) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - New integral and not initialization pass\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* If new integral state, allocate space in instance */
|
||||
/* struct for this intgr descriptor and register it with */
|
||||
/* the cm_analog_converge() function */
|
||||
if(! got_index) {
|
||||
if(here->num_intgr == 0) {
|
||||
here->num_intgr = 1;
|
||||
here->intgr = (void *) MALLOC(sizeof(Mif_Intgr_t));
|
||||
}
|
||||
else {
|
||||
here->num_intgr++;
|
||||
here->intgr = (void *) REALLOC(here->intgr,
|
||||
here->num_intgr * sizeof(Mif_Intgr_t));
|
||||
}
|
||||
intgr = &(here->intgr[here->num_intgr - 1]);
|
||||
intgr->byte_index = byte_index;
|
||||
if(cm_analog_converge(integral)) {
|
||||
printf("%s\n",g_mif_info.errmsg);
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_integrate() - Failure in cm_analog_converge() call\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the new integral and the partial */
|
||||
cm_static_integrate(byte_index, integrand, integral, partial);
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_converge()
|
||||
|
||||
This function registers a state variable allocated with
|
||||
cm_analog_alloc() to be subjected to a convergence test at the end of
|
||||
each iteration. The state variable must be a double.
|
||||
Information is entered into the instance structure to mark that
|
||||
the state variable should be processed by MIFconvTest.
|
||||
*/
|
||||
|
||||
int cm_analog_converge(
|
||||
double *state) /* The state to be converged */
|
||||
{
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_Conv_t *conv;
|
||||
|
||||
char *char_state0;
|
||||
char *char_state;
|
||||
|
||||
int byte_index;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Preliminary check to be sure argument was allocated by cm_analog_alloc() */
|
||||
if(ckt->CKTnumStates <= 0) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_converge() - Argument must be memory allocated by cm_analog_alloc()\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Compute byte offset from start of state0 vector */
|
||||
char_state0 = (char *) ckt->CKTstate0;
|
||||
char_state = (char *) state;
|
||||
byte_index = char_state - char_state0;
|
||||
|
||||
/* Check to be sure argument address is in range of state0 vector */
|
||||
if((byte_index < 0) ||
|
||||
(byte_index > ((ckt->CKTnumStates - 1) * sizeof(double)) ) ) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_converge() - Argument must be in state vector 0\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Scan the conv array in the instance struct to see if already registered */
|
||||
/* If so, do nothing, just return */
|
||||
for(i = 0; i < here->num_conv; i++) {
|
||||
if(here->conv[i].byte_index == byte_index)
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
/* Allocate space in instance struct for this conv descriptor */
|
||||
if(here->num_conv == 0) {
|
||||
here->num_conv = 1;
|
||||
here->conv = (void *) MALLOC(sizeof(Mif_Conv_t));
|
||||
}
|
||||
else {
|
||||
here->num_conv++;
|
||||
here->conv = (void *) REALLOC(here->conv,
|
||||
here->num_conv * sizeof(Mif_Conv_t));
|
||||
}
|
||||
|
||||
/* Fill in the conv descriptor data */
|
||||
conv = &(here->conv[here->num_conv - 1]);
|
||||
conv->byte_index = byte_index;
|
||||
conv->last_value = 1.0e30; /* There should be a better way ... */
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_message_get_errmsg()
|
||||
|
||||
This function returns the address of an error message string set
|
||||
by a call to some code model support function.
|
||||
*/
|
||||
|
||||
char *cm_message_get_errmsg(void)
|
||||
{
|
||||
return(g_mif_info.errmsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_set_temp_bkpt()
|
||||
|
||||
This function is called by a code model C function to set a
|
||||
temporary breakpoint. These temporary breakpoints remain in
|
||||
effect only until the next timestep is taken. A temporary
|
||||
breakpoint added with a time less than the current time, but
|
||||
greater than the last successful timestep causes the simulator to
|
||||
abandon the current timestep and decrease the timestep to hit the
|
||||
breakpoint. A temporary breakpoint with a time greater than the
|
||||
current time causes the simulator to make the breakpoint the next
|
||||
timepoint if the next timestep would produce a time greater than
|
||||
that of the breakpoint.
|
||||
*/
|
||||
|
||||
|
||||
int cm_analog_set_temp_bkpt(
|
||||
double time) /* The time of the breakpoint to be set */
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Make sure breakpoint is not prior to last accepted timepoint */
|
||||
if(time < ((ckt->CKTtime - ckt->CKTdelta) + ckt->CKTminBreak)) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_set_temp_bkpt() - Time < last accepted timepoint\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* If too close to a permanent breakpoint or the current time, discard it */
|
||||
if( (fabs(time - ckt->CKTbreaks[0]) < ckt->CKTminBreak) ||
|
||||
(fabs(time - ckt->CKTbreaks[1]) < ckt->CKTminBreak) ||
|
||||
(fabs(time - ckt->CKTtime) < ckt->CKTminBreak) )
|
||||
return(MIF_OK);
|
||||
|
||||
/* If < current dynamic breakpoint, make it the current breakpoint */
|
||||
if( time < g_mif_info.breakpoint.current)
|
||||
g_mif_info.breakpoint.current = time;
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_set_perm_bkpt()
|
||||
|
||||
This function is called by a code model C function to set a
|
||||
permanent breakpoint. These permanent breakpoints remain in
|
||||
effect from the time they are introduced until the simulation
|
||||
time equals or exceeds the breakpoint time. A permanent
|
||||
breakpoint added with a time less than the current time, but
|
||||
greater than the last successful timestep causes the simulator to
|
||||
abandon the current timestep and decrease the timestep to hit the
|
||||
breakpoint. A permanent breakpoint with a time greater than the
|
||||
current time causes the simulator to make the breakpoint the next
|
||||
timepoint if the next timestep would produce a time greater than
|
||||
that of the breakpoint.
|
||||
*/
|
||||
|
||||
|
||||
int cm_analog_set_perm_bkpt(
|
||||
double time) /* The time of the breakpoint to be set */
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Call cm_analog_set_temp_bkpt() to force backup if less than current time */
|
||||
if(time < (ckt->CKTtime + ckt->CKTminBreak))
|
||||
return(cm_analog_set_temp_bkpt(time));
|
||||
else
|
||||
CKTsetBreak(ckt,time);
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_ramp_factor()
|
||||
|
||||
This function returns the current value of the ramp factor
|
||||
associated with the ``ramptime'' option. For this option
|
||||
to work best, models with analog outputs that may be non-zero at
|
||||
time zero should call this function and scale their outputs
|
||||
and partials by the ramp factor.
|
||||
*/
|
||||
|
||||
|
||||
double cm_analog_ramp_factor(void)
|
||||
{
|
||||
|
||||
CKTcircuit *ckt;
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
||||
/* if ramptime == 0.0, no ramptime option given, so return 1.0 */
|
||||
/* this is the most common case, so it goes first */
|
||||
if(ckt->enh->ramp.ramptime == 0.0)
|
||||
return(1.0);
|
||||
|
||||
/* else if not transient analysis, return 1.0 */
|
||||
else if( (!(ckt->CKTmode & MODETRANOP)) && (!(ckt->CKTmode & MODETRAN)) )
|
||||
return(1.0);
|
||||
|
||||
/* else if time >= ramptime, return 1.0 */
|
||||
else if(ckt->CKTtime >= ckt->enh->ramp.ramptime)
|
||||
return(1.0);
|
||||
|
||||
/* else time < end of ramp, so compute and return factor based on time */
|
||||
else
|
||||
return(ckt->CKTtime / ckt->enh->ramp.ramptime);
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************ */
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985 Thomas L. Quarles
|
||||
*
|
||||
* This is a modified version of the function NIintegrate()
|
||||
*
|
||||
* Modifications are Copyright 1991 Georgia Tech Research Institute
|
||||
*
|
||||
*/
|
||||
|
||||
static void cm_static_integrate(int byte_index,
|
||||
double integrand,
|
||||
double *integral,
|
||||
double *partial)
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
double intgr[7];
|
||||
double cur=0;
|
||||
double *double_ptr;
|
||||
|
||||
double ceq;
|
||||
double geq;
|
||||
|
||||
char *char_ptr;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt struct from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Get integral values from current and previous timesteps */
|
||||
for(i = 0; i <= ckt->CKTorder; i++) {
|
||||
char_ptr = (char *) ckt->CKTstates[i];
|
||||
char_ptr += byte_index;
|
||||
double_ptr = (double *) char_ptr;
|
||||
intgr[i] = *double_ptr;
|
||||
}
|
||||
|
||||
|
||||
/* Do what SPICE3C1 does for its implicit integration */
|
||||
|
||||
switch(ckt->CKTintegrateMethod) {
|
||||
|
||||
case TRAPEZOIDAL:
|
||||
|
||||
switch(ckt->CKTorder) {
|
||||
|
||||
case 1:
|
||||
cur = ckt->CKTag[1] * intgr[1];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* WARNING - This code needs to be redone. */
|
||||
/* The correct code should rely on one previous value */
|
||||
/* of cur as done in NIintegrate() */
|
||||
cur = -0.5 * ckt->CKTag[0] * intgr[1];
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GEAR:
|
||||
cur = 0.0;
|
||||
|
||||
switch(ckt->CKTorder) {
|
||||
|
||||
case 6:
|
||||
cur += ckt->CKTag[6] * intgr[6];
|
||||
/* fall through */
|
||||
case 5:
|
||||
cur += ckt->CKTag[5] * intgr[5];
|
||||
/* fall through */
|
||||
case 4:
|
||||
cur += ckt->CKTag[4] * intgr[4];
|
||||
/* fall through */
|
||||
case 3:
|
||||
cur += ckt->CKTag[3] * intgr[3];
|
||||
/* fall through */
|
||||
case 2:
|
||||
cur += ckt->CKTag[2] * intgr[2];
|
||||
/* fall through */
|
||||
case 1:
|
||||
cur += ckt->CKTag[1] * intgr[1];
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ceq = cur;
|
||||
geq = ckt->CKTag[0];
|
||||
|
||||
/* WARNING: Take this out when the case 2: above is fixed */
|
||||
if((ckt->CKTintegrateMethod == TRAPEZOIDAL) &&
|
||||
(ckt->CKTorder == 2))
|
||||
geq *= 0.5;
|
||||
|
||||
|
||||
/* The following code is equivalent to */
|
||||
/* the solution of one matrix iteration to produce the */
|
||||
/* integral value. */
|
||||
|
||||
*integral = (integrand - ceq) / geq;
|
||||
*partial = 1.0 / geq;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_not_converged()
|
||||
|
||||
This function tells the simulator not to allow the current
|
||||
iteration to be the final iteration. It is called when
|
||||
a code model performs internal limiting on one or more of
|
||||
its inputs to assist convergence.
|
||||
*/
|
||||
|
||||
void cm_analog_not_converged(void)
|
||||
{
|
||||
(g_mif_info.ckt->CKTnoncon)++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_message_send()
|
||||
|
||||
This function prints a message output from a code model, prepending
|
||||
the instance name.
|
||||
*/
|
||||
|
||||
|
||||
int cm_message_send(
|
||||
char *msg) /* The message to output. */
|
||||
{
|
||||
MIFinstance *here;
|
||||
|
||||
/* Get the address of the instance struct from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
|
||||
/* Print the name of the instance and the message */
|
||||
printf("\nInstance: %s Message: %s\n", (char *) here->MIFname, msg);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_auto_partial()
|
||||
|
||||
This function tells the simulator to automatically compute
|
||||
approximations of partial derivatives of analog outputs
|
||||
with respect to analog inputs. When called from a code
|
||||
model, it sets a flag in the g_mif_info structure
|
||||
which tells function MIFload() and it's associated
|
||||
MIFauto_partial() function to perform the necessary
|
||||
calculations.
|
||||
*/
|
||||
|
||||
|
||||
void cm_analog_auto_partial(void)
|
||||
{
|
||||
g_mif_info.auto_partial.local = MIF_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
/* ===========================================================================
|
||||
FILE CMevt.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from user code models
|
||||
that are associated with the event-driven algorithm.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_event_alloc()
|
||||
cm_event_get_ptr()
|
||||
cm_event_queue()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "cm.h"
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_event_alloc()
|
||||
|
||||
This function is called from code model C functions to allocate
|
||||
state storage for a particular event-driven
|
||||
instance. It is similar to the
|
||||
function cm_analog_alloc() used by analog models, but allocates states
|
||||
that are rotated during event-driven 'timesteps' instead of analog
|
||||
timesteps.
|
||||
*/
|
||||
|
||||
|
||||
void *cm_event_alloc(
|
||||
int tag, /* The user-specified tag for the memory block */
|
||||
int bytes) /* The number of bytes to be allocated */
|
||||
{
|
||||
|
||||
int inst_index;
|
||||
int num_tags;
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
void *ptr;
|
||||
|
||||
Evt_State_Desc_t **desc_ptr;
|
||||
Evt_State_Desc_t *desc;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_State_t *state;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
||||
/* If not initialization pass, return error */
|
||||
if(here->initialized) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_alloc() - Cannot alloc when not initialization pass\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_index = here->inst_index;
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
|
||||
/* Scan state descriptor list to determine if tag is present and to */
|
||||
/* find the end of the list. Report error if duplicate tag */
|
||||
desc_ptr = &(state_data->desc[inst_index]);
|
||||
desc = *desc_ptr;
|
||||
num_tags = 1;
|
||||
while(desc) {
|
||||
if(desc->tag == tag) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_alloc() - Duplicate tag\n";
|
||||
return(NULL);
|
||||
}
|
||||
desc_ptr = &(desc->next);
|
||||
desc = *desc_ptr;
|
||||
num_tags++;
|
||||
}
|
||||
|
||||
/* Create a new state description structure at end of list */
|
||||
/* and fill in the data and update the total size */
|
||||
*desc_ptr = (void *) MALLOC(sizeof(Evt_State_Desc_t));
|
||||
desc = *desc_ptr;
|
||||
desc->tag = tag;
|
||||
desc->size = bytes;
|
||||
desc->offset = state_data->total_size[inst_index];
|
||||
state_data->total_size[inst_index] += bytes;
|
||||
|
||||
/* Create a new state structure if list starting at head is null */
|
||||
state = state_data->head[inst_index];
|
||||
if(state == NULL) {
|
||||
state = (void *) MALLOC(sizeof(Evt_State_t));
|
||||
state_data->head[inst_index] = state;
|
||||
}
|
||||
|
||||
/* Create or enlarge the block and set the time */
|
||||
if(num_tags == 1)
|
||||
state->block = MALLOC(state_data->total_size[inst_index]);
|
||||
else
|
||||
state->block = REALLOC(state->block,
|
||||
state_data->total_size[inst_index]);
|
||||
|
||||
state->step = g_mif_info.circuit.evt_step;
|
||||
|
||||
|
||||
/* Return allocated memory */
|
||||
ptr = ((char *)state->block) + desc->offset;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_event_get_ptr()
|
||||
|
||||
This function is called from code model C functions to return a
|
||||
pointer to state storage allocated with cm_event_alloc(). A tag
|
||||
specified in its argument list is used to locate the state in
|
||||
question. A second argument specifies whether the desired state
|
||||
is for the current timestep or from a preceding timestep. The
|
||||
location of the state in memory is then computed and returned.
|
||||
*/
|
||||
|
||||
|
||||
void *cm_event_get_ptr(
|
||||
int tag, /* The user-specified tag for the memory block */
|
||||
int timepoint) /* The timepoint - 0=current, 1=previous */
|
||||
{
|
||||
|
||||
int i;
|
||||
int inst_index;
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
void *ptr;
|
||||
|
||||
Evt_State_Desc_t *desc;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_State_t *state;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
||||
/* If initialization pass, return error */
|
||||
if((! here->initialized) && (timepoint > 0)) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_get_ptr() - Cannot get_ptr(tag,1) during initialization pass\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_index = here->inst_index;
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
/* Scan state descriptor list to find the descriptor for this tag. */
|
||||
/* Report error if tag not found */
|
||||
desc = state_data->desc[inst_index];
|
||||
while(desc) {
|
||||
if(desc->tag == tag)
|
||||
break;
|
||||
desc = desc->next;
|
||||
}
|
||||
|
||||
if(desc == NULL) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_get_ptr() - Specified tag not found\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Get the state pointer from the current array */
|
||||
state = *(state_data->tail[inst_index]);
|
||||
|
||||
/* Backup the specified number of timesteps */
|
||||
for(i = 0; i < timepoint; i++)
|
||||
if(state->prev)
|
||||
state = state->prev;
|
||||
|
||||
/* Return pointer */
|
||||
ptr = ((char *) state->block) + desc->offset;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_event_queue()
|
||||
|
||||
This function queues an event for an instance participating
|
||||
in the event-driven algorithm.
|
||||
*/
|
||||
|
||||
|
||||
int cm_event_queue(
|
||||
double time) /* The time of the event to be queued */
|
||||
{
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* If breakpoint time <= current event time, return error */
|
||||
if(time <= g_mif_info.circuit.evt_step) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_queue() - Event time cannot be <= current time\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Add the event time to the inst queue */
|
||||
EVTqueue_inst(ckt, here->inst_index, g_mif_info.circuit.evt_step,
|
||||
time);
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
|
@ -0,0 +1,314 @@
|
|||
/* ===========================================================================
|
||||
FILE CMmeters.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from code models.
|
||||
These functions are primarily designed for use by the
|
||||
"cmeter" and "lmeter" models provided in the XSPICE
|
||||
code model library.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_netlist_get_c()
|
||||
cm_netlist_get_l()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
#include "ngspice.h"
|
||||
#include "cm.h"
|
||||
#include "mif.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
|
||||
#include "mifdefs.h"
|
||||
#include "cap/capdefs.h"
|
||||
#include "ind/inddefs.h"
|
||||
#include "vsrc/vsrcdefs.h"
|
||||
#include "inpdefs.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_netlist_get_c()
|
||||
|
||||
This is a special function designed for use with the c_meter
|
||||
model. It returns the parallel combination of the capacitance
|
||||
connected to the first port on the instance.
|
||||
*/
|
||||
|
||||
double cm_netlist_get_c()
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
MIFinstance *cmeter_inst;
|
||||
CAPinstance *cap_inst;
|
||||
VSRCinstance *vsrc_inst;
|
||||
|
||||
CAPmodel *cap_head;
|
||||
CAPmodel *cap_model;
|
||||
VSRCmodel *vsrc_head;
|
||||
VSRCmodel *vsrc_model;
|
||||
|
||||
int cap_type;
|
||||
int vsrc_type;
|
||||
|
||||
int cmeter_node;
|
||||
int vsrc_node;
|
||||
|
||||
double c;
|
||||
|
||||
|
||||
/* Get the circuit data structure and current instance */
|
||||
ckt = g_mif_info.ckt;
|
||||
cmeter_inst = g_mif_info.instance;
|
||||
|
||||
/* Get internal node number for positive node of cmeter input */
|
||||
cmeter_node = cmeter_inst->conn[0]->port[0]->smp_data.pos_node;
|
||||
|
||||
/* Initialize total capacitance value to zero */
|
||||
c = 0.0;
|
||||
|
||||
|
||||
/* ****************************************************** */
|
||||
/* Look for capacitors connected directly to cmeter input */
|
||||
/* ****************************************************** */
|
||||
|
||||
/* Get the head of the list of capacitor models in the circuit */
|
||||
cap_type = INPtypelook("Capacitor");
|
||||
if(cap_type < 0) {
|
||||
printf("\nERROR - Capacitor type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
cap_head = (CAPmodel *) ckt->CKThead[cap_type];
|
||||
|
||||
/* Scan through all capacitor instances and add in values */
|
||||
/* of any capacitors connected to cmeter input */
|
||||
|
||||
for(cap_model = cap_head; cap_model; cap_model = cap_model->CAPnextModel) {
|
||||
for(cap_inst = cap_model->CAPinstances;
|
||||
cap_inst;
|
||||
cap_inst = cap_inst->CAPnextInstance) {
|
||||
if((cmeter_node == cap_inst->CAPposNode) ||
|
||||
(cmeter_node == cap_inst->CAPnegNode)) {
|
||||
c += cap_inst->CAPcapac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ***************************************************************** */
|
||||
/* Look for capacitors connected through zero-valued voltage sources */
|
||||
/* ***************************************************************** */
|
||||
|
||||
/* Get the head of the list of voltage source models in the circuit */
|
||||
vsrc_type = INPtypelook("Vsource");
|
||||
if(vsrc_type < 0) {
|
||||
printf("\nERROR - Vsource type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
vsrc_head = (VSRCmodel *) ckt->CKThead[vsrc_type];
|
||||
|
||||
/* Scan through all voltage source instances and add in values */
|
||||
/* of any capacitors connected to cmeter input through voltage source */
|
||||
|
||||
for(vsrc_model = vsrc_head; vsrc_model; vsrc_model = vsrc_model->VSRCnextModel) {
|
||||
for(vsrc_inst = vsrc_model->VSRCinstances;
|
||||
vsrc_inst;
|
||||
vsrc_inst = vsrc_inst->VSRCnextInstance) {
|
||||
|
||||
/* Skip to next if not DC source with value = 0.0 */
|
||||
if((vsrc_inst->VSRCfunctionType != 0) ||
|
||||
(vsrc_inst->VSRCdcValue != 0.0))
|
||||
continue;
|
||||
|
||||
/* See if voltage source is connected to cmeter input */
|
||||
/* If so, get other node voltage source is connected to */
|
||||
/* If not, skip to next source */
|
||||
if(cmeter_node == vsrc_inst->VSRCposNode)
|
||||
vsrc_node = vsrc_inst->VSRCnegNode;
|
||||
else if(cmeter_node == vsrc_inst->VSRCnegNode)
|
||||
vsrc_node = vsrc_inst->VSRCposNode;
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
/* Scan through all capacitor instances and add in values */
|
||||
/* of any capacitors connected to the voltage source node */
|
||||
|
||||
for(cap_model = cap_head; cap_model; cap_model = cap_model->CAPnextModel) {
|
||||
for(cap_inst = cap_model->CAPinstances;
|
||||
cap_inst;
|
||||
cap_inst = cap_inst->CAPnextInstance) {
|
||||
if((vsrc_node == cap_inst->CAPposNode) ||
|
||||
(vsrc_node == cap_inst->CAPnegNode)) {
|
||||
c += cap_inst->CAPcapac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* end for all vsrc instances */
|
||||
} /* end for all vsrc models */
|
||||
|
||||
|
||||
/* Return the total capacitance value */
|
||||
return(c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_netlist_get_l()
|
||||
|
||||
This is a special function designed for use with the l_meter
|
||||
model. It returns the equivalent value of inductance
|
||||
connected to the first port on the instance.
|
||||
*/
|
||||
|
||||
|
||||
double cm_netlist_get_l()
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
MIFinstance *lmeter_inst;
|
||||
INDinstance *ind_inst;
|
||||
VSRCinstance *vsrc_inst;
|
||||
|
||||
INDmodel *ind_head;
|
||||
INDmodel *ind_model;
|
||||
VSRCmodel *vsrc_head;
|
||||
VSRCmodel *vsrc_model;
|
||||
|
||||
int ind_type;
|
||||
int vsrc_type;
|
||||
|
||||
int lmeter_node;
|
||||
int vsrc_node;
|
||||
|
||||
double l;
|
||||
|
||||
|
||||
/* Get the circuit data structure and current instance */
|
||||
ckt = g_mif_info.ckt;
|
||||
lmeter_inst = g_mif_info.instance;
|
||||
|
||||
/* Get internal node number for positive node of lmeter input */
|
||||
lmeter_node = lmeter_inst->conn[0]->port[0]->smp_data.pos_node;
|
||||
|
||||
/* Initialize total inductance to infinity */
|
||||
l = 1.0e12;
|
||||
|
||||
|
||||
/* ****************************************************** */
|
||||
/* Look for inductors connected directly to lmeter input */
|
||||
/* ****************************************************** */
|
||||
|
||||
/* Get the head of the list of inductor models in the circuit */
|
||||
ind_type = INPtypelook("Inductor");
|
||||
if(ind_type < 0) {
|
||||
printf("\nERROR - Inductor type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
ind_head = (INDmodel *) ckt->CKThead[ind_type];
|
||||
|
||||
/* Scan through all inductor instances and add in values */
|
||||
/* of any inductors connected to lmeter input */
|
||||
|
||||
for(ind_model = ind_head; ind_model; ind_model = ind_model->INDnextModel) {
|
||||
for(ind_inst = ind_model->INDinstances;
|
||||
ind_inst;
|
||||
ind_inst = ind_inst->INDnextInstance) {
|
||||
if((lmeter_node == ind_inst->INDposNode) ||
|
||||
(lmeter_node == ind_inst->INDnegNode)) {
|
||||
l = 1.0 / ( (1.0 / l) + (1.0 / ind_inst->INDinduct) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ***************************************************************** */
|
||||
/* Look for inductors connected through zero-valued voltage sources */
|
||||
/* ***************************************************************** */
|
||||
|
||||
/* Get the head of the list of voltage source models in the circuit */
|
||||
vsrc_type = INPtypelook("Vsource");
|
||||
if(vsrc_type < 0) {
|
||||
printf("\nERROR - Vsource type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
vsrc_head = (VSRCmodel *) ckt->CKThead[vsrc_type];
|
||||
|
||||
/* Scan through all voltage source instances and add in values */
|
||||
/* of any inductors connected to lmeter input through voltage source */
|
||||
|
||||
for(vsrc_model = vsrc_head; vsrc_model; vsrc_model = vsrc_model->VSRCnextModel) {
|
||||
for(vsrc_inst = vsrc_model->VSRCinstances;
|
||||
vsrc_inst;
|
||||
vsrc_inst = vsrc_inst->VSRCnextInstance) {
|
||||
|
||||
/* Skip to next if not DC source with value = 0.0 */
|
||||
if((vsrc_inst->VSRCfunctionType != 0) ||
|
||||
(vsrc_inst->VSRCdcValue != 0.0))
|
||||
continue;
|
||||
|
||||
/* See if voltage source is connected to lmeter input */
|
||||
/* If so, get other node voltage source is connected to */
|
||||
/* If not, skip to next source */
|
||||
if(lmeter_node == vsrc_inst->VSRCposNode)
|
||||
vsrc_node = vsrc_inst->VSRCnegNode;
|
||||
else if(lmeter_node == vsrc_inst->VSRCnegNode)
|
||||
vsrc_node = vsrc_inst->VSRCposNode;
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
/* Scan through all inductor instances and add in values */
|
||||
/* of any inductors connected to the voltage source node */
|
||||
|
||||
for(ind_model = ind_head; ind_model; ind_model = ind_model->INDnextModel) {
|
||||
for(ind_inst = ind_model->INDinstances;
|
||||
ind_inst;
|
||||
ind_inst = ind_inst->INDnextInstance) {
|
||||
if((vsrc_node == ind_inst->INDposNode) ||
|
||||
(vsrc_node == ind_inst->INDnegNode)) {
|
||||
l = 1.0 / ( (1.0 / l) + (1.0 / ind_inst->INDinduct) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* end for all vsrc instances */
|
||||
} /* end for all vsrc models */
|
||||
|
||||
|
||||
/* Return the total capacitance value */
|
||||
return(l);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
/* ===========================================================================
|
||||
FILE CMutil.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Jeff Murray
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from user code models.
|
||||
These functions were written to support code models in the
|
||||
XSPICE library, but may be useful in general.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_smooth_corner()
|
||||
cm_smooth_discontinuity()
|
||||
cm_smooth_pwl()
|
||||
|
||||
cm_climit_fcn()
|
||||
|
||||
cm_complex_set()
|
||||
cm_complex_add()
|
||||
cm_complex_subtract()
|
||||
cm_complex_multiply()
|
||||
cm_complex_divide()
|
||||
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "cm.h"
|
||||
|
||||
/* Corner Smoothing Function ************************************
|
||||
* *
|
||||
* The following function smooths the transition between two *
|
||||
* slopes into a quadratic (parabolic) curve. The calling *
|
||||
* function passes an x,y coordinate representing the *
|
||||
* "breakpoint", a smoothing domain value (d), and the slopes at *
|
||||
* both endpoints, and the x value itself. The situation is *
|
||||
* shown below: B C *
|
||||
* A |<-d->| ^ y *
|
||||
* ---------*-----* | | *
|
||||
* lower_slope-^ |<-d->|\ | | *
|
||||
* \ | | *
|
||||
* \ | *------>x *
|
||||
* At A<x<C, cm_smooth_corner \ | *
|
||||
* returns a "y" value which \| *
|
||||
* smoothly transitions from *__ *
|
||||
* f(A) to f(C) in a parabolic \ | upper_slope *
|
||||
* fashion...the slope of the new \| *
|
||||
* function is also returned. \ *
|
||||
* *
|
||||
*****************************************************************/
|
||||
|
||||
void cm_smooth_corner(
|
||||
double x_input, /* The value of the x input */
|
||||
double x_center, /* The x intercept of the two slopes */
|
||||
double y_center, /* The y intercept of the two slopes */
|
||||
double domain, /* The smoothing domain */
|
||||
double lower_slope, /* The lower slope */
|
||||
double upper_slope, /* The upper slope */
|
||||
double *y_output, /* The smoothed y output */
|
||||
double *dy_dx) /* The partial of y wrt x */
|
||||
{
|
||||
double x_upper,y_upper,a,b,c,dy_dx_temp;
|
||||
|
||||
/* Set up parabolic constants */
|
||||
|
||||
x_upper = x_center + domain;
|
||||
y_upper = y_center + (upper_slope * domain);
|
||||
a = ((upper_slope - lower_slope) / 4.0) * (1 / domain);
|
||||
b = upper_slope - (2.0 * a * x_upper);
|
||||
c = y_upper - (a * x_upper * x_upper) - (b * x_upper);
|
||||
|
||||
/* Calculate y value & derivative */
|
||||
|
||||
dy_dx_temp = 2.0*a*x_input + b; /* Prevents reassignment problems */
|
||||
/* for x-limiting cases. */
|
||||
|
||||
*y_output = a*x_input*x_input + b*x_input + c;
|
||||
*dy_dx = dy_dx_temp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Discontinuity Smoothing Function *****************************
|
||||
* *
|
||||
* The following function smooths the transition between two *
|
||||
* values using an x^2 function. The calling function *
|
||||
* function passes an x1,y1 coordinate representing the *
|
||||
* starting point, an x2,y2 coordinate representing an ending *
|
||||
* point, and the x value itself. The situation is shown below: *
|
||||
* *
|
||||
* ^ y (xu,yu) *
|
||||
* | ---*----------- *
|
||||
* | --- | *
|
||||
* | -- *
|
||||
* | - | *
|
||||
* | - *
|
||||
* | - | *
|
||||
* | -- *
|
||||
* | (xl,yl) --- | *
|
||||
* ----|----*--- *
|
||||
* | | | *
|
||||
* O------------------------------------->x *
|
||||
*****************************************************************/
|
||||
|
||||
void cm_smooth_discontinuity(
|
||||
double x_input, /* The x value at which to compute y */
|
||||
double x_lower, /* The x value of the lower corner */
|
||||
double y_lower, /* The y value of the lower corner */
|
||||
double x_upper, /* The x value of the upper corner */
|
||||
double y_upper, /* The y value of the upper corner */
|
||||
double *y_output, /* The computed smoothed y value */
|
||||
double *dy_dx) /* The partial of y wrt x */
|
||||
{
|
||||
double x_center,y_center,a,b,c,center_slope;
|
||||
|
||||
|
||||
/* Derive x_center, y_center & center_slope values */
|
||||
x_center = (x_upper + x_lower) / 2.0;
|
||||
y_center = (y_upper + y_lower) / 2.0;
|
||||
center_slope = 2.0 * (y_upper - y_lower) / (x_upper - x_lower);
|
||||
|
||||
|
||||
if (x_input < x_lower) { /* x_input @ lower level */
|
||||
*y_output = y_lower;
|
||||
*dy_dx = 0.0;
|
||||
}
|
||||
else {
|
||||
if (x_input < x_center) { /* x_input in lower transition */
|
||||
a = center_slope / (x_upper - x_lower);
|
||||
b = center_slope - 2.0 * a * x_center;
|
||||
c = y_center - a * x_center * x_center - b * x_center;
|
||||
*y_output = a * x_input * x_input + b * x_input + c;
|
||||
*dy_dx = 2.0 * a * x_input + b;
|
||||
}
|
||||
else { /* x_input in upper transition */
|
||||
if (x_input < x_upper) {
|
||||
a = -center_slope / (x_upper - x_lower);
|
||||
b = -2.0 * a * x_upper;
|
||||
c = y_upper - a * x_upper * x_upper - b * x_upper;
|
||||
*y_output = a * x_input * x_input + b * x_input + c;
|
||||
*dy_dx = 2.0 * a * x_input + b;
|
||||
}
|
||||
else { /* x_input @ upper level */
|
||||
*y_output = y_upper;
|
||||
*dy_dx = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Controlled Limiter Function (modified CLIMIT) */
|
||||
|
||||
/*
|
||||
This is a special function created for use with the CLIMIT
|
||||
controlled limiter model.
|
||||
*/
|
||||
|
||||
void cm_climit_fcn(
|
||||
double in, /* The input value */
|
||||
double in_offset, /* The input offset */
|
||||
double cntl_upper, /* The upper control input value */
|
||||
double cntl_lower, /* The lower control input value */
|
||||
double lower_delta, /* The delta from control to limit value */
|
||||
double upper_delta, /* The delta from control to limit value */
|
||||
double limit_range, /* The limiting range */
|
||||
double gain, /* The gain from input to output */
|
||||
int percent, /* The fraction vs. absolute range flag */
|
||||
double *out_final, /* The output value */
|
||||
double *pout_pin_final, /* The partial of output wrt input */
|
||||
double *pout_pcntl_lower_final, /* The partial of output wrt lower control input */
|
||||
double *pout_pcntl_upper_final) /* The partial of output wrt upper control input */
|
||||
{
|
||||
|
||||
/* Define error message string constants */
|
||||
|
||||
char *climit_range_error = "\n**** ERROR ****\n* CLIMIT function linear range less than zero. *\n";
|
||||
|
||||
|
||||
double threshold_upper,threshold_lower,linear_range,
|
||||
out_lower_limit,out_upper_limit,limited_out,
|
||||
out,pout_pin,pout_pcntl_lower,pout_pcntl_upper,junk;
|
||||
|
||||
/* Find Upper & Lower Limits */
|
||||
|
||||
out_lower_limit = cntl_lower + lower_delta;
|
||||
out_upper_limit = cntl_upper - upper_delta;
|
||||
|
||||
|
||||
if (percent == TRUE) /* Set range to absolute value */
|
||||
limit_range = limit_range *
|
||||
(out_upper_limit - out_lower_limit);
|
||||
|
||||
|
||||
|
||||
threshold_upper = out_upper_limit - /* Set Upper Threshold */
|
||||
limit_range;
|
||||
threshold_lower = out_lower_limit + /* Set Lower Threshold */
|
||||
limit_range;
|
||||
linear_range = threshold_upper - threshold_lower;
|
||||
|
||||
|
||||
/* Test the linear region & make sure there IS one... */
|
||||
if (linear_range < 0.0) {
|
||||
printf("%s\n",climit_range_error);
|
||||
/* limited_out = 0.0;
|
||||
pout_pin = 0.0;
|
||||
pout_pcntl_lower = 0.0;
|
||||
pout_pcntl_upper = 0.0;
|
||||
return;
|
||||
*/ }
|
||||
|
||||
/* Compute Un-Limited Output */
|
||||
out = gain * (in_offset + in);
|
||||
|
||||
|
||||
if (out < threshold_lower) { /* Limit Out @ Lower Bound */
|
||||
|
||||
pout_pcntl_upper= 0.0;
|
||||
|
||||
if (out > (out_lower_limit - limit_range)) { /* Parabolic */
|
||||
cm_smooth_corner(out,out_lower_limit,out_lower_limit,
|
||||
limit_range,0.0,1.0,&limited_out,
|
||||
&pout_pin);
|
||||
pout_pin = gain * pout_pin;
|
||||
cm_smooth_discontinuity(out,out_lower_limit,1.0,threshold_lower,
|
||||
0.0,&pout_pcntl_lower,&junk);
|
||||
}
|
||||
else { /* Hard-Limited Region */
|
||||
limited_out = out_lower_limit;
|
||||
pout_pin = 0.0;
|
||||
pout_pcntl_lower = 1.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (out > threshold_upper) { /* Limit Out @ Upper Bound */
|
||||
|
||||
pout_pcntl_lower= 0.0;
|
||||
|
||||
if (out < (out_upper_limit+limit_range)) { /* Parabolic */
|
||||
cm_smooth_corner(out,out_upper_limit,out_upper_limit,
|
||||
limit_range,1.0,0.0,&limited_out,
|
||||
&pout_pin);
|
||||
pout_pin = gain * pout_pin;
|
||||
cm_smooth_discontinuity(out,threshold_upper,0.0,out_upper_limit,
|
||||
1.0,&pout_pcntl_upper,&junk);
|
||||
}
|
||||
else { /* Hard-Limited Region */
|
||||
limited_out = out_upper_limit;
|
||||
pout_pin = 0.0;
|
||||
pout_pcntl_upper = 1.0;
|
||||
}
|
||||
}
|
||||
else { /* No Limiting Needed */
|
||||
limited_out = out;
|
||||
pout_pin = gain;
|
||||
pout_pcntl_lower = 0.0;
|
||||
pout_pcntl_upper = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*out_final = limited_out;
|
||||
*pout_pin_final = pout_pin;
|
||||
*pout_pcntl_lower_final = pout_pcntl_lower;
|
||||
*pout_pcntl_upper_final = pout_pcntl_upper;
|
||||
|
||||
}
|
||||
|
||||
/**** End Controlled Limiter Function ****/
|
||||
|
||||
/*=============================================================================*/
|
||||
|
||||
|
||||
/* Piecewise Linear Smoothing Function *********************
|
||||
* The following is a transfer curve function which *
|
||||
* accepts as input an "x" value, and returns a "y" *
|
||||
* value. The transfer characteristic is a smoothed *
|
||||
* piece-wise linear curve described by *x and *y array *
|
||||
* coordinate pairs. *
|
||||
* *
|
||||
* Created 8/14/91 *
|
||||
* Last Modified 8/14/91 J.P.Murray *
|
||||
***********************************************************/
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* ^ x[4] *
|
||||
* x[1] | * *
|
||||
* | midpoint /|\ *
|
||||
* | | / \ *
|
||||
* | V | / | \ *
|
||||
* *----*----* \ *
|
||||
* midpoint /| | | \ *
|
||||
* | / || * <- midpoint *
|
||||
* V/ | |x[3] \ *
|
||||
* <-----------*------------O------------\-------------> *
|
||||
* | / | \ | | *
|
||||
* / | \ *
|
||||
* |/ | \| | *
|
||||
* * | *-----*---> *
|
||||
* /| | x[5] x[6] *
|
||||
* / | *
|
||||
* / x[0] | *
|
||||
* / | *
|
||||
* / | *
|
||||
* / | *
|
||||
* V *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* Note that for the cm_smooth_pwl function, the arguments *
|
||||
* are as listed below: *
|
||||
* *
|
||||
* *
|
||||
* double x_input; input * *
|
||||
* double *x; pointer to the x-coordinate *
|
||||
* array * *
|
||||
* double *y; pointer to the y-coordinate *
|
||||
* array * *
|
||||
* int size; size of the arrays *
|
||||
* *
|
||||
* double input_domain; smoothing range * *
|
||||
* double dout_din; partial derivative of the *
|
||||
* output w.r.t. the input * *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
|
||||
double cm_smooth_pwl(double x_input, double *x, double *y, int size,
|
||||
double input_domain, double *dout_din)
|
||||
{
|
||||
|
||||
int i; /* generic loop counter index */
|
||||
|
||||
double lower_seg; /* x segment below which input resides */
|
||||
double upper_seg; /* x segment above which the input resides */
|
||||
double lower_slope; /* slope of the lower segment */
|
||||
double upper_slope; /* slope of the upper segment */
|
||||
double out; /* output */
|
||||
double threshold_lower; /* value below which the output begins smoothing */
|
||||
double threshold_upper; /* value above which the output begins smoothing */
|
||||
|
||||
|
||||
/* char *limit_error="\n***ERROR***\nViolation of 50% rule in breakpoints!\n";*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Determine segment boundaries within which x_input resides */
|
||||
|
||||
if (x_input <= (*(x+1) + *x)/2.0) {/*** x_input below lowest midpoint ***/
|
||||
*dout_din = (*(y+1) - *y)/(*(x+1) - *x);
|
||||
out = *y + (x_input - *x) * *dout_din;
|
||||
}
|
||||
else {
|
||||
if (x_input >= (*(x+size-2) + *(x+size-1))/2.0) {
|
||||
/*** x_input above highest midpoint ***/
|
||||
*dout_din = (*(y+size-1) - *(y+size-2)) /
|
||||
(*(x+size-1) - *(x+size-2));
|
||||
out = *(y+size-1) + (x_input - *(x+size-1)) * *dout_din;
|
||||
}
|
||||
else { /*** x_input within bounds of end midpoints... ***/
|
||||
/*** must determine position progressively & then ***/
|
||||
/*** calculate required output. ***/
|
||||
|
||||
for (i=1; i<size; i++) {
|
||||
|
||||
if (x_input < (*(x+i) + *(x+i+1))/2.0) {
|
||||
/* approximate position known... */
|
||||
|
||||
lower_seg = (*(x+i) - *(x+i-1));
|
||||
upper_seg = (*(x+i+1) - *(x+i));
|
||||
|
||||
|
||||
/* Calculate input_domain about this region's breakpoint.*/
|
||||
|
||||
/* Translate input_domain into an absolute.... */
|
||||
if ( lower_seg <= upper_seg ) /* Use lower */
|
||||
/* segment */
|
||||
/* for % calc.*/
|
||||
input_domain = input_domain * lower_seg;
|
||||
else /* Use upper */
|
||||
/* segment */
|
||||
/* for % calc.*/
|
||||
input_domain = input_domain * upper_seg;
|
||||
|
||||
|
||||
/* Set up threshold values about breakpoint... */
|
||||
threshold_lower = *(x+i) - input_domain;
|
||||
threshold_upper = *(x+i) + input_domain;
|
||||
|
||||
/* Determine where x_input is within region & determine */
|
||||
/* output and partial values.... */
|
||||
if (x_input < threshold_lower) { /* Lower linear region */
|
||||
*dout_din = (*(y+i) - *(y+i-1))/lower_seg;
|
||||
out = *(y+i) + (x_input - *(x+i)) * *dout_din;
|
||||
}
|
||||
else {
|
||||
if (x_input < threshold_upper) { /* Parabolic region */
|
||||
lower_slope = (*(y+i) - *(y+i-1))/lower_seg;
|
||||
upper_slope = (*(y+i+1) - *(y+i))/upper_seg;
|
||||
cm_smooth_corner(x_input,*(x+i),*(y+i),input_domain,
|
||||
lower_slope,upper_slope,&out,dout_din);
|
||||
}
|
||||
else { /* Upper linear region */
|
||||
*dout_din = (*(y+i+1) - *(y+i))/upper_seg;
|
||||
out = *(y+i) + (x_input - *(x+i)) * *dout_din;
|
||||
}
|
||||
}
|
||||
break; /* Break search loop...x_input has been found, */
|
||||
/* and out and *dout_din have been assigned. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Complex_t cm_complex_set(double real, double imag)
|
||||
{
|
||||
/* Create a complex number with the real and imaginary */
|
||||
/* parts specified in the argument list, and return it */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = real;
|
||||
c.imag = imag;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_add(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Add the two complex numbers and return the result */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = x.real + y.real;
|
||||
c.imag = x.imag + y.imag;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_subtract(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Subtract the second arg from the first and return the result */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = x.real - y.real;
|
||||
c.imag = x.imag - y.imag;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_multiply(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Multiply the two complex numbers and return the result */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = (x.real * y.real) - (x.imag * y.imag);
|
||||
c.imag = (x.real * y.imag) + (x.imag * y.real);
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_divide(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Divide the first number by the second and return the result */
|
||||
|
||||
Complex_t c;
|
||||
double mag_y_squared;
|
||||
|
||||
mag_y_squared = (y.real * y.real) + (y.imag * y.imag);
|
||||
|
||||
if(mag_y_squared < 1e-100) {
|
||||
printf("\nWARNING: cm_complex_divide() - divide by zero\n");
|
||||
mag_y_squared = 1e-100;
|
||||
}
|
||||
|
||||
c.real = ((x.real * y.real) + (x.imag * y.imag)) / mag_y_squared;
|
||||
c.imag = ((x.imag * y.real) - (y.imag * x.real)) / mag_y_squared;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
cmpp_OBJS=main.o pp_ifs.o pp_lst.o pp_mod.o read_ifs.o util.o writ_ifs.o \
|
||||
ifs_yacc.o ifs_lex.o mod_yacc.o mod_lex.o
|
||||
|
||||
cmpp_GEN=ifs_yacc.c ifs_tok.h \
|
||||
ifs_lex.c ifs_lex.h \
|
||||
mod_lex.c mod_lex.h \
|
||||
mod_yacc.c mod_tok.h
|
||||
|
||||
YACC=bison -d --yacc
|
||||
#YACC=yacc -d
|
||||
|
||||
CC=gcc -O2 -g
|
||||
|
||||
LEX=flex -t
|
||||
|
||||
all: cmpp
|
||||
|
||||
cmpp: $(cmpp_OBJS)
|
||||
$(CC) -o cmpp $(cmpp_OBJS)
|
||||
|
||||
%.c : %.y
|
||||
$(YACC) -p $(*:yacc=)yy $<
|
||||
mv -f y.tab.c $*.c
|
||||
mv -f y.tab.h $(*:yacc=)tok.h
|
||||
|
||||
%.c : %.l
|
||||
$(LEX) -P$(*:lex=)yy $< > $@
|
||||
|
||||
ifs_lex.c : ifs_lex.l
|
||||
$(LEX) -i -P$(*:lex=)yy $< > $@
|
||||
|
||||
install:
|
||||
|
||||
clean:
|
||||
rm -f $(cmpp_OBJS) $(cmpp_GEN) cmpp
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/*============================================================================
|
||||
FILE cmpp.h
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains shared constants, type definitions,
|
||||
and function prototypes used in the cmpp process.
|
||||
|
||||
INTERFACES
|
||||
|
||||
None.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define IFSPEC_FILENAME "ifspec.ifs"
|
||||
#define UDNFUNC_FILENAME "udnfunc.c"
|
||||
#define MODPATH_FILENAME "modpath.lst"
|
||||
#define UDNPATH_FILENAME "udnpath.lst"
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
typedef enum {
|
||||
|
||||
OK, /* Returned with no error */
|
||||
ERROR, /* Returned with error */
|
||||
|
||||
} Status_t;
|
||||
|
||||
|
||||
|
||||
#define GET_IFS_TABLE 0 /* Read the entire ifs table */
|
||||
#define GET_IFS_NAME 1 /* Get the C function name out of the table only */
|
||||
|
||||
#define MAX_PATH_LEN 1024 /* Maximum pathname length */
|
||||
#define MAX_NAME_LEN 1024 /* Maximum SPICE name length */
|
||||
#define MAX_FN_LEN 31 /* Maximum filename length */
|
||||
|
||||
|
||||
/* ******************************************************************** */
|
||||
/* Structures used by parser to check for valid connections/parameters */
|
||||
/* ******************************************************************** */
|
||||
|
||||
/*
|
||||
* The boolean type
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
FALSE,
|
||||
TRUE,
|
||||
} Boolean_t;
|
||||
|
||||
|
||||
/*
|
||||
* The direction of a connector
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
IN,
|
||||
OUT,
|
||||
INOUT,
|
||||
} Dir_t;
|
||||
|
||||
|
||||
/*
|
||||
* The type of a port
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
VOLTAGE, /* v - Single-ended voltage */
|
||||
DIFF_VOLTAGE, /* vd - Differential voltage */
|
||||
CURRENT, /* i - Single-ended current */
|
||||
DIFF_CURRENT, /* id - Differential current */
|
||||
VSOURCE_CURRENT, /* vnam - Vsource name for input current */
|
||||
CONDUCTANCE, /* g - Single-ended VCIS */
|
||||
DIFF_CONDUCTANCE, /* gd - Differential VCIS */
|
||||
RESISTANCE, /* h - Single-ended ICVS */
|
||||
DIFF_RESISTANCE, /* hd - Differential ICVS */
|
||||
DIGITAL, /* d - Digital */
|
||||
USER_DEFINED, /* <identifier> - Any user defined type */
|
||||
} Port_Type_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The type of a parameter or Static_Var
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
BOOLEAN,
|
||||
INTEGER,
|
||||
REAL,
|
||||
COMPLEX,
|
||||
STRING,
|
||||
POINTER, /* NOTE: POINTER should not be used for Parameters - only
|
||||
* Static_Vars - this is enforced by the cmpp.
|
||||
*/
|
||||
} Data_Type_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The complex type
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
double real;
|
||||
double imag;
|
||||
} Complex_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Values of different types.
|
||||
*
|
||||
* Note that a struct is used instead of a union for conformity
|
||||
* with the use of the Mif_Value_t type in the simulator where
|
||||
* the type must be statically initialized. ANSI C does not
|
||||
* support useful initialization of unions.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
|
||||
Boolean_t bvalue; /* For BOOLEAN parameters */
|
||||
int ivalue; /* For INTEGER parameters */
|
||||
double rvalue; /* For REAL parameters */
|
||||
Complex_t cvalue; /* For COMPLEX parameters */
|
||||
char *svalue; /* For STRING parameters */
|
||||
|
||||
} Value_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Information about the model as a whole
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
char *c_fcn_name; /* Name used in the C function */
|
||||
char *model_name; /* Name used in a spice deck */
|
||||
char *description; /* Description of the model */
|
||||
|
||||
} Name_Info_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Information about a connection
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
char *name; /* Name of this connection */
|
||||
char *description; /* Description of this connection */
|
||||
Dir_t direction; /* IN, OUT, or INOUT */
|
||||
Port_Type_t default_port_type; /* The default port type */
|
||||
char *default_type; /* The default type in string form */
|
||||
int num_allowed_types; /* The size of the allowed type arrays */
|
||||
Port_Type_t *allowed_port_type; /* Array of allowed types */
|
||||
char **allowed_type; /* Array of allowed types in string form */
|
||||
Boolean_t is_array; /* True if connection is an array */
|
||||
Boolean_t has_conn_ref; /* True if there is associated with an array conn */
|
||||
int conn_ref; /* Subscript of the associated array conn */
|
||||
Boolean_t has_lower_bound; /* True if there is an array size lower bound */
|
||||
int lower_bound; /* Array size lower bound */
|
||||
Boolean_t has_upper_bound; /* True if there is an array size upper bound */
|
||||
int upper_bound; /* Array size upper bound */
|
||||
Boolean_t null_allowed; /* True if null is allowed for this connection */
|
||||
|
||||
} Conn_Info_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Information about a parameter
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
|
||||
char *name; /* Name of this parameter */
|
||||
char *description; /* Description of this parameter */
|
||||
Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */
|
||||
Boolean_t has_default; /* True if there is a default value */
|
||||
Value_t default_value; /* The default value */
|
||||
Boolean_t has_lower_limit; /* True if there is a lower limit */
|
||||
Value_t lower_limit; /* The lower limit for this parameter */
|
||||
Boolean_t has_upper_limit; /* True if there is a upper limit */
|
||||
Value_t upper_limit; /* The upper limit for this parameter */
|
||||
Boolean_t is_array; /* True if parameter is an array */
|
||||
Boolean_t has_conn_ref; /* True if there is associated with an array conn */
|
||||
int conn_ref; /* Subscript of the associated array conn */
|
||||
Boolean_t has_lower_bound; /* True if there is an array size lower bound */
|
||||
int lower_bound; /* Array size lower bound */
|
||||
Boolean_t has_upper_bound; /* True if there is an array size upper bound */
|
||||
int upper_bound; /* Array size upper bound */
|
||||
Boolean_t null_allowed; /* True if null is allowed for this parameter */
|
||||
|
||||
} Param_Info_t;
|
||||
|
||||
|
||||
/*
|
||||
* Information about an instance variable
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
|
||||
char *name; /* Name of this parameter */
|
||||
char *description; /* Description of this parameter */
|
||||
Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */
|
||||
Boolean_t is_array; /* True if parameter is an array */
|
||||
|
||||
} Inst_Var_Info_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The all encompassing structure for the ifs table information
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
|
||||
Name_Info_t name; /* The name table entries */
|
||||
int num_conn; /* Number of entries in the connection table(s) */
|
||||
Conn_Info_t *conn; /* Array of connection info structs */
|
||||
int num_param; /* Number of entries in the parameter table(s) */
|
||||
Param_Info_t *param; /* Array of parameter info structs */
|
||||
int num_inst_var; /* Number of entries in the instance var table(s) */
|
||||
Inst_Var_Info_t *inst_var; /* Array of instance variable info structs */
|
||||
|
||||
} Ifs_Table_t;
|
||||
|
||||
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
|
||||
|
||||
void preprocess_ifs_file(void);
|
||||
|
||||
void preprocess_lst_files(void);
|
||||
|
||||
void preprocess_mod_file(char *filename);
|
||||
|
||||
|
||||
void print_error(char *message);
|
||||
|
||||
|
||||
Status_t read_ifs_file(char *filename, int mode, Ifs_Table_t *ifs_table);
|
||||
|
||||
Status_t write_ifs_c_file(char *filename, Ifs_Table_t *ifs_table);
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
%option yylineno
|
||||
%option noyywrap
|
||||
%{ /* $Id$ */
|
||||
|
||||
/*============================================================================
|
||||
FILE ifs_lex.l
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
12/31/91 Bill Kuhn Change "array" to "vector" and "array_bounds"
|
||||
to "vector_bounds".
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file defines tokens applicable to parsing the ifspec.ifs
|
||||
file, and actions to be taken on encountering those tokens.
|
||||
|
||||
INTERFACES
|
||||
|
||||
None.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
ifs_yacc.y
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "ifs_yacc.h"
|
||||
#include "ifs_tok.h"
|
||||
|
||||
int yyival;
|
||||
double yydval;
|
||||
extern int atoi();
|
||||
extern double atof();
|
||||
|
||||
/*
|
||||
* IFS specs are case insensitive:
|
||||
*/
|
||||
|
||||
/* saj - use -i flex command line option
|
||||
#undef input
|
||||
#define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:isupper(yytchar)?tolower(yytchar):yytchar)
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
%}
|
||||
|
||||
%start BOOL CTYPE DIR DTYPE
|
||||
|
||||
%x comment stringl
|
||||
|
||||
%p 5000
|
||||
|
||||
W [ \t\n]
|
||||
A [_a-z]
|
||||
D [0-9]
|
||||
I [a-z_]
|
||||
Z [0-9a-z_]
|
||||
E [eE][+-]?{D}+
|
||||
|
||||
%%
|
||||
|
||||
"/*" { BEGIN(comment); }
|
||||
|
||||
<comment>[^*\n]* /* eat anything that's not a '*' */
|
||||
|
||||
<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
|
||||
|
||||
<comment>\n /* new line */
|
||||
|
||||
<comment><<EOF>> {ifs_yyerror ("Unterminated comment");
|
||||
BEGIN(INITIAL);
|
||||
yyterminate(); }
|
||||
|
||||
<comment>"*"+"/" { BEGIN(INITIAL); }
|
||||
|
||||
"\"" { BEGIN(stringl); }
|
||||
|
||||
<stringl>[^\"]* { return TOK_STRING_LITERAL; }
|
||||
|
||||
<stringl>"\"" { BEGIN(INITIAL); }
|
||||
|
||||
<stringl><<EOF>> {ifs_yyerror ("Unterminated string literal");
|
||||
BEGIN(INITIAL);
|
||||
yyterminate(); }
|
||||
|
||||
allowed_types{W}*: {BEGIN CTYPE; return TOK_ALLOWED_TYPES;}
|
||||
vector{W}*: {BEGIN BOOL; return TOK_ARRAY;}
|
||||
vector_bounds{W}*: {return TOK_ARRAY_BOUNDS;}
|
||||
c_function_name{W}*: {return TOK_C_FUNCTION_NAME;}
|
||||
port_name{W}*: {return TOK_PORT_NAME;}
|
||||
port_table{W}*: {return TOK_PORT_TABLE;}
|
||||
data_type{W}*: {BEGIN DTYPE; return TOK_DATA_TYPE;}
|
||||
default_type{W}*: {BEGIN CTYPE; return TOK_DEFAULT_TYPE;}
|
||||
default_value{W}*: {return TOK_DEFAULT_VALUE;}
|
||||
description{W}*: {return TOK_DESCRIPTION;}
|
||||
direction{W}*: {BEGIN DIR; return TOK_DIRECTION;}
|
||||
static_var_name{W}*: {return TOK_STATIC_VAR_NAME;}
|
||||
static_var_table{W}*: {return TOK_STATIC_VAR_TABLE;}
|
||||
limits{W}*: {return TOK_LIMITS;}
|
||||
name_table{W}*: {return TOK_NAME_TABLE;}
|
||||
null_allowed{W}*: {BEGIN BOOL; return TOK_NULL_ALLOWED;}
|
||||
parameter_name{W}*: {return TOK_PARAMETER_NAME;}
|
||||
parameter_table{W}*: {return TOK_PARAMETER_TABLE;}
|
||||
spice_model_name{W}*: {return TOK_SPICE_MODEL_NAME;}
|
||||
|
||||
<BOOL>yes {return TOK_BOOL_YES;}
|
||||
<BOOL>no {return TOK_BOOL_NO;}
|
||||
true {return TOK_BOOL_YES;}
|
||||
false {return TOK_BOOL_NO;}
|
||||
|
||||
<CTYPE>v {return TOK_CTYPE_V;}
|
||||
<CTYPE>vd {return TOK_CTYPE_VD;}
|
||||
<CTYPE>vnam {return TOK_CTYPE_VNAM;}
|
||||
<CTYPE>i {return TOK_CTYPE_I;}
|
||||
<CTYPE>id {return TOK_CTYPE_ID;}
|
||||
<CTYPE>g {return TOK_CTYPE_G;}
|
||||
<CTYPE>gd {return TOK_CTYPE_GD;}
|
||||
<CTYPE>h {return TOK_CTYPE_H;}
|
||||
<CTYPE>hd {return TOK_CTYPE_HD;}
|
||||
<CTYPE>d {return TOK_CTYPE_D;}
|
||||
|
||||
<DIR>in {return TOK_DIR_IN;}
|
||||
<DIR>out {return TOK_DIR_OUT;}
|
||||
<DIR>inout {return TOK_DIR_INOUT;}
|
||||
|
||||
<DTYPE>real {return TOK_DTYPE_REAL;}
|
||||
<DTYPE>int {return TOK_DTYPE_INT;}
|
||||
<DTYPE>boolean {return TOK_DTYPE_BOOLEAN;}
|
||||
<DTYPE>complex {return TOK_DTYPE_COMPLEX;}
|
||||
<DTYPE>string {return TOK_DTYPE_STRING;}
|
||||
<DTYPE>pointer {return TOK_DTYPE_POINTER;}
|
||||
|
||||
"<" {return TOK_LANGLE;}
|
||||
">" {return TOK_RANGLE;}
|
||||
"[" {return TOK_LBRACKET;}
|
||||
"]" {return TOK_RBRACKET;}
|
||||
"," {return TOK_COMMA;}
|
||||
"-" {return TOK_DASH;}
|
||||
|
||||
|
||||
{I}+{Z}* {return TOK_IDENTIFIER;}
|
||||
|
||||
[+-]?{D}+ {yyival = atoi (yytext);
|
||||
return TOK_INT_LITERAL;}
|
||||
|
||||
[+-]?{D}+"."{D}*({E})? |
|
||||
[+-]?{D}*"."{D}+({E})? |
|
||||
[+-]?{D}+({E})? {yydval = atof (yytext);
|
||||
return TOK_REAL_LITERAL;}
|
||||
|
||||
. ; /* ignore anything else */
|
||||
\n ; /* ignore anything else */
|
||||
|
||||
%%
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void reset_lex_context ()
|
||||
{
|
||||
BEGIN 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*============================================================================
|
||||
FILE ifs_yacc.h
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
Typedefs needed by the YYSTYPE union (%union operator) in the yacc
|
||||
file. These are only used in the yacc file, but must be defined here since
|
||||
the generated token.h file includes a definition of the union YYSTYPE.
|
||||
|
||||
INTERFACES
|
||||
|
||||
None.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "cmpp.h"
|
||||
|
||||
typedef struct {
|
||||
Boolean_t has_value;
|
||||
Data_Type_t kind;
|
||||
union {
|
||||
Boolean_t bvalue;
|
||||
int ivalue;
|
||||
double rvalue;
|
||||
Complex_t cvalue;
|
||||
char *svalue;
|
||||
} u;
|
||||
} My_Value_t;
|
||||
|
||||
typedef struct {
|
||||
Boolean_t has_bound;
|
||||
My_Value_t bound;
|
||||
} Bound_t;
|
||||
|
||||
typedef struct {
|
||||
Boolean_t is_named;
|
||||
union {
|
||||
char *name;
|
||||
struct {
|
||||
Bound_t upper;
|
||||
Bound_t lower;
|
||||
} bounds;
|
||||
} u;
|
||||
} Range_t;
|
||||
|
||||
typedef struct {
|
||||
Port_Type_t kind;
|
||||
char *id; /* undefined unless kind == USER_DEFINED */
|
||||
} My_Port_Type_t;
|
||||
|
||||
typedef struct ctype_list_s {
|
||||
My_Port_Type_t ctype;
|
||||
struct ctype_list_s *next;
|
||||
} Ctype_List_t;
|
||||
|
|
@ -0,0 +1,901 @@
|
|||
%{ /* $Id$ */
|
||||
|
||||
/*============================================================================
|
||||
FILE ifs_yacc.y
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
12/31/91 Bill Kuhn Fix bug in usage of strcmp in check_default_type()
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains the BNF specification of the language used in
|
||||
the ifspec.ifs file together with various support functions,
|
||||
and parses the ifspec.ifs file to get the information from it
|
||||
and place this information into a data structure
|
||||
of type Ifs_Table_t.
|
||||
|
||||
INTERFACES
|
||||
|
||||
yyparse() - Generated automatically by UNIX 'yacc' utility.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
ifs_lex.l
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "ifs_yacc.h"
|
||||
|
||||
extern int yylineno;
|
||||
extern int yyival;
|
||||
extern double yydval;
|
||||
extern char *ifs_yytext;
|
||||
extern char *strdup();
|
||||
|
||||
Boolean_t parser_just_names;
|
||||
static Boolean_t saw_model_name;
|
||||
static Boolean_t saw_function_name;
|
||||
|
||||
static char *dtype_to_str[] = {
|
||||
"BOOLEAN", "INTEGER", "REAL", "COMPLEX", "STRING", "POINTER"
|
||||
};
|
||||
|
||||
static Boolean_t did_default_type;
|
||||
static Boolean_t did_allowed_types;
|
||||
|
||||
static int num_items;
|
||||
static int item;
|
||||
static int item_offset;
|
||||
static Boolean_t num_items_fixed;
|
||||
|
||||
Ifs_Table_t *parser_ifs_table;
|
||||
#define TBL parser_ifs_table
|
||||
|
||||
static int alloced_size [4];
|
||||
|
||||
/*
|
||||
* !!!!! Make sure these are large enough so that they never get realloced
|
||||
* !!!!! since that will cause garbage uninitialized data...
|
||||
* !!!!! (FIX THIS!)
|
||||
*/
|
||||
#define DEFAULT_SIZE_CONN 100
|
||||
#define DEFAULT_SIZE_PARAM 100
|
||||
#define DEFAULT_SIZE_INST_VAR 100
|
||||
#define GROW_SIZE 10
|
||||
|
||||
typedef enum {
|
||||
TBL_NAME,
|
||||
TBL_PORT,
|
||||
TBL_PARAMETER,
|
||||
TBL_STATIC_VAR,
|
||||
} Table_t;
|
||||
|
||||
typedef struct {
|
||||
Table_t table;
|
||||
int record;
|
||||
} Context_t;
|
||||
|
||||
Context_t context;
|
||||
|
||||
#define ITEM_BUFFER_SIZE 20 /* number of items that can be put in a table
|
||||
* before requiring a new xxx_TABLE: keyword
|
||||
*/
|
||||
#define FOR_ITEM(i) for (i = item_offset; i < num_items; i++)
|
||||
#define ITEM_BUF(i) item_buffer[i-item_offset]
|
||||
|
||||
#define ASSIGN_BOUNDS(struct_name, i) \
|
||||
if (ITEM_BUF(i).range.is_named) {\
|
||||
TBL->struct_name[i].has_conn_ref = TRUE;\
|
||||
TBL->struct_name[i].conn_ref = find_conn_ref (ITEM_BUF(i).range.u.name);\
|
||||
} else {\
|
||||
TBL->struct_name[i].has_conn_ref = FALSE;\
|
||||
TBL->struct_name[i].has_lower_bound =\
|
||||
ITEM_BUF(i).range.u.bounds.lower.has_bound;\
|
||||
TBL->struct_name[i].has_upper_bound =\
|
||||
ITEM_BUF(i).range.u.bounds.upper.has_bound;\
|
||||
if (TBL->struct_name[i].has_lower_bound) {\
|
||||
assert (ITEM_BUF(i).range.u.bounds.lower.bound.kind == INTEGER);\
|
||||
TBL->struct_name[i].lower_bound =\
|
||||
ITEM_BUF(i).range.u.bounds.lower.bound.u.ivalue;\
|
||||
}\
|
||||
if (TBL->struct_name[i].has_upper_bound) {\
|
||||
assert (ITEM_BUF(i).range.u.bounds.upper.bound.kind == INTEGER);\
|
||||
TBL->struct_name[i].upper_bound =\
|
||||
ITEM_BUF(i).range.u.bounds.upper.bound.u.ivalue;\
|
||||
}\
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void fatal (char *str)
|
||||
{
|
||||
yyerror (str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int find_conn_ref (name)
|
||||
char *name;
|
||||
{
|
||||
int i;
|
||||
char str[130];
|
||||
|
||||
for (i = 0; i < TBL->num_conn; i++) {
|
||||
if (strcmp (name, TBL->conn[i].name) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
sprintf (str, "Port `%s' not found", name);
|
||||
yyerror (str);
|
||||
}
|
||||
|
||||
typedef enum {C_DOUBLE, C_BOOLEAN, C_POINTER, C_UNDEF} Ctype_Class_t;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static Ctype_Class_t get_ctype_class (Port_Type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case USER_DEFINED:
|
||||
return C_POINTER;
|
||||
break;
|
||||
case DIGITAL:
|
||||
return C_BOOLEAN;
|
||||
break;
|
||||
default:
|
||||
return C_DOUBLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_port_type_direction (Dir_t dir, Port_Type_t port_type)
|
||||
{
|
||||
switch (port_type) {
|
||||
case VOLTAGE:
|
||||
case DIFF_VOLTAGE:
|
||||
case CURRENT:
|
||||
case DIFF_CURRENT:
|
||||
case DIGITAL:
|
||||
case USER_DEFINED:
|
||||
/*
|
||||
* anything goes
|
||||
*/
|
||||
break;
|
||||
case VSOURCE_CURRENT:
|
||||
if (dir != IN) {
|
||||
yyerror ("Port type `vnam' is only valid for `in' ports");
|
||||
}
|
||||
break;
|
||||
case CONDUCTANCE:
|
||||
case DIFF_CONDUCTANCE:
|
||||
case RESISTANCE:
|
||||
case DIFF_RESISTANCE:
|
||||
if (dir != INOUT) {
|
||||
yyerror ("Port types `g', `gd', `h', `hd' are only valid for `inout' ports");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_dtype_not_pointer (Data_Type_t dtype)
|
||||
{
|
||||
if (dtype == POINTER) {
|
||||
yyerror("Invalid parameter type - POINTER type valid only for STATIC_VARs");
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_default_type (Conn_Info_t conn)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < conn.num_allowed_types; i++) {
|
||||
if (conn.default_port_type == conn.allowed_port_type[i]) {
|
||||
if ((conn.default_port_type != USER_DEFINED) ||
|
||||
(strcmp (conn.default_type, conn.allowed_type[i]) == 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
yyerror ("Port default type is not an allowed type");
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void assign_ctype_list (conn, ctype_list)
|
||||
Conn_Info_t *conn;
|
||||
Ctype_List_t *ctype_list;
|
||||
{
|
||||
int i;
|
||||
Ctype_List_t *p;
|
||||
Ctype_Class_t class = C_UNDEF;
|
||||
|
||||
conn->num_allowed_types = 0;
|
||||
for (p = ctype_list; p; p = p->next) {
|
||||
conn->num_allowed_types++;
|
||||
}
|
||||
conn->allowed_type = (char**) calloc (conn->num_allowed_types,
|
||||
sizeof (char*));
|
||||
conn->allowed_port_type = (Port_Type_t*) calloc (conn->num_allowed_types,
|
||||
sizeof (Port_Type_t));
|
||||
if (! (conn->allowed_type && conn->allowed_port_type)) {
|
||||
fatal ("Could not allocate memory");
|
||||
}
|
||||
for (i = conn->num_allowed_types-1, p = ctype_list; p; i--, p = p->next) {
|
||||
if (class == C_UNDEF) {
|
||||
class = get_ctype_class (p->ctype.kind);
|
||||
}
|
||||
if (class != get_ctype_class (p->ctype.kind)) {
|
||||
yyerror ("Incompatible port types in `allowed_types' clause");
|
||||
}
|
||||
check_port_type_direction (conn->direction, p->ctype.kind);
|
||||
|
||||
conn->allowed_port_type[i] = p->ctype.kind;
|
||||
conn->allowed_type[i] = p->ctype.id;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void assign_value (type, dest_value, src_value)
|
||||
Data_Type_t type;
|
||||
Value_t *dest_value;
|
||||
My_Value_t src_value;
|
||||
{
|
||||
char str[200];
|
||||
if ((type == REAL) && (src_value.kind == INTEGER)) {
|
||||
dest_value->rvalue = src_value.u.ivalue;
|
||||
return;
|
||||
} else if (type != src_value.kind) {
|
||||
sprintf (str, "Invalid parameter type (saw %s - expected %s)",
|
||||
dtype_to_str[src_value.kind],
|
||||
dtype_to_str[type] );
|
||||
yyerror (str);
|
||||
}
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
dest_value->bvalue = src_value.u.bvalue;
|
||||
break;
|
||||
case INTEGER:
|
||||
dest_value->ivalue = src_value.u.ivalue;
|
||||
break;
|
||||
case REAL:
|
||||
dest_value->rvalue = src_value.u.rvalue;
|
||||
break;
|
||||
case COMPLEX:
|
||||
dest_value->cvalue = src_value.u.cvalue;
|
||||
break;
|
||||
case STRING:
|
||||
dest_value->svalue = src_value.u.svalue;
|
||||
break;
|
||||
default:
|
||||
yyerror ("INTERNAL ERROR - unexpected data type in `assign_value'");
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void assign_limits (type, param, range)
|
||||
Data_Type_t type;
|
||||
Param_Info_t *param;
|
||||
Range_t range;
|
||||
{
|
||||
if (range.is_named) {
|
||||
yyerror ("Named range not allowed for limits");
|
||||
}
|
||||
param->has_lower_limit = range.u.bounds.lower.has_bound;
|
||||
if (param->has_lower_limit) {
|
||||
assign_value (type, ¶m->lower_limit, range.u.bounds.lower.bound);
|
||||
}
|
||||
param->has_upper_limit = range.u.bounds.upper.has_bound;
|
||||
if (param->has_upper_limit) {
|
||||
assign_value (type, ¶m->upper_limit, range.u.bounds.upper.bound);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_item_num ()
|
||||
{
|
||||
if (item-item_offset >= ITEM_BUFFER_SIZE) {
|
||||
fatal ("Too many items in table - split into sub-tables");
|
||||
}
|
||||
if (item > alloced_size [context.table] ) {
|
||||
switch (context.table) {
|
||||
case TBL_NAME:
|
||||
break;
|
||||
case TBL_PORT:
|
||||
alloced_size[context.table] += GROW_SIZE;
|
||||
TBL->conn = (Conn_Info_t*)
|
||||
realloc (TBL->conn,
|
||||
alloced_size [context.table] * sizeof (Conn_Info_t));
|
||||
if (! TBL->conn) {
|
||||
fatal ("Error allocating memory for port definition");
|
||||
}
|
||||
break;
|
||||
case TBL_PARAMETER:
|
||||
alloced_size [context.table] += GROW_SIZE;
|
||||
TBL->param = (Param_Info_t*)
|
||||
realloc (TBL->param,
|
||||
alloced_size [context.table] * sizeof (Param_Info_t));
|
||||
if (! TBL->param) {
|
||||
fatal ("Error allocating memory for parameter definition");
|
||||
}
|
||||
break;
|
||||
case TBL_STATIC_VAR:
|
||||
alloced_size [context.table] += GROW_SIZE;
|
||||
TBL->inst_var = (Inst_Var_Info_t*)
|
||||
realloc (TBL->inst_var,
|
||||
alloced_size [context.table] * sizeof (Inst_Var_Info_t));
|
||||
if (! TBL->inst_var) {
|
||||
fatal ("Error allocating memory for static variable definition");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
item++;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_end_item_num ()
|
||||
{
|
||||
if (num_items_fixed) {
|
||||
if (item != num_items) {
|
||||
char buf[200];
|
||||
sprintf
|
||||
(buf,
|
||||
"Wrong number of elements in sub-table (saw %d - expected %d)",
|
||||
item - item_offset,
|
||||
num_items - item_offset);
|
||||
fatal (buf);
|
||||
}
|
||||
} else {
|
||||
num_items = item;
|
||||
num_items_fixed = TRUE;
|
||||
switch (context.table) {
|
||||
case TBL_NAME:
|
||||
break;
|
||||
case TBL_PORT:
|
||||
TBL->num_conn = num_items;
|
||||
break;
|
||||
case TBL_PARAMETER:
|
||||
TBL->num_param = num_items;
|
||||
break;
|
||||
case TBL_STATIC_VAR:
|
||||
TBL->num_inst_var = num_items;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item = item_offset;
|
||||
}
|
||||
|
||||
#define INIT(n) item = (n); item_offset = (n); num_items = (n); num_items_fixed = FALSE
|
||||
#define ITEM check_item_num()
|
||||
#define END check_end_item_num()
|
||||
|
||||
%}
|
||||
|
||||
%token TOK_ALLOWED_TYPES
|
||||
%token TOK_ARRAY
|
||||
%token TOK_ARRAY_BOUNDS
|
||||
%token TOK_BOOL_NO
|
||||
%token TOK_BOOL_YES
|
||||
%token TOK_COMMA
|
||||
%token TOK_PORT_NAME
|
||||
%token TOK_PORT_TABLE
|
||||
%token TOK_CTYPE_D
|
||||
%token TOK_CTYPE_G
|
||||
%token TOK_CTYPE_GD
|
||||
%token TOK_CTYPE_H
|
||||
%token TOK_CTYPE_HD
|
||||
%token TOK_CTYPE_I
|
||||
%token TOK_CTYPE_ID
|
||||
%token TOK_CTYPE_V
|
||||
%token TOK_CTYPE_VD
|
||||
%token TOK_CTYPE_VNAM
|
||||
%token TOK_C_FUNCTION_NAME
|
||||
%token TOK_DASH
|
||||
%token TOK_DATA_TYPE
|
||||
%token TOK_DEFAULT_TYPE
|
||||
%token TOK_DEFAULT_VALUE
|
||||
%token TOK_DESCRIPTION
|
||||
%token TOK_DIRECTION
|
||||
%token TOK_DIR_IN
|
||||
%token TOK_DIR_INOUT
|
||||
%token TOK_DIR_OUT
|
||||
%token TOK_DTYPE_BOOLEAN
|
||||
%token TOK_DTYPE_COMPLEX
|
||||
%token TOK_DTYPE_INT
|
||||
%token TOK_DTYPE_POINTER
|
||||
%token TOK_DTYPE_REAL
|
||||
%token TOK_DTYPE_STRING
|
||||
%token TOK_IDENTIFIER
|
||||
%token TOK_STATIC_VAR_NAME
|
||||
%token TOK_STATIC_VAR_TABLE
|
||||
%token TOK_INT_LITERAL
|
||||
%token TOK_LANGLE
|
||||
%token TOK_LBRACKET
|
||||
%token TOK_LIMITS
|
||||
%token TOK_NAME_TABLE
|
||||
%token TOK_NULL_ALLOWED
|
||||
%token TOK_PARAMETER_NAME
|
||||
%token TOK_PARAMETER_TABLE
|
||||
%token TOK_RANGLE
|
||||
%token TOK_RBRACKET
|
||||
%token TOK_REAL_LITERAL
|
||||
%token TOK_SPICE_MODEL_NAME
|
||||
%token TOK_STRING_LITERAL
|
||||
|
||||
%union {
|
||||
Ctype_List_t *ctype_list;
|
||||
Dir_t dir;
|
||||
Boolean_t bool;
|
||||
Range_t range;
|
||||
Data_Type_t dtype;
|
||||
My_Port_Type_t ctype;
|
||||
My_Value_t value;
|
||||
char *str;
|
||||
Bound_t bound;
|
||||
int ival;
|
||||
double rval;
|
||||
Complex_t cval;
|
||||
}
|
||||
|
||||
%type <ctype_list> ctype_list delimited_ctype_list
|
||||
%type <dir> direction
|
||||
%type <ctype> ctype
|
||||
%type <dtype> dtype
|
||||
%type <range> range int_range
|
||||
%type <value> value number integer_value value_or_dash
|
||||
%type <str> identifier string
|
||||
%type <bool> bool
|
||||
%type <bound> int_or_dash number_or_dash
|
||||
%type <ival> integer
|
||||
%type <rval> real
|
||||
%type <cval> complex
|
||||
|
||||
%start ifs_file
|
||||
|
||||
%{
|
||||
/*
|
||||
* resuse the Yacc union for our buffer:
|
||||
*/
|
||||
YYSTYPE item_buffer [ITEM_BUFFER_SIZE];
|
||||
|
||||
/*
|
||||
* Shorthand for refering to the current element of the item buffer:
|
||||
*/
|
||||
#define BUF ITEM_BUF(item-1)
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
ifs_file : {TBL->num_conn = 0;
|
||||
TBL->num_param = 0;
|
||||
TBL->num_inst_var = 0;
|
||||
|
||||
saw_function_name = FALSE;
|
||||
saw_model_name = FALSE;
|
||||
|
||||
alloced_size [TBL_PORT] = DEFAULT_SIZE_CONN;
|
||||
alloced_size [TBL_PARAMETER] = DEFAULT_SIZE_PARAM;
|
||||
alloced_size [TBL_STATIC_VAR] =
|
||||
DEFAULT_SIZE_INST_VAR;
|
||||
|
||||
TBL->conn = (Conn_Info_t*)
|
||||
calloc (DEFAULT_SIZE_CONN,
|
||||
sizeof (Conn_Info_t));
|
||||
TBL->param = (Param_Info_t*)
|
||||
calloc (DEFAULT_SIZE_PARAM,
|
||||
sizeof (Param_Info_t));
|
||||
TBL->inst_var = (Inst_Var_Info_t*)
|
||||
calloc (DEFAULT_SIZE_INST_VAR,
|
||||
sizeof (Inst_Var_Info_t));
|
||||
if (! (TBL->conn && TBL->param &&
|
||||
TBL->inst_var) ) {
|
||||
fatal ("Could not allocate enough memory");
|
||||
}
|
||||
}
|
||||
list_of_tables
|
||||
;
|
||||
|
||||
list_of_tables : table
|
||||
| list_of_tables table
|
||||
;
|
||||
|
||||
table : TOK_NAME_TABLE
|
||||
{context.table = TBL_NAME;}
|
||||
name_table
|
||||
| TOK_PORT_TABLE
|
||||
{context.table = TBL_PORT;
|
||||
did_default_type = FALSE;
|
||||
did_allowed_types = FALSE;
|
||||
INIT (TBL->num_conn);}
|
||||
port_table
|
||||
{TBL->num_conn = num_items;}
|
||||
| TOK_PARAMETER_TABLE
|
||||
{context.table = TBL_PARAMETER;
|
||||
INIT (TBL->num_param);}
|
||||
parameter_table
|
||||
{TBL->num_param = num_items;}
|
||||
| TOK_STATIC_VAR_TABLE
|
||||
{context.table = TBL_STATIC_VAR;
|
||||
INIT (TBL->num_inst_var);}
|
||||
static_var_table
|
||||
{TBL->num_inst_var = num_items;}
|
||||
;
|
||||
|
||||
name_table : /* empty */
|
||||
| name_table name_table_item
|
||||
;
|
||||
|
||||
name_table_item : TOK_C_FUNCTION_NAME identifier
|
||||
{TBL->name.c_fcn_name =strdup (ifs_yytext);
|
||||
saw_function_name = TRUE;
|
||||
if (parser_just_names && saw_model_name) return 0;}
|
||||
| TOK_SPICE_MODEL_NAME identifier
|
||||
{TBL->name.model_name = strdup (ifs_yytext);
|
||||
saw_model_name = TRUE;
|
||||
if (parser_just_names && saw_function_name) return 0;}
|
||||
| TOK_DESCRIPTION string
|
||||
{TBL->name.description = strdup (ifs_yytext);}
|
||||
;
|
||||
|
||||
port_table : /* empty */
|
||||
| port_table port_table_item
|
||||
;
|
||||
|
||||
port_table_item : TOK_PORT_NAME list_of_ids
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->conn[i].name = ITEM_BUF(i).str;
|
||||
}}
|
||||
| TOK_DESCRIPTION list_of_strings
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->conn[i].description = ITEM_BUF(i).str;
|
||||
}}
|
||||
| TOK_DIRECTION list_of_directions
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->conn[i].direction = ITEM_BUF(i).dir;
|
||||
}}
|
||||
| TOK_DEFAULT_TYPE list_of_ctypes
|
||||
{int i;
|
||||
END;
|
||||
did_default_type = TRUE;
|
||||
FOR_ITEM (i) {
|
||||
TBL->conn[i].default_port_type =
|
||||
ITEM_BUF(i).ctype.kind;
|
||||
TBL->conn[i].default_type = ITEM_BUF(i).ctype.id;
|
||||
if (did_allowed_types) {
|
||||
check_default_type (TBL->conn[i]);
|
||||
}
|
||||
}}
|
||||
| TOK_ALLOWED_TYPES list_of_ctype_lists
|
||||
{int i;
|
||||
END;
|
||||
did_allowed_types = TRUE;
|
||||
FOR_ITEM (i) {
|
||||
assign_ctype_list (&TBL->conn[i],
|
||||
ITEM_BUF(i).ctype_list);
|
||||
if (did_default_type) {
|
||||
check_default_type (TBL->conn[i]);
|
||||
}
|
||||
}}
|
||||
| TOK_ARRAY list_of_bool
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->conn[i].is_array = ITEM_BUF(i).bool;
|
||||
}}
|
||||
| TOK_ARRAY_BOUNDS list_of_array_bounds
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
ASSIGN_BOUNDS (conn, i);
|
||||
assert (!TBL->conn[i].has_conn_ref);
|
||||
}}
|
||||
| TOK_NULL_ALLOWED list_of_bool
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->conn[i].null_allowed = ITEM_BUF(i).bool;
|
||||
}}
|
||||
;
|
||||
|
||||
parameter_table : /* empty */
|
||||
| parameter_table parameter_table_item
|
||||
;
|
||||
|
||||
parameter_table_item : TOK_PARAMETER_NAME list_of_ids
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->param[i].name = ITEM_BUF(i).str;
|
||||
}}
|
||||
| TOK_DESCRIPTION list_of_strings
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->param[i].description = ITEM_BUF(i).str;
|
||||
}}
|
||||
| TOK_DATA_TYPE list_of_dtypes
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
check_dtype_not_pointer (ITEM_BUF(i).dtype);
|
||||
TBL->param[i].type = ITEM_BUF(i).dtype;
|
||||
}}
|
||||
| TOK_DEFAULT_VALUE list_of_values
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->param[i].has_default =
|
||||
ITEM_BUF(i).value.has_value;
|
||||
if (TBL->param[i].has_default) {
|
||||
assign_value (TBL->param[i].type,
|
||||
&TBL->param[i].default_value,
|
||||
ITEM_BUF(i).value);
|
||||
}
|
||||
}}
|
||||
| TOK_LIMITS list_of_ranges
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
assign_limits (TBL->param[i].type,
|
||||
&TBL->param[i],
|
||||
ITEM_BUF(i).range);
|
||||
}}
|
||||
| TOK_ARRAY list_of_bool
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->param[i].is_array = ITEM_BUF(i).bool;
|
||||
}}
|
||||
| TOK_ARRAY_BOUNDS list_of_array_bounds
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
ASSIGN_BOUNDS (param, i);
|
||||
}}
|
||||
| TOK_NULL_ALLOWED list_of_bool
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->param[i].null_allowed = ITEM_BUF(i).bool;
|
||||
}}
|
||||
;
|
||||
|
||||
static_var_table : /* empty */
|
||||
| static_var_table static_var_table_item
|
||||
;
|
||||
|
||||
static_var_table_item : TOK_STATIC_VAR_NAME list_of_ids
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->inst_var[i].name = ITEM_BUF(i).str;
|
||||
}}
|
||||
| TOK_DESCRIPTION list_of_strings
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->inst_var[i].description = ITEM_BUF(i).str;
|
||||
}}
|
||||
| TOK_DATA_TYPE list_of_dtypes
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->inst_var[i].type = ITEM_BUF(i).dtype;
|
||||
}}
|
||||
| TOK_ARRAY list_of_bool
|
||||
{int i;
|
||||
END;
|
||||
FOR_ITEM (i) {
|
||||
TBL->inst_var[i].is_array = ITEM_BUF(i).bool;
|
||||
}}
|
||||
;
|
||||
|
||||
list_of_ids : /* empty */
|
||||
| list_of_ids identifier {ITEM; BUF.str = $2;}
|
||||
;
|
||||
|
||||
list_of_array_bounds : /* empty */
|
||||
| list_of_array_bounds int_range
|
||||
{ITEM;
|
||||
BUF.range = $2;}
|
||||
| list_of_array_bounds identifier
|
||||
{ITEM;
|
||||
BUF.range.is_named = TRUE;
|
||||
BUF.range.u.name = $2;}
|
||||
;
|
||||
|
||||
list_of_strings : /* empty */
|
||||
| list_of_strings string {ITEM; BUF.str = $2;}
|
||||
;
|
||||
|
||||
list_of_directions : /* empty */
|
||||
| list_of_directions direction {ITEM; BUF.dir = $2;}
|
||||
;
|
||||
|
||||
direction : TOK_DIR_IN {$$ = IN;}
|
||||
| TOK_DIR_OUT {$$ = OUT;}
|
||||
| TOK_DIR_INOUT {$$ = INOUT;}
|
||||
;
|
||||
|
||||
list_of_bool : /* empty */
|
||||
| list_of_bool bool {ITEM; BUF.bool = $2;}
|
||||
;
|
||||
|
||||
list_of_ctypes : /* empty */
|
||||
| list_of_ctypes ctype {ITEM; BUF.ctype = $2;}
|
||||
;
|
||||
|
||||
ctype : TOK_CTYPE_V {$$.kind = VOLTAGE;}
|
||||
| TOK_CTYPE_VD {$$.kind = DIFF_VOLTAGE;}
|
||||
| TOK_CTYPE_VNAM {$$.kind = VSOURCE_CURRENT;}
|
||||
| TOK_CTYPE_I {$$.kind = CURRENT;}
|
||||
| TOK_CTYPE_ID {$$.kind = DIFF_CURRENT;}
|
||||
| TOK_CTYPE_G {$$.kind = CONDUCTANCE;}
|
||||
| TOK_CTYPE_GD {$$.kind = DIFF_CONDUCTANCE;}
|
||||
| TOK_CTYPE_H {$$.kind = RESISTANCE;}
|
||||
| TOK_CTYPE_HD {$$.kind = DIFF_RESISTANCE;}
|
||||
| TOK_CTYPE_D {$$.kind = DIGITAL;}
|
||||
| identifier {$$.kind = USER_DEFINED;
|
||||
$$.id = $1;}
|
||||
;
|
||||
|
||||
list_of_dtypes : /* empty */
|
||||
| list_of_dtypes dtype {ITEM; BUF.dtype = $2;}
|
||||
;
|
||||
|
||||
dtype : TOK_DTYPE_REAL {$$ = REAL;}
|
||||
| TOK_DTYPE_INT {$$ = INTEGER;}
|
||||
| TOK_DTYPE_BOOLEAN {$$ = BOOLEAN;}
|
||||
| TOK_DTYPE_COMPLEX {$$ = COMPLEX;}
|
||||
| TOK_DTYPE_STRING {$$ = STRING;}
|
||||
| TOK_DTYPE_POINTER {$$ = POINTER;}
|
||||
;
|
||||
|
||||
list_of_ranges : /* empty */
|
||||
| list_of_ranges range {ITEM; BUF.range = $2;}
|
||||
;
|
||||
|
||||
int_range : TOK_DASH {$$.is_named = FALSE;
|
||||
$$.u.bounds.lower.has_bound = FALSE;
|
||||
$$.u.bounds.upper.has_bound = FALSE;}
|
||||
| TOK_LBRACKET int_or_dash maybe_comma int_or_dash
|
||||
TOK_RBRACKET
|
||||
{$$.is_named = FALSE;
|
||||
$$.u.bounds.lower = $2;
|
||||
$$.u.bounds.upper = $4;}
|
||||
;
|
||||
|
||||
maybe_comma : /* empty */
|
||||
| TOK_COMMA
|
||||
;
|
||||
|
||||
int_or_dash : TOK_DASH {$$.has_bound = FALSE;}
|
||||
| integer_value {$$.has_bound = TRUE;
|
||||
$$.bound = $1;}
|
||||
;
|
||||
|
||||
range : TOK_DASH {$$.is_named = FALSE;
|
||||
$$.u.bounds.lower.has_bound = FALSE;
|
||||
$$.u.bounds.upper.has_bound = FALSE;}
|
||||
| TOK_LBRACKET number_or_dash maybe_comma
|
||||
number_or_dash TOK_RBRACKET
|
||||
{$$.is_named = FALSE;
|
||||
$$.u.bounds.lower = $2;
|
||||
$$.u.bounds.upper = $4;}
|
||||
;
|
||||
|
||||
number_or_dash : TOK_DASH {$$.has_bound = FALSE;}
|
||||
| number {$$.has_bound = TRUE;
|
||||
$$.bound = $1;}
|
||||
;
|
||||
|
||||
list_of_values : /* empty */
|
||||
| list_of_values value_or_dash {ITEM; BUF.value = $2;}
|
||||
;
|
||||
|
||||
value_or_dash : TOK_DASH {$$.has_value = FALSE;}
|
||||
| value
|
||||
;
|
||||
|
||||
value : string {$$.has_value = TRUE;
|
||||
$$.kind = STRING;
|
||||
$$.u.svalue = $1;}
|
||||
| bool {$$.has_value = TRUE;
|
||||
$$.kind = BOOLEAN;
|
||||
$$.u.bvalue = $1;}
|
||||
| complex {$$.has_value = TRUE;
|
||||
$$.kind = COMPLEX;
|
||||
$$.u.cvalue = $1;}
|
||||
| number
|
||||
;
|
||||
|
||||
complex : TOK_LANGLE real maybe_comma real TOK_RANGLE
|
||||
{$$.real = $2;
|
||||
$$.imag = $4;}
|
||||
;
|
||||
|
||||
list_of_ctype_lists : /* empty */
|
||||
| list_of_ctype_lists delimited_ctype_list
|
||||
{ITEM; BUF.ctype_list = $2;}
|
||||
;
|
||||
|
||||
delimited_ctype_list : TOK_LBRACKET ctype_list TOK_RBRACKET {$$ = $2;}
|
||||
;
|
||||
|
||||
ctype_list : ctype
|
||||
{$$ = (Ctype_List_t*)calloc (1,
|
||||
sizeof (Ctype_List_t));
|
||||
if (!$$) {
|
||||
fatal ("Error allocating memory");
|
||||
}
|
||||
$$->ctype = $1;
|
||||
$$->next = (Ctype_List_t*)0;}
|
||||
| ctype_list maybe_comma ctype
|
||||
{$$ = (Ctype_List_t*)calloc (1,
|
||||
sizeof (Ctype_List_t));
|
||||
if (!$$) {
|
||||
fatal ("Error allocating memory");
|
||||
}
|
||||
$$->ctype = $3;
|
||||
$$->next = $1;
|
||||
/*$$->next = (Ctype_List_t*)0;
|
||||
assert ($1);
|
||||
$1->next = $$;*/}
|
||||
;
|
||||
|
||||
bool : TOK_BOOL_YES {$$ = TRUE;}
|
||||
| TOK_BOOL_NO {$$ = FALSE;}
|
||||
;
|
||||
|
||||
string : TOK_STRING_LITERAL {$$ = strdup(ifs_yytext);}
|
||||
;
|
||||
|
||||
identifier : TOK_IDENTIFIER {$$ = strdup(ifs_yytext);}
|
||||
;
|
||||
|
||||
number : real {$$.has_value = TRUE;
|
||||
$$.kind = REAL;
|
||||
$$.u.rvalue = $1;}
|
||||
| integer_value
|
||||
;
|
||||
|
||||
integer_value : integer {$$.has_value = TRUE;
|
||||
$$.kind = INTEGER;
|
||||
$$.u.ivalue = $1;}
|
||||
;
|
||||
|
||||
real : TOK_REAL_LITERAL {$$ = yydval;}
|
||||
;
|
||||
|
||||
integer : TOK_INT_LITERAL {$$ = yyival;}
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*============================================================================
|
||||
FILE main.c
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains the top-level function for the Code Model
|
||||
PreProcessor (cmpp). It handles reading the command-line
|
||||
arguments, and then vectors to an appropriate function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
main()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "cmpp.h"
|
||||
|
||||
|
||||
#define USAGE_MSG "Usage: cmpp [-ifs] [-mod [<filename>]] [-lst]"
|
||||
#define TOO_FEW_ARGS "ERROR - Too few arguments"
|
||||
#define TOO_MANY_ARGS "ERROR - Too many arguments"
|
||||
#define UNRECOGNIZED_ARGS "ERROR - Unrecognized argument"
|
||||
|
||||
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
|
||||
/*
|
||||
main
|
||||
|
||||
Function main checks the validity of the command-line arguments
|
||||
supplied when the program is invoked and calls one of the three
|
||||
major functions as appropriate:
|
||||
|
||||
preprocess_ifs_file Process Interface Specification File.
|
||||
preprocess_mod_file Process Model Definition File.
|
||||
preprocess_lst_file Process Pathname List Files.
|
||||
|
||||
depending on the argument.
|
||||
*/
|
||||
|
||||
main(
|
||||
int argc, /* Number of command line arguments */
|
||||
char *argv[]) /* Command line argument text */
|
||||
{
|
||||
|
||||
init_error (argv[0]);
|
||||
|
||||
/* Process command line arguments and vector to appropriate function */
|
||||
|
||||
if(argc < 2) {
|
||||
print_error(TOO_FEW_ARGS);
|
||||
print_error(USAGE_MSG);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(strcmp(argv[1],"-ifs") == 0) {
|
||||
if(argc == 2) {
|
||||
preprocess_ifs_file();
|
||||
}
|
||||
else {
|
||||
print_error(TOO_MANY_ARGS);
|
||||
print_error(USAGE_MSG);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"-lst") == 0) {
|
||||
if(argc == 2) {
|
||||
preprocess_lst_files();
|
||||
}
|
||||
else {
|
||||
print_error(TOO_MANY_ARGS);
|
||||
print_error(USAGE_MSG);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"-mod") == 0) {
|
||||
if(argc == 2) {
|
||||
preprocess_mod_file("cfunc.mod");
|
||||
}
|
||||
else if(argc == 3) {
|
||||
preprocess_mod_file(argv[2]);
|
||||
}
|
||||
else {
|
||||
print_error(TOO_MANY_ARGS);
|
||||
print_error(USAGE_MSG);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
print_error(UNRECOGNIZED_ARGS);
|
||||
print_error(USAGE_MSG);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
%option yylineno
|
||||
%option noyywrap
|
||||
%{ /* $Id$ */
|
||||
|
||||
/*============================================================================
|
||||
FILE mod_lex.l
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file defines tokens applicable to parsing the cfunc.mod
|
||||
file, and actions to be taken on encountering those tokens.
|
||||
|
||||
INTERFACES
|
||||
|
||||
None.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
mod_yacc.y
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "mod_yacc.h"
|
||||
#include "mod_tok.h"
|
||||
|
||||
%}
|
||||
|
||||
I [A-Za-z_]
|
||||
Z [0-9A-Za-z_]
|
||||
|
||||
%%
|
||||
|
||||
"/*" {char ch, last_ch;
|
||||
ECHO; /* a comment - repeat it */
|
||||
ch = '\0';
|
||||
do {
|
||||
last_ch = ch;
|
||||
ch = input();
|
||||
fputc(ch,mod_yyout);
|
||||
} while (ch && !((last_ch == '*') && (ch == '/')));
|
||||
if (!ch) {mod_yyerror ("Unterminated comment");}}
|
||||
|
||||
ARGS {return TOK_ARGS;}
|
||||
INIT {return TOK_INIT;}
|
||||
ANALYSIS {return TOK_ANALYSIS;}
|
||||
NEW_TIMEPOINT {return TOK_NEW_TIMEPOINT;}
|
||||
CALL_TYPE {return TOK_CALL_TYPE;}
|
||||
TIME {return TOK_TIME;}
|
||||
RAD_FREQ {return TOK_RAD_FREQ;}
|
||||
TEMPERATURE {return TOK_TEMPERATURE;}
|
||||
T {return TOK_T;}
|
||||
LOAD {return TOK_LOAD;}
|
||||
TOTAL_LOAD {return TOK_TOTAL_LOAD;}
|
||||
MESSAGE {return TOK_MESSAGE;}
|
||||
PARAM {return TOK_PARAM;}
|
||||
PARAM_SIZE {return TOK_PARAM_SIZE;}
|
||||
PARAM_NULL {return TOK_PARAM_NULL;}
|
||||
PORT_SIZE {return TOK_PORT_SIZE;}
|
||||
PORT_NULL {return TOK_PORT_NULL;}
|
||||
PARTIAL {return TOK_PARTIAL;}
|
||||
AC_GAIN {return TOK_AC_GAIN;}
|
||||
OUTPUT_DELAY {return TOK_OUTPUT_DELAY;}
|
||||
STATIC_VAR {return TOK_STATIC_VAR;}
|
||||
STATIC_VAR_SIZE {return TOK_STATIC_VAR_SIZE;}
|
||||
INPUT {return TOK_INPUT;}
|
||||
INPUT_STATE {return TOK_INPUT_STATE;}
|
||||
INPUT_TYPE {return TOK_INPUT_TYPE;}
|
||||
INPUT_STRENGTH {return TOK_INPUT_STRENGTH;}
|
||||
OUTPUT {return TOK_OUTPUT;}
|
||||
OUTPUT_STATE {return TOK_OUTPUT_STATE;}
|
||||
OUTPUT_STRENGTH {return TOK_OUTPUT_STRENGTH;}
|
||||
OUTPUT_TYPE {return TOK_OUTPUT_TYPE;}
|
||||
OUTPUT_CHANGED {return TOK_OUTPUT_CHANGED;}
|
||||
|
||||
"(" {return TOK_LPAREN;}
|
||||
")" {return TOK_RPAREN;}
|
||||
"[" {return TOK_LBRACKET;}
|
||||
"]" {return TOK_RBRACKET;}
|
||||
"," {return TOK_COMMA;}
|
||||
|
||||
{I}+{Z}* {return TOK_IDENTIFIER;}
|
||||
[ \t] ECHO; /* just eat non-newline whitespace */
|
||||
\n ECHO; /* echo newlines */
|
||||
. {return TOK_MISC_C;}
|
||||
|
||||
%%
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/* $Id$ */
|
||||
|
||||
/*============================================================================
|
||||
FILE mod_yacc.h
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
Typedefs needed by the YYSTYPE union (%union operator) in the yacc
|
||||
file. These are only used in the yacc file, but must be defined here since
|
||||
the generated token.h file includes a definition of the union YYSTYPE.
|
||||
|
||||
INTERFACES
|
||||
|
||||
None.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "cmpp.h"
|
||||
|
||||
typedef struct {
|
||||
char *id;
|
||||
Boolean_t has_subscript;
|
||||
char *subscript;
|
||||
} Sub_Id_t;
|
||||
|
|
@ -0,0 +1,559 @@
|
|||
%{ /* $Id$ */
|
||||
|
||||
/*============================================================================
|
||||
FILE mod_yacc.y
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains a BNF specification of the translation of
|
||||
cfunc.mod files to cfunc.c files, together with various support
|
||||
functions.
|
||||
|
||||
INTERFACES
|
||||
|
||||
mod_yyparse() - Function 'yyparse()' is generated automatically
|
||||
by UNIX 'yacc' utility and then converted to
|
||||
'mod_yyparse()' by UNIX 'sed' utility under
|
||||
direction of Makefile.
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
mod_lex.l
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
Names of functions generated by 'yacc' are translated by 'sed'
|
||||
under direction of the Makefile to prevent collisions with
|
||||
functions generated from ifs_yacc.y.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "mod_yacc.h"
|
||||
|
||||
Ifs_Table_t *mod_ifs_table;
|
||||
|
||||
extern char *mod_yytext;
|
||||
extern FILE* mod_yyout;
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int mod_num_errors;
|
||||
|
||||
#define BUFFER_SIZE 3000
|
||||
static char buffer [BUFFER_SIZE];
|
||||
static int buf_len;
|
||||
|
||||
typedef enum {CONN, PARAM, STATIC_VAR} Id_Kind_t;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static char *subscript (Sub_Id_t sub_id)
|
||||
{
|
||||
if (sub_id.has_subscript) {
|
||||
return sub_id.subscript;
|
||||
} else {
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int strcmpi(s, t)
|
||||
char *s;
|
||||
char *t;
|
||||
/* string compare - case insensitive */
|
||||
{
|
||||
for (; *s && t && tolower(*s) == tolower(*t); s++, t++);
|
||||
if (*s && !*t) {
|
||||
return 1;
|
||||
}
|
||||
if (!*s && *t) {
|
||||
return -1;
|
||||
}
|
||||
if (! (*s || *t)) {
|
||||
return 0;
|
||||
}
|
||||
return (tolower(*s) - tolower(*t));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void put_type (FILE *fp, Data_Type_t type)
|
||||
{
|
||||
char ch;
|
||||
|
||||
switch (type) {
|
||||
case INTEGER:
|
||||
ch = 'i';
|
||||
break;
|
||||
case REAL:
|
||||
ch = 'r';
|
||||
break;
|
||||
case COMPLEX:
|
||||
ch = 'c';
|
||||
break;
|
||||
case BOOLEAN:
|
||||
ch = 'b';
|
||||
break;
|
||||
case STRING:
|
||||
ch = 's';
|
||||
break;
|
||||
case POINTER:
|
||||
ch = 'p';
|
||||
break;
|
||||
}
|
||||
fprintf (fp, ".%cvalue", ch);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void put_conn_type (FILE *fp, Port_Type_t type)
|
||||
{
|
||||
char ch;
|
||||
|
||||
switch (type) {
|
||||
case USER_DEFINED:
|
||||
ch = 'p';
|
||||
break;
|
||||
case DIGITAL:
|
||||
ch = 'p';
|
||||
break;
|
||||
default:
|
||||
ch = 'r';
|
||||
break;
|
||||
}
|
||||
fprintf (fp, ".%cvalue", ch);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_dir (int conn_number, Dir_t dir, char *context)
|
||||
{
|
||||
Dir_t conn_dir;
|
||||
|
||||
if (conn_number >= 0) {
|
||||
/*
|
||||
* If negative, this is an invalid port ID and we've already issued
|
||||
* an error.
|
||||
*/
|
||||
conn_dir = mod_ifs_table->conn[conn_number].direction;
|
||||
if ((conn_dir != dir) && (conn_dir != INOUT)) {
|
||||
char error_str[200];
|
||||
|
||||
sprintf (error_str,
|
||||
"Direction of port `%s' in %s() is not %s or INOUT",
|
||||
mod_ifs_table->conn[conn_number].name, context,
|
||||
(dir == IN) ? "IN" : "OUT");
|
||||
yyerror (error_str);
|
||||
mod_num_errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void check_subscript (Boolean_t formal, Boolean_t actual,
|
||||
Boolean_t missing_actual_ok,
|
||||
char *context, char *id)
|
||||
{
|
||||
char error_str[200];
|
||||
|
||||
if ((formal && !actual) && !missing_actual_ok) {
|
||||
sprintf (error_str,
|
||||
"%s `%s' is an array - subscript required",
|
||||
context, id);
|
||||
yyerror (error_str);
|
||||
mod_num_errors++;
|
||||
return;
|
||||
} else if (!formal && actual) {
|
||||
sprintf (error_str,
|
||||
"%s `%s' is not an array - subscript prohibited",
|
||||
context, id);
|
||||
yyerror (error_str);
|
||||
mod_num_errors++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript)
|
||||
{
|
||||
int i;
|
||||
char error_str[200];
|
||||
|
||||
switch (kind) {
|
||||
case CONN:
|
||||
for (i = 0; i < mod_ifs_table->num_conn; i++) {
|
||||
if (0 == strcmpi (sub_id.id, mod_ifs_table->conn[i].name)) {
|
||||
if (do_subscript) {
|
||||
check_subscript (mod_ifs_table->conn[i].is_array,
|
||||
sub_id.has_subscript, FALSE, "Port",
|
||||
sub_id.id);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PARAM:
|
||||
for (i = 0; i < mod_ifs_table->num_param; i++) {
|
||||
if (0 == strcmpi (sub_id.id, mod_ifs_table->param[i].name)) {
|
||||
if (do_subscript) {
|
||||
check_subscript (mod_ifs_table->param[i].is_array,
|
||||
sub_id.has_subscript, FALSE, "Parameter",
|
||||
sub_id.id);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATIC_VAR:
|
||||
for (i = 0; i < mod_ifs_table->num_inst_var; i++) {
|
||||
if (0 == strcmpi (sub_id.id, mod_ifs_table->inst_var[i].name)) {
|
||||
if (do_subscript) {
|
||||
check_subscript (mod_ifs_table->inst_var[i].is_array,
|
||||
sub_id.has_subscript, TRUE,
|
||||
"Static Variable",
|
||||
sub_id.id);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf (error_str, "No %s named '%s'",
|
||||
((kind==CONN)
|
||||
? "port"
|
||||
: ((kind==PARAM)
|
||||
? "parameter"
|
||||
:"static variable")),
|
||||
sub_id.id);
|
||||
yyerror (error_str);
|
||||
mod_num_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int valid_id (Sub_Id_t sub_id, Id_Kind_t kind)
|
||||
{
|
||||
return check_id (sub_id, kind, FALSE);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int valid_subid (Sub_Id_t sub_id, Id_Kind_t kind)
|
||||
{
|
||||
return check_id (sub_id, kind, TRUE);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static init_buffer ()
|
||||
{
|
||||
buf_len = 0;
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static append (char *str)
|
||||
{
|
||||
int len = strlen (str);
|
||||
if (len + buf_len > BUFFER_SIZE) {
|
||||
yyerror ("Buffer overflow - try reducing the complexity of CM-macro array subscripts");
|
||||
exit (1);
|
||||
}
|
||||
(void)strcat (buffer,str);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *str;
|
||||
Sub_Id_t sub_id;
|
||||
}
|
||||
|
||||
%type <str> buffered_c_code
|
||||
%type <sub_id> subscriptable_id id
|
||||
|
||||
%token TOK_ARGS
|
||||
%token TOK_INIT
|
||||
%token TOK_ANALYSIS
|
||||
%token TOK_NEW_TIMEPOINT
|
||||
%token TOK_TIME
|
||||
%token TOK_RAD_FREQ
|
||||
%token TOK_TEMPERATURE
|
||||
%token TOK_T
|
||||
%token TOK_PARAM
|
||||
%token TOK_PARAM_SIZE
|
||||
%token TOK_PARAM_NULL
|
||||
%token TOK_PORT_SIZE
|
||||
%token TOK_PORT_NULL
|
||||
%token TOK_PARTIAL
|
||||
%token TOK_AC_GAIN
|
||||
%token TOK_CHANGED
|
||||
%token TOK_OUTPUT_DELAY
|
||||
%token TOK_STATIC_VAR
|
||||
%token TOK_STATIC_VAR_SIZE
|
||||
%token TOK_INPUT
|
||||
%token TOK_INPUT_STRENGTH
|
||||
%token TOK_INPUT_STATE
|
||||
%token TOK_INPUT_TYPE
|
||||
%token TOK_OUTPUT
|
||||
%token TOK_OUTPUT_CHANGED
|
||||
%token TOK_OUTPUT_STRENGTH
|
||||
%token TOK_OUTPUT_STATE
|
||||
%token TOK_OUTPUT_TYPE
|
||||
%token TOK_COMMA
|
||||
%token TOK_LPAREN
|
||||
%token TOK_RPAREN
|
||||
%token TOK_LBRACKET
|
||||
%token TOK_RBRACKET
|
||||
%token TOK_MISC_C
|
||||
%token TOK_IDENTIFIER
|
||||
%token TOK_LOAD
|
||||
%token TOK_TOTAL_LOAD
|
||||
%token TOK_MESSAGE
|
||||
%token TOK_CALL_TYPE
|
||||
|
||||
%start mod_file
|
||||
|
||||
%%
|
||||
|
||||
mod_file : /* empty */
|
||||
| mod_file c_code
|
||||
;
|
||||
|
||||
c_code : /* empty */
|
||||
| c_code c_char
|
||||
| c_code macro
|
||||
/*| TOK_RPAREN {yyerror ("Unmatched )"); YYERROR;}
|
||||
| TOK_RBRACKET {yyerror ("Unmatched ]"); YYERROR;}*/
|
||||
;
|
||||
|
||||
buffered_c_code : {init_buffer();} buffered_c_code2
|
||||
{$$ = strdup (buffer);}
|
||||
;
|
||||
|
||||
buffered_c_code2 : /* empty */
|
||||
| buffered_c_code2 buffered_c_char
|
||||
;
|
||||
|
||||
buffered_c_char : TOK_IDENTIFIER {append (mod_yytext);}
|
||||
| TOK_MISC_C {append (mod_yytext);}
|
||||
| TOK_COMMA {append (mod_yytext);}
|
||||
| TOK_LBRACKET
|
||||
{append("[");}
|
||||
buffered_c_code2 TOK_RBRACKET
|
||||
{append("]");}
|
||||
| TOK_LPAREN
|
||||
{append("(");}
|
||||
buffered_c_code2 TOK_RPAREN
|
||||
{append(")");}
|
||||
;
|
||||
|
||||
c_char : TOK_IDENTIFIER {fputs (mod_yytext, mod_yyout);}
|
||||
| TOK_MISC_C {fputs (mod_yytext, mod_yyout);}
|
||||
| TOK_COMMA {fputs (mod_yytext, mod_yyout);}
|
||||
| TOK_LBRACKET
|
||||
{putc ('[', mod_yyout);}
|
||||
c_code TOK_RBRACKET
|
||||
{putc (']', mod_yyout);}
|
||||
| TOK_LPAREN
|
||||
{putc ('(', mod_yyout);}
|
||||
c_code TOK_RPAREN
|
||||
{putc (')', mod_yyout);}
|
||||
;
|
||||
|
||||
macro : TOK_INIT
|
||||
{fprintf (mod_yyout, "private->circuit.init");}
|
||||
| TOK_ARGS
|
||||
{fprintf (mod_yyout, "Mif_Private_t *private");}
|
||||
| TOK_ANALYSIS
|
||||
{fprintf (mod_yyout, "private->circuit.anal_type");}
|
||||
| TOK_NEW_TIMEPOINT
|
||||
{fprintf (mod_yyout, "private->circuit.anal_init");}
|
||||
| TOK_CALL_TYPE
|
||||
{fprintf (mod_yyout, "private->circuit.call_type");}
|
||||
| TOK_TIME
|
||||
{fprintf (mod_yyout, "private->circuit.time");}
|
||||
| TOK_RAD_FREQ
|
||||
{fprintf (mod_yyout, "private->circuit.frequency");}
|
||||
| TOK_TEMPERATURE
|
||||
{fprintf (mod_yyout, "private->circuit.temperature");}
|
||||
| TOK_T TOK_LPAREN buffered_c_code TOK_RPAREN
|
||||
{fprintf (mod_yyout, "private->circuit.t[%s]", $3);}
|
||||
| TOK_PARAM TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, PARAM);
|
||||
fprintf (mod_yyout, "private->param[%d]->element[%s]",
|
||||
i, subscript ($3));
|
||||
put_type (mod_yyout, mod_ifs_table->param[i].type);
|
||||
}
|
||||
| TOK_PARAM_SIZE TOK_LPAREN id TOK_RPAREN
|
||||
{int i = valid_id ($3, PARAM);
|
||||
fprintf (mod_yyout, "private->param[%d]->size", i);}
|
||||
| TOK_PARAM_NULL TOK_LPAREN id TOK_RPAREN
|
||||
{int i = valid_id ($3, PARAM);
|
||||
fprintf (mod_yyout, "private->param[%d]->is_null", i);}
|
||||
| TOK_PORT_SIZE TOK_LPAREN id TOK_RPAREN
|
||||
{int i = valid_id ($3, CONN);
|
||||
fprintf (mod_yyout, "private->conn[%d]->size", i);}
|
||||
| TOK_PORT_NULL TOK_LPAREN id TOK_RPAREN
|
||||
{int i = valid_id ($3, CONN);
|
||||
fprintf (mod_yyout, "private->conn[%d]->is_null", i);}
|
||||
| TOK_PARTIAL TOK_LPAREN subscriptable_id TOK_COMMA
|
||||
subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
int j = valid_subid ($5, CONN);
|
||||
check_dir (i, OUT, "PARTIAL");
|
||||
check_dir (j, IN, "PARTIAL");
|
||||
fprintf (mod_yyout, "private->conn[%d]->port[%s]->partial[%d].port[%s]",
|
||||
i, subscript($3), j, subscript($5));}
|
||||
| TOK_AC_GAIN TOK_LPAREN subscriptable_id TOK_COMMA
|
||||
subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
int j = valid_subid ($5, CONN);
|
||||
check_dir (i, OUT, "AC_GAIN");
|
||||
check_dir (j, IN, "AC_GAIN");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->ac_gain[%d].port[%s]",
|
||||
i, subscript($3), j, subscript($5));}
|
||||
| TOK_STATIC_VAR TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, STATIC_VAR);
|
||||
fprintf (mod_yyout,
|
||||
"private->inst_var[%d]->element[%s]",
|
||||
i, subscript($3));
|
||||
if (mod_ifs_table->inst_var[i].is_array
|
||||
&& !($3.has_subscript)) {
|
||||
/* null - eg. for malloc lvalue */
|
||||
} else {
|
||||
put_type (mod_yyout,
|
||||
mod_ifs_table->inst_var[i].type);
|
||||
} }
|
||||
| TOK_STATIC_VAR_SIZE TOK_LPAREN id TOK_RPAREN
|
||||
{int i = valid_subid ($3, STATIC_VAR);
|
||||
fprintf (mod_yyout, "private->inst_var[%d]->size",
|
||||
i, subscript($3));}
|
||||
| TOK_OUTPUT_DELAY TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, OUT, "OUTPUT_DELAY");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->delay", i,
|
||||
subscript($3));}
|
||||
| TOK_CHANGED TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, OUT, "CHANGED");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->changed", i,
|
||||
subscript($3));}
|
||||
| TOK_INPUT TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, IN, "INPUT");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->input",
|
||||
i, subscript($3));
|
||||
put_conn_type (mod_yyout,
|
||||
mod_ifs_table->conn[i].allowed_port_type[0]);}
|
||||
| TOK_INPUT_TYPE TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, IN, "INPUT_TYPE");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->type_str",
|
||||
i, subscript($3)); }
|
||||
| TOK_OUTPUT_TYPE TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, OUT, "OUTPUT_TYPE");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->type_str",
|
||||
i, subscript($3)); }
|
||||
| TOK_INPUT_STRENGTH TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, IN, "INPUT_STRENGTH");
|
||||
fprintf (mod_yyout,
|
||||
"((Digital_t*)(private->conn[%d]->port[%s]->input",
|
||||
i, subscript($3));
|
||||
put_conn_type (mod_yyout,
|
||||
mod_ifs_table->conn[i].allowed_port_type[0]);
|
||||
fprintf (mod_yyout, "))->strength");}
|
||||
| TOK_INPUT_STATE TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, IN, "INPUT_STATE");
|
||||
fprintf (mod_yyout,
|
||||
"((Digital_t*)(private->conn[%d]->port[%s]->input",
|
||||
i, subscript($3));
|
||||
put_conn_type (mod_yyout,
|
||||
mod_ifs_table->conn[i].allowed_port_type[0]);
|
||||
fprintf (mod_yyout, "))->state");}
|
||||
| TOK_OUTPUT TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, OUT, "OUTPUT");
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->output",
|
||||
i, subscript($3));
|
||||
put_conn_type (mod_yyout,
|
||||
mod_ifs_table->conn[i].allowed_port_type[0]);}
|
||||
| TOK_OUTPUT_STRENGTH TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, OUT, "OUTPUT_STRENGTH");
|
||||
fprintf (mod_yyout,
|
||||
"((Digital_t*)(private->conn[%d]->port[%s]->output",
|
||||
i, subscript($3));
|
||||
put_conn_type (mod_yyout,
|
||||
mod_ifs_table->conn[i].allowed_port_type[0]);
|
||||
fprintf (mod_yyout, "))->strength");}
|
||||
| TOK_OUTPUT_STATE TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
check_dir (i, OUT, "OUTPUT_STATE");
|
||||
fprintf (mod_yyout,
|
||||
"((Digital_t*)(private->conn[%d]->port[%s]->output",
|
||||
i, subscript($3));
|
||||
put_conn_type (mod_yyout,
|
||||
mod_ifs_table->conn[i].allowed_port_type[0]);
|
||||
fprintf (mod_yyout, "))->state");}
|
||||
| TOK_OUTPUT_CHANGED TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->changed", i,
|
||||
subscript($3));}
|
||||
| TOK_LOAD TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->load", i,
|
||||
subscript($3));}
|
||||
| TOK_TOTAL_LOAD TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->total_load", i,
|
||||
subscript($3));}
|
||||
| TOK_MESSAGE TOK_LPAREN subscriptable_id TOK_RPAREN
|
||||
{int i = valid_subid ($3, CONN);
|
||||
fprintf (mod_yyout,
|
||||
"private->conn[%d]->port[%s]->msg", i,
|
||||
subscript($3));}
|
||||
;
|
||||
|
||||
subscriptable_id : id
|
||||
| id TOK_LBRACKET buffered_c_code TOK_RBRACKET
|
||||
{$$ = $1;
|
||||
$$.has_subscript = TRUE;
|
||||
$$.subscript = $3;}
|
||||
;
|
||||
|
||||
id : TOK_IDENTIFIER
|
||||
{$$.has_subscript = FALSE;
|
||||
$$.id = strdup (mod_yytext);}
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*============================================================================
|
||||
FILE pp_ifs.c
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains the main function for processing an Interface Spec
|
||||
File (ifspec.ifs).
|
||||
|
||||
INTERFACES
|
||||
|
||||
preprocess_ifs_file()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "cmpp.h"
|
||||
|
||||
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
|
||||
/*
|
||||
preprocess_ifs_file
|
||||
|
||||
Function preprocess_ifs_file is the top-level driver function for
|
||||
preprocessing an Interface Specification file (ifspec.ifs). This
|
||||
function calls read_ifs_file() requesting it to read and parse
|
||||
the Interface Specification file and place the information
|
||||
contained in it into an internal data structure. Then
|
||||
write_ifs_c_file() is called to write the information out in a C
|
||||
file that will be compiled and linked with the simulator.
|
||||
*/
|
||||
|
||||
|
||||
void preprocess_ifs_file(void)
|
||||
{
|
||||
|
||||
Ifs_Table_t ifs_table; /* Repository for info read from ifspec.ifs file */
|
||||
|
||||
Status_t status; /* Return status */
|
||||
|
||||
|
||||
/* Read the entire ifspec.ifs file and load the data into ifs_table */
|
||||
|
||||
status = read_ifs_file(IFSPEC_FILENAME,GET_IFS_TABLE,&ifs_table);
|
||||
|
||||
if(status != OK) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Write the ifspec.c file required by the spice simulator */
|
||||
|
||||
status = write_ifs_c_file("ifspec.c",&ifs_table);
|
||||
|
||||
if(status != OK) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,181 @@
|
|||
/*============================================================================
|
||||
FILE pp_mod.c
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains the top-level driver function for preprocessing the
|
||||
"cfunc.mod" file. First, the "ifspec.ifs" file is opened and parsed to
|
||||
get the data that will be needed in the .mod to .c translation (See
|
||||
read_ifs.c). Then the .mod file is translated. Most of the work of the
|
||||
translation is handled by the UNIX 'lex' and 'yacc' utilities. This
|
||||
translation is begun at the call to mod_yyparse() below. See also files:
|
||||
|
||||
mod_lex.l
|
||||
mod_yacc.y
|
||||
|
||||
Note that to allow lex/yacc to be used twice (once for the ifspec.ifs
|
||||
file, and then again for the cfunc.mod file), the functions created by
|
||||
lex/yacc for the latter are translated using the UNIX text editor 'sed'
|
||||
under the direction of the Makefile and the following 'sed scripts':
|
||||
|
||||
mod_lex.sed
|
||||
mod_yacc.sed
|
||||
|
||||
Hence the call to 'mod_yyparse()' rather than 'yyparse()' below.
|
||||
|
||||
INTERFACES
|
||||
|
||||
preprocess_mod_file()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "cmpp.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void change_extension (char *filename, char *ext, char *new_filename)
|
||||
{
|
||||
int i = strlen (filename);
|
||||
|
||||
strcpy (new_filename, filename);
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
if (new_filename[i] == '.') {
|
||||
new_filename[i+1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
strcat (new_filename, ext);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
preprocess_mod_file
|
||||
|
||||
Function preprocess_mod_file is the top-level driver function for
|
||||
preprocessing a code model file (cfunc.mod). This function calls
|
||||
read_ifs_file() requesting it to read and parse the Interface
|
||||
Specification file (ifspec.ifs) and place the information
|
||||
contained in it into an internal data structure. It then calls
|
||||
mod_yyparse() to read the cfunc.mod file and translate it
|
||||
according to the Interface Specification information. Function
|
||||
mod_yyparse() is automatically generated by UNIX lex/yacc
|
||||
utilities.
|
||||
*/
|
||||
|
||||
|
||||
void preprocess_mod_file (
|
||||
char *filename) /* The file to read */
|
||||
{
|
||||
extern FILE *mod_yyin;
|
||||
extern FILE *mod_yyout;
|
||||
extern char *current_filename;
|
||||
extern int mod_yylineno;
|
||||
extern int mod_num_errors;
|
||||
extern Ifs_Table_t *mod_ifs_table;
|
||||
|
||||
Ifs_Table_t ifs_table; /* info read from ifspec.ifs file */
|
||||
Status_t status; /* Return status */
|
||||
char error_str[200];
|
||||
char output_filename[200];
|
||||
|
||||
/*
|
||||
* Read the entire ifspec.ifs file and load the data into ifs_table
|
||||
*/
|
||||
|
||||
status = read_ifs_file (IFSPEC_FILENAME, GET_IFS_TABLE, &ifs_table);
|
||||
|
||||
if (status != OK) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mod_yyin = fopen (filename, "r");
|
||||
if (mod_yyin == NULL) {
|
||||
sprintf(error_str, "ERROR - Could not open input .mod file: %s",
|
||||
filename);
|
||||
print_error(error_str);
|
||||
return;
|
||||
}
|
||||
|
||||
current_filename = filename;
|
||||
|
||||
change_extension (filename, "c", output_filename);
|
||||
mod_yyout = fopen (output_filename, "w");
|
||||
|
||||
if (mod_yyout == NULL) {
|
||||
sprintf(error_str, "ERROR - Could not open output .c: %s",
|
||||
output_filename);
|
||||
print_error(error_str);
|
||||
return;
|
||||
}
|
||||
|
||||
mod_ifs_table = &ifs_table;
|
||||
mod_num_errors = 0;
|
||||
|
||||
fprintf (mod_yyout, "#line 1 \"%s\"\n", filename);
|
||||
fprintf (mod_yyout, "#include \"cm.h\"\n");
|
||||
fprintf (mod_yyout, "#line 1 \"%s\"\n", filename);
|
||||
|
||||
mod_yylineno = 1;
|
||||
if (!mod_yyin) {
|
||||
sprintf (error_str, "Could not open .mod file: \"%s\"", filename);
|
||||
print_error (error_str);
|
||||
unlink (output_filename);
|
||||
exit(1);
|
||||
}
|
||||
if (!mod_yyout) {
|
||||
sprintf (error_str, "Could not create .c file: \"%s\"",
|
||||
output_filename);
|
||||
print_error (error_str);
|
||||
unlink (output_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mod_yyparse() || (mod_num_errors > 0)) {
|
||||
sprintf (error_str, "Error parsing .mod file: \"%s\"", filename);
|
||||
print_error (error_str);
|
||||
unlink (output_filename);
|
||||
exit (1);
|
||||
}
|
||||
fclose (mod_yyout);
|
||||
mod_yyrestart(NULL);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int mod_yyerror (str)
|
||||
char *str;
|
||||
{
|
||||
extern int mod_yylineno;
|
||||
extern char *mod_yytext;
|
||||
extern char *current_filename;
|
||||
extern char *prog_name;
|
||||
|
||||
fprintf (stderr, "%s: Error: \"%s\": line %d (near \'%s\'):\n\t%s.\n",
|
||||
prog_name, current_filename, mod_yylineno, mod_yytext, str);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*============================================================================
|
||||
FILE read_ifs.c
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn and Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains top-level functions used in reading information
|
||||
from the ifspec.ifs file and building an internal data structure that
|
||||
holds the information. Most of the work in parsing of the
|
||||
ifspec.ifs file and in building the structure is handled by
|
||||
the UNIX 'lex' and 'yacc' utilities. This processing is begun
|
||||
at the call to yyparse() in read_ifs_table() below. See also files:
|
||||
|
||||
ifs_lex.l
|
||||
ifs_yacc.y
|
||||
|
||||
INTERFACES
|
||||
|
||||
read_ifs_file()
|
||||
yywrap()
|
||||
yyerror()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "cmpp.h"
|
||||
|
||||
extern char *prog_name;
|
||||
|
||||
void *malloc(unsigned size);
|
||||
|
||||
static Status_t read_ifs_table(FILE *fp, int mode, Ifs_Table_t *ifs_table);
|
||||
|
||||
char *current_filename;
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
|
||||
/*
|
||||
NOTE
|
||||
|
||||
The following function may be called either by cmpp -ifs or cmpp -lst with
|
||||
mode set to GET_IFS_TABLE or GET_IFS_NAME respectively.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
read_ifs_file
|
||||
|
||||
Function read_ifs_file() opens the Interface Specification file
|
||||
(ifspec.ifs) for read access and calls read_ifs_table() with the
|
||||
assigned file pointer to read and parse the file. Upon return
|
||||
from read_ifs_table(), the file is closed.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Status_t read_ifs_file(
|
||||
char *filename, /* File to read */
|
||||
int mode, /* Get names only or get everything? */
|
||||
Ifs_Table_t *ifs_table) /* Table to put info in */
|
||||
{
|
||||
|
||||
FILE *fp; /* Ifs file pointer */
|
||||
|
||||
char msg[MAX_PATH_LEN+257]; /* space for an error message */
|
||||
|
||||
Status_t status; /* returned status from function */
|
||||
|
||||
|
||||
/* Open the ifs file for read access */
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
|
||||
if(fp == NULL) {
|
||||
perror (prog_name);
|
||||
sprintf(msg, "ERROR - File not found: %s", filename);
|
||||
print_error(msg);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
current_filename = filename;
|
||||
|
||||
/* Get the stuff from the file into the ifs_table struct */
|
||||
|
||||
status = read_ifs_table(fp, mode, ifs_table);
|
||||
|
||||
/* Close file and return */
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return(status);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
|
||||
/*
|
||||
read_ifs_table
|
||||
|
||||
Function read_ifs_table() calls yyparse() to read and parse the
|
||||
Interface Specification file contents and place the information
|
||||
into an internal data structure. Function yyparse() is
|
||||
automatically generated by UNIX lex/yacc.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static Status_t read_ifs_table(
|
||||
FILE *fp, /* File to read from */
|
||||
int mode, /* Get names only or get everything? */
|
||||
Ifs_Table_t *ifs_table) /* Table to put info in */
|
||||
{
|
||||
|
||||
extern FILE *ifs_yyin;
|
||||
extern Ifs_Table_t *parser_ifs_table;
|
||||
extern Boolean_t parser_just_names;
|
||||
extern int ifs_yylineno;
|
||||
|
||||
assert (ifs_table);
|
||||
assert (fp);
|
||||
|
||||
ifs_yylineno = 1;
|
||||
ifs_yyin = fp;
|
||||
parser_just_names = (mode == GET_IFS_NAME);
|
||||
parser_ifs_table = ifs_table;
|
||||
|
||||
if (ifs_yyparse()) {
|
||||
print_error ("Error parsing interface specification file");
|
||||
ifs_yyrestart(NULL);
|
||||
return ERROR;
|
||||
}
|
||||
ifs_yyrestart(NULL);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int ifs_yyerror (str)
|
||||
char *str;
|
||||
{
|
||||
extern int ifs_yylineno;
|
||||
extern char *ifs_yytext;
|
||||
|
||||
fprintf (stderr, "%s: Error: \"%s\": line %d (near \'%s\'):\n\t%s.\n",
|
||||
prog_name, current_filename, ifs_yylineno, ifs_yytext, str);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*============================================================================
|
||||
FILE util.c
|
||||
|
||||
MEMBER OF process cmpp
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn and Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains miscellaneous utility functions used in cmpp.
|
||||
|
||||
INTERFACES
|
||||
|
||||
init_error()
|
||||
print_error()
|
||||
str_to_lower()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "cmpp.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
/* *********************************************************************** */
|
||||
|
||||
char *prog_name;
|
||||
|
||||
|
||||
/* Initialize print_error() with the name of the program */
|
||||
|
||||
void init_error (char *program_name)
|
||||
{
|
||||
prog_name = program_name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Print an error message to stderr */
|
||||
|
||||
void print_error(
|
||||
char *msg) /* The message to write */
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", prog_name, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Convert a string to all lower case */
|
||||
|
||||
str_to_lower(s)
|
||||
|
||||
char *s; /* The string to convert */
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
|
||||
for(i = 0; (c = s[i]) != '\0'; i++)
|
||||
if(isalpha(c))
|
||||
if(isupper(c))
|
||||
s[i] = tolower(c);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,13 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LIBRARIES = libenhxsp.a
|
||||
|
||||
libenhxsp_a_SOURCES = \
|
||||
enh.c \
|
||||
enhtrans.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*============================================================================
|
||||
FILE ENH.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains routines used for general enhancements made
|
||||
to the Berkeley SPICE3 core.
|
||||
|
||||
INTERFACES
|
||||
|
||||
ENHreport_conv_prob()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "enh.h"
|
||||
|
||||
/*
|
||||
ENHreport_conv_prob()
|
||||
|
||||
Report convergence problem messages from nodes, branch currents,
|
||||
or instances. This function is setup to allow providing the SI
|
||||
with information identifying the type of convergence problem.
|
||||
For now, it simply writes to stdout.
|
||||
*/
|
||||
|
||||
|
||||
void ENHreport_conv_prob(
|
||||
Enh_Conv_Source_t type, /* node, branch, or instance */
|
||||
char *name, /* the name of the node/branch/instance */
|
||||
char *msg) /* an optional message */
|
||||
{
|
||||
|
||||
char *type_str;
|
||||
char *msg_str;
|
||||
|
||||
/* Convert the type enum to a string for printing */
|
||||
switch(type) {
|
||||
|
||||
case ENH_ANALOG_NODE:
|
||||
case ENH_EVENT_NODE:
|
||||
type_str = "node";
|
||||
break;
|
||||
|
||||
case ENH_ANALOG_BRANCH:
|
||||
type_str = "branch current";
|
||||
break;
|
||||
|
||||
case ENH_ANALOG_INSTANCE:
|
||||
case ENH_EVENT_INSTANCE:
|
||||
case ENH_HYBRID_INSTANCE:
|
||||
type_str = "instance";
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("\nERROR: Internal error in ENHreport_conv_prob - impossible type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for msg == NULL and turn into null string */
|
||||
if(msg)
|
||||
msg_str = msg;
|
||||
else
|
||||
msg_str = "";
|
||||
|
||||
/* Print the convergence problem report */
|
||||
printf("\nWARNING: Convergence problems at %s (%s). %s\n",
|
||||
type_str, name, msg_str);
|
||||
|
||||
} /* ENHreport_conv_prob */
|
||||
|
||||
|
|
@ -0,0 +1,536 @@
|
|||
/* ===========================================================================
|
||||
FILE ENHtranslate_poly.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions used by the simulator in
|
||||
calling the internal "poly" code model to substitute for
|
||||
SPICE 2G6 style poly sources found in the input deck.
|
||||
|
||||
INTERFACES
|
||||
|
||||
ENHtranslate_poly()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
|
||||
/*=== FUNCTION PROTOTYPES ===*/
|
||||
|
||||
//void free(void *); //ka removed compiler error
|
||||
/* int atoi(char *); */
|
||||
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
|
||||
/* #include "prefix.h" */
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "fteinp.h"
|
||||
#include "enh.h"
|
||||
#include "cpdefs.h"
|
||||
#include "ftedefs.h"
|
||||
#include "mifproto.h"
|
||||
|
||||
/* #include "suffix.h" */
|
||||
|
||||
|
||||
/*=== FUNCTION PROTOTYPES ===*/
|
||||
static int needs_translating(char *card);
|
||||
static int count_tokens(char *card);
|
||||
static char *two2three_translate(char *orig_card, char **inst_card,
|
||||
char **mod_card);
|
||||
static int get_poly_dimension(char *card);
|
||||
|
||||
/*
|
||||
ENHtranslate_poly()
|
||||
|
||||
Translate all 2G6 style polynomial controlled sources in the deck
|
||||
to new polynomial controlled source code model syntax.
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* ENHtranslate_poly takes (a pointer to) the SPICE deck as argument. */
|
||||
/* It loops through the deck, and translates all POLY statements */
|
||||
/* in dependent sources into a .model conformant with the needs of */
|
||||
/* XSPICE. It splices the new statements in the deck, and comments */
|
||||
/* out the old dependent source. */
|
||||
/* It returns (a pointer to) the processed deck. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
struct line * ENHtranslate_poly(
|
||||
struct line *deck) /* Linked list of lines in input deck */
|
||||
{
|
||||
struct line *d;
|
||||
struct line *l1;
|
||||
struct line *l2;
|
||||
|
||||
char *card;
|
||||
|
||||
/* Iterate through each card in the deck and translate as needed */
|
||||
for(d = deck; d; d = d->li_next)
|
||||
{
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In ENHtranslate_poly, now examining card %s . . . \n", d->li_line);
|
||||
#endif
|
||||
|
||||
/* If doesn't need to be translated, continue to next card */
|
||||
if(! needs_translating(d->li_line)) {
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
/* printf("Card doesn't need translating. Continuing . . . .\n"); */
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("Found a card to translate . . . .\n");
|
||||
#endif
|
||||
|
||||
/* Create two new line structs and splice into deck */
|
||||
/* l1 = alloc(line); */ /* jgroves */
|
||||
/* l2 = alloc(line); */ /* jgroves */
|
||||
l1 = alloc(struct line);
|
||||
l2 = alloc(struct line);
|
||||
l2->li_next = d->li_next;
|
||||
l1->li_next = l2;
|
||||
d->li_next = l1;
|
||||
|
||||
/* Create the translated cards */
|
||||
d->li_error = two2three_translate(d->li_line, &(l1->li_line), &(l2->li_line));
|
||||
|
||||
/* Comment out the original line */
|
||||
card = (void *) MALLOC(strlen(d->li_line) + 2);
|
||||
strcpy(card,"*");
|
||||
strcat(card, d->li_line);
|
||||
d->li_line = card;
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In ENHtranslate_poly, translated card = %s . . . \n", card);
|
||||
#endif
|
||||
|
||||
/* Advance deck pointer to last line added */
|
||||
d = l2;
|
||||
}
|
||||
|
||||
/* Return head of deck */
|
||||
return(deck);
|
||||
|
||||
} /* ENHtranslate_poly */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/*
|
||||
needs_translating()
|
||||
|
||||
Test to see if card needs translating. Return true if card defines
|
||||
an e,f,g, or h controlled source and has too many tokens to be
|
||||
a simple linear dependent source. Otherwise return false.
|
||||
*/
|
||||
|
||||
|
||||
static int needs_translating(
|
||||
char *card) /* the card text to check */
|
||||
{
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
/* printf("In needs_translating, examining card %s . . . \n", card); */
|
||||
#endif
|
||||
|
||||
switch(*card) {
|
||||
|
||||
case 'e': case 'E':
|
||||
case 'g': case 'G':
|
||||
if(count_tokens(card) <=6)
|
||||
return(0);
|
||||
else
|
||||
return(1);
|
||||
|
||||
case 'f': case 'F':
|
||||
case 'h': case 'H':
|
||||
if(count_tokens(card) <= 5)
|
||||
return(0);
|
||||
else
|
||||
return(1);
|
||||
|
||||
default:
|
||||
return(0);
|
||||
}
|
||||
|
||||
} /* needs_translating */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/*
|
||||
count_tokens()
|
||||
|
||||
Count and return the number of tokens on the card.
|
||||
*/
|
||||
static int count_tokens(
|
||||
char *card) /* the card text on which to count tokens */
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Get and count tokens until end of line reached */
|
||||
for(i = 0; *card != '\0'; i++)
|
||||
txfree(MIFgettok(&card));
|
||||
|
||||
return(i);
|
||||
|
||||
} /* count_tokens */
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/*====================================================================
|
||||
|
||||
two2three_translate()
|
||||
|
||||
Do the syntax translation of the 2G6 source to the new code model
|
||||
syntax. The translation proceeds according to the template below.
|
||||
|
||||
--------------------------------------------
|
||||
VCVS:
|
||||
ename N+ N- POLY(dim) NC+ NC- P0 P1 P2 . . .
|
||||
N+ N- = outputs
|
||||
NC+ NC- = inputs
|
||||
|
||||
aname %vd[NC+ NC-] %vd[N+ N-] pname
|
||||
.model pname spice2poly(coef=P0 P1 P2 . . . )
|
||||
%vd[NC+ NC-] = inputs
|
||||
%vd[N+ N-] = outputs
|
||||
--------------------------------------------
|
||||
CCCS
|
||||
fname N+ N- POLY(dim) Vname P0 P1 P2 . . .
|
||||
N+ N- = outputs
|
||||
Vname = input voltage source (measures current)
|
||||
|
||||
aname %vnam[Vname] %id[N+ N-] pname
|
||||
.model pname spice2poly(coef=P0 P1 P2 . . . )
|
||||
%vnam[Vname] = input
|
||||
%id[N+ N-] = output
|
||||
--------------------------------------------
|
||||
VCCS
|
||||
gname N+ N- POLY(dim) NC+ NC- P0 P1 P2 , , ,
|
||||
N+ N- = outputs
|
||||
NC+ NC- = inputs
|
||||
|
||||
aname %vd[NC+ NC-] %id[N+ N-] pname
|
||||
.model pname spice2poly(coef=P0 P1 P2 . . . )
|
||||
%vd[NC+ NC-] = inputs
|
||||
%id[N+ N-] = outputs
|
||||
--------------------------------------------
|
||||
CCVS
|
||||
hname N+ N- POLY(dim) Vname P0 P1 P2 . . .
|
||||
N+ N- = outputs
|
||||
Vname = input voltage source (measures current)
|
||||
|
||||
aname %vnam[Vname] %vd[N+ N-] pname
|
||||
.model pname spice2poly(coef=P0 P1 P2 . . . )
|
||||
%vnam[Vname] = input
|
||||
%vd[N+ N-] = output
|
||||
|
||||
====================================================================*/
|
||||
/********************************************************************/
|
||||
|
||||
static char *two2three_translate(
|
||||
char *orig_card, /* the original untranslated card */
|
||||
char **inst_card, /* the instance card created by the translation */
|
||||
char **mod_card) /* the model card created by the translation */
|
||||
{
|
||||
int dim;
|
||||
int num_tokens;
|
||||
|
||||
int num_conns;
|
||||
int num_coefs;
|
||||
int inst_card_len;
|
||||
int mod_card_len;
|
||||
|
||||
int i;
|
||||
|
||||
char type;
|
||||
|
||||
char *tok;
|
||||
char *name;
|
||||
char **out_conn;
|
||||
char **in_conn;
|
||||
char **coef;
|
||||
|
||||
char *card;
|
||||
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In two2three_translate, card to translate = %s . . .\n", orig_card);
|
||||
#endif
|
||||
|
||||
/* Put the first character into local storage for checking type */
|
||||
type = *orig_card;
|
||||
|
||||
/* Count the number of tokens for use in parsing */
|
||||
num_tokens = count_tokens(orig_card);
|
||||
|
||||
/* Determine the dimension of the poly source */
|
||||
/* Note that get_poly_dimension returns 0 for "no poly", -1 for
|
||||
invalid dimensiion, otherwise returns numeric value of POLY */
|
||||
dim = get_poly_dimension(orig_card);
|
||||
if(dim == -1) {
|
||||
printf("ERROR in two2three_translate -- Argument to poly() is not an integer\n");
|
||||
return("ERROR - Argument to poly() is not an integer\n");
|
||||
}
|
||||
|
||||
/* Compute number of output connections based on type and dimension */
|
||||
switch(type) {
|
||||
case 'E':
|
||||
case 'e':
|
||||
case 'G':
|
||||
case 'g':
|
||||
num_conns = 2 * dim;
|
||||
break;
|
||||
|
||||
default:
|
||||
num_conns = dim;
|
||||
}
|
||||
|
||||
/* Compute number of coefficients. Return error if less than one. */
|
||||
if(dim == 0)
|
||||
num_coefs = num_tokens - num_conns - 3; /* no POLY token */
|
||||
else
|
||||
num_coefs = num_tokens - num_conns - 5; /* POLY token present */
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In two2three_translate, num_tokens=%d, num_conns=%d, num_coefs=%d . . .\n", num_tokens, num_conns, num_coefs);
|
||||
#endif
|
||||
|
||||
|
||||
if(num_coefs < 1)
|
||||
return("ERROR - Number of connections differs from poly dimension\n");
|
||||
|
||||
/* Split card into name, output connections, input connections, */
|
||||
/* and coefficients */
|
||||
|
||||
card = orig_card;
|
||||
name = MIFgettok(&card);
|
||||
|
||||
/* Get output connections (2 netnames) */
|
||||
out_conn = (void *) MALLOC(2 * sizeof(char *));
|
||||
for(i = 0; i < 2; i++)
|
||||
out_conn[i] = MIFgettok(&card);
|
||||
|
||||
/* check for POLY, and ignore it if present */
|
||||
if (dim > 0) {
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In two2three_translate, found poly!!! dim = %d \n", dim);
|
||||
#endif
|
||||
|
||||
tok = MIFgettok(&card); /* read and discard POLY */
|
||||
tok = MIFgettok(&card); /* read and discard dimension */
|
||||
}
|
||||
|
||||
|
||||
/* Get input connections (2 netnames per dimension) */
|
||||
in_conn = (void *) MALLOC(num_conns * sizeof(char *));
|
||||
for(i = 0; i < num_conns; i++)
|
||||
in_conn[i] = MIFgettok(&card);
|
||||
|
||||
/* The remainder of the line are the poly coeffs. */
|
||||
coef = (void *) MALLOC(num_coefs * sizeof(char *));
|
||||
for(i = 0; i < num_coefs; i++)
|
||||
coef[i] = MIFgettok(&card);
|
||||
|
||||
/* Compute the size needed for the new cards to be created */
|
||||
/* Allow a fair amount of extra space for connection types, etc. */
|
||||
/* to be safe... */
|
||||
|
||||
inst_card_len = 70;
|
||||
inst_card_len += 2 * (strlen(name) + 1);
|
||||
for(i = 0; i < 2; i++)
|
||||
inst_card_len += strlen(out_conn[i]) + 1;
|
||||
for(i = 0; i < num_conns; i++)
|
||||
inst_card_len += strlen(in_conn[i]) + 1;
|
||||
|
||||
mod_card_len = 70;
|
||||
mod_card_len += strlen(name) + 1;
|
||||
for(i = 0; i < num_coefs; i++)
|
||||
mod_card_len += strlen(coef[i]) + 1;
|
||||
|
||||
/* Allocate space for the cards and write them into the strings */
|
||||
|
||||
*inst_card = (void *) MALLOC(inst_card_len);
|
||||
*mod_card = (void *) MALLOC(mod_card_len);
|
||||
|
||||
strcpy(*inst_card, "a$poly$");
|
||||
sprintf(*inst_card + strlen(*inst_card), "%s ", name);
|
||||
|
||||
/* Write input nets/sources */
|
||||
if((type == 'e') || (type == 'g') ||
|
||||
(type == 'E') || (type == 'G'))
|
||||
sprintf(*inst_card + strlen(*inst_card), "%%vd [ ");
|
||||
else
|
||||
sprintf(*inst_card + strlen(*inst_card), "%%vnam [ ");
|
||||
|
||||
for(i = 0; i < num_conns; i++)
|
||||
sprintf(*inst_card + strlen(*inst_card), "%s ", in_conn[i]);
|
||||
|
||||
sprintf(*inst_card + strlen(*inst_card), "] ");
|
||||
|
||||
|
||||
/* Write output nets */
|
||||
if((type == 'e') || (type == 'h') ||
|
||||
(type == 'E') || (type == 'H'))
|
||||
sprintf(*inst_card + strlen(*inst_card), "%%vd [ ");
|
||||
else
|
||||
sprintf(*inst_card + strlen(*inst_card), "%%id [ ");
|
||||
|
||||
for(i = 0; i < 2; i++)
|
||||
sprintf(*inst_card + strlen(*inst_card), "%s ", out_conn[i]);
|
||||
|
||||
sprintf(*inst_card + strlen(*inst_card), "] ");
|
||||
|
||||
|
||||
/* Write model name */
|
||||
sprintf(*inst_card + strlen(*inst_card), "a$poly$%s", name);
|
||||
|
||||
|
||||
/* Now create model card */
|
||||
sprintf(*mod_card, ".model a$poly$%s spice2poly coef = [ ", name);
|
||||
for(i = 0; i < num_coefs; i++)
|
||||
sprintf(*mod_card + strlen(*mod_card), "%s ", coef[i]);
|
||||
sprintf(*mod_card + strlen(*mod_card), "]");
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In two2three_translate, translated statements:\n%s \n%s \n", *inst_card, *mod_card);
|
||||
#endif
|
||||
|
||||
/* Free the temporary space */
|
||||
FREE(name);
|
||||
name = NULL;
|
||||
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
FREE(out_conn[i]);
|
||||
out_conn[i] = NULL;
|
||||
}
|
||||
|
||||
FREE(out_conn);
|
||||
out_conn = NULL;
|
||||
|
||||
for(i = 0; i < num_conns; i++)
|
||||
{
|
||||
FREE(in_conn[i]);
|
||||
in_conn[i] = NULL;
|
||||
}
|
||||
|
||||
FREE(in_conn);
|
||||
in_conn = NULL;
|
||||
|
||||
for(i = 0; i < num_coefs; i++)
|
||||
{
|
||||
FREE(coef[i]);
|
||||
coef[i] = NULL;
|
||||
}
|
||||
|
||||
FREE(coef);
|
||||
|
||||
coef = NULL;
|
||||
|
||||
/* Return NULL to indicate no error */
|
||||
return(NULL);
|
||||
|
||||
} /* two2three_translate */
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*
|
||||
get_poly_dimension()
|
||||
|
||||
Get the poly source dimension from the token immediately following
|
||||
the 'poly' if any. Return values changed by SDB on 5.23.2003 to be:
|
||||
If "poly" is not present, return 0.
|
||||
If the dimension token following "poly" is invalid, return -1.
|
||||
Otherwise, return the integer dimension.
|
||||
Note that the dimension may only be 1 or 2. Is this correct SPICE?
|
||||
*/
|
||||
|
||||
|
||||
static int get_poly_dimension(
|
||||
char *card) /* the card text */
|
||||
{
|
||||
|
||||
int i;
|
||||
int dim;
|
||||
char *local_tok;
|
||||
|
||||
|
||||
/* Skip over name and output connections */
|
||||
for(i = 0; i < 3; i++)
|
||||
txfree(MIFgettok(&card));
|
||||
|
||||
/* Check the next token to see if it is "poly" */
|
||||
/* If not, return 0 */
|
||||
local_tok = MIFgettok(&card);
|
||||
if( strcmp(local_tok, "poly") &&
|
||||
strcmp(local_tok, "POLY") ) /* check that local_tok is *not* poly */
|
||||
{
|
||||
FREE(local_tok);
|
||||
local_tok = NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
FREE(local_tok);
|
||||
|
||||
/* Must have been "poly", so next line must be a number */
|
||||
/* Try to convert it. If successful, return the number */
|
||||
/* else, return -1 to indicate an error... */
|
||||
local_tok = MIFgettok(&card);
|
||||
dim = atoi(local_tok);
|
||||
FREE(local_tok);
|
||||
|
||||
/* This is stupid, but it works. . . . */
|
||||
if ( (dim == 0) || (dim == 1) || (dim == 2) ) {
|
||||
return(dim);
|
||||
}
|
||||
else {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
} /* get_poly_dimension */
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LIBRARIES = libevtxsp.a
|
||||
|
||||
libevtxsp_a_SOURCES = \
|
||||
evtaccept.c \
|
||||
evtcall_hybrids.c \
|
||||
evtdump.c \
|
||||
evtiter.c \
|
||||
evtnext_time.c \
|
||||
evtop.c \
|
||||
evtprint.c \
|
||||
evtsetup.c \
|
||||
evtbackup.c \
|
||||
evtdeque.c \
|
||||
evtinit.c \
|
||||
evtload.c \
|
||||
evtnode_copy.c \
|
||||
evtplot.c \
|
||||
evtqueue.c \
|
||||
evttermi.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/*============================================================================
|
||||
FILE EVTaccept.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains a function called at the end of a
|
||||
successful (accepted) analog timepoint. It saves pointers
|
||||
to the states of the queues and data at this accepted time.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTaccept(CKTcircuit *ckt, double time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include "cktdefs.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTaccept()
|
||||
|
||||
This function is called at the end of a successful (accepted)
|
||||
analog timepoint. It saves pointers to the states of the
|
||||
queues and data at this accepted time.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void EVTaccept(
|
||||
CKTcircuit *ckt, /* main circuit struct */
|
||||
double time) /* time at which analog soln was accepted */
|
||||
{
|
||||
|
||||
int i;
|
||||
int index;
|
||||
int num_modified;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
|
||||
|
||||
/* Exit if no event instances */
|
||||
if(ckt->evt->counts.num_insts == 0)
|
||||
return;
|
||||
|
||||
/* Get often used pointers */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
node_data = ckt->evt->data.node;
|
||||
state_data = ckt->evt->data.state;
|
||||
msg_data = ckt->evt->data.msg;
|
||||
|
||||
|
||||
/* Process the inst queue */
|
||||
num_modified = inst_queue->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the inst modified */
|
||||
index = inst_queue->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
inst_queue->last_step[index] = inst_queue->current[index];
|
||||
/* Reset the modified flag */
|
||||
inst_queue->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Record the new last_time and reset number modified to zero */
|
||||
inst_queue->last_time = time;
|
||||
inst_queue->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the output queue */
|
||||
num_modified = output_queue->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the output modified */
|
||||
index = output_queue->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
output_queue->last_step[index] = output_queue->current[index];
|
||||
/* Reset the modified flag */
|
||||
output_queue->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Record the new last_time and reset number modified to zero */
|
||||
output_queue->last_time = time;
|
||||
output_queue->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the node data */
|
||||
num_modified = node_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
node_data->last_step[index] = node_data->tail[index];
|
||||
/* Reset the modified flag */
|
||||
node_data->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Reset number modified to zero */
|
||||
node_data->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the state data */
|
||||
num_modified = state_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the state modified */
|
||||
index = state_data->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
state_data->last_step[index] = state_data->tail[index];
|
||||
/* Reset the modified flag */
|
||||
state_data->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Reset number modified to zero */
|
||||
state_data->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the msg data */
|
||||
num_modified = msg_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the msg modified */
|
||||
index = msg_data->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
msg_data->last_step[index] = msg_data->tail[index];
|
||||
/* Reset the modified flag */
|
||||
msg_data->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Reset number modified to zero */
|
||||
msg_data->num_modified = 0;
|
||||
|
||||
} /* EVTaccept */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
/*============================================================================
|
||||
FILE EVTbackup.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains a function that resets the queues and data
|
||||
structures to their state at the new analog simulation time specified
|
||||
following the rejection of an analog timestep by the DCtran routine.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTbackup(CKTcircuit *ckt, double new_time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
#include <stdio.h>
|
||||
#include "ngspice.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
/*=== FUNCTION PROTOTYPES ===*/
|
||||
|
||||
|
||||
static void EVTbackup_node_data(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_state_data(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_msg_data(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_inst_queue(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_output_queue(CKTcircuit *ckt, double new_time);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup()
|
||||
|
||||
This function resets the queues and data structures to their state
|
||||
at the new analog simulation time specified. The algorithms in this file
|
||||
assume the following timestep coordination between
|
||||
analog and event-driven algorithms:
|
||||
|
||||
while(not end of analysis) {
|
||||
|
||||
while (next event time <= next analog time) {
|
||||
do event solution with call_type = event_driven
|
||||
if any instance set analog breakpoint < next analog time
|
||||
set next analog time to breakpoint
|
||||
}
|
||||
|
||||
do analog timestep solution with call_type = analog
|
||||
call all hybrid models with call_type = event_driven
|
||||
|
||||
if(analog solution doesn't converge)
|
||||
Call EVTbackup
|
||||
else
|
||||
Call EVTaccept
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void EVTbackup(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
|
||||
/* Backup the node data */
|
||||
EVTbackup_node_data(ckt, new_time);
|
||||
|
||||
/* Backup the state data */
|
||||
EVTbackup_state_data(ckt, new_time);
|
||||
|
||||
/* Backup the msg data */
|
||||
EVTbackup_msg_data(ckt, new_time);
|
||||
|
||||
/* Backup the inst queue */
|
||||
EVTbackup_inst_queue(ckt, new_time);
|
||||
|
||||
/* Backup the output queue */
|
||||
EVTbackup_output_queue(ckt, new_time);
|
||||
|
||||
/* Record statistics */
|
||||
(ckt->evt->data.statistics->tran_time_backups)++;
|
||||
|
||||
} /* EVTbackup */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_node_data()
|
||||
|
||||
Reset the node structure data.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_node_data(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int node_index;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_Node_t **node_ptr;
|
||||
Evt_Node_t *node;
|
||||
Evt_Node_t *from_node;
|
||||
Evt_Node_t *to_node;
|
||||
Evt_Node_t *head;
|
||||
Evt_Node_t *tail;
|
||||
Evt_Node_t *free_head;
|
||||
|
||||
/* Get pointers for quick access */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
num_modified = node_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the needed node and udn indexes */
|
||||
node_index = node_data->modified_index[i];
|
||||
|
||||
/* Scan data for this node from last_step to determine new setting */
|
||||
/* for tail, and splice later data into the free list */
|
||||
node_ptr = node_data->last_step[node_index];
|
||||
node = *node_ptr;
|
||||
while(1) {
|
||||
if((node->next == NULL) || (node->next->step > new_time)) {
|
||||
|
||||
/* Splice rest of list, if any, into free list */
|
||||
head = node->next;
|
||||
if(head) {
|
||||
tail = *(node_data->tail[node_index]);
|
||||
free_head = node_data->free[node_index];
|
||||
node_data->free[node_index] = head;
|
||||
tail->next = free_head;
|
||||
}
|
||||
|
||||
/* Set the tail */
|
||||
node_data->tail[node_index] = node_ptr;
|
||||
node->next = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
node_ptr = &(node->next);
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
/* Copy data from the location at tail to rhs and rhsold */
|
||||
from_node = *(node_data->tail[node_index]);
|
||||
to_node = &(node_data->rhs[node_index]);
|
||||
EVTnode_copy(ckt, node_index, from_node, &to_node);
|
||||
to_node = &(node_data->rhsold[node_index]);
|
||||
EVTnode_copy(ckt, node_index, from_node, &to_node);
|
||||
|
||||
} /* end for number modified */
|
||||
|
||||
/* Update/compact the modified list */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
node_index = node_data->modified_index[i];
|
||||
/* If nothing after last_step, remove this index from the modified list */
|
||||
if((*(node_data->last_step[node_index]))->next == NULL) {
|
||||
node_data->modified[node_index] = MIF_FALSE;
|
||||
(node_data->num_modified)--;
|
||||
}
|
||||
/* else, keep the index */
|
||||
else {
|
||||
node_data->modified_index[j] = node_data->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
} /* EVTbackup_node_data */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_state_data()
|
||||
|
||||
Reset the state structure data.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_state_data(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int inst_index;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
|
||||
Evt_State_t **state_ptr;
|
||||
Evt_State_t *state;
|
||||
Evt_State_t *head;
|
||||
Evt_State_t *tail;
|
||||
Evt_State_t *free_head;
|
||||
|
||||
/* Get pointers for quick access */
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
num_modified = state_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the inst index */
|
||||
inst_index = state_data->modified_index[i];
|
||||
|
||||
/* Scan data for this inst from last_step to determine new setting */
|
||||
/* for tail, and splice later data into the free list */
|
||||
state_ptr = state_data->last_step[inst_index];
|
||||
state = *state_ptr;
|
||||
while(1) {
|
||||
if((state->next == NULL) || (state->next->step > new_time)) {
|
||||
|
||||
/* Splice rest of list, if any, into free list */
|
||||
head = state->next;
|
||||
if(head) {
|
||||
tail = *(state_data->tail[inst_index]);
|
||||
free_head = state_data->free[inst_index];
|
||||
state_data->free[inst_index] = head;
|
||||
tail->next = free_head;
|
||||
}
|
||||
|
||||
/* Set the tail */
|
||||
state_data->tail[inst_index] = state_ptr;
|
||||
state->next = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
state_ptr = &(state->next);
|
||||
state = state->next;
|
||||
}
|
||||
} /* end for number modified */
|
||||
|
||||
/* Update/compact the modified list */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
inst_index = state_data->modified_index[i];
|
||||
/* If nothing after last_step, remove this index from the modified list */
|
||||
if((*(state_data->last_step[inst_index]))->next == NULL) {
|
||||
state_data->modified[inst_index] = MIF_FALSE;
|
||||
(state_data->num_modified)--;
|
||||
}
|
||||
/* else, keep the index */
|
||||
else {
|
||||
state_data->modified_index[j] = state_data->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
} /* EVTbackup_state_data */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_msg_data()
|
||||
|
||||
Backup the message data.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_msg_data(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int port_index;
|
||||
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
|
||||
Evt_Msg_t **msg_ptr;
|
||||
Evt_Msg_t *msg;
|
||||
Evt_Msg_t *head;
|
||||
Evt_Msg_t *tail;
|
||||
Evt_Msg_t *free_head;
|
||||
|
||||
/* Get pointers for quick access */
|
||||
msg_data = ckt->evt->data.msg;
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
num_modified = msg_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the port index */
|
||||
port_index = msg_data->modified_index[i];
|
||||
|
||||
/* Scan data for this port from last_step to determine new setting */
|
||||
/* for tail, and splice later data into the free list */
|
||||
msg_ptr = msg_data->last_step[port_index];
|
||||
msg = *msg_ptr;
|
||||
while(1) {
|
||||
if((msg->next == NULL) || (msg->next->step > new_time)) {
|
||||
|
||||
/* Splice rest of list, if any, into free list */
|
||||
head = msg->next;
|
||||
if(head) {
|
||||
tail = *(msg_data->tail[port_index]);
|
||||
free_head = msg_data->free[port_index];
|
||||
msg_data->free[port_index] = head;
|
||||
tail->next = free_head;
|
||||
}
|
||||
|
||||
/* Set the tail */
|
||||
msg_data->tail[port_index] = msg_ptr;
|
||||
msg->next = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
msg_ptr = &(msg->next);
|
||||
msg = msg->next;
|
||||
}
|
||||
|
||||
} /* end for number modified */
|
||||
|
||||
/* Update/compact the modified list */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
port_index = msg_data->modified_index[i];
|
||||
/* If nothing after last_step, remove this index from the modified list */
|
||||
if((*(msg_data->last_step[port_index]))->next == NULL) {
|
||||
msg_data->modified[port_index] = MIF_FALSE;
|
||||
(msg_data->num_modified)--;
|
||||
}
|
||||
/* else, keep the index */
|
||||
else {
|
||||
msg_data->modified_index[j] = msg_data->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_inst_queue()
|
||||
|
||||
Backup data in inst queue.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_inst_queue(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int num_pending;
|
||||
int inst_index;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
|
||||
Evt_Inst_Event_t **inst_ptr;
|
||||
Evt_Inst_Event_t *inst;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
|
||||
/* Get pointers for quick access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
/* and remove events with posted time > new_time */
|
||||
num_modified = inst_queue->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the inst index */
|
||||
inst_index = inst_queue->modified_index[i];
|
||||
|
||||
/* Scan forward from last_step and cut out data with posted time */
|
||||
/* > new_time and add it to the free list */
|
||||
|
||||
inst_ptr = inst_queue->last_step[inst_index];
|
||||
inst = *inst_ptr;
|
||||
|
||||
while(inst) {
|
||||
if(inst->posted_time > new_time) {
|
||||
*inst_ptr = inst->next;
|
||||
inst->next = inst_queue->free[inst_index];
|
||||
inst_queue->free[inst_index] = inst;
|
||||
inst = *inst_ptr;
|
||||
}
|
||||
else {
|
||||
inst_ptr = &(inst->next);
|
||||
inst = *inst_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan forward from last_step and set current to first */
|
||||
/* event with event_time > new_time */
|
||||
|
||||
inst_ptr = inst_queue->last_step[inst_index];
|
||||
inst = *inst_ptr;
|
||||
|
||||
while(inst) {
|
||||
if(inst->event_time > new_time)
|
||||
break;
|
||||
inst_ptr = &((*inst_ptr)->next);
|
||||
inst = *inst_ptr;
|
||||
}
|
||||
inst_queue->current[inst_index] = inst_ptr;
|
||||
}
|
||||
|
||||
/* Add set of items modified to set of items pending before updating the */
|
||||
/* pending list because things may have been pulled from the pending list */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
j = inst_queue->modified_index[i];
|
||||
if(! inst_queue->pending[j]) {
|
||||
inst_queue->pending[j] = MIF_TRUE;
|
||||
inst_queue->pending_index[(inst_queue->num_pending)++] = j;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the pending list and the next time by seeing if there */
|
||||
/* is anything at the location pointed to by current */
|
||||
next_time = 1e30;
|
||||
num_pending = inst_queue->num_pending;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
inst_index = inst_queue->pending_index[i];
|
||||
inst = *(inst_queue->current[inst_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! inst) {
|
||||
inst_queue->pending[inst_index] = MIF_FALSE;
|
||||
(inst_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
inst_queue->pending_index[j] = inst_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = inst->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
inst_queue->next_time = next_time;
|
||||
|
||||
/* Update the modified list by looking for any queued events */
|
||||
/* with posted time > last_time */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
|
||||
inst_index = inst_queue->modified_index[i];
|
||||
inst = *(inst_queue->last_step[inst_index]);
|
||||
|
||||
while(inst) {
|
||||
if(inst->posted_time > inst_queue->last_time)
|
||||
break;
|
||||
inst = inst->next;
|
||||
}
|
||||
|
||||
if(! inst) {
|
||||
inst_queue->modified[inst_index] = MIF_FALSE;
|
||||
(inst_queue->num_modified)--;
|
||||
}
|
||||
else {
|
||||
inst_queue->modified_index[j] = inst_queue->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_output_queue()
|
||||
|
||||
Backup data in output queue.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static void EVTbackup_output_queue(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int num_pending;
|
||||
|
||||
int output_index;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Output_Event_t **output_ptr;
|
||||
Evt_Output_Event_t *output;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
|
||||
/* Get pointers for quick access */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
/* and remove events with posted time > new_time */
|
||||
num_modified = output_queue->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the output index */
|
||||
output_index = output_queue->modified_index[i];
|
||||
|
||||
/* Scan forward from last_step and cut out data with posted time */
|
||||
/* > new_time and add it to the free list */
|
||||
/* Also, unremove anything with removed time > new_time */
|
||||
|
||||
output_ptr = output_queue->last_step[output_index];
|
||||
output = *output_ptr;
|
||||
|
||||
while(output) {
|
||||
if(output->posted_time > new_time) {
|
||||
*output_ptr = output->next;
|
||||
output->next = output_queue->free[output_index];
|
||||
output_queue->free[output_index] = output;
|
||||
output = *output_ptr;
|
||||
}
|
||||
else {
|
||||
if(output->removed && (output->removed_time > new_time))
|
||||
output->removed = MIF_FALSE;
|
||||
output_ptr = &(output->next);
|
||||
output = *output_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan forward from last_step and set current to first */
|
||||
/* event with event_time > new_time */
|
||||
|
||||
output_ptr = output_queue->last_step[output_index];
|
||||
output = *output_ptr;
|
||||
|
||||
while(output) {
|
||||
if(output->event_time > new_time)
|
||||
break;
|
||||
output_ptr = &((*output_ptr)->next);
|
||||
output = *output_ptr;
|
||||
}
|
||||
output_queue->current[output_index] = output_ptr;
|
||||
}
|
||||
|
||||
/* Add set of items modified to set of items pending before updating the */
|
||||
/* pending list because things may have been pulled from the pending list */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
j = output_queue->modified_index[i];
|
||||
if(! output_queue->pending[j]) {
|
||||
output_queue->pending[j] = MIF_TRUE;
|
||||
output_queue->pending_index[(output_queue->num_pending)++] = j;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the pending list and the next time by seeing if there */
|
||||
/* is anything at the location pointed to by current */
|
||||
next_time = 1e30;
|
||||
num_pending = output_queue->num_pending;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
output_index = output_queue->pending_index[i];
|
||||
output = *(output_queue->current[output_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! output) {
|
||||
output_queue->pending[output_index] = MIF_FALSE;
|
||||
(output_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
output_queue->pending_index[j] = output_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = output->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
output_queue->next_time = next_time;
|
||||
|
||||
/* Update the modified list by looking for any queued events */
|
||||
/* with posted time > last_time */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
|
||||
output_index = output_queue->modified_index[i];
|
||||
output = *(output_queue->last_step[output_index]);
|
||||
|
||||
while(output) {
|
||||
if(output->posted_time > output_queue->last_time)
|
||||
break;
|
||||
output = output->next;
|
||||
}
|
||||
|
||||
if(! output) {
|
||||
output_queue->modified[output_index] = MIF_FALSE;
|
||||
(output_queue->num_modified)--;
|
||||
}
|
||||
else {
|
||||
output_queue->modified_index[j] = output_queue->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*============================================================================
|
||||
FILE EVTcall_hybrids.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTcall_hybrids which calls all models
|
||||
which have both analog and event-driven ports. It is called following
|
||||
successful evaluation of an analog iteration attempt to allow
|
||||
events to be scheduled by the hybrid models. The 'CALL_TYPE' is set
|
||||
to 'EVENT_DRIVEN' when the model is called from this function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTcall_hybrids(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
/*
|
||||
EVTcall_hybrids
|
||||
|
||||
This function calls all the hybrid instances. It is called following
|
||||
the successful evaluation of an analog iteration.
|
||||
*/
|
||||
|
||||
|
||||
void EVTcall_hybrids(
|
||||
CKTcircuit *ckt) /* the main circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_hybrids;
|
||||
|
||||
int *hybrid_index;
|
||||
|
||||
|
||||
/* Get needed data for fast access */
|
||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||
hybrid_index = ckt->evt->info.hybrid_index;
|
||||
|
||||
/* Call EVTload for all hybrids */
|
||||
for(i = 0; i < num_hybrids; i++)
|
||||
EVTload(ckt, hybrid_index[i]);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,366 @@
|
|||
/*============================================================================
|
||||
FILE EVTdequeue.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTdequeue which removes any items on the
|
||||
output and instance queues with event times matching the specified
|
||||
simulation time.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTdequeue(CKTcircuit *ckt, double time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
static void EVTdequeue_output(CKTcircuit *ckt, double time);
|
||||
static void EVTdequeue_inst(CKTcircuit *ckt, double time);
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt,
|
||||
int output_index,
|
||||
void *value);
|
||||
|
||||
|
||||
/*
|
||||
EVTdequeue
|
||||
|
||||
This function removes any items on the output and instance queues
|
||||
with event times matching the specified simulation time. EVTiter
|
||||
is then called to determine which instances need to be called.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void EVTdequeue(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
double time) /* The event time of the events to dequeue */
|
||||
{
|
||||
|
||||
/* Take all items on output queue with matching time */
|
||||
/* and set changed flags in output queue */
|
||||
EVTdequeue_output(ckt, time);
|
||||
|
||||
/* Take all items on inst queue with matching time */
|
||||
/* and set to_call flags in inst queue */
|
||||
EVTdequeue_inst(ckt, time);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTdequeue_output
|
||||
|
||||
This function de-queues output events with times matching the
|
||||
specified time.
|
||||
*/
|
||||
|
||||
static void EVTdequeue_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
double time) /* The event time of the events to dequeue */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_pending;
|
||||
int index;
|
||||
int output_index;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Output_Event_t *output;
|
||||
Evt_Output_Event_t **output_ptr;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* Exit if nothing pending on output queue or if next_time */
|
||||
/* != specified time */
|
||||
if(output_queue->num_pending == 0)
|
||||
return;
|
||||
if(output_queue->next_time != time)
|
||||
return;
|
||||
|
||||
/* Scan the list of outputs pending */
|
||||
num_pending = output_queue->num_pending;
|
||||
for(i = 0; i < num_pending; i++) {
|
||||
|
||||
/* Get the index of the output */
|
||||
index = output_queue->pending_index[i];
|
||||
|
||||
/* Get pointer to next event in queue at this index */
|
||||
output = *(output_queue->current[index]);
|
||||
|
||||
/* If event time does not match current time, skip */
|
||||
if(output->event_time != time)
|
||||
continue;
|
||||
|
||||
/* It must match, so pull the event from the queue and process it */
|
||||
EVTprocess_output(ckt, index, output->value);
|
||||
|
||||
/* Move current to point to next non-removed item in list */
|
||||
output_ptr = &(output->next);
|
||||
output = *output_ptr;
|
||||
while(output) {
|
||||
if(! output->removed)
|
||||
break;
|
||||
output_ptr = &(output->next);
|
||||
output = *output_ptr;
|
||||
}
|
||||
output_queue->current[index] = output_ptr;
|
||||
|
||||
/* Mark that this index in the queue has been modified */
|
||||
if(! output_queue->modified[index]) {
|
||||
output_queue->modified[index] = MIF_TRUE;
|
||||
output_queue->modified_index[(output_queue->num_modified)++] = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update/compact the pending list and update the next_time */
|
||||
next_time = 1e30;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
output_index = output_queue->pending_index[i];
|
||||
output = *(output_queue->current[output_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! output) {
|
||||
output_queue->pending[output_index] = MIF_FALSE;
|
||||
(output_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
output_queue->pending_index[j] = output_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = output->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
output_queue->next_time = next_time;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTdequeue_inst
|
||||
|
||||
This function de-queues instance events with times matching the
|
||||
specified time.
|
||||
*/
|
||||
|
||||
|
||||
void EVTdequeue_inst(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
double time) /* The event time of the events to dequeue */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_pending;
|
||||
int index;
|
||||
int inst_index;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
|
||||
Evt_Inst_Event_t *inst;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Exit if nothing pending on inst queue or if next_time */
|
||||
/* != specified time */
|
||||
if(inst_queue->num_pending == 0)
|
||||
return;
|
||||
if(inst_queue->next_time != time)
|
||||
return;
|
||||
|
||||
/* Scan the list of insts pending */
|
||||
num_pending = inst_queue->num_pending;
|
||||
for(i = 0; i < num_pending; i++) {
|
||||
|
||||
/* Get the index of the inst */
|
||||
index = inst_queue->pending_index[i];
|
||||
|
||||
/* Get pointer to next event in queue at this index */
|
||||
inst = *(inst_queue->current[index]);
|
||||
|
||||
/* If event time does not match current time, skip */
|
||||
if(inst->event_time != time)
|
||||
continue;
|
||||
|
||||
/* It must match, so pull the event from the queue and process it */
|
||||
if(! inst_queue->to_call[index]) {
|
||||
inst_queue->to_call[index] = MIF_TRUE;
|
||||
inst_queue->to_call_index[(inst_queue->num_to_call)++] =
|
||||
index;
|
||||
}
|
||||
|
||||
/* Move current to point to next item in list */
|
||||
inst_queue->current[index] = &(inst->next);
|
||||
|
||||
/* Mark that this index in the queue has been modified */
|
||||
if(! inst_queue->modified[index]) {
|
||||
inst_queue->modified[index] = MIF_TRUE;
|
||||
inst_queue->modified_index[(inst_queue->num_modified)++] = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update/compact the pending list and update the next_time */
|
||||
next_time = 1e30;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
inst_index = inst_queue->pending_index[i];
|
||||
inst = *(inst_queue->current[inst_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! inst) {
|
||||
inst_queue->pending[inst_index] = MIF_FALSE;
|
||||
(inst_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
inst_queue->pending_index[j] = inst_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = inst->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
inst_queue->next_time = next_time;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTprocess_output
|
||||
|
||||
This function processes a specified output after it is pulled
|
||||
from the queue.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int output_index, /* The index of the output to process */
|
||||
void *value) /* The output value */
|
||||
{
|
||||
|
||||
int num_outputs;
|
||||
int node_index;
|
||||
int udn_index;
|
||||
int output_subindex;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
output_table = ckt->evt->info.output_table;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
node_index = output_table[output_index]->node_index;
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
|
||||
rhs = ckt->evt->data.node->rhs;
|
||||
rhsold = ckt->evt->data.node->rhsold;
|
||||
|
||||
/* Determine if output is different from rhsold value */
|
||||
/* and copy it to rhs AND rhsold if so */
|
||||
/* This is somewhat inefficient, but that's the way */
|
||||
/* we have setup the structures (rhs and rhsold must match)... */
|
||||
if(num_outputs > 1) {
|
||||
output_subindex = output_table[output_index]->output_subindex;
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(value,
|
||||
rhsold[node_index].output_value[output_subindex],
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhs[node_index].output_value[output_subindex]);
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhsold[node_index].output_value[output_subindex]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(value,
|
||||
rhsold[node_index].node_value,
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhs[node_index].node_value);
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhsold[node_index].node_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* If different, put in changed list of output queue */
|
||||
if(! equal) {
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
if(! output_queue->changed[output_index]) {
|
||||
output_queue->changed[output_index] = MIF_TRUE;
|
||||
output_queue->changed_index[(output_queue->num_changed)++] =
|
||||
output_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
/*============================================================================
|
||||
FILE EVTdump.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
6/15/92 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions used
|
||||
to send event-driven node results data to the IPC channel when
|
||||
the simulator is used with CAE software.
|
||||
|
||||
INTERFACES
|
||||
|
||||
EVTdump()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtproto.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "ipc.h"
|
||||
#include "ipctiein.h"
|
||||
#include "ipcproto.h"
|
||||
|
||||
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index); /* The user-defined node index */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTdump
|
||||
|
||||
This function is called to send event-driven node data to the IPC
|
||||
channel. A ``mode'' argument determines how the data is located in
|
||||
the event data structure and what data is sent.
|
||||
|
||||
If the mode is DCOP, then this is necessarily the first call to
|
||||
the function. In this case, the set of event-driven nodes is
|
||||
scanned to determine which should be sent. Only nodes that are
|
||||
not inside subcircuits are sent. Next, the function sends
|
||||
a ``dictionary'' of node names/types vs. node indexes.
|
||||
Finally, the function sends the DC operating point solutions
|
||||
for the event-driven nodes in the dictionary.
|
||||
|
||||
If the mode is DCTRCURVE, it is assumed that the function has
|
||||
already been called with mode = DCOP. The function scans the solution
|
||||
vector and sends data for any nodes that have changed.
|
||||
|
||||
If the mode is TRAN, it is assumed that the function has already
|
||||
been called once with mode = DCOP. The function scans the
|
||||
event data for nodes that have changed since the last accepted
|
||||
analog timepoint and sends the new data.
|
||||
|
||||
Note: This function must be called BEFORE calling EVTop_save or
|
||||
EVTaccept() so that the state of the node data structure will allow
|
||||
it to determine what has changed.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct evtdump_s {
|
||||
Mif_Boolean_t send; /* True if this node should be sent */
|
||||
int ipc_index; /* Index for this node in dict sent to CAE system */
|
||||
char *node_name_str; /* Node name */
|
||||
char *udn_type_str; /* UDN type */
|
||||
} evtdump_dict_t;
|
||||
|
||||
|
||||
|
||||
void EVTdump(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Ipc_Anal_t mode, /* The analysis mode for this call */
|
||||
double step) /* The sweep step for a DCTRCURVE analysis, or */
|
||||
/* 0.0 for DCOP and TRAN */
|
||||
{
|
||||
static evtdump_dict_t *node_dict = NULL;
|
||||
static int num_send_nodes;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int num_nodes;
|
||||
int num_modified;
|
||||
int index;
|
||||
|
||||
char *name;
|
||||
int name_len;
|
||||
|
||||
Mif_Boolean_t firstcall;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhsold;
|
||||
Evt_Node_t **head;
|
||||
Evt_Node_t *here;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
char buff[10000];
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
/* Return immediately if IPC is not enabled */
|
||||
if(! g_ipc.enabled)
|
||||
return;
|
||||
|
||||
/* Get number of event-driven nodes */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
/* Exit immediately if no event-driven nodes in circuit */
|
||||
if(num_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* Get pointers for fast access to event data */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
rhsold = node_data->rhsold;
|
||||
head = node_data->head;
|
||||
|
||||
|
||||
/* Determine if this is the first call */
|
||||
if(node_dict == NULL)
|
||||
firstcall = MIF_TRUE;
|
||||
else
|
||||
firstcall = MIF_FALSE;
|
||||
|
||||
|
||||
/* If this is the first call, get the dictionary info */
|
||||
if(firstcall) {
|
||||
|
||||
/* Allocate local data structure used to process nodes */
|
||||
node_dict = (void *) MALLOC(num_nodes * sizeof(evtdump_dict_t));
|
||||
|
||||
/* Loop through all nodes to determine which nodes should be sent. */
|
||||
/* Only nodes not within subcircuits qualify. */
|
||||
|
||||
num_send_nodes = 0;
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
|
||||
/* Get the name of the node. */
|
||||
name = node_table[i]->name;
|
||||
|
||||
/* If name is in a subcircuit, mark that node should not be sent */
|
||||
/* and continue to next node. */
|
||||
name_len = strlen(name);
|
||||
for(j = 0; j < name_len; j++) {
|
||||
if(name[j] == ':')
|
||||
break;
|
||||
}
|
||||
if(j < name_len) {
|
||||
node_dict[i].send = MIF_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise, fill in info in dictionary. */
|
||||
node_dict[i].send = MIF_TRUE;
|
||||
node_dict[i].ipc_index = num_send_nodes;
|
||||
node_dict[i].node_name_str = name;
|
||||
node_dict[i].udn_type_str = g_evt_udn_info[node_table[i]->udn_index]->name;
|
||||
|
||||
/* Increment the count of nodes to be sent. */
|
||||
num_send_nodes++;
|
||||
} /* end for */
|
||||
} /* end if first call */
|
||||
|
||||
|
||||
/* Exit if there are no nodes to be sent */
|
||||
if(num_send_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* If this is the first call, send the dictionary */
|
||||
if(firstcall) {
|
||||
ipc_send_evtdict_prefix();
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
if(node_dict[i].send) {
|
||||
sprintf(buff, "%d %s %s", node_dict[i].ipc_index,
|
||||
node_dict[i].node_name_str,
|
||||
node_dict[i].udn_type_str);
|
||||
ipc_send_line(buff);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdict_suffix();
|
||||
}
|
||||
|
||||
/* If this is the first call, send the operating point solution */
|
||||
/* and return. */
|
||||
if(firstcall) {
|
||||
ipc_send_evtdata_prefix();
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
if(node_dict[i].send) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, this must be DCTRCURVE or TRAN mode and we need to */
|
||||
/* send only stuff that has changed since the last call. */
|
||||
/* The determination of what to send is modeled after code in */
|
||||
/* EVTop_save() for DCTRCURVE and EVTaccept() for TRAN. */
|
||||
|
||||
if(mode == IPC_ANAL_DCTRCURVE) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through event nodes */
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if(node_dict[i].send) {
|
||||
/* Locate end of node data */
|
||||
here = head[i];
|
||||
for(;;) {
|
||||
if(here->next)
|
||||
here = here->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Compare entry at end of list to rhsold */
|
||||
(*(g_evt_udn_info[node_table[i]->udn_index]->compare)) (
|
||||
rhsold[i].node_value,
|
||||
here->node_value,
|
||||
&equal);
|
||||
/* If value in rhsold is different, send it */
|
||||
if(!equal) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(mode == IPC_ANAL_TRAN) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through list of nodes modified since last time */
|
||||
num_modified = node_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if(node_dict[index].send) {
|
||||
/* Scan through new events and send the data for each event */
|
||||
here = *(node_data->last_step[index]);
|
||||
while((here = here->next)) {
|
||||
EVTsend_line(node_dict[index].ipc_index,
|
||||
here->step,
|
||||
here->node_value,
|
||||
node_table[index]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsend_line
|
||||
|
||||
This function formats the event node data and sends it to the IPC channel.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index) /* The user-defined node index */
|
||||
{
|
||||
double dvalue;
|
||||
char *svalue;
|
||||
void *pvalue;
|
||||
int len;
|
||||
|
||||
/* Get the data to send */
|
||||
if(g_evt_udn_info[udn_index]->plot_val)
|
||||
(*(g_evt_udn_info[udn_index]->plot_val)) (node_value, "", &dvalue);
|
||||
else
|
||||
dvalue = 0.0;
|
||||
|
||||
if(g_evt_udn_info[udn_index]->print_val)
|
||||
(*(g_evt_udn_info[udn_index]->print_val)) (node_value, "", &svalue);
|
||||
else
|
||||
svalue = "";
|
||||
|
||||
if(g_evt_udn_info[udn_index]->ipc_val)
|
||||
(*(g_evt_udn_info[udn_index]->ipc_val)) (node_value, &pvalue, &len);
|
||||
else {
|
||||
pvalue = NULL;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Send it to the IPC channel */
|
||||
ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len);
|
||||
}
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
/*============================================================================
|
||||
FILE EVTinit.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTinit which allocates and initializes
|
||||
evt structure elements after the number of instances, nodes, etc.
|
||||
have been determined in parsing during INPpas2. EVTinit also checks
|
||||
to be sure no nodes have been used for both analog and event-driven
|
||||
algorithms simultaneously.
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTinit(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
static int EVTcheck_nodes(CKTcircuit *ckt);
|
||||
static int EVTcount_hybrids(CKTcircuit *ckt);
|
||||
static int EVTinit_info(CKTcircuit *ckt);
|
||||
static int EVTinit_queue(CKTcircuit *ckt);
|
||||
static int EVTinit_limits(CKTcircuit *ckt);
|
||||
|
||||
|
||||
|
||||
/* Allocation macro with built-in check for out-of-memory */
|
||||
/* Adapted from SPICE 3C1 code in CKTsetup.c */
|
||||
#define CKALLOC(var,size,type) \
|
||||
if(size) { \
|
||||
if(!(var = (void *) MALLOC((size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTinit
|
||||
|
||||
Allocate and initialize additional evt structure elements now that
|
||||
we can determine the number of instances, nodes, etc.
|
||||
|
||||
Also check to be sure that no nodes have been used in both event-driven
|
||||
and analog domains.
|
||||
|
||||
In this version, we also report an error if there are no hybrids in the
|
||||
circuit. This restriction may be removed in the future to allow the
|
||||
simulator to be used with digital only circuits...
|
||||
*/
|
||||
|
||||
|
||||
int EVTinit(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int err; /* SPICE error return code 0 = OK */
|
||||
|
||||
/* static char *err_no_hybrids = "ERROR - no hybrids found in input deck";*/
|
||||
|
||||
|
||||
/* Exit immediately if there are no event-driven instances */
|
||||
/* but don't complain */
|
||||
if(ckt->evt->counts.num_insts == 0)
|
||||
return(OK);
|
||||
|
||||
/* Count the number of hybrids and hybrid outputs */
|
||||
err = EVTcount_hybrids(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Exit with error if there are no hybrids in the circuit. */
|
||||
/* Will probably remove this restriction later... */
|
||||
/*
|
||||
if(ckt->evt->counts.num_hybrids == 0) {
|
||||
errMsg = MALLOC(strlen(err_no_hybrids) + 1);
|
||||
strcpy(errMsg, err_no_hybrids);
|
||||
return(E_PRIVATE);
|
||||
}
|
||||
*/
|
||||
/* Check that event nodes have not been used as analog nodes also */
|
||||
err = EVTcheck_nodes(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Create info table arrays */
|
||||
err = EVTinit_info(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Setup queues */
|
||||
err = EVTinit_queue(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Initialize limits */
|
||||
err = EVTinit_limits(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Note: Options were initialized in CKTinit so that INPpas2 */
|
||||
/* could set values according to .options cards in deck. The */
|
||||
/* structure 'jobs' will be setup immediately prior to each */
|
||||
/* simulation job. The results data structure is also */
|
||||
/* allocated immediately prior to each simulation job. */
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTcount_hybrids
|
||||
|
||||
Count the number of hybrids and the number of outputs on all hybrids.
|
||||
*/
|
||||
|
||||
static int EVTcount_hybrids(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_hybrids;
|
||||
int num_hybrid_outputs;
|
||||
int num_conn;
|
||||
int num_port;
|
||||
|
||||
MIFinstance *fast;
|
||||
|
||||
Evt_Inst_Info_t *inst;
|
||||
|
||||
|
||||
/* Count number of hybrids and hybrid outputs in the inst list */
|
||||
/* created during parsing. Note: other counts */
|
||||
/* are created during parsing, but these were */
|
||||
/* too difficult to do until now... */
|
||||
num_hybrids = 0;
|
||||
num_hybrid_outputs = 0;
|
||||
inst = ckt->evt->info.inst_list;
|
||||
while(inst) {
|
||||
fast = inst->inst_ptr;
|
||||
if(fast->analog && fast->event_driven) {
|
||||
num_hybrids++;
|
||||
num_conn = fast->num_conn;
|
||||
for(i = 0; i < num_conn; i++) {
|
||||
if((! fast->conn[i]->is_null) && (fast->conn[i]->is_output)) {
|
||||
num_port = fast->conn[i]->size;
|
||||
for(j = 0; j < num_port; j++)
|
||||
if(! fast->conn[i]->port[j]->is_null)
|
||||
num_hybrid_outputs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
inst = inst->next;
|
||||
}
|
||||
ckt->evt->counts.num_hybrids = num_hybrids;
|
||||
ckt->evt->counts.num_hybrid_outputs = num_hybrid_outputs;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTcheck_nodes
|
||||
|
||||
Report error if any event node name is also used as an analog node.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTcheck_nodes(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
CKTnode *analog_node;
|
||||
Evt_Node_Info_t *event_node;
|
||||
|
||||
static char *err_prefix = "ERROR - node ";
|
||||
static char *err_collide = " cannot be both analog and digital";
|
||||
|
||||
|
||||
/* Report error if any analog node name matches any event node name */
|
||||
event_node = ckt->evt->info.node_list;
|
||||
while(event_node) {
|
||||
analog_node = ckt->CKTnodes;
|
||||
while(analog_node) {
|
||||
if(strcmp(event_node->name, analog_node->name) == 0) {
|
||||
errMsg = MALLOC(strlen(err_prefix) + strlen(event_node->name) +
|
||||
strlen(err_collide) + 1);
|
||||
sprintf(errMsg, "%s%s%s", err_prefix,
|
||||
event_node->name,
|
||||
err_collide);
|
||||
|
||||
fprintf(stdout,errMsg);
|
||||
|
||||
return(E_PRIVATE);
|
||||
}
|
||||
analog_node = analog_node->next;
|
||||
}
|
||||
event_node = event_node->next;
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTinit_info
|
||||
|
||||
This function creates the ``info'' pointer tables used in the
|
||||
event-driven circuit representation. These arrays allow faster
|
||||
access to data associated with instances, nodes, ports, and
|
||||
outputs than could be provided by having to scan the linked-list
|
||||
representations created during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTinit_info(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_insts;
|
||||
int num_nodes;
|
||||
int num_ports;
|
||||
int num_outputs;
|
||||
|
||||
Evt_Inst_Info_t *inst;
|
||||
Evt_Node_Info_t *node;
|
||||
Evt_Port_Info_t *port;
|
||||
Evt_Output_Info_t *output;
|
||||
|
||||
Evt_Inst_Info_t **inst_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
Evt_Output_Info_t **output_table;
|
||||
|
||||
int *hybrid_index;
|
||||
|
||||
int num_hybrids;
|
||||
|
||||
|
||||
/* Allocate and initialize table of inst pointers */
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
CKALLOC(inst_table, num_insts, void *)
|
||||
inst = ckt->evt->info.inst_list;
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_table[i] = inst;
|
||||
inst = inst->next;
|
||||
}
|
||||
ckt->evt->info.inst_table = inst_table;
|
||||
|
||||
/* Allocate and initialize table of node pointers */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
CKALLOC(node_table, num_nodes, void *)
|
||||
node = ckt->evt->info.node_list;
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
node_table[i] = node;
|
||||
node = node->next;
|
||||
}
|
||||
ckt->evt->info.node_table = node_table;
|
||||
|
||||
/* Allocate and initialize table of port pointers */
|
||||
num_ports = ckt->evt->counts.num_ports;
|
||||
CKALLOC(port_table, num_ports, void *)
|
||||
port = ckt->evt->info.port_list;
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
port_table[i] = port;
|
||||
port = port->next;
|
||||
}
|
||||
ckt->evt->info.port_table = port_table;
|
||||
|
||||
/* Allocate and initialize table of output pointers */
|
||||
num_outputs = ckt->evt->counts.num_outputs;
|
||||
CKALLOC(output_table, num_outputs, void *)
|
||||
output = ckt->evt->info.output_list;
|
||||
for(i = 0; i < num_outputs; i++) {
|
||||
output_table[i] = output;
|
||||
output = output->next;
|
||||
}
|
||||
ckt->evt->info.output_table = output_table;
|
||||
|
||||
|
||||
/* Allocate and create table of indexes into inst_table for hybrids */
|
||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||
CKALLOC(hybrid_index, num_hybrids, int)
|
||||
for(i = 0, j = 0; i < num_insts; i++) {
|
||||
if(inst_table[i]->inst_ptr->analog)
|
||||
hybrid_index[j++] = i;
|
||||
}
|
||||
ckt->evt->info.hybrid_index = hybrid_index;
|
||||
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTinit_queue
|
||||
|
||||
This function prepares the event-driven queues for simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTinit_queue(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int num_insts;
|
||||
int num_nodes;
|
||||
int num_outputs;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Node_Queue_t *node_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
|
||||
/* Allocate elements in the inst queue */
|
||||
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
CKALLOC(inst_queue->head, num_insts, void *)
|
||||
CKALLOC(inst_queue->current, num_insts, void *)
|
||||
CKALLOC(inst_queue->last_step, num_insts, void *)
|
||||
CKALLOC(inst_queue->free, num_insts, void *)
|
||||
CKALLOC(inst_queue->modified_index, num_insts, int)
|
||||
CKALLOC(inst_queue->modified, num_insts, Mif_Boolean_t)
|
||||
CKALLOC(inst_queue->pending_index, num_insts, int)
|
||||
CKALLOC(inst_queue->pending, num_insts, Mif_Boolean_t)
|
||||
CKALLOC(inst_queue->to_call_index, num_insts, int)
|
||||
CKALLOC(inst_queue->to_call, num_insts, Mif_Boolean_t)
|
||||
|
||||
|
||||
/* Allocate elements in the node queue */
|
||||
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
node_queue = &(ckt->evt->queue.node);
|
||||
|
||||
CKALLOC(node_queue->to_eval_index, num_nodes, int)
|
||||
CKALLOC(node_queue->to_eval, num_nodes, Mif_Boolean_t)
|
||||
CKALLOC(node_queue->changed_index, num_nodes, int)
|
||||
CKALLOC(node_queue->changed, num_nodes, Mif_Boolean_t)
|
||||
|
||||
|
||||
/* Allocate elements in the output queue */
|
||||
|
||||
num_outputs = ckt->evt->counts.num_outputs;
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
CKALLOC(output_queue->head, num_outputs, void *)
|
||||
CKALLOC(output_queue->current, num_outputs, void *)
|
||||
CKALLOC(output_queue->last_step, num_outputs, void *)
|
||||
CKALLOC(output_queue->free, num_outputs, void *)
|
||||
CKALLOC(output_queue->modified_index, num_outputs, int)
|
||||
CKALLOC(output_queue->modified, num_outputs, Mif_Boolean_t)
|
||||
CKALLOC(output_queue->pending_index, num_outputs, int)
|
||||
CKALLOC(output_queue->pending, num_outputs, Mif_Boolean_t)
|
||||
CKALLOC(output_queue->changed_index, num_outputs, int)
|
||||
CKALLOC(output_queue->changed, num_outputs, Mif_Boolean_t)
|
||||
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTinit_limits
|
||||
|
||||
This function initializes the iteration limits applicable to the
|
||||
event-driven algorithm.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTinit_limits(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
/* Set maximum number of event load calls within a single event iteration */
|
||||
/* to the number of event outputs. This should allow for the */
|
||||
/* maximum possible number of events that can trickle through any */
|
||||
/* circuit that does not contain loops. */
|
||||
|
||||
ckt->evt->limits.max_event_passes = ckt->evt->counts.num_outputs + 1;
|
||||
|
||||
|
||||
/* Set maximum number of alternations between analog and event-driven */
|
||||
/* iterations to the number of event outputs on hybrids. */
|
||||
|
||||
ckt->evt->limits.max_op_alternations = ckt->evt->counts.num_hybrid_outputs + 1;
|
||||
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
/*============================================================================
|
||||
FILE EVTiter.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTiter which iterates through
|
||||
event-driven outputs and instances until the outputs no longer change.
|
||||
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTiter(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
/*
|
||||
EVTiter
|
||||
|
||||
This function iterates through event-driven outputs and instances
|
||||
until the outputs no longer change. The general algorithm used
|
||||
is:
|
||||
|
||||
Do:
|
||||
|
||||
Scan list of changed outputs
|
||||
Put items on the node queue 'to_eval' list for
|
||||
each changed output.
|
||||
|
||||
Scan list of changed nodes
|
||||
Resolve nodes with multiple outputs posted.
|
||||
Create inverted state for nodes with attached
|
||||
inverted inputs.
|
||||
Put items on the instance queue 'to_call' list
|
||||
for each changed node.
|
||||
If transient analysis, put state of the node
|
||||
into the node data structure.
|
||||
|
||||
Scan instance to_call list
|
||||
Call EVTload for each instance on list.
|
||||
|
||||
While there are changed outputs
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int EVTiter(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_changed;
|
||||
|
||||
int num_to_eval;
|
||||
int num_to_call;
|
||||
|
||||
int output_index;
|
||||
/* int output_subindex;*/
|
||||
int inst_index;
|
||||
int node_index;
|
||||
int port_index;
|
||||
|
||||
int num_outputs;
|
||||
int udn_index;
|
||||
|
||||
int passes;
|
||||
|
||||
Evt_Ckt_Data_t *evt;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Node_Queue_t *node_queue;
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
|
||||
Evt_Inst_Index_t *inst_list;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Node_t *node;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
char *err_msg;
|
||||
|
||||
|
||||
/* Get temporary pointers for fast access */
|
||||
evt = ckt->evt;
|
||||
|
||||
output_queue = &(evt->queue.output);
|
||||
node_queue = &(evt->queue.node);
|
||||
inst_queue = &(evt->queue.inst);
|
||||
|
||||
output_table = evt->info.output_table;
|
||||
node_table = evt->info.node_table;
|
||||
port_table = evt->info.port_table;
|
||||
|
||||
node_data = evt->data.node;
|
||||
rhs = node_data->rhs;
|
||||
rhsold = node_data->rhsold;
|
||||
|
||||
|
||||
/* Loop until no more output change, or too many passes through loop */
|
||||
for(passes = 0; passes < evt->limits.max_event_passes; passes++) {
|
||||
|
||||
|
||||
/* Create list of nodes to evaluate from list of changed outputs */
|
||||
num_changed = output_queue->num_changed;
|
||||
for(i = 0; i < num_changed; i++) {
|
||||
|
||||
/* Get index of node that output is connected to */
|
||||
output_index = output_queue->changed_index[i];
|
||||
node_index = output_table[output_index]->node_index;
|
||||
|
||||
/* If not already on list of nodes to evaluate, add it */
|
||||
if(! node_queue->to_eval[node_index]) {
|
||||
node_queue->to_eval[node_index] = MIF_TRUE;
|
||||
node_queue->to_eval_index[(node_queue->num_to_eval)++]
|
||||
= node_index;
|
||||
}
|
||||
|
||||
/* Reset the changed flag on the output queue */
|
||||
output_queue->changed[output_index] = MIF_FALSE;
|
||||
|
||||
}
|
||||
output_queue->num_changed = 0;
|
||||
|
||||
|
||||
|
||||
/* Evaluate nodes and for any which have changed, enter */
|
||||
/* the instances that receive inputs from them on the list */
|
||||
/* of instances to call */
|
||||
|
||||
num_to_eval = node_queue->num_to_eval;
|
||||
for(i = 0; i < num_to_eval; i++) {
|
||||
|
||||
/* Get the node index, udn index and number of outputs */
|
||||
node_index = node_queue->to_eval_index[i];
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
|
||||
/* Resolve the node value if multiple outputs on it */
|
||||
/* and test if new node value is different than old value */
|
||||
if(num_outputs > 1) {
|
||||
(*(g_evt_udn_info[udn_index]->resolve))
|
||||
(num_outputs,
|
||||
rhs[node_index].output_value,
|
||||
rhs[node_index].node_value);
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value,
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value);
|
||||
}
|
||||
}
|
||||
/* Else, load function has already determined that they were */
|
||||
/* not equal */
|
||||
else
|
||||
equal = MIF_FALSE;
|
||||
|
||||
/* If not equal, make inverted copy in rhsold if */
|
||||
/* needed, and place indexes of instances with inputs connected */
|
||||
/* to the node in the to_call list of inst queue */
|
||||
if(! equal) {
|
||||
if(node_table[node_index]->invert) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhsold[node_index].node_value,
|
||||
rhsold[node_index].inverted_value);
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(rhsold[node_index].inverted_value);
|
||||
}
|
||||
inst_list = node_table[node_index]->inst_list;
|
||||
while(inst_list) {
|
||||
inst_index = inst_list->index;
|
||||
if(! inst_queue->to_call[inst_index]) {
|
||||
inst_queue->to_call[inst_index] = MIF_TRUE;
|
||||
inst_queue->to_call_index[(inst_queue->num_to_call)++]
|
||||
= inst_index;
|
||||
}
|
||||
inst_list = inst_list->next;
|
||||
} /* end while instances with inputs on node */
|
||||
} /* end if not equal */
|
||||
|
||||
/* If transient analysis mode */
|
||||
/* Save the node data onto the node results list and mark */
|
||||
/* that it has been modified, even if the */
|
||||
/* resolved node value has not changed */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
|
||||
node = *(node_data->tail[node_index]);
|
||||
node_data->tail[node_index] = &(node->next);
|
||||
EVTnode_copy(ckt, node_index, &(rhsold[node_index]), &(node->next));
|
||||
node->next->step = g_mif_info.circuit.evt_step;
|
||||
|
||||
if(! node_data->modified[node_index]) {
|
||||
node_data->modified[node_index] = MIF_TRUE;
|
||||
node_data->modified_index[(node_data->num_modified)++] = node_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the to_eval flag on the node queue */
|
||||
node_queue->to_eval[node_index] = MIF_FALSE;
|
||||
|
||||
} /* end for number of nodes to evaluate */
|
||||
node_queue->num_to_eval = 0;
|
||||
|
||||
|
||||
|
||||
/* Call the instances with inputs on nodes that have changed */
|
||||
num_to_call = inst_queue->num_to_call;
|
||||
for(i = 0; i < num_to_call; i++) {
|
||||
inst_index = inst_queue->to_call_index[i];
|
||||
inst_queue->to_call[inst_index] = MIF_FALSE;
|
||||
EVTload(ckt, inst_index);
|
||||
}
|
||||
inst_queue->num_to_call = 0;
|
||||
|
||||
|
||||
/* Record statistics */
|
||||
if(g_mif_info.circuit.anal_type == MIF_DC)
|
||||
(ckt->evt->data.statistics->op_event_passes)++;
|
||||
|
||||
|
||||
/* If no outputs changed, iteration is over, so return with success! */
|
||||
if(output_queue->num_changed == 0)
|
||||
return(0);
|
||||
|
||||
} /* end for */
|
||||
|
||||
|
||||
/* Too many passes through loop, report problems and exit with error */
|
||||
|
||||
err_msg = MALLOC(10000);
|
||||
for(i = 0; i < output_queue->num_changed; i++) {
|
||||
output_index = output_queue->changed_index[i];
|
||||
port_index = output_table[output_index]->port_index;
|
||||
sprintf(err_msg, "\n Instance: %s\n Connection: %s\n Port: %d",
|
||||
port_table[port_index]->inst_name,
|
||||
port_table[port_index]->conn_name,
|
||||
port_table[port_index]->port_num);
|
||||
ENHreport_conv_prob(ENH_EVENT_NODE,
|
||||
port_table[port_index]->node_name,
|
||||
err_msg);
|
||||
}
|
||||
FREE(err_msg);
|
||||
|
||||
(*(SPfrontEnd->IFerror)) (ERR_WARNING,
|
||||
"Too many iteration passes in event-driven circuits",
|
||||
(IFuid *) NULL);
|
||||
return(E_ITERLIM);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,613 @@
|
|||
/*============================================================================
|
||||
FILE EVTload.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTload which is used to call a
|
||||
specified event-driven or hybrid code model during an event-driven
|
||||
iteration. The 'CALL_TYPE' is set to 'EVENT_DRIVEN' when the
|
||||
model is called from this function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTload(CKTcircuit *ckt, int inst_index)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "devdefs.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
extern SPICEdev **DEVices;
|
||||
|
||||
|
||||
|
||||
static void EVTcreate_state(
|
||||
CKTcircuit *ckt,
|
||||
int inst_index);
|
||||
|
||||
static void EVTadd_msg(
|
||||
CKTcircuit *ckt,
|
||||
int port_index,
|
||||
char *msg_text);
|
||||
|
||||
static void EVTcreate_output_event(
|
||||
CKTcircuit *ckt,
|
||||
int node_index,
|
||||
int output_index,
|
||||
void **value_ptr);
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt,
|
||||
Mif_Boolean_t changed,
|
||||
int output_index,
|
||||
Mif_Boolean_t invert,
|
||||
double delay);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTload
|
||||
|
||||
This function calls the code model function for the specified
|
||||
instance with CALL_TYPE set to EVENT_DRIVEN. Event outputs,
|
||||
messages, etc. are processed on return from the code model.
|
||||
Analog outputs, partials, etc. should not be computed by the
|
||||
code model when the call type is event-driven and are
|
||||
ignored.
|
||||
*/
|
||||
|
||||
int EVTload(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index) /* The instance to call code model for */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_conn;
|
||||
int num_port;
|
||||
int mod_type;
|
||||
|
||||
Mif_Conn_Data_t *conn;
|
||||
Mif_Port_Data_t *port;
|
||||
|
||||
Mif_Private_t cm_data;
|
||||
|
||||
MIFinstance *inst;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
void *value_ptr;
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Prepare the code model inputs */
|
||||
/* ***************************** */
|
||||
|
||||
/* Get pointer to instance data structure and other data */
|
||||
/* needed for fast access */
|
||||
inst = ckt->evt->info.inst_table[inst_index]->inst_ptr;
|
||||
node_data = ckt->evt->data.node;
|
||||
|
||||
/* Setup circuit data in struct to be passed to code model function */
|
||||
|
||||
if(inst->initialized)
|
||||
cm_data.circuit.init = MIF_FALSE;
|
||||
else
|
||||
cm_data.circuit.init = MIF_TRUE;
|
||||
|
||||
cm_data.circuit.anal_init = MIF_FALSE;
|
||||
cm_data.circuit.anal_type = g_mif_info.circuit.anal_type;
|
||||
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
cm_data.circuit.time = g_mif_info.circuit.evt_step;
|
||||
else
|
||||
cm_data.circuit.time = 0.0;
|
||||
|
||||
cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
cm_data.circuit.temperature = ckt->CKTtemp - 273.15;
|
||||
|
||||
|
||||
/* Setup data needed by cm_... functions */
|
||||
|
||||
g_mif_info.ckt = ckt;
|
||||
g_mif_info.instance = inst;
|
||||
g_mif_info.errmsg = "";
|
||||
g_mif_info.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
|
||||
if(inst->initialized)
|
||||
g_mif_info.circuit.init = MIF_FALSE;
|
||||
else
|
||||
g_mif_info.circuit.init = MIF_TRUE;
|
||||
|
||||
|
||||
/* If after initialization and in transient analysis mode */
|
||||
/* create a new state for the instance */
|
||||
|
||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized)
|
||||
EVTcreate_state(ckt, inst_index);
|
||||
|
||||
|
||||
/* Loop through all connections on the instance and setup */
|
||||
/* load, total_load, and msg on all ports, and changed flag */
|
||||
/* and output pointer on all outputs */
|
||||
|
||||
num_conn = inst->num_conn;
|
||||
for(i = 0; i < num_conn; i++) {
|
||||
|
||||
conn = inst->conn[i];
|
||||
|
||||
/* if connection is null, continue to next */
|
||||
if(conn->is_null)
|
||||
continue;
|
||||
|
||||
/* Loop through each port on the connection */
|
||||
num_port = conn->size;
|
||||
for(j = 0; j < num_port; j++) {
|
||||
|
||||
port = conn->port[j];
|
||||
|
||||
/* Skip if port is null */
|
||||
if(port->is_null)
|
||||
continue;
|
||||
|
||||
/* If port type is Digital or User-Defined */
|
||||
if((port->type == MIF_DIGITAL) || (port->type == MIF_USER_DEFINED)) {
|
||||
|
||||
/* Initialize the msg pointer on the port to NULL, */
|
||||
/* initialize the load value to zero, and get the total load */
|
||||
port->msg = NULL;
|
||||
port->load = 0.0;
|
||||
port->total_load = node_data->total_load[port->evt_data.node_index];
|
||||
|
||||
/* If connection is an output, initialize changed to true */
|
||||
/* and create a new output event object in the free list */
|
||||
/* if transient analysis mode */
|
||||
if(conn->is_output) {
|
||||
port->changed = MIF_TRUE;
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
EVTcreate_output_event(ckt,
|
||||
port->evt_data.node_index,
|
||||
port->evt_data.output_index,
|
||||
&value_ptr);
|
||||
port->output.pvalue = value_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Get the analog input value. All we need to do is */
|
||||
/* set it to zero if mode is INITJCT. Otherwise, value */
|
||||
/* should still be around from last successful analog call */
|
||||
if(ckt->CKTmode & MODEINITJCT)
|
||||
port->input.rvalue = 0.0;
|
||||
}
|
||||
|
||||
} /* end for number of ports */
|
||||
} /* end for number of connections */
|
||||
|
||||
|
||||
/* Prepare the structure to be passed to the code model */
|
||||
cm_data.num_conn = inst->num_conn;
|
||||
cm_data.conn = inst->conn;
|
||||
cm_data.num_param = inst->num_param;
|
||||
cm_data.param = inst->param;
|
||||
cm_data.num_inst_var = inst->num_inst_var;
|
||||
cm_data.inst_var = inst->inst_var;
|
||||
|
||||
|
||||
/* ******************* */
|
||||
/* Call the code model */
|
||||
/* ******************* */
|
||||
|
||||
mod_type = inst->MIFmodPtr->MIFmodType;
|
||||
(*(DEVices[mod_type]->DEVpublic.cm_func)) (&cm_data);
|
||||
|
||||
|
||||
/* ****************************** */
|
||||
/* Process the code model outputs */
|
||||
/* ****************************** */
|
||||
|
||||
/* Loop through all connections and ports and process the msgs */
|
||||
/* and event outputs */
|
||||
|
||||
num_conn = inst->num_conn;
|
||||
for(i = 0; i < num_conn; i++) {
|
||||
|
||||
conn = inst->conn[i];
|
||||
if(conn->is_null)
|
||||
continue;
|
||||
|
||||
/* Loop through each port on the connection */
|
||||
num_port = conn->size;
|
||||
for(j = 0; j < num_port; j++) {
|
||||
|
||||
port = conn->port[j];
|
||||
|
||||
/* Skip if port is null */
|
||||
if(port->is_null)
|
||||
continue;
|
||||
|
||||
/* Process the message if any */
|
||||
if(port->msg)
|
||||
EVTadd_msg(ckt, port->evt_data.port_index, port->msg);
|
||||
|
||||
/* If this is the initialization pass, process the load factor */
|
||||
if(! inst->initialized) {
|
||||
node_data->total_load[port->evt_data.node_index] +=
|
||||
port->load;
|
||||
}
|
||||
|
||||
/* If connection is not an event output, continue to next port */
|
||||
if(! conn->is_output)
|
||||
continue;
|
||||
if((port->type != MIF_DIGITAL) && (port->type != MIF_USER_DEFINED))
|
||||
continue;
|
||||
|
||||
/* If output changed, process it */
|
||||
EVTprocess_output(ckt, port->changed,
|
||||
port->evt_data.output_index,
|
||||
port->invert, port->delay);
|
||||
|
||||
/* And prevent erroneous models from overwriting it during */
|
||||
/* analog iterations */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
port->output.pvalue = NULL;
|
||||
|
||||
} /* end for number of ports */
|
||||
} /* end for number of connections */
|
||||
|
||||
|
||||
/* Record statistics */
|
||||
if(g_mif_info.circuit.anal_type == MIF_DC)
|
||||
(ckt->evt->data.statistics->op_load_calls)++;
|
||||
else if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
(ckt->evt->data.statistics->tran_load_calls)++;
|
||||
|
||||
/* Mark that the instance has been called once */
|
||||
inst->initialized = MIF_TRUE;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTcreate_state
|
||||
|
||||
This function creates a new state storage area for a particular instance
|
||||
during an event-driven simulation. New states must be created so
|
||||
that old states are saved and can be accessed by code models in the
|
||||
future. The new state is initialized to the previous state value.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTcreate_state(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index) /* The instance to create state for */
|
||||
{
|
||||
int i;
|
||||
int total_size;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
|
||||
Evt_State_t *new_state;
|
||||
Evt_State_t *prev_state;
|
||||
|
||||
char *from;
|
||||
char *to;
|
||||
|
||||
|
||||
/* Get variables for fast access */
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
/* Exit immediately if no states on this instance */
|
||||
if(state_data->desc[inst_index] == NULL)
|
||||
return;
|
||||
|
||||
/* Get size of state block to be allocated */
|
||||
total_size = state_data->total_size[inst_index];
|
||||
|
||||
/* Allocate a new state for the instance */
|
||||
if(state_data->free[inst_index])
|
||||
{
|
||||
new_state = state_data->free[inst_index];
|
||||
state_data->free[inst_index] = new_state->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
new_state = (void *) MALLOC(sizeof(Evt_State_t));
|
||||
new_state->block = (void *) MALLOC(total_size);
|
||||
|
||||
}
|
||||
|
||||
/* Splice the new state into the state data linked list */
|
||||
/* and update the tail pointer */
|
||||
prev_state = *(state_data->tail[inst_index]);
|
||||
prev_state->next = new_state;
|
||||
new_state->prev = prev_state;
|
||||
state_data->tail[inst_index] = &(prev_state->next);
|
||||
|
||||
/* Copy the old state to the new state and set the step */
|
||||
from = prev_state->block;
|
||||
to = new_state->block;
|
||||
for(i = 0; i < total_size; i++)
|
||||
to[i] = from[i];
|
||||
new_state->step = g_mif_info.circuit.evt_step;
|
||||
|
||||
/* Mark that the state data on the instance has been modified */
|
||||
if(! state_data->modified[inst_index]) {
|
||||
state_data->modified[inst_index] = MIF_TRUE;
|
||||
state_data->modified_index[(state_data->num_modified)++] = inst_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTcreate_output_event
|
||||
|
||||
This function creates a new output event.
|
||||
*/
|
||||
|
||||
static void EVTcreate_output_event(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int node_index, /* The node type port is on */
|
||||
int output_index, /* The output index for this port */
|
||||
void **value_ptr) /* The event created */
|
||||
{
|
||||
int udn_index;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Output_Event_t *event;
|
||||
|
||||
|
||||
/* Check the output queue free list and use the structure */
|
||||
/* at the head of the list if non-null. Otherwise, create a new one. */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
if(output_queue->free[output_index]) {
|
||||
*value_ptr = output_queue->free[output_index]->value;
|
||||
}
|
||||
else {
|
||||
/* Create a new event */
|
||||
event = (void *) MALLOC(sizeof(Evt_Output_Event_t));
|
||||
event->next = NULL;
|
||||
|
||||
/* Initialize the value */
|
||||
node_table = ckt->evt->info.node_table;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(event->value));
|
||||
|
||||
/* Put the event onto the free list and return the value pointer */
|
||||
output_queue->free[output_index] = event;
|
||||
*value_ptr = event->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTadd_msg
|
||||
|
||||
This function records a message output by a code model into the
|
||||
message results data structure.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTadd_msg(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int port_index, /* The port to add message to */
|
||||
char *msg_text) /* The message text */
|
||||
{
|
||||
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
|
||||
Evt_Msg_t **msg_ptr;
|
||||
Evt_Msg_t *msg;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
msg_data = ckt->evt->data.msg;
|
||||
msg_ptr = msg_data->tail[port_index];
|
||||
|
||||
/* Set pointer to location at which to add, and update tail */
|
||||
if(*msg_ptr != NULL) {
|
||||
msg_ptr = &((*msg_ptr)->next);
|
||||
msg_data->tail[port_index] = msg_ptr;
|
||||
}
|
||||
|
||||
/* Add a new entry in the list of messages for this port */
|
||||
if(msg_data->free[port_index]) {
|
||||
*msg_ptr = msg_data->free[port_index];
|
||||
msg_data->free[port_index] = msg_data->free[port_index]->next;
|
||||
}
|
||||
else {
|
||||
*msg_ptr = (void *) MALLOC(sizeof(Evt_Msg_t));
|
||||
}
|
||||
|
||||
/* Fill in the values */
|
||||
msg = *msg_ptr;
|
||||
msg->next = NULL;
|
||||
if((ckt->CKTmode & MODEDCOP) == MODEDCOP)
|
||||
msg->op = MIF_TRUE;
|
||||
else
|
||||
msg->step = g_mif_info.circuit.evt_step;
|
||||
msg->text = MIFcopy(msg_text);
|
||||
|
||||
/* Update the modified indexes */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
if(! msg_data->modified[port_index]) {
|
||||
msg_data->modified[port_index] = MIF_TRUE;
|
||||
msg_data->modified_index[(msg_data->num_modified)++] = port_index;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTprocess_output
|
||||
|
||||
This function processes an event-driven output produced by a code
|
||||
model. If transient analysis mode, the event is placed into the
|
||||
output queue according to its (non-zero) delay. If DC analysis,
|
||||
the event is processed immediately.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Mif_Boolean_t changed, /* Has output changed? */
|
||||
int output_index, /* The output of interest */
|
||||
Mif_Boolean_t invert, /* Does output need to be inverted? */
|
||||
double delay) /* The output delay in transient analysis */
|
||||
{
|
||||
|
||||
int num_outputs;
|
||||
int node_index;
|
||||
int udn_index;
|
||||
int output_subindex;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Output_Event_t *output_event;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
output_table = ckt->evt->info.output_table;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
node_index = output_table[output_index]->node_index;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
|
||||
|
||||
/* if transient analysis, just put the output event on the queue */
|
||||
/* to be processed at a later time */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
/* If model signaled that output was not posted, */
|
||||
/* leave the event struct on the free list and return */
|
||||
if((! changed) || (delay <= 0.0)) {
|
||||
if(changed && (delay <= 0.0))
|
||||
printf("\nERROR - Output delay <= 0 not allowed - output ignored!\n");
|
||||
return;
|
||||
}
|
||||
/* Remove the (now used) struct from the head of the free list */
|
||||
output_event = output_queue->free[output_index];
|
||||
output_queue->free[output_index] = output_event->next;
|
||||
/* Invert the output value if necessary */
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(output_event->value);
|
||||
/* Add it to the queue */
|
||||
EVTqueue_output(ckt, output_index, udn_index, output_event,
|
||||
g_mif_info.circuit.evt_step,
|
||||
g_mif_info.circuit.evt_step + delay);
|
||||
return;
|
||||
}
|
||||
/* If not transient analysis, process immediately. */
|
||||
/* Determine if output has changed from rhsold value */
|
||||
/* and put entry in output queue changed list if so */
|
||||
else {
|
||||
|
||||
/* If model signaled that output was not posted, */
|
||||
/* just return */
|
||||
if(! changed)
|
||||
return;
|
||||
/*
|
||||
if(delay > 0.0)
|
||||
printf("\nWARNING - Non-zero output delay not allowed in DCOP - delay ignored!\n");
|
||||
*/
|
||||
rhs = ckt->evt->data.node->rhs;
|
||||
rhsold = ckt->evt->data.node->rhsold;
|
||||
|
||||
/* Determine if changed */
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
if(num_outputs > 1) {
|
||||
output_subindex = output_table[output_index]->output_subindex;
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(rhs[node_index].output_value[output_subindex]);
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(rhs[node_index].output_value[output_subindex],
|
||||
rhsold[node_index].output_value[output_subindex],
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhs[node_index].output_value[output_subindex],
|
||||
rhsold[node_index].output_value[output_subindex]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(rhs[node_index].node_value);
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value,
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* If changed, put in changed list of output queue */
|
||||
if(! equal) {
|
||||
if(! output_queue->changed[output_index]) {
|
||||
output_queue->changed[output_index] = MIF_TRUE;
|
||||
output_queue->changed_index[(output_queue->num_changed)++] =
|
||||
output_index;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
} /* end else process immediately */
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*============================================================================
|
||||
FILE EVTnext_time.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTnext_time which determines and
|
||||
returns the time of the next scheduled event on the inst and output
|
||||
queues.
|
||||
|
||||
INTERFACES
|
||||
|
||||
double EVTnext_time(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTnext_time
|
||||
|
||||
Get the next event time as the minimum of the next times
|
||||
in the inst and output queues. If no next time in either,
|
||||
return machine infinity.
|
||||
*/
|
||||
|
||||
|
||||
double EVTnext_time(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
double next_time;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
|
||||
/* Initialize next time to machine infinity */
|
||||
next_time = 1e30;
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* If anything pending in inst queue, set next time */
|
||||
/* to minimum of itself and the inst queue next time */
|
||||
if(inst_queue->num_pending)
|
||||
if(inst_queue->next_time < next_time)
|
||||
next_time = inst_queue->next_time;
|
||||
|
||||
/* If anything pending in output queue, set next time */
|
||||
/* to minimum of itself and the output queue next time */
|
||||
if(output_queue->num_pending)
|
||||
if(output_queue->next_time < next_time)
|
||||
next_time = output_queue->next_time;
|
||||
|
||||
return(next_time);
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*============================================================================
|
||||
FILE EVTnode_copy.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTnode_copy which copies the state
|
||||
of a node structure.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTnode_copy(CKTcircuit *ckt, int node_index, Evt_Node_t *from,
|
||||
Evt_Node_t **to)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
#include "cm.h"
|
||||
|
||||
/*
|
||||
EVTnode_copy
|
||||
|
||||
This function copies the state of a node structure.
|
||||
|
||||
If the destination is NULL, it is allocated before the copy. This is the
|
||||
case when EVTiter copies a node during a transient analysis to
|
||||
save the state of an element of rhsold into the node data structure
|
||||
lists.
|
||||
|
||||
If the destination is non-NULL, only the internal elements of the node
|
||||
structure are copied. This is the case when EVTbackup restores that state
|
||||
of nodes that existed at a certain timestep back into rhs and rhsold.
|
||||
*/
|
||||
|
||||
|
||||
void EVTnode_copy(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int node_index, /* The node to copy */
|
||||
Evt_Node_t *from, /* Location to copy from */
|
||||
Evt_Node_t **to) /* Location to copy to */
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
int udn_index;
|
||||
int num_outputs;
|
||||
Mif_Boolean_t invert;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
Evt_Node_t *here;
|
||||
|
||||
/* Digital_t *dummy;*/
|
||||
|
||||
/* char buff[128];*/
|
||||
|
||||
/* Get data for fast access */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
invert = node_table[node_index]->invert;
|
||||
|
||||
|
||||
/* If destination is not allocated, allocate it */
|
||||
/* otherwise we just copy into the node struct */
|
||||
here = *to;
|
||||
|
||||
if(here == NULL)
|
||||
{
|
||||
/* Use allocated structure on free list if available */
|
||||
/* Otherwise, allocate a new one */
|
||||
here = node_data->free[node_index];
|
||||
if(here)
|
||||
{
|
||||
*to = here;
|
||||
node_data->free[node_index] = here->next;
|
||||
here->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
here = (void *) MALLOC(sizeof(Evt_Node_t));
|
||||
*to = here;
|
||||
/* Allocate/initialize the data in the new node struct */
|
||||
if(num_outputs > 1)
|
||||
{
|
||||
here->output_value = (void *) MALLOC(num_outputs * sizeof(void *));
|
||||
|
||||
for(i = 0; i < num_outputs; i++)
|
||||
{
|
||||
(*(g_evt_udn_info[udn_index]->create))
|
||||
( &(here->output_value[i]) );
|
||||
}
|
||||
}
|
||||
|
||||
here->node_value = NULL;
|
||||
|
||||
(*(g_evt_udn_info[udn_index]->create)) ( &(here->node_value) );
|
||||
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->create)) ( &(here->inverted_value) );
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the node data */
|
||||
here->op = from->op;
|
||||
here->step = from->step;
|
||||
if(num_outputs > 1)
|
||||
{
|
||||
for(i = 0; i < num_outputs; i++)
|
||||
{
|
||||
(*(g_evt_udn_info[udn_index]->copy)) (from->output_value[i],
|
||||
here->output_value[i]);
|
||||
}
|
||||
}
|
||||
(*(g_evt_udn_info[udn_index]->copy)) (from->node_value, here->node_value);
|
||||
if(invert)
|
||||
{
|
||||
(*(g_evt_udn_info[udn_index]->copy)) (from->inverted_value,
|
||||
here->inverted_value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/*============================================================================
|
||||
FILE EVTop.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTop which is used to perform an
|
||||
operating point analysis in place of CKTop when there are
|
||||
event-driven instances in the circuit. It alternates between doing
|
||||
event-driven iterations with EVTiter and doing analog iterations with
|
||||
NIiter/CKTop until no more event-driven outputs change.
|
||||
|
||||
INTERFACES
|
||||
|
||||
EVTop()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtproto.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
|
||||
static void EVTnode_compare(
|
||||
CKTcircuit *ckt,
|
||||
int node_index,
|
||||
Evt_Node_t *node1,
|
||||
Evt_Node_t *node2,
|
||||
Mif_Boolean_t *equal);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTop
|
||||
|
||||
This function is used to perform an operating point analysis
|
||||
in place of CKTop when there are event-driven instances in the
|
||||
circuit. It alternates between doing event-driven iterations
|
||||
with EVTiter and doing analog iterations with NIiter/CKTop
|
||||
until no more event-driven outputs change.
|
||||
*/
|
||||
|
||||
|
||||
int EVTop(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
long firstmode, /* The SPICE 3C1 CKTop() firstmode parameter */
|
||||
long continuemode, /* The SPICE 3C1 CKTop() continuemode paramter */
|
||||
int max_iter, /* The SPICE 3C1 CKTop() max iteration parameter */
|
||||
Mif_Boolean_t first_call) /* Is this the first time through? */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_insts;
|
||||
int converged;
|
||||
int output_index;
|
||||
int port_index;
|
||||
|
||||
char *err_msg;
|
||||
|
||||
Mif_Boolean_t firstime;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
|
||||
|
||||
/* get data to local storage for fast access */
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Initialize to_call entries in event inst queue */
|
||||
/* to force calling all event/hybrid instance the first */
|
||||
/* time through */
|
||||
|
||||
if(first_call) {
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_queue->to_call[i] = MIF_TRUE;
|
||||
inst_queue->to_call_index[i] = i;
|
||||
}
|
||||
inst_queue->num_to_call = num_insts;
|
||||
}
|
||||
|
||||
|
||||
/* Alternate between event-driven and analog solutions until */
|
||||
/* there are no changed event-driven outputs */
|
||||
|
||||
firstime = MIF_TRUE;
|
||||
for(;;) {
|
||||
|
||||
/* Call EVTiter to establish initial outputs from */
|
||||
/* event/hybrid instances with states (e.g. flip-flops) */
|
||||
|
||||
ckt->CKTmode = firstmode;
|
||||
converged = EVTiter(ckt);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
|
||||
/* Now do analog solution for current state of hybrid outputs */
|
||||
|
||||
/* If first analog solution, call CKTop */
|
||||
if(firstime) {
|
||||
firstime = MIF_FALSE;
|
||||
converged = CKTop(ckt,
|
||||
firstmode,
|
||||
continuemode,
|
||||
max_iter);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
}
|
||||
/* Otherwise attempt to converge with mode = continuemode */
|
||||
else {
|
||||
ckt->CKTmode = continuemode;
|
||||
converged = NIiter(ckt,max_iter);
|
||||
if(converged != 0) {
|
||||
converged = CKTop(ckt,
|
||||
firstmode,
|
||||
continuemode,
|
||||
max_iter);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call all hybrids to allow new event outputs to be posted */
|
||||
EVTcall_hybrids(ckt);
|
||||
|
||||
/* Increment count of successful alternations */
|
||||
(ckt->evt->data.statistics->op_alternations)++;
|
||||
|
||||
/* If .option card specified not to alternate solutions, exit */
|
||||
/* immediately with this first pass solution */
|
||||
if(! ckt->evt->options.op_alternate)
|
||||
return(0);
|
||||
|
||||
/* If no hybrid instances produced different event outputs, */
|
||||
/* alternation is completed, so exit */
|
||||
if(ckt->evt->queue.output.num_changed == 0)
|
||||
return(0);
|
||||
|
||||
/* If too many alternations, exit with error */
|
||||
if(ckt->evt->data.statistics->op_alternations >=
|
||||
ckt->evt->limits.max_op_alternations) {
|
||||
|
||||
(*(SPfrontEnd->IFerror)) (ERR_WARNING,
|
||||
"Too many analog/event-driven solution alternations",
|
||||
(IFuid *) NULL);
|
||||
|
||||
err_msg = MALLOC(10000);
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
output_table = ckt->evt->info.output_table;
|
||||
port_table = ckt->evt->info.port_table;
|
||||
|
||||
for(i = 0; i < output_queue->num_changed; i++) {
|
||||
output_index = output_queue->changed_index[i];
|
||||
port_index = output_table[output_index]->port_index;
|
||||
sprintf(err_msg, "\n Instance: %s\n Connection: %s\n Port: %d",
|
||||
port_table[port_index]->inst_name,
|
||||
port_table[port_index]->conn_name,
|
||||
port_table[port_index]->port_num);
|
||||
ENHreport_conv_prob(ENH_EVENT_NODE,
|
||||
port_table[port_index]->node_name,
|
||||
err_msg);
|
||||
}
|
||||
FREE(err_msg);
|
||||
|
||||
return(E_ITERLIM);
|
||||
}
|
||||
|
||||
} /* end forever */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTop_save
|
||||
|
||||
Save result from operating point iteration into the node data area.
|
||||
*/
|
||||
|
||||
void EVTop_save(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Mif_Boolean_t op, /* True if from a DCOP analysis, false if TRANOP, etc. */
|
||||
double step)
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_nodes;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhsold;
|
||||
Evt_Node_t **head;
|
||||
Evt_Node_t **here;
|
||||
|
||||
/* char buff[128];*/
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
node_data = ckt->evt->data.node;
|
||||
rhsold = node_data->rhsold;
|
||||
head = node_data->head;
|
||||
|
||||
/* For number of event nodes, copy rhsold to node data */
|
||||
/* and set the op member if appropriate */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
for(i = 0; i < num_nodes; i++)
|
||||
{
|
||||
/* if head is null, just copy there */
|
||||
if(head[i] == NULL)
|
||||
{
|
||||
EVTnode_copy(ckt, i, &(rhsold[i]), &(head[i]));
|
||||
|
||||
head[i]->op = op;
|
||||
head[i]->step = step;
|
||||
|
||||
}
|
||||
/* Otherwise, add to the end of the list */
|
||||
else
|
||||
{
|
||||
/* Locate end of list */
|
||||
here = &(head[i]);
|
||||
for(;;)
|
||||
{
|
||||
if((*here)->next)
|
||||
here = &((*here)->next);
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Compare entry at end of list to rhsold */
|
||||
|
||||
EVTnode_compare(ckt, i, &(rhsold[i]), *here, &equal);
|
||||
|
||||
/* If new value in rhsold is different, add it to the list */
|
||||
if(!equal)
|
||||
{
|
||||
here = &((*here)->next);
|
||||
EVTnode_copy(ckt, i, &(rhsold[i]), here);
|
||||
(*here)->op = op;
|
||||
(*here)->step = step;
|
||||
}
|
||||
} /* end else add to end of list */
|
||||
} /* end for number of nodes */
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ************************************************************ */
|
||||
|
||||
|
||||
/*
|
||||
EVTnode_compare
|
||||
|
||||
This function compares the resolved values of the old and
|
||||
new states on a node. The actual comparison is done by
|
||||
calling the appropriate user-defined node compare function.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTnode_compare(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int node_index, /* The index for the node in question */
|
||||
Evt_Node_t *node1, /* The first value */
|
||||
Evt_Node_t *node2, /* The second value */
|
||||
Mif_Boolean_t *equal) /* The computed result */
|
||||
{
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
int udn_index;
|
||||
|
||||
|
||||
/* Get data for fast access */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
|
||||
|
||||
/* Do compare based on changes in resolved node value only */
|
||||
(*(g_evt_udn_info[udn_index]->compare)) (
|
||||
node1->node_value,
|
||||
node2->node_value,
|
||||
equal);
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/*============================================================================
|
||||
FILE EVTplot.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1992
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
5/7/92 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTplot which is used to provide basic
|
||||
plotting of event driven nodes through SPICE3's 'plot' command.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTplot()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//nclude "misc.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
#include "evtproto.h"
|
||||
#include "mif.h"
|
||||
#include "mifproto.h"
|
||||
|
||||
/*saj for output */
|
||||
#include "sim.h"
|
||||
#include "dvec.h"
|
||||
//#include "ftedata.h"
|
||||
//#include "fteconstant.h"
|
||||
//#include "util.h"
|
||||
#include "cpstd.h"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
EVTfindvec()
|
||||
|
||||
This function is called from FTE/vectors.c:findvec() when a node specified
|
||||
for plotting cannot be located in the analog plot data. It scans the
|
||||
event driven data structures looking for the node, and if found, returns
|
||||
a new 'dvec' structure holding the data to be plotted. The dvec struct
|
||||
is created with it's own v_scale member holding the event time vector
|
||||
for this node since the time vector is not aligned with the analog data
|
||||
points or with other event vectors.
|
||||
|
||||
The node name supplied as argument can either be a simple node name, or a
|
||||
name of the form <node name>(<member>), where <member> is the member of
|
||||
the event-driven structure to be plotted. These member names are defined
|
||||
by the individual "user-defined node" plot_val routines for the node
|
||||
type in question. If the simple node name form is used, the special
|
||||
keyword "all" is supplied to the plot_val routine for the member name.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
struct dvec *EVTfindvec(
|
||||
char *node) /* The node name (and optional member name) */
|
||||
{
|
||||
char *name;
|
||||
char *member = "all";
|
||||
char *ptr;
|
||||
|
||||
int i;
|
||||
int len;
|
||||
int num_nodes;
|
||||
int udn_index;
|
||||
int num_events;
|
||||
|
||||
Mif_Boolean_t found;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Node_t *head;
|
||||
Evt_Node_t *event;
|
||||
|
||||
double *anal_point_vec;
|
||||
double *value_vec;
|
||||
double value;
|
||||
|
||||
struct dvec *d;
|
||||
struct dvec *scale;
|
||||
|
||||
/* Exit immediately if event-driven stuff not allocated yet, */
|
||||
/* or if number of event nodes is zero. */
|
||||
if(! g_mif_info.ckt)
|
||||
return(NULL);
|
||||
if(! g_mif_info.ckt->evt)
|
||||
return(NULL);
|
||||
if(g_mif_info.ckt->evt->counts.num_nodes == 0)
|
||||
return(NULL);
|
||||
|
||||
/* Make a copy of the node name. */
|
||||
/* Do not free this string. It is assigned into the dvec structure below. */
|
||||
name = MIFcopy(node);
|
||||
|
||||
/* Convert to all lower case */
|
||||
len = strlen(name);
|
||||
for(i = 0; i < len; i++)
|
||||
if(isupper(name[i]))
|
||||
name[i] = tolower(name[i]);
|
||||
|
||||
/* Divide into the node name and member name */
|
||||
for(ptr = name; *ptr != '\0'; ptr++)
|
||||
if(*ptr == '(')
|
||||
break;
|
||||
|
||||
if(*ptr == '(') {
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
member = ptr;
|
||||
for( ; *ptr != '\0'; ptr++)
|
||||
if(*ptr == ')')
|
||||
break;
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
/* Look for node name in the event-driven node list */
|
||||
num_nodes = g_mif_info.ckt->evt->counts.num_nodes;
|
||||
node_table = g_mif_info.ckt->evt->info.node_table;
|
||||
|
||||
for(i = 0, found = MIF_FALSE; i < num_nodes; i++) {
|
||||
if(cieq(name, node_table[i]->name)) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(! found)
|
||||
return(NULL);
|
||||
|
||||
/* Get the UDN type index */
|
||||
udn_index = node_table[i]->udn_index;
|
||||
|
||||
/* Count the number of events */
|
||||
head = g_mif_info.ckt->evt->data.node->head[i];
|
||||
|
||||
for(event = head, num_events = 0; event; event = event->next)
|
||||
num_events++;
|
||||
|
||||
/* Allocate arrays to hold the analysis point and node value vectors */
|
||||
anal_point_vec = (double *) MALLOC(2 * (num_events + 2) * sizeof(double));
|
||||
value_vec = (double *) MALLOC(2 * (num_events + 2) * sizeof(double));
|
||||
|
||||
/* Iterate through the events and fill the arrays. */
|
||||
/* Note that we create vertical segments every time an event occurs. */
|
||||
/* Need to modify this in the future to complete the vector out to the */
|
||||
/* last analysis point... */
|
||||
for(i = 0, event = head; event; event = event->next) {
|
||||
|
||||
/* If not first point, put the second value of the horizontal line in the vectors */
|
||||
if(i > 0) {
|
||||
anal_point_vec[i] = event->step;
|
||||
value_vec[i] = value;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Get the next value by calling the appropriate UDN plot_val function */
|
||||
value = 0.0;
|
||||
(*(g_evt_udn_info[udn_index]->plot_val)) (event->node_value,
|
||||
member,
|
||||
&value);
|
||||
|
||||
/* Put the first value of the horizontal line in the vector */
|
||||
anal_point_vec[i] = event->step;
|
||||
value_vec[i] = value;
|
||||
i++;
|
||||
|
||||
}
|
||||
|
||||
/* Allocate dvec structures and assign the vectors into them. */
|
||||
/* See FTE/OUTinterface.c:plotInit() for initialization example. */
|
||||
|
||||
scale = (void *) MALLOC(sizeof(struct dvec));
|
||||
|
||||
scale->v_name = MIFcopy("step");
|
||||
scale->v_type = SV_TIME;
|
||||
scale->v_flags = VF_REAL & ~VF_PERMANENT;
|
||||
scale->v_length = i;
|
||||
scale->v_realdata = anal_point_vec;
|
||||
scale->v_scale = NULL;
|
||||
|
||||
d = (void *) MALLOC(sizeof(struct dvec));
|
||||
|
||||
d->v_name = name;
|
||||
d->v_type = SV_VOLTAGE;
|
||||
d->v_flags = VF_REAL & ~VF_PERMANENT;
|
||||
d->v_length = i;
|
||||
d->v_realdata = value_vec;
|
||||
d->v_scale = scale;
|
||||
|
||||
|
||||
/* Return the dvec */
|
||||
return(d);
|
||||
}
|
||||
|
|
@ -0,0 +1,369 @@
|
|||
/*============================================================================
|
||||
FILE EVTprint.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTprint which is used to provide a simple
|
||||
tabular output of event-driven node data. This printout is invoked
|
||||
through a new nutmeg command called 'eprint' which takes event-driven
|
||||
node names as argument.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTprint(wordlist *wl)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cpstd.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
static int get_index(char *node_name);
|
||||
|
||||
static void print_data(
|
||||
Mif_Boolean_t dcop,
|
||||
double step,
|
||||
char **node_value,
|
||||
int nargs);
|
||||
|
||||
/*
|
||||
EVTprint
|
||||
|
||||
This function implements the 'eprint' command used to print
|
||||
event-driven node values and messages from the latest simulation.
|
||||
|
||||
This is a simple prototype implementation of the
|
||||
eprint command for testing purposes. It is currently lacking
|
||||
in the following areas:
|
||||
|
||||
1) It accepts only up to 16 nodes.
|
||||
|
||||
2) It does not support the selected printing of different
|
||||
members of a user-defined data struct.
|
||||
|
||||
3) It is dumb in its output formatting - just tries to print
|
||||
everything on a line with 4 space separators.
|
||||
|
||||
4) It works only for the latest simulation - i.e. it does not
|
||||
use the evt jobs structure to find old results.
|
||||
|
||||
5) It does not allow a range of timesteps to be selected.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define EPRINT_MAXARGS 16
|
||||
|
||||
|
||||
void EVTprint(
|
||||
wordlist *wl) /* The command line entered by user */
|
||||
{
|
||||
|
||||
int i;
|
||||
int nargs;
|
||||
int num_ports;
|
||||
|
||||
wordlist *w;
|
||||
|
||||
char *node_name[EPRINT_MAXARGS];
|
||||
int node_index[EPRINT_MAXARGS];
|
||||
int udn_index[EPRINT_MAXARGS];
|
||||
Evt_Node_t *node_data[EPRINT_MAXARGS];
|
||||
char *node_value[EPRINT_MAXARGS];
|
||||
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
|
||||
Mif_Boolean_t more;
|
||||
Mif_Boolean_t dcop;
|
||||
|
||||
double step;
|
||||
double next_step;
|
||||
double this_step;
|
||||
|
||||
char *value;
|
||||
|
||||
Evt_Msg_t *msg_data;
|
||||
Evt_Statistic_t *statistics;
|
||||
|
||||
|
||||
/* Count the number of arguments to the command */
|
||||
nargs = 0;
|
||||
w = wl;
|
||||
while(w) {
|
||||
nargs++;
|
||||
w = w->wl_next;
|
||||
}
|
||||
|
||||
if(nargs < 1) {
|
||||
printf("Usage: eprint <node1> <node2> ...\n");
|
||||
return;
|
||||
}
|
||||
if(nargs > EPRINT_MAXARGS) {
|
||||
printf("ERROR - eprint currently limited to 16 arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get needed pointers */
|
||||
ckt = g_mif_info.ckt;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
/* Get data for each argument */
|
||||
w = wl;
|
||||
for(i = 0; i < nargs; i++) {
|
||||
node_name[i] = w->wl_word;
|
||||
node_index[i] = get_index(node_name[i]);
|
||||
if(node_index[i] < 0) {
|
||||
printf("ERROR - Node %s is not an event node.\n", node_name[i]);
|
||||
return;
|
||||
}
|
||||
udn_index[i] = node_table[node_index[i]]->udn_index;
|
||||
node_data[i] = ckt->evt->data.node->head[node_index[i]];
|
||||
node_value[i] = "";
|
||||
w = w->wl_next;
|
||||
}
|
||||
|
||||
|
||||
/* Print results data */
|
||||
printf("\n**** Results Data ****\n\n");
|
||||
|
||||
/* Print the column identifiers */
|
||||
printf("Time or Step\n");
|
||||
for(i = 0; i < nargs; i++)
|
||||
printf("%s\n",node_name[i]);
|
||||
printf("\n\n");
|
||||
|
||||
/* Scan the node data and determine if the first vector */
|
||||
/* is for a DCOP analysis or the first step in a swept DC */
|
||||
/* or transient analysis. Also, determine if there is */
|
||||
/* more data following it and if so, what the next step */
|
||||
/* is. */
|
||||
more = MIF_FALSE;
|
||||
dcop = MIF_FALSE;
|
||||
next_step = 1e30;
|
||||
for(i = 0; i < nargs; i++) {
|
||||
if(node_data[i]->op)
|
||||
dcop = MIF_TRUE;
|
||||
else
|
||||
step = node_data[i]->step;
|
||||
(*(g_evt_udn_info[udn_index[i]]->print_val))
|
||||
(node_data[i]->node_value, "all", &value);
|
||||
node_value[i] = value;
|
||||
node_data[i] = node_data[i]->next;
|
||||
if(node_data[i]) {
|
||||
more = MIF_TRUE;
|
||||
if(node_data[i]->step < next_step)
|
||||
next_step = node_data[i]->step;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the data */
|
||||
print_data(dcop, step, node_value, nargs);
|
||||
|
||||
/* While there is more data, get the next values and print */
|
||||
while(more) {
|
||||
|
||||
more = MIF_FALSE;
|
||||
this_step = next_step;
|
||||
next_step = 1e30;
|
||||
|
||||
for(i = 0; i < nargs; i++) {
|
||||
|
||||
if(node_data[i]) {
|
||||
if(node_data[i]->step == this_step) {
|
||||
(*(g_evt_udn_info[udn_index[i]]->print_val))
|
||||
(node_data[i]->node_value, "all", &value);
|
||||
node_value[i] = value;
|
||||
node_data[i] = node_data[i]->next;
|
||||
}
|
||||
if(node_data[i]) {
|
||||
more = MIF_TRUE;
|
||||
if(node_data[i]->step < next_step)
|
||||
next_step = node_data[i]->step;
|
||||
}
|
||||
|
||||
} /* end if node_data not NULL */
|
||||
|
||||
} /* end for number of args */
|
||||
|
||||
print_data(MIF_FALSE, this_step, node_value, nargs);
|
||||
|
||||
} /* end while there is more data */
|
||||
printf("\n\n");
|
||||
|
||||
|
||||
/* Print messages for all ports */
|
||||
printf("\n**** Messages ****\n\n");
|
||||
|
||||
num_ports = ckt->evt->counts.num_ports;
|
||||
port_table = ckt->evt->info.port_table;
|
||||
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
|
||||
/* Get pointer to messages for this port */
|
||||
msg_data = ckt->evt->data.msg->head[i];
|
||||
|
||||
/* If no messages on this port, skip */
|
||||
if(! msg_data)
|
||||
continue;
|
||||
|
||||
/* Print the port description */
|
||||
printf("Node: %s Inst: %s Conn: %s Port: %d\n\n",
|
||||
port_table[i]->node_name,
|
||||
port_table[i]->inst_name,
|
||||
port_table[i]->conn_name,
|
||||
port_table[i]->port_num);
|
||||
|
||||
/* Print the messages on this port */
|
||||
while(msg_data) {
|
||||
if(msg_data->op)
|
||||
printf("DCOP ");
|
||||
else
|
||||
printf("%-16.9e", msg_data->step);
|
||||
printf("%s\n", msg_data->text);
|
||||
msg_data = msg_data->next;
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
} /* end for number of ports */
|
||||
|
||||
|
||||
/* Print statistics */
|
||||
printf("\n**** Statistics ****\n\n");
|
||||
|
||||
statistics = ckt->evt->data.statistics;
|
||||
printf("Operating point analog/event alternations: %d\n",
|
||||
statistics->op_alternations);
|
||||
printf("Operating point load calls: %d\n",
|
||||
statistics->op_load_calls);
|
||||
printf("Operating point event passes: %d\n",
|
||||
statistics->op_event_passes);
|
||||
printf("Transient analysis load calls: %d\n",
|
||||
statistics->tran_load_calls);
|
||||
printf("Transient analysis timestep backups: %d\n",
|
||||
statistics->tran_time_backups);
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
get_index
|
||||
|
||||
This function determines the index of a specified event-driven node.
|
||||
*/
|
||||
|
||||
|
||||
static int get_index(
|
||||
char *node_name /* The name of the node to search for */
|
||||
)
|
||||
{
|
||||
|
||||
/* Get the event-driven node index for the specified name */
|
||||
|
||||
int index;
|
||||
|
||||
Mif_Boolean_t found;
|
||||
Evt_Node_Info_t *node;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Scan list of nodes in event structure to see if there */
|
||||
|
||||
found = MIF_FALSE;
|
||||
index = 0;
|
||||
|
||||
ckt = g_mif_info.ckt;
|
||||
node = ckt->evt->info.node_list;
|
||||
|
||||
while(node) {
|
||||
if(strcmp(node_name, node->name) == 0) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the index or -1 if not found */
|
||||
if(! found)
|
||||
return(-1);
|
||||
else
|
||||
return(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
print_data
|
||||
|
||||
This function prints the values of one or more nodes to
|
||||
standard output.
|
||||
*/
|
||||
|
||||
|
||||
static void print_data(
|
||||
Mif_Boolean_t dcop, /* Is this the operating point data */
|
||||
double step, /* The analysis step if dcop */
|
||||
char **node_value, /* The array of values to be printed */
|
||||
int nargs) /* The size of the value array */
|
||||
{
|
||||
|
||||
int i;
|
||||
char step_str[100];
|
||||
|
||||
if(dcop)
|
||||
strcpy(step_str, "DCOP ");
|
||||
else
|
||||
sprintf(step_str, "%-16.9e", step);
|
||||
|
||||
printf("%s", step_str);
|
||||
for(i = 0; i < nargs; i++)
|
||||
printf(" %s", node_value[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*============================================================================
|
||||
FILE EVTqueue.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions that place new events into the output and
|
||||
instance queues.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTqueue_output(
|
||||
CKTcircuit *ckt,
|
||||
int output_index,
|
||||
int udn_index,
|
||||
Evt_Output_Event_t *new_event,
|
||||
double posted_time,
|
||||
double event_time)
|
||||
|
||||
void EVTqueue_inst(
|
||||
CKTcircuit *ckt,
|
||||
int inst_index,
|
||||
double posted_time,
|
||||
double event_time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTqueue_output
|
||||
|
||||
This function places the specified output event onto the output
|
||||
queue. It is called by EVTload during a transient analysis.
|
||||
|
||||
The linked list in the queue for the specified output is
|
||||
searched beginning at the current head of the pending events
|
||||
to find the location at which to insert the new event. The
|
||||
events are ordered in the list by event_time. If the event
|
||||
is placed before the end of the list, subsequent events are
|
||||
removed from the list by marking them as 'removed' and
|
||||
recording the time of removal. This allows efficient backup
|
||||
of the state of the queue if a subsequent analog timestep
|
||||
fails.
|
||||
*/
|
||||
|
||||
|
||||
void EVTqueue_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int output_index, /* The output in question */
|
||||
int udn_index, /* The associated user-defined node type */
|
||||
Evt_Output_Event_t *new_event, /* The event to queue */
|
||||
double posted_time, /* The current time */
|
||||
double event_time) /* The time the event should happen */
|
||||
{
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Output_Event_t **here;
|
||||
Evt_Output_Event_t *next;
|
||||
|
||||
Mif_Boolean_t splice;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* Put the times into the event struct */
|
||||
new_event->event_time = event_time;
|
||||
new_event->posted_time = posted_time;
|
||||
new_event->removed = MIF_FALSE;
|
||||
|
||||
/* Update next_time in output queue */
|
||||
if((output_queue->num_pending <= 0) ||
|
||||
(event_time < output_queue->next_time))
|
||||
output_queue->next_time = event_time;
|
||||
|
||||
/* Find location at which to insert event */
|
||||
splice = MIF_FALSE;
|
||||
here = output_queue->current[output_index];
|
||||
while(*here) {
|
||||
if(event_time <= (*here)->event_time) {
|
||||
splice = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
here = &((*here)->next);
|
||||
}
|
||||
|
||||
/* If needs to be spliced into middle of existing list */
|
||||
if(splice) {
|
||||
/* splice it in */
|
||||
next = *here;
|
||||
*here = new_event;
|
||||
new_event->next = next;
|
||||
/* mark later events as removed */
|
||||
while(next) {
|
||||
if(! next->removed) {
|
||||
next->removed = MIF_TRUE;
|
||||
next->removed_time = posted_time;
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
/* else, just put it at the end */
|
||||
else {
|
||||
*here = new_event;
|
||||
new_event->next = NULL;
|
||||
}
|
||||
|
||||
/* Add to the list of outputs modified since last accepted timestep */
|
||||
if(! output_queue->modified[output_index]) {
|
||||
output_queue->modified[output_index] = MIF_TRUE;
|
||||
output_queue->modified_index[(output_queue->num_modified)++] =
|
||||
output_index;
|
||||
}
|
||||
|
||||
/* Add to the list of outputs with events pending */
|
||||
if(! output_queue->pending[output_index]) {
|
||||
output_queue->pending[output_index] = MIF_TRUE;
|
||||
output_queue->pending_index[(output_queue->num_pending)++] =
|
||||
output_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTqueue_inst
|
||||
|
||||
This function places the specified inst event onto the inst
|
||||
queue.
|
||||
|
||||
The linked list in the queue for the specified inst is
|
||||
searched beginning at the current head of the pending events
|
||||
to find the location at which to insert the new event. The
|
||||
events are ordered in the list by event_time.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
void EVTqueue_inst(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index, /* The instance in question */
|
||||
double posted_time, /* The current time */
|
||||
double event_time) /* The time the event should happen */
|
||||
{
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Inst_Event_t **here;
|
||||
Evt_Inst_Event_t *new_event;
|
||||
Evt_Inst_Event_t *next;
|
||||
|
||||
Mif_Boolean_t splice;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Update next_time in inst queue */
|
||||
if((inst_queue->num_pending <= 0) ||
|
||||
(event_time < inst_queue->next_time))
|
||||
inst_queue->next_time = event_time;
|
||||
|
||||
/* Create a new event or get one from the free list and copy in data */
|
||||
if(inst_queue->free[inst_index]) {
|
||||
new_event = inst_queue->free[inst_index];
|
||||
inst_queue->free[inst_index] = new_event->next;
|
||||
}
|
||||
else {
|
||||
new_event = (void *) MALLOC(sizeof(Evt_Inst_Event_t));
|
||||
}
|
||||
new_event->event_time = event_time;
|
||||
new_event->posted_time = posted_time;
|
||||
|
||||
/* Find location at which to insert event */
|
||||
splice = MIF_FALSE;
|
||||
here = inst_queue->current[inst_index];
|
||||
while(*here) {
|
||||
/* If there's an event with the same time, don't duplicate it */
|
||||
if(event_time == (*here)->event_time)
|
||||
return;
|
||||
else if(event_time < (*here)->event_time) {
|
||||
splice = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
here = &((*here)->next);
|
||||
}
|
||||
|
||||
/* If needs to be spliced into middle of existing list */
|
||||
if(splice) {
|
||||
/* splice it in */
|
||||
next = *here;
|
||||
*here = new_event;
|
||||
new_event->next = next;
|
||||
}
|
||||
/* else, just put it at the end */
|
||||
else {
|
||||
*here = new_event;
|
||||
new_event->next = NULL;
|
||||
}
|
||||
|
||||
/* Add to the list of insts modified since last accepted timestep */
|
||||
if(! inst_queue->modified[inst_index]) {
|
||||
inst_queue->modified[inst_index] = MIF_TRUE;
|
||||
inst_queue->modified_index[(inst_queue->num_modified)++] =
|
||||
inst_index;
|
||||
}
|
||||
|
||||
/* Add to the list of insts with events pending */
|
||||
if(! inst_queue->pending[inst_index]) {
|
||||
inst_queue->pending[inst_index] = MIF_TRUE;
|
||||
inst_queue->pending_index[(inst_queue->num_pending)++] =
|
||||
inst_index;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,578 @@
|
|||
/*============================================================================
|
||||
FILE EVTsetup.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTsetup which clears/allocates the
|
||||
event-driven queues and data structures immediately prior to a new
|
||||
analysis. In addition, it places entries in the job list so that
|
||||
results data from multiple analysis can be retrieved similar to
|
||||
SPICE3C1 saving multiple 'plots'.
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTsetup(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
#include "sperror.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
static int EVTsetup_queues(CKTcircuit *ckt);
|
||||
static int EVTsetup_data(CKTcircuit *ckt);
|
||||
static int EVTsetup_jobs(CKTcircuit *ckt);
|
||||
static int EVTsetup_load_ptrs(CKTcircuit *ckt);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Allocation macros with built-in check for out-of-memory */
|
||||
/* Adapted from SPICE 3C1 code in CKTsetup.c */
|
||||
|
||||
#define CKALLOC(var,size,type) \
|
||||
if(size) { \
|
||||
if(!(var = (void *) MALLOC((size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
}
|
||||
|
||||
#define CKREALLOC(var,size,type) \
|
||||
if((size) == 1) { \
|
||||
if(!(var = (void *) MALLOC((size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
} else if((size) > 1) { \
|
||||
if(!(var = (void *) REALLOC((void *) (var), (size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup
|
||||
|
||||
This function clears/allocates the event-driven queues and data structures
|
||||
immediately prior to a new analysis. In addition, it places entries
|
||||
in the job list so that results data from multiple analysis can be
|
||||
retrieved similar to SPICE3C1 saving multiple 'plots'.
|
||||
*/
|
||||
|
||||
|
||||
int EVTsetup(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int err;
|
||||
|
||||
|
||||
/* Exit immediately if no event-driven instances in circuit */
|
||||
if(ckt->evt->counts.num_insts == 0)
|
||||
return(OK);
|
||||
|
||||
/* Clear the inst, node, and output queues, and initialize the to_call */
|
||||
/* elements in the instance queue to call all event-driven instances */
|
||||
err = EVTsetup_queues(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Allocate and initialize the node, state, message, and statistics data */
|
||||
err = EVTsetup_data(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Set the job pointers to the allocated results, states, messages, */
|
||||
/* and statistics so that data will be accessable after run */
|
||||
err = EVTsetup_jobs(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Setup the pointers in the MIFinstance structure for inputs, outputs, */
|
||||
/* and total loads */
|
||||
err = EVTsetup_load_ptrs(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Initialize additional event data */
|
||||
g_mif_info.circuit.evt_step = 0.0;
|
||||
|
||||
/* Return OK */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_queues
|
||||
|
||||
This function clears the event-driven queues in preparation for
|
||||
a new simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_queues(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_insts;
|
||||
int num_nodes;
|
||||
int num_outputs;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Node_Queue_t *node_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Inst_Event_t *inst_event;
|
||||
Evt_Output_Event_t *output_event;
|
||||
|
||||
void *ptr;
|
||||
|
||||
/* ************************ */
|
||||
/* Clear the instance queue */
|
||||
/* ************************ */
|
||||
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_event = inst_queue->head[i];
|
||||
while(inst_event) {
|
||||
ptr = inst_event;
|
||||
inst_event = inst_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
inst_event = inst_queue->free[i];
|
||||
while(inst_event) {
|
||||
ptr = inst_event;
|
||||
inst_event = inst_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
inst_queue->head[i] = NULL;
|
||||
inst_queue->current[i] = &(inst_queue->head[i]);
|
||||
inst_queue->last_step[i] = &(inst_queue->head[i]);
|
||||
inst_queue->free[i] = NULL;
|
||||
}
|
||||
|
||||
inst_queue->next_time = 0.0;
|
||||
inst_queue->last_time = 0.0;
|
||||
|
||||
inst_queue->num_modified = 0;
|
||||
inst_queue->num_pending = 0;
|
||||
inst_queue->num_to_call = 0;
|
||||
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_queue->modified[i] = MIF_FALSE;
|
||||
inst_queue->pending[i] = MIF_FALSE;
|
||||
inst_queue->to_call[i] = MIF_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* ******************** */
|
||||
/* Clear the node queue */
|
||||
/* ******************** */
|
||||
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
node_queue = &(ckt->evt->queue.node);
|
||||
|
||||
node_queue->num_changed = 0;
|
||||
node_queue->num_to_eval = 0;
|
||||
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
node_queue->changed[i] = MIF_FALSE;
|
||||
node_queue->to_eval[i] = MIF_FALSE;
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
/* Clear the output queue */
|
||||
/* ********************** */
|
||||
|
||||
num_outputs = ckt->evt->counts.num_outputs;
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
for(i = 0; i < num_outputs; i++) {
|
||||
output_event = output_queue->head[i];
|
||||
while(output_event) {
|
||||
ptr = output_event;
|
||||
output_event = output_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
output_event = output_queue->free[i];
|
||||
while(output_event) {
|
||||
ptr = output_event;
|
||||
output_event = output_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
output_queue->head[i] = NULL;
|
||||
output_queue->current[i] = &(output_queue->head[i]);
|
||||
output_queue->last_step[i] = &(output_queue->head[i]);
|
||||
output_queue->free[i] = NULL;
|
||||
}
|
||||
|
||||
output_queue->next_time = 0.0;
|
||||
output_queue->last_time = 0.0;
|
||||
|
||||
output_queue->num_modified = 0;
|
||||
output_queue->num_pending = 0;
|
||||
output_queue->num_changed = 0;
|
||||
|
||||
for(i = 0; i < num_outputs; i++) {
|
||||
output_queue->modified[i] = MIF_FALSE;
|
||||
output_queue->pending[i] = MIF_FALSE;
|
||||
output_queue->changed[i] = MIF_FALSE;
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_data
|
||||
|
||||
This function sets up the event-driven node, state, and
|
||||
message data runtime structures in preparation for
|
||||
a new simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_data(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
Evt_Data_t *data;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_insts;
|
||||
int num_ports;
|
||||
int num_nodes;
|
||||
|
||||
int udn_index;
|
||||
int num_outputs;
|
||||
|
||||
Mif_Boolean_t invert;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
/* Evt_Statistic_t *statistics_data;*/
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Node_Info_t *node_info;
|
||||
|
||||
|
||||
/* Allocate main substructures of data */
|
||||
/* Note that we don't free any old structures */
|
||||
/* since they are pointed to by jobs and need */
|
||||
/* to be maintained so that results from multiple */
|
||||
/* jobs are kept around like SPICE does */
|
||||
|
||||
data = &(ckt->evt->data);
|
||||
CKALLOC(data->node, 1, Evt_Node_Data_t)
|
||||
CKALLOC(data->state, 1, Evt_State_Data_t)
|
||||
CKALLOC(data->msg, 1, Evt_Msg_Data_t)
|
||||
CKALLOC(data->statistics, 1, Evt_Statistic_t)
|
||||
|
||||
/* Allocate node data */
|
||||
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
node_data = data->node;
|
||||
|
||||
CKALLOC(node_data->head, num_nodes, void *)
|
||||
CKALLOC(node_data->tail, num_nodes, void *)
|
||||
CKALLOC(node_data->last_step, num_nodes, void *)
|
||||
CKALLOC(node_data->free, num_nodes, void *)
|
||||
CKALLOC(node_data->modified_index, num_nodes, int)
|
||||
CKALLOC(node_data->modified, num_nodes, Mif_Boolean_t)
|
||||
CKALLOC(node_data->rhs, num_nodes, Evt_Node_t)
|
||||
CKALLOC(node_data->rhsold, num_nodes, Evt_Node_t)
|
||||
CKALLOC(node_data->total_load, num_nodes, double)
|
||||
|
||||
/* Initialize the node data */
|
||||
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
node_data->tail[i] = &(node_data->head[i]);
|
||||
node_data->last_step[i] = &(node_data->head[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
|
||||
/* Get pointers to rhs & rhsold, the user-defined node type index, */
|
||||
/* the number of outputs on the node and the invert flag */
|
||||
rhs = &(node_data->rhs[i]);
|
||||
rhsold = &(node_data->rhsold[i]);
|
||||
node_info = ckt->evt->info.node_table[i];
|
||||
udn_index = node_info->udn_index;
|
||||
num_outputs = node_info->num_outputs;
|
||||
invert = node_info->invert;
|
||||
|
||||
/* Initialize the elements within rhs and rhsold */
|
||||
rhs->step = 0.0;
|
||||
rhsold->step = 0.0;
|
||||
if(num_outputs > 1) {
|
||||
CKALLOC(rhs->output_value, num_outputs, void *)
|
||||
CKALLOC(rhsold->output_value, num_outputs, void *)
|
||||
for(j = 0; j < num_outputs; j++) {
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhs->output_value[j]));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhs->output_value[j]);
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhsold->output_value[j]));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhsold->output_value[j]);
|
||||
}
|
||||
}
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhs->node_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhs->node_value);
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhsold->node_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhsold->node_value);
|
||||
if(invert) {
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhs->inverted_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhs->inverted_value);
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhsold->inverted_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhsold->inverted_value);
|
||||
}
|
||||
|
||||
/* Initialize the total load value to zero */
|
||||
node_data->total_load[i] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate and initialize state data */
|
||||
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
state_data = data->state;
|
||||
|
||||
CKALLOC(state_data->head, num_insts, void *)
|
||||
CKALLOC(state_data->tail, num_insts, void *)
|
||||
CKALLOC(state_data->last_step, num_insts, void *)
|
||||
CKALLOC(state_data->free, num_insts, void *)
|
||||
CKALLOC(state_data->modified_index, num_insts, int)
|
||||
CKALLOC(state_data->modified, num_insts, Mif_Boolean_t)
|
||||
CKALLOC(state_data->total_size, num_insts, int)
|
||||
CKALLOC(state_data->desc, num_insts, void *)
|
||||
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
state_data->tail[i] = &(state_data->head[i]);
|
||||
state_data->last_step[i] = &(state_data->head[i]);
|
||||
}
|
||||
|
||||
|
||||
/* Allocate and initialize msg data */
|
||||
|
||||
num_ports = ckt->evt->counts.num_ports;
|
||||
msg_data = data->msg;
|
||||
|
||||
CKALLOC(msg_data->head, num_ports, void *)
|
||||
CKALLOC(msg_data->tail, num_ports, void *)
|
||||
CKALLOC(msg_data->last_step, num_ports, void *)
|
||||
CKALLOC(msg_data->free, num_ports, void *)
|
||||
CKALLOC(msg_data->modified_index, num_ports, int)
|
||||
CKALLOC(msg_data->modified, num_ports, Mif_Boolean_t)
|
||||
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
msg_data->tail[i] = &(msg_data->head[i]);
|
||||
msg_data->last_step[i] = &(msg_data->head[i]);
|
||||
}
|
||||
|
||||
/* Don't need to initialize statistics since they were */
|
||||
/* calloc'ed above */
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_jobs
|
||||
|
||||
This function prepares the jobs data for a new simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_jobs(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_jobs;
|
||||
|
||||
Evt_Job_t *jobs;
|
||||
Evt_Data_t *data;
|
||||
|
||||
|
||||
jobs = &(ckt->evt->jobs);
|
||||
data = &(ckt->evt->data);
|
||||
|
||||
/* Increment the number of jobs */
|
||||
num_jobs = ++(jobs->num_jobs);
|
||||
|
||||
/* Allocate/reallocate necessary pointers */
|
||||
CKREALLOC(jobs->job_name, num_jobs, void *)
|
||||
CKREALLOC(jobs->node_data, num_jobs, void *)
|
||||
CKREALLOC(jobs->state_data, num_jobs, void *)
|
||||
CKREALLOC(jobs->msg_data, num_jobs, void *)
|
||||
CKREALLOC(jobs->statistics, num_jobs, void *)
|
||||
|
||||
/* Fill in the pointers, etc. for this new job */
|
||||
i = num_jobs - 1;
|
||||
jobs->job_name[i] = MIFcopy((char *) ckt->CKTcurJob->JOBname);
|
||||
jobs->node_data[i] = data->node;
|
||||
jobs->state_data[i] = data->state;
|
||||
jobs->msg_data[i] = data->msg;
|
||||
jobs->statistics[i] = data->statistics;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_load_ptrs
|
||||
|
||||
This function setups up the required data in the MIFinstance
|
||||
structure of event-driven and hybrid instances.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_load_ptrs(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
|
||||
int num_insts;
|
||||
int num_conn;
|
||||
int num_port;
|
||||
int num_outputs;
|
||||
|
||||
int node_index;
|
||||
int output_subindex;
|
||||
|
||||
MIFinstance *fast;
|
||||
|
||||
Mif_Conn_Data_t *conn;
|
||||
|
||||
Mif_Port_Type_t type;
|
||||
Mif_Port_Data_t *port;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
|
||||
/* This function setups up the required data in the MIFinstance */
|
||||
/* structure of event-driven and hybrid instances */
|
||||
|
||||
/* Loop through all event-driven and hybrid instances */
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
|
||||
/* Get the MIFinstance pointer */
|
||||
fast = ckt->evt->info.inst_table[i]->inst_ptr;
|
||||
|
||||
/* Loop through all connections */
|
||||
num_conn = fast->num_conn;
|
||||
for(j = 0; j < num_conn; j++) {
|
||||
|
||||
/* Skip if connection is null */
|
||||
if(fast->conn[j]->is_null)
|
||||
continue;
|
||||
|
||||
conn = fast->conn[j];
|
||||
|
||||
/* Loop through all ports */
|
||||
num_port = conn->size;
|
||||
for(k = 0; k < num_port; k++) {
|
||||
|
||||
/* Get port data pointer for quick access */
|
||||
port = conn->port[k];
|
||||
|
||||
if(port->is_null)
|
||||
continue;
|
||||
|
||||
/* Skip if port is not digital or user-defined type */
|
||||
type = port->type;
|
||||
if((type != MIF_DIGITAL) && (type != MIF_USER_DEFINED))
|
||||
continue;
|
||||
|
||||
/* Set input.pvalue to point to rhsold.node_value or to */
|
||||
/* rhsold.inverted_value as appropriate */
|
||||
node_index = port->evt_data.node_index;
|
||||
node_data = ckt->evt->data.node;
|
||||
if(conn->is_input) {
|
||||
if(port->invert) {
|
||||
port->input.pvalue = node_data->rhsold[node_index].
|
||||
inverted_value;
|
||||
}
|
||||
else {
|
||||
port->input.pvalue = node_data->rhsold[node_index].
|
||||
node_value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set output.pvalue to point to rhs.node_value or rhs.output_value[i] */
|
||||
/* where i is given by the output_subindex in output info */
|
||||
/* depending on whether more than one output is connected to the node. */
|
||||
/* Note that this is only for the DCOP analysis. During a transient */
|
||||
/* analysis, new structures will be created and the pointers will */
|
||||
/* be set by EVTload */
|
||||
if(conn->is_output) {
|
||||
num_outputs = ckt->evt->info.node_table[node_index]->num_outputs;
|
||||
if(num_outputs <= 1) {
|
||||
port->output.pvalue = node_data->rhs[node_index].
|
||||
node_value;
|
||||
}
|
||||
else {
|
||||
output_subindex = port->evt_data.output_subindex;
|
||||
port->output.pvalue = node_data->rhs[node_index].
|
||||
output_value[output_subindex];
|
||||
}
|
||||
}
|
||||
|
||||
} /* end for number of ports */
|
||||
} /* end for number of connections */
|
||||
} /* end for number of insts */
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -0,0 +1,512 @@
|
|||
/*============================================================================
|
||||
FILE EVTtermInsert.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTtermInsert which is called by
|
||||
MIF_INP2A during the parsing of the input deck. EVTtermInsert is
|
||||
similar to SPICE3's INPtermInsert except that it is used when the node
|
||||
type is event-driven. Calls to this function build the info lists
|
||||
for instances, nodes, outputs, and ports. The completion of the info
|
||||
struct is carried out by EVTinit following the parsing of all
|
||||
instances in the deck.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTtermInsert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
char *node_name,
|
||||
char *type_name,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
char **err_msg)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
static void EVTinst_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int *inst_index,
|
||||
char **err_msg);
|
||||
|
||||
static void EVTnode_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int inst_index,
|
||||
char *node_name,
|
||||
char *type_name,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
int *node_index,
|
||||
int *output_subindex,
|
||||
char **err_msg);
|
||||
|
||||
static void EVTport_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int inst_index,
|
||||
int node_index,
|
||||
char *node_name,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
int *port_index,
|
||||
char **err_msg);
|
||||
|
||||
static void EVToutput_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int inst_index,
|
||||
int node_index,
|
||||
int port_index,
|
||||
int output_subindex,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
char **err_msg);
|
||||
|
||||
|
||||
/*
|
||||
EVTtermInsert
|
||||
|
||||
This function is called by MIF_INP2A during the parsing of the input
|
||||
deck. EVTtermInsert is similar to 3C1's INPtermInsert except that it is
|
||||
used when the node type is event-driven. Calls to this function build
|
||||
the info lists for instances, nodes, outputs, and ports. The
|
||||
completion of the info struct is carried out by EVTinit following
|
||||
the parsing of all instances in the deck.
|
||||
*/
|
||||
|
||||
|
||||
void EVTtermInsert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
char *node_name, /* The node name */
|
||||
char *type_name, /* The type of node */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 for scalar ports */
|
||||
char **err_msg) /* Returned error message if any */
|
||||
{
|
||||
|
||||
int inst_index;
|
||||
int node_index;
|
||||
int port_index;
|
||||
|
||||
int output_subindex;
|
||||
|
||||
|
||||
/* Get the instance index and create new entry in inst */
|
||||
/* info list if this is a new instance. */
|
||||
EVTinst_insert(ckt, fast, &inst_index, err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
|
||||
/* Get the node index and create new entry in node info */
|
||||
/* list if this is a new node */
|
||||
EVTnode_insert(ckt, fast, inst_index, node_name, type_name,
|
||||
conn_num, port_num, &node_index, &output_subindex,
|
||||
err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
|
||||
/* Create new entry in port info list and return port index */
|
||||
EVTport_insert(ckt, fast, inst_index, node_index, node_name, conn_num,
|
||||
port_num, &port_index, err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
|
||||
/* Create new entry in output info list if appropriate */
|
||||
if(fast->conn[conn_num]->is_output) {
|
||||
EVToutput_insert(ckt, fast, inst_index, node_index, port_index,
|
||||
output_subindex, conn_num, port_num, err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTinst_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
instance in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTinst_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int *inst_index, /* The index found or added */
|
||||
char **err_msg) /* Error message if any */
|
||||
{
|
||||
|
||||
Mif_Boolean_t found;
|
||||
int index;
|
||||
|
||||
Evt_Inst_Info_t *inst;
|
||||
Evt_Inst_Info_t **inst_ptr;
|
||||
|
||||
|
||||
/* Scan list of instances in event structure to see if already there */
|
||||
/* and get the index */
|
||||
found = MIF_FALSE;
|
||||
index = 0;
|
||||
inst = ckt->evt->info.inst_list;
|
||||
inst_ptr = &(ckt->evt->info.inst_list);
|
||||
|
||||
while(inst) {
|
||||
if(inst->inst_ptr == fast) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
inst_ptr = &(inst->next);
|
||||
inst = inst->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If not found, create a new entry in list and increment the */
|
||||
/* instance count in the event structure */
|
||||
if(! found) {
|
||||
*inst_ptr = (void *) MALLOC(sizeof(Evt_Inst_Info_t));
|
||||
inst = *inst_ptr;
|
||||
inst->next = NULL;
|
||||
inst->inst_ptr = fast;
|
||||
index = ckt->evt->counts.num_insts;
|
||||
(ckt->evt->counts.num_insts)++;
|
||||
}
|
||||
|
||||
/* Record the inst index in the MIFinstance structure and return it */
|
||||
fast->inst_index = index;
|
||||
*inst_index = index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTnode_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
node in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTnode_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int inst_index, /* The index of inst in evt structures */
|
||||
char *node_name, /* The node name */
|
||||
char *type_name, /* The node type specified */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 if scalar port */
|
||||
int *node_index, /* The node index found or added */
|
||||
int *output_subindex, /* The output number on this node */
|
||||
char **err_msg) /* Error message text if any */
|
||||
{
|
||||
|
||||
int i;
|
||||
int udn_index=0;
|
||||
Mif_Boolean_t found;
|
||||
|
||||
int index;
|
||||
|
||||
Evt_Node_Info_t *node;
|
||||
Evt_Node_Info_t **node_ptr;
|
||||
|
||||
Evt_Inst_Index_t *inst;
|
||||
Evt_Inst_Index_t **inst_ptr;
|
||||
|
||||
|
||||
/* *************************************** */
|
||||
/* Get and check the node type information */
|
||||
/* *************************************** */
|
||||
|
||||
/* Scan the list of user-defined node types and get the index */
|
||||
found = MIF_FALSE;
|
||||
for(i = 0; i < g_evt_num_udn_types; i++) {
|
||||
if(strcmp(type_name, g_evt_udn_info[i]->name) == 0) {
|
||||
udn_index = i;
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report error if not recognized */
|
||||
if(! found) {
|
||||
*err_msg = "Unrecognized connection type";
|
||||
return;
|
||||
}
|
||||
|
||||
/* If inverted, check to be sure invert function exists for type */
|
||||
if(fast->conn[conn_num]->port[port_num]->invert) {
|
||||
if(g_evt_udn_info[udn_index]->invert == NULL) {
|
||||
*err_msg = "Connection type cannot be inverted";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************* */
|
||||
/* Find/create entry in event-driven node list */
|
||||
/* ******************************************* */
|
||||
|
||||
/* Scan list of nodes in event structure to see if already there */
|
||||
/* and get the index */
|
||||
found = MIF_FALSE;
|
||||
index = 0;
|
||||
node = ckt->evt->info.node_list;
|
||||
node_ptr = &(ckt->evt->info.node_list);
|
||||
|
||||
while(node) {
|
||||
if(strcmp(node_name, node->name) == 0) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
node_ptr = &(node->next);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If found, verify that connection type is same as type of node */
|
||||
if(found) {
|
||||
if(udn_index != node->udn_index) {
|
||||
*err_msg = "Node cannot have two different types";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found, create a new entry in list and increment the */
|
||||
/* node count in the event structure */
|
||||
if(! found) {
|
||||
*node_ptr = (void *) MALLOC(sizeof(Evt_Node_Info_t));
|
||||
node = *node_ptr;
|
||||
node->next = NULL;
|
||||
node->name = MIFcopy(node_name);
|
||||
node->udn_index = udn_index;
|
||||
index = ckt->evt->counts.num_nodes;
|
||||
(ckt->evt->counts.num_nodes)++;
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************* */
|
||||
/* Update remaining items in node list struct */
|
||||
/* ******************************************* */
|
||||
|
||||
/* Update flag on node that indicates if inversion is used by any */
|
||||
/* instance inputs */
|
||||
if(fast->conn[conn_num]->is_input)
|
||||
if(! node->invert)
|
||||
node->invert = fast->conn[conn_num]->port[port_num]->invert;
|
||||
|
||||
/* Increment counts of ports, outputs connected to node */
|
||||
(node->num_ports)++;
|
||||
if(fast->conn[conn_num]->is_output)
|
||||
(node->num_outputs)++;
|
||||
|
||||
/* If this is an input, add instance to list if not already there */
|
||||
if(fast->conn[conn_num]->is_input) {
|
||||
|
||||
found = MIF_FALSE;
|
||||
inst = node->inst_list;
|
||||
inst_ptr = &(node->inst_list);
|
||||
|
||||
while(inst) {
|
||||
if(inst_index == inst->index) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
inst_ptr = &(inst->next);
|
||||
inst = inst->next;
|
||||
}
|
||||
}
|
||||
|
||||
if(! found) {
|
||||
(node->num_insts)++;
|
||||
*inst_ptr = (void *) MALLOC(sizeof(Evt_Inst_Index_t));
|
||||
inst = *inst_ptr;
|
||||
inst->next = NULL;
|
||||
inst->index = inst_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the node index in the MIFinstance structure */
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.node_index = index;
|
||||
|
||||
/* Return the node index */
|
||||
*node_index = index;
|
||||
if(fast->conn[conn_num]->is_output)
|
||||
*output_subindex = node->num_outputs - 1;
|
||||
else
|
||||
*output_subindex = 0; /* just for safety - shouldn't need this */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTport_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
port in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTport_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int inst_index, /* The index of inst in evt structures */
|
||||
int node_index, /* The index of the node in evt structures */
|
||||
char *node_name, /* The node name */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 if scalar port */
|
||||
int *port_index, /* The port index found or added */
|
||||
char **err_msg) /* Error message text if any */
|
||||
{
|
||||
|
||||
Evt_Port_Info_t *port;
|
||||
Evt_Port_Info_t **port_ptr;
|
||||
|
||||
int index;
|
||||
|
||||
/* Find the end of the port info list */
|
||||
port = ckt->evt->info.port_list;
|
||||
port_ptr = &(ckt->evt->info.port_list);
|
||||
|
||||
index = 0;
|
||||
while(port) {
|
||||
port_ptr = &(port->next);
|
||||
port = port->next;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
||||
/* Update the port count and create a new entry in the list */
|
||||
|
||||
(ckt->evt->counts.num_ports)++;
|
||||
|
||||
*port_ptr = (void *) MALLOC(sizeof(Evt_Port_Info_t));
|
||||
port = *port_ptr;
|
||||
|
||||
/* Fill in the elements */
|
||||
port->next = NULL;
|
||||
port->inst_index = inst_index;
|
||||
port->node_index = node_index;
|
||||
port->node_name = MIFcopy(node_name);
|
||||
port->inst_name = MIFcopy((char *) fast->MIFname);
|
||||
port->conn_name = MIFcopy((char *) fast->conn[conn_num]->name);
|
||||
port->port_num = port_num;
|
||||
|
||||
/* Record the port index in the MIFinstance structure */
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.port_index = index;
|
||||
|
||||
/* Return the port index */
|
||||
*port_index = index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVToutput_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
output in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVToutput_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int inst_index, /* The index of inst in evt structures */
|
||||
int node_index, /* The index of the node in evt structures */
|
||||
int port_index, /* The index of the port in the evt structures */
|
||||
int output_subindex, /* The output on this node */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 if scalar port */
|
||||
char **err_msg) /* Error message text if any */
|
||||
{
|
||||
Evt_Output_Info_t *output;
|
||||
Evt_Output_Info_t **output_ptr;
|
||||
|
||||
int index;
|
||||
|
||||
/* Find the end of the port info list */
|
||||
output = ckt->evt->info.output_list;
|
||||
output_ptr = &(ckt->evt->info.output_list);
|
||||
|
||||
index = 0;
|
||||
while(output) {
|
||||
output_ptr = &(output->next);
|
||||
output = output->next;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
||||
/* Update the port count and create a new entry in the list */
|
||||
|
||||
(ckt->evt->counts.num_outputs)++;
|
||||
|
||||
*output_ptr = (void *) MALLOC(sizeof(Evt_Output_Info_t));
|
||||
output = *output_ptr;
|
||||
|
||||
/* Fill in the elements */
|
||||
output->next = NULL;
|
||||
output->inst_index = inst_index;
|
||||
output->node_index = node_index;
|
||||
output->port_index = port_index;
|
||||
output->output_subindex = output_subindex;
|
||||
|
||||
/* Record the output index and subindex in the MIFinstance structure */
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.output_index = index;
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.output_subindex
|
||||
= output_subindex;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
Code Model Test - AC: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.ac dec 10 10 1000
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
v2 2 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
v3 3 0 DC 2.0
|
||||
*
|
||||
v4 4 0 0.5 AC 0.5 0.0
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 3] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 1 3 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=1.0e-10 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 4 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[-1.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
r4 4 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
Code Model Test - DC: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 1] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=0.1 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 2 1 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=1.0e-10 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 1 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[ 0.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
Code Model Test - Swept DC: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.dc v1 .1 10 .1
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 1] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=0.1 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 2 1 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=1.0e-10 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 1 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[ 0.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
Code Model Test - Transient: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .1s 10s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 DC PWL(0 0 10 10)
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 1] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=0.1 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 2 1 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=0.1 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 1 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[ 0.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
Code Model Test - Swept DC: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.ac dec 10 10 1000
|
||||
*
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 1 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.414214 1.0] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=628.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
v40 45 46 0.0
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 46) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
*
|
||||
r10 10 0 1e12
|
||||
r20 20 0 1e12
|
||||
r30 30 0 1e12
|
||||
r40 40 0 1e12
|
||||
r45 45 0 1e12
|
||||
r50 50 0 1e12
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
Code Model Test - DC: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 1.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 1 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.425625 1.516203] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=6283.2)
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 45) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
Code Model Test - Swept DC: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.dc v1 .1 10 .5
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 1 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.414214 1.0] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
v40 45 46 0.0
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 46) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
*
|
||||
r10 10 0 1e12
|
||||
r20 20 0 1e12
|
||||
r30 30 0 1e12
|
||||
r40 40 0 1e12
|
||||
r45 45 0 1e12
|
||||
r50 50 0 1e12
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
Code Model Test - Transient: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .1s 10s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 DC PWL(0 0 10 10)
|
||||
*
|
||||
v2 2 0 DC PWL(0 0 0.1 0.1 0.2 0.9 0.3 1.0 10 1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 2 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.414214 1.0] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 45) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
Code Model Test - AC: hyst, limit, ilimit, climit, cmeter, lmeter
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.ac dec 10 10 1000
|
||||
*
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
v2 2 0 DC 10.0
|
||||
*
|
||||
v3 3 0 DC -10.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*** hyst block ***
|
||||
a1 1 10 hyst1
|
||||
.model hyst1 hyst (in_low=0.0 in_high=1.0 hyst=0.1 out_lower_limit=0.0
|
||||
+ out_upper_limit=1.0 input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** limit block ***
|
||||
a2 1 20 limit1
|
||||
.model limit1 limit (in_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** ilimit block ***
|
||||
a3 1 2 3 30 ilimit1
|
||||
.model ilimit1 ilimit (in_offset=0.0 gain=1.0 r_out_source=1.0
|
||||
+ r_out_sink=1.0 i_limit_source=1.0
|
||||
+ i_limit_sink=1.0 v_pwr_range=1.0e-3
|
||||
+ i_source_range=1.0e-6 i_sink_range=1.0e-6
|
||||
+ r_out_domain=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** climit block ***
|
||||
a4 1 2 3 40 climit1
|
||||
.model climit1 climit (in_offset=0.0 gain=1.0 upper_delta=0.0
|
||||
+ lower_delta=0.0 limit_range=1.0e-6
|
||||
+ fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** cmeter block ***
|
||||
c5 51 0 1.0e-6
|
||||
a5 51 50 cmeter1
|
||||
.model cmeter1 cmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** lmeter block ***
|
||||
l6 61 0 1.0e-6
|
||||
a6 61 60 lmeter1
|
||||
.model lmeter1 lmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r51 51 0 10k
|
||||
r60 60 0 10k
|
||||
r61 61 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
Code Model Test - DC: hyst, limit, ilimit, climit, cmeter, lmeter
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 1.0
|
||||
*
|
||||
v2 2 0 DC 10.0
|
||||
*
|
||||
v3 3 0 DC -10.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*** hyst block ***
|
||||
a1 1 10 hyst1
|
||||
.model hyst1 hyst (in_low=0.0 in_high=1.0 hyst=0.1 out_lower_limit=0.0
|
||||
+ out_upper_limit=1.0 input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** limit block ***
|
||||
a2 1 20 limit1
|
||||
.model limit1 limit (in_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** ilimit block ***
|
||||
a3 1 2 3 30 ilimit1
|
||||
.model ilimit1 ilimit (in_offset=0.0 gain=1.0 r_out_source=1.0
|
||||
+ r_out_sink=1.0 i_limit_source=1.0
|
||||
+ i_limit_sink=1.0 v_pwr_range=1.0e-3
|
||||
+ i_source_range=1.0e-3 i_sink_range=1.0e-3
|
||||
+ r_out_domain=1.0e-3)
|
||||
*
|
||||
*
|
||||
*** climit block ***
|
||||
a4 1 2 3 40 climit1
|
||||
.model climit1 climit (in_offset=0.0 gain=1.0 upper_delta=0.0
|
||||
+ lower_delta=0.0 limit_range=1.0e-6
|
||||
+ fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** cmeter block ***
|
||||
c5 51 0 1.0e-6
|
||||
a5 51 50 cmeter1
|
||||
.model cmeter1 cmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** lmeter block ***
|
||||
l6 61 0 1.0e-6
|
||||
a6 61 60 lmeter1
|
||||
.model lmeter1 lmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r51 51 0 10k
|
||||
r60 60 0 10k
|
||||
r61 61 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
Code Model Test - DC: hyst, limit, ilimit, climit, cmeter, lmeter
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.dc v1 .1 15 .5
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 1.0
|
||||
*
|
||||
v2 2 0 DC 10.0
|
||||
*
|
||||
v3 3 0 DC -10.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*** hyst block ***
|
||||
a1 1 10 hyst1
|
||||
.model hyst1 hyst (in_low=0.0 in_high=1.0 hyst=0.1 out_lower_limit=0.0
|
||||
+ out_upper_limit=1.0 input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** limit block ***
|
||||
a2 1 20 limit1
|
||||
.model limit1 limit (in_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** ilimit block ***
|
||||
a3 1 2 3 30 ilimit1
|
||||
.model ilimit1 ilimit (in_offset=0.0 gain=1.0 r_out_source=1.0
|
||||
+ r_out_sink=1.0 i_limit_source=1.0
|
||||
+ i_limit_sink=1.0 v_pwr_range=1.0e-3
|
||||
+ i_source_range=1.0e-6 i_sink_range=1.0e-6
|
||||
+ r_out_domain=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** climit block ***
|
||||
a4 1 2 3 40 climit1
|
||||
.model climit1 climit (in_offset=0.0 gain=1.0 upper_delta=0.0
|
||||
+ lower_delta=0.0 limit_range=1.0e-6
|
||||
+ fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** cmeter block ***
|
||||
c5 51 0 1.0e-6
|
||||
a5 51 50 cmeter1
|
||||
.model cmeter1 cmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** lmeter block ***
|
||||
l6 61 0 1.0e-6
|
||||
a6 61 60 lmeter1
|
||||
.model lmeter1 lmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r51 51 0 10k
|
||||
r60 60 0 10k
|
||||
r61 61 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
Code Model Test - Transient: hyst, limit, ilimit, climit, cmeter, lmeter
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .1s 15s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 DC PWL(0 0 15 15)
|
||||
*
|
||||
v2 2 0 DC 10.0
|
||||
*
|
||||
v3 3 0 DC -10.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*** hyst block ***
|
||||
a1 1 10 hyst1
|
||||
.model hyst1 hyst (in_low=0.0 in_high=1.0 hyst=0.1 out_lower_limit=0.0
|
||||
+ out_upper_limit=1.0 input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** limit block ***
|
||||
a2 1 20 limit1
|
||||
.model limit1 limit (in_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** ilimit block ***
|
||||
a3 1 2 3 30 ilimit1
|
||||
.model ilimit1 ilimit (in_offset=0.0 gain=1.0 r_out_source=1.0
|
||||
+ r_out_sink=1.0 i_limit_source=1.0
|
||||
+ i_limit_sink=1.0 v_pwr_range=1.0e-3
|
||||
+ i_source_range=1.0e-6 i_sink_range=1.0e-6
|
||||
+ r_out_domain=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** climit block ***
|
||||
a4 1 2 3 40 climit1
|
||||
.model climit1 climit (in_offset=0.0 gain=1.0 upper_delta=0.0
|
||||
+ lower_delta=0.0 limit_range=1.0e-6
|
||||
+ fraction=FALSE)
|
||||
*
|
||||
*
|
||||
*** cmeter block ***
|
||||
c5 51 0 1.0e-6
|
||||
a5 51 50 cmeter1
|
||||
.model cmeter1 cmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** lmeter block ***
|
||||
l6 61 0 1.0e-6
|
||||
a6 61 60 lmeter1
|
||||
.model lmeter1 lmeter (gain=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r51 51 0 10k
|
||||
r60 60 0 10k
|
||||
r61 61 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
Code Model Test - DC: sine, triangle, aswitch, zener, oneshot
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.ac dec 10 10 1000
|
||||
*
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
v2 2 0 DC 1.0
|
||||
*
|
||||
v3 3 0 DC 1.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** sine block ***
|
||||
a1 1 10 sine1
|
||||
.model sine1 sine (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 100.0 100.0]
|
||||
+ out_low=-1.0 out_high=1.0)
|
||||
*
|
||||
*
|
||||
*** triangle block ***
|
||||
a2 1 20 triangle1
|
||||
.model triangle1 triangle (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 100.0 100.0]
|
||||
+ out_low=-1.0 out_high=1.0 duty_cycle=0.8)
|
||||
*
|
||||
*
|
||||
*** aswitch block ***
|
||||
a3 1 (2 30) aswitch1
|
||||
.model aswitch1 aswitch (cntl_off=0.0 cntl_on=1.0 log=TRUE
|
||||
+ r_off=1.0e12 r_on=10.0)
|
||||
*
|
||||
*
|
||||
*** zener diode ***
|
||||
r4 1 40 10K
|
||||
a4 (40 0) zener1
|
||||
.model zener1 zener (v_breakdown=10.0 i_breakdown=2.0e-2
|
||||
+ r_breakdown=1.0 i_rev=1.0e-6 i_sat=1.0e-12
|
||||
+ n_forward=1.0 limit_switch=FALSE)
|
||||
*
|
||||
*
|
||||
*** oneshot block ***
|
||||
a5 3 1 2 50 oneshot1
|
||||
.model oneshot1 oneshot (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ pw_array=[1.0 1.0 0.1 0.1] clk_trig=0.5
|
||||
+ pos_edge_trig=TRUE out_low=0.0 out_high=1.0
|
||||
+ rise_time=1.0e-6 rise_delay=1.0e-9
|
||||
+ fall_delay=1.0e-9 fall_time=1.0e-6
|
||||
+ retrig=FALSE)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r60 60 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
Code Model Test - DC: sine triangle aswitch zener oneshot
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 1.0
|
||||
*
|
||||
v2 2 0 DC 1.0
|
||||
*
|
||||
v3 3 0 DC 1.0
|
||||
*
|
||||
*
|
||||
*** sine block ***
|
||||
a1 1 10 sine1
|
||||
.model sine1 sine (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 100.0 100.0]
|
||||
+ out_low=-1.0 out_high=1.0)
|
||||
*
|
||||
*
|
||||
*** triangle block ***
|
||||
a2 1 20 triangle1
|
||||
.model triangle1 triangle (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 100.0 100.0]
|
||||
+ out_low=-1.0 out_high=1.0 duty_cycle=0.8)
|
||||
*
|
||||
*
|
||||
*** aswitch block ***
|
||||
a3 1 (2 30) aswitch1
|
||||
.model aswitch1 aswitch (cntl_off=0.0 cntl_on=1.0 log=TRUE
|
||||
+ r_off=1.0e12 r_on=10.0)
|
||||
*
|
||||
*
|
||||
*** zener diode ***
|
||||
r4 1 40 10K
|
||||
a4 (40 0) zener1
|
||||
.model zener1 zener (v_breakdown=10.0 i_breakdown=2.0e-2
|
||||
+ r_breakdown=1.0 i_rev=1.0e-6 i_sat=1.0e-12
|
||||
+ n_forward=1.0 limit_switch=FALSE)
|
||||
*
|
||||
*
|
||||
*** oneshot block ***
|
||||
a5 3 1 2 50 oneshot1
|
||||
.model oneshot1 oneshot (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ pw_array=[1.0 1.0 0.1 0.1] clk_trig=0.5
|
||||
+ pos_edge_trig=TRUE out_low=0.0 out_high=1.0
|
||||
+ rise_time=1.0e-6 rise_delay=1.0e-9
|
||||
+ fall_delay=1.0e-9 fall_time=1.0e-6
|
||||
+ retrig=FALSE)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r60 60 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
Code Model Test - Swept DC: sine, triangle, aswitch, zener, oneshot
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.dc v1 .1 15 .5
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 1.0
|
||||
*
|
||||
v2 2 0 DC 1.0
|
||||
*
|
||||
v3 3 0 DC 1.0
|
||||
*
|
||||
*
|
||||
*** sine block ***
|
||||
a1 1 10 sine1
|
||||
.model sine1 sine (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 100.0 100.0]
|
||||
+ out_low=-1.0 out_high=1.0)
|
||||
*
|
||||
*
|
||||
*** triangle block ***
|
||||
a2 1 20 triangle1
|
||||
.model triangle1 triangle (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 100.0 100.0]
|
||||
+ out_low=-1.0 out_high=1.0 duty_cycle=0.8)
|
||||
*
|
||||
*
|
||||
*** aswitch block ***
|
||||
a3 1 (2 30) aswitch1
|
||||
.model aswitch1 aswitch (cntl_off=0.0 cntl_on=1.0 log=TRUE
|
||||
+ r_off=1.0e12 r_on=10.0)
|
||||
*
|
||||
*
|
||||
*** zener diode ***
|
||||
r4 1 40 100
|
||||
a4 (0 40) zener1
|
||||
.model zener1 zener (v_breakdown=8.0 i_breakdown=2.0e-2
|
||||
+ r_breakdown=1.0 i_rev=1.0e-6 i_sat=1.0e-12
|
||||
+ n_forward=1.0 limit_switch=FALSE)
|
||||
*
|
||||
*
|
||||
*** oneshot block ***
|
||||
a5 3 1 2 50 oneshot1
|
||||
.model oneshot1 oneshot (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ pw_array=[1.0 1.0 0.1 0.1] clk_trig=0.5
|
||||
+ pos_edge_trig=TRUE out_low=0.0 out_high=1.0
|
||||
+ rise_time=1.0e-6 rise_delay=1.0e-9
|
||||
+ fall_delay=1.0e-9 fall_time=1.0e-6
|
||||
+ retrig=FALSE)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r60 60 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
Code Model Test - Transient: sine, triangle, aswitch, zener, oneshot
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .01ms 2ms
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 DC 0.0 PWL(0 0 2e-3 2)
|
||||
*
|
||||
v2 2 0 DC 0.0 PWL(0 0 2e-3 10)
|
||||
*
|
||||
v3 3 0 DC 0.0 PWL(0 0.0 0.9e-3 0.0 1e-3 1.0 1.9e-3 1.0 2e-3 0.0 2.9e-3 0.0)
|
||||
*
|
||||
v4 4 0 DC 1.0
|
||||
*
|
||||
*
|
||||
*** sine block ***
|
||||
a1 1 10 sine1
|
||||
.model sine1 sine (cntl_array=[-1.0 0.0 10.0 20.0]
|
||||
+ freq_array=[500 500 2000 2000]
|
||||
+ out_low=-1.0 out_high=1.0)
|
||||
*
|
||||
*
|
||||
*** triangle block ***
|
||||
a2 1 20 triangle1
|
||||
.model triangle1 triangle (cntl_array=[-1.0 0.0 10.0 20.0]
|
||||
+ freq_array=[500 500 10000 10000]
|
||||
+ out_low=-1.0 out_high=1.0 duty_cycle=0.5)
|
||||
*
|
||||
*
|
||||
*** aswitch block ***
|
||||
a3 1 (4 30) aswitch1
|
||||
.model aswitch1 aswitch (cntl_off=0.0 cntl_on=1.0 log=TRUE
|
||||
+ r_off=1.0e12 r_on=10.0)
|
||||
*
|
||||
*
|
||||
*** zener diode ***
|
||||
rzener 2 40 100
|
||||
a4 (0 40) zener1
|
||||
.model zener1 zener (v_breakdown=9.0 i_breakdown=2.0e-2
|
||||
+ r_breakdown=1.0 i_rev=1.0e-6 i_sat=1.0e-12
|
||||
+ n_forward=1.0 limit_switch=FALSE)
|
||||
*
|
||||
*
|
||||
*** oneshot block ***
|
||||
a5 3 1 0 50 oneshot1
|
||||
.model oneshot1 oneshot (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ pw_array=[2.0e-3 2.0e-3 0.1e-3 0.1e-3] clk_trig=0.5
|
||||
+ pos_edge_trig=TRUE out_low=0.0 out_high=1.0
|
||||
+ rise_time=1.0e-6 rise_delay=1.0e-9
|
||||
+ fall_delay=1.0e-9 fall_time=1.0e-6
|
||||
+ retrig=FALSE)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 10k
|
||||
r2 2 0 10k
|
||||
r3 3 0 10k
|
||||
r4 4 0 10k
|
||||
*
|
||||
r10 10 0 10k
|
||||
r20 20 0 10k
|
||||
r30 30 0 10k
|
||||
r40 40 0 10k
|
||||
r50 50 0 10k
|
||||
r60 60 0 10k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Arbitrary Phase SIN and PULSE Sources
|
||||
*
|
||||
* This circuit generates two cycles of sine and square waves
|
||||
* beginning at +45 degrees.
|
||||
*
|
||||
* Phase shift is specified after Berkeley defined parameters
|
||||
* on the independent source cards.
|
||||
*
|
||||
.tran 2e-5 2e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k 0 0 45.0)
|
||||
r1 1 0 1k
|
||||
*
|
||||
v2 2 0 0.0 pulse(-1 1 0 1e-5 1e-5 5e-4 1e-3 45.0)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Invalid number of inputs/outputs
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator reports an error if the number of
|
||||
* connections on the code model is incorrect.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 3 gain_block
|
||||
a2 1 gain_block
|
||||
.model gain_block gain (gain=10)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
Invalid input/output type
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator reports an error if an invalid type
|
||||
* is used with the code model connections.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
* Both connections on the gain block must be analog, but
|
||||
* the second is specified as digital
|
||||
*
|
||||
a1 1 %d 2 gain_block
|
||||
.model gain_block gain (gain=10)
|
||||
r2 2 0 1k
|
||||
*
|
||||
* Node 1 below should be a digital node, but is an analog node
|
||||
*
|
||||
a2 [1] [3] dac
|
||||
.model dac dac_bridge
|
||||
r3 3 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Unknown code model name
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator reports an error if the code model name
|
||||
* is incorrect.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 gain_block
|
||||
.model gain_block this_model_doesnt_exist (gain=10)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Unknown code model parameter
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator reports an error if the .model card
|
||||
* references a parameter that doesn't exist
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 gain_block
|
||||
.model gain_block gain (this_parameter_doesnt_exist=2 gain=10)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Invalid parameter type
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator reports an error if the parameter value
|
||||
* is invalid.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 gain_block
|
||||
.model gain_block gain (gain=false)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# $Id$
|
||||
#
|
||||
# Makefile for Code Model directories
|
||||
#
|
||||
|
||||
# Include global XSPICE selections for CC and other macros
|
||||
include /usr/local/xspice-1-0/include/make.include
|
||||
|
||||
INCLUDE = -I. -I$(ROOT)/include/sim
|
||||
|
||||
CFLAGS = -g
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Edit the following definition to specify the object files that comprise
|
||||
# your code model. If your code model is completely specified in the
|
||||
# cfunc.mod file, there is no need to edit this definition.
|
||||
# DO NOT include the ifspec.o file.
|
||||
|
||||
CODE_MODEL_OBJECTS = cfunc.o
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# DO NOT MODIFY THE FOLLOWING DEFINITIONS:
|
||||
|
||||
.SUFFIXES: $(SUFFIXES) .mod .ifs
|
||||
|
||||
.mod.c:
|
||||
$(BINDIR)/cmpp -mod $<
|
||||
|
||||
.ifs.c:
|
||||
$(BINDIR)/cmpp -ifs
|
||||
|
||||
.c.o: $*.c
|
||||
${CC} ${CFLAGS} ${INCLUDE} -c $*.c
|
||||
|
||||
all : ifspec.o $(CODE_MODEL_OBJECTS)
|
||||
|
||||
cfunc.o : cfunc.c
|
||||
ifspec.o : ifspec.c
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/* $Id$ */
|
||||
|
||||
void ucm_d_to_real (ARGS)
|
||||
{
|
||||
|
||||
Digital_State_t in;
|
||||
|
||||
double *out;
|
||||
double delay;
|
||||
double zero;
|
||||
double one;
|
||||
double ena;
|
||||
|
||||
|
||||
in = INPUT_STATE(in);
|
||||
if(PORT_NULL(enable))
|
||||
ena = 1.0;
|
||||
else if(INPUT_STATE(enable) == ONE)
|
||||
ena = 1.0;
|
||||
else
|
||||
ena = 0.0;
|
||||
out = OUTPUT(out);
|
||||
|
||||
zero = PARAM(zero);
|
||||
one = PARAM(one);
|
||||
delay = PARAM(delay);
|
||||
|
||||
|
||||
if(in == ZERO)
|
||||
*out = zero * ena;
|
||||
else if(in == UNKNOWN)
|
||||
*out = (zero + one) / 2.0 * ena;
|
||||
else
|
||||
*out = one * ena;
|
||||
|
||||
if(TIME > 0.0)
|
||||
OUTPUT_DELAY(out) = delay;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* $Id$ */
|
||||
|
||||
NAME_TABLE:
|
||||
|
||||
Spice_Model_Name: d_to_real
|
||||
C_Function_Name: ucm_d_to_real
|
||||
Description: "Node bridge from digital to real with enable"
|
||||
|
||||
|
||||
PORT_TABLE:
|
||||
|
||||
Port_Name: in enable out
|
||||
Description: "input" "enable" "output"
|
||||
Direction: in in out
|
||||
Default_Type: d d real
|
||||
Allowed_Types: [d] [d] [real]
|
||||
Vector: no no no
|
||||
Vector_Bounds: - - -
|
||||
Null_Allowed: no yes no
|
||||
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: zero one delay
|
||||
Description: "value for 0" "value for 1" "delay"
|
||||
Data_Type: real real real
|
||||
Default_Value: 0.0 1.0 1e-9
|
||||
Limits: - - [1e-15 -]
|
||||
Vector: no no no
|
||||
Vector_Bounds: - - -
|
||||
Null_Allowed: yes yes yes
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
difpair ckt - simple differential pair
|
||||
*.width in=72
|
||||
.opt acct list node lvlcod=2
|
||||
*.tf v(5) vin
|
||||
*.dc vin -0.25 0.25 0.005
|
||||
*.ac dec 10 1 10ghz
|
||||
.tran 5ns 500ns
|
||||
vin 1 0 sin(0 0.1 5meg) ac 1
|
||||
vcc 8 0 12
|
||||
vee 9 0 -12
|
||||
q1 4 2 6 qnl
|
||||
q2 5 3 6 qnl
|
||||
rs1 1 2 1k
|
||||
rs2 3 0 1k
|
||||
rc1 4 8 10k
|
||||
rc2 5 8 10k
|
||||
q3 6 7 9 qnl
|
||||
q4 7 7 9 qnl
|
||||
rbias 7 8 20k
|
||||
.model qnl npn(bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf
|
||||
+ va=50)
|
||||
.print dc v(4) v(5)
|
||||
.plot dc v(5)
|
||||
.print ac vm(5) vp(5)
|
||||
.plot ac vm(5) vp(5)
|
||||
.print tran v(4) v(5)
|
||||
.plot tran v(5)
|
||||
.end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
Digital inversions
|
||||
*
|
||||
.tran 1e-8 1e-6
|
||||
*
|
||||
v1 1 0 0.0 pulse(0 1 0 1e-8 1e-8 0.25e-6 0.5e-6)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 [1] [2] adc
|
||||
.model adc adc_bridge
|
||||
*
|
||||
a2 2 3 inv
|
||||
a3 2 ~4 inv
|
||||
a4 ~2 5 inv
|
||||
a5 ~2 ~6 inv
|
||||
.model inv d_inverter
|
||||
*
|
||||
a6 [2 ~4] 7 nand
|
||||
.model nand d_nand
|
||||
*
|
||||
a8 [2 3 4 5 6 7] [12 13 14 15 16 17] dac
|
||||
.model dac dac_bridge
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
Digital models
|
||||
*
|
||||
* This circuit contains a nand gate oscillator enabled by
|
||||
* a pulse input after 20nS. Node 1 is an analog node.
|
||||
* Nodes 2 and 3 are digital nodes.
|
||||
*
|
||||
.tran 1e-8 1e-7
|
||||
*
|
||||
v1 1 0 0.0 pulse(0 1 2e-8 1e-9 1e-9)
|
||||
*
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 [1] [2] atod1
|
||||
.model atod1 adc_bridge (in_low=0.25 in_high=0.75
|
||||
+ rise_delay=1e-9 fall_delay=1e-9)
|
||||
*
|
||||
a2 [2 3] 3 nand
|
||||
.model nand d_nand (rise_delay=1e-9 fall_delay=1e-9)
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
Code Model Test: buffer, inverter, and, nand, or, nor, xor, xnor
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .01s 4s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v2 200 0 DC PWL( (0 0.0) (2 0.0) (2.0000000001 1.0) (3 1.0) )
|
||||
*
|
||||
v1 100 0 DC PWL( (0 0.0) (1.0 0.0) (1.0000000001 1.0) (2 1.0)
|
||||
+ (2.0000000001 0.0) (3 0.0) (3.0000000001 1.0) (4 1.0) )
|
||||
*
|
||||
*
|
||||
*** adc_bridge blocks ***
|
||||
aconverter [200 100] [2 1] adc_bridge1
|
||||
.model adc_bridge1 adc_bridge (in_low=0.1 in_high=0.9
|
||||
+ rise_delay=1.0e-12 fall_delay=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** buffer block ***
|
||||
a1 1 10 d_buffer1
|
||||
.model d_buffer1 d_buffer (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** inverter block ***
|
||||
a2 1 20 d_inv1
|
||||
.model d_inv1 d_inverter (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** and block ***
|
||||
a3 [1 2] 30 d_and1
|
||||
.model d_and1 d_and (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** nand block ***
|
||||
a4 [1 2] 40 d_nand1
|
||||
.model d_nand1 d_nand (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** or block ***
|
||||
a5 [1 2] 50 d_or1
|
||||
.model d_or1 d_or (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** nor block ***
|
||||
a6 [1 2] 60 d_nor1
|
||||
.model d_nor1 d_nor (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** xor block ***
|
||||
a7 [1 2] 70 d_xor1
|
||||
.model d_xor1 d_xor (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** xnor block ***
|
||||
a8 [1 2] 80 d_xnor1
|
||||
.model d_xnor1 d_xnor (rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ input_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 100 0 1k
|
||||
r2 200 0 1k
|
||||
*
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
Code Model Test: d flip-flop, jk flip-flop, toggle ff, set-reset ff
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .01s 4s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
vdata1 100 0 DC PWL( (0 0.0) (2 0.0) (2.0000000001 1.0) (3 1.0) )
|
||||
*
|
||||
*
|
||||
vdata2 200 0 DC PWL( (0 0.0) (1.0 0.0) (1.0000000001 1.0) (2 1.0)
|
||||
+ (2.0000000001 0.0) (3 0.0) (3.0000000001 1.0) (4 1.0) )
|
||||
*
|
||||
*
|
||||
vclk 300 0 DC PWL( (0 0.0) (0.5 0.0) (0.50000000001 1.0)
|
||||
+ (1.0 1.0) (1.00000000001 0.0)
|
||||
+ (1.5 0.0) (1.50000000001 1.0)
|
||||
+ (2.0 1.0) (2.00000000001 0.0)
|
||||
+ (2.5 0.0) (2.50000000001 1.0)
|
||||
+ (3.0 1.0) (3.00000000001 0.0)
|
||||
+ (3.5 0.0) (3.50000000001 1.0) (4.0 1.0) )
|
||||
*
|
||||
*
|
||||
vset 400 0 DC 0.0
|
||||
*
|
||||
*
|
||||
vreset 500 0 DC PWL( (0 0.0) (3.8 0.0) (3.80000000001 1.0) (4 1.0) )
|
||||
*
|
||||
*
|
||||
*** adc_bridge blocks ***
|
||||
aconverter [100 200 300 400 500] [1 2 3 4 5] adc_bridge1
|
||||
.model adc_bridge1 adc_bridge (in_low=0.1 in_high=0.9
|
||||
+ rise_delay=1.0e-12 fall_delay=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** d flip-flop block ***
|
||||
a1 1 3 4 5 10 11 d_dff1
|
||||
.model d_dff1 d_dff (clk_delay=1.0e-6 set_delay=2.0e-6
|
||||
+ reset_delay=3.0e-6 ic=0
|
||||
+ rise_delay=4.0e-6 fall_delay=5.0e-6
|
||||
+ data_load=1.0e-12 clk_load=1.0e-12
|
||||
+ set_load=1.0e-12 reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** jk flip-flop block ***
|
||||
a2 1 2 3 4 5 20 21 d_jkff1
|
||||
.model d_jkff1 d_jkff (clk_delay=1.0e-6 set_delay=2.0e-6
|
||||
+ reset_delay=3.0e-6 ic=0
|
||||
+ rise_delay=4.0e-6 fall_delay=5.0e-6
|
||||
+ jk_load=1.0e-12 clk_load=1.0e-12
|
||||
+ set_load=1.0e-12 reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** toggle flip-flop block ***
|
||||
a3 1 3 4 5 30 31 d_tff1
|
||||
.model d_tff1 d_tff (clk_delay=1.0e-6 set_delay=2.0e-6
|
||||
+ reset_delay=3.0e-6 ic=0
|
||||
+ rise_delay=4.0e-6 fall_delay=5.0e-6
|
||||
+ t_load=1.0e-12 clk_load=1.0e-12
|
||||
+ set_load=1.0e-12 reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** set-reset flip-flop block ***
|
||||
a4 1 2 3 4 5 40 41 d_srff1
|
||||
.model d_srff1 d_srff (clk_delay=1.0e-6 set_delay=2.0e-6
|
||||
+ reset_delay=3.0e-6 ic=0
|
||||
+ rise_delay=4.0e-6 fall_delay=5.0e-6
|
||||
+ sr_load=1.0e-12 clk_load=1.0e-12
|
||||
+ set_load=1.0e-12 reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 100 0 1k
|
||||
r2 200 0 1k
|
||||
r3 300 0 1k
|
||||
r4 400 0 1k
|
||||
r5 500 0 1k
|
||||
*
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
Code Model Test: d latch, set-reset latch, frequency divider
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .01s 8s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
vdata1 100 0 DC PWL( (0 0.0) (2 0.0) (2.0000000001 1.0) (3 1.0) )
|
||||
*
|
||||
*
|
||||
vdata2 200 0 DC PWL( (0 0.0) (1.0 0.0) (1.0000000001 1.0) (2 1.0)
|
||||
+ (2.0000000001 0.0) (3 0.0) (3.0000000001 1.0) (4 1.0) )
|
||||
*
|
||||
*
|
||||
vclk 300 0 DC PWL( (0 0.0) (0.5 0.0) (0.50000000001 1.0)
|
||||
+ (1.0 1.0) (1.00000000001 0.0)
|
||||
+ (1.5 0.0) (1.50000000001 1.0)
|
||||
+ (2.0 1.0) (2.00000000001 0.0)
|
||||
+ (2.5 0.0) (2.50000000001 1.0)
|
||||
+ (3.0 1.0) (3.00000000001 0.0)
|
||||
+ (3.5 0.0) (3.50000000001 1.0)
|
||||
+ (4.0 1.0) (4.00000000001 0.0)
|
||||
+ (4.5 0.0) (4.50000000001 1.0)
|
||||
+ (5.0 1.0) (5.00000000001 0.0)
|
||||
+ (5.5 0.0) (5.50000000001 1.0)
|
||||
+ (6.0 1.0) (6.00000000001 0.0)
|
||||
+ (6.5 0.0) (6.50000000001 1.0)
|
||||
+ (7.0 1.0) (7.00000000001 0.0)
|
||||
+ (7.5 0.0) (7.50000000001 1.0) (4.0 1.0) )
|
||||
*
|
||||
*
|
||||
vset 400 0 DC 0.0
|
||||
*
|
||||
*
|
||||
vreset 500 0 DC PWL( (0 0.0) (3.8 0.0) (3.80000000001 1.0) (4 1.0) )
|
||||
*
|
||||
*
|
||||
*** adc_bridge block ***
|
||||
aconverter [100 200 300 400 500] [1 2 3 4 5] adc_bridge1
|
||||
.model adc_bridge1 adc_bridge (in_low=0.1 in_high=0.9
|
||||
+ rise_delay=1.0e-12 fall_delay=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** d latch block ***
|
||||
a1 1 3 4 5 10 11 d_dlatch1
|
||||
.model d_dlatch1 d_dlatch (data_delay=1.0e-6 enable_delay=2.0e-6
|
||||
+ set_delay=3.0e-6 reset_delay=4.0e-6
|
||||
+ ic=0
|
||||
+ rise_delay=5.0e-6 fall_delay=6.0e-6
|
||||
+ data_load=1.0e-12 enable_load=1.0e-12
|
||||
+ set_load=1.0e-12 reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** set-reset latch block ***
|
||||
a2 1 2 3 4 5 20 21 d_srlatch1
|
||||
.model d_srlatch1 d_srlatch (sr_delay=1.0e-6 enable_delay=2.0e-6
|
||||
+ set_delay=3.0e-6 reset_delay=4.0e-6
|
||||
+ ic=0
|
||||
+ rise_delay=5.0e-6 fall_delay=6.0e-6
|
||||
+ sr_load=1.0e-12 enable_load=1.0e-12
|
||||
+ set_load=1.0e-12 reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** frequency divider block ***
|
||||
a3 3 30 d_fdiv1
|
||||
.model d_fdiv1 d_fdiv (div_factor=3 high_cycles=2
|
||||
+ i_count=0 rise_delay=1.0e-6 fall_delay=2.0e-6
|
||||
+ freq_in_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 100 0 1k
|
||||
r2 200 0 1k
|
||||
r3 300 0 1k
|
||||
r4 400 0 1k
|
||||
r5 500 0 1k
|
||||
*
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
Code Model Test: State Machine, RAM
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .01s 8s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
vdata1 100 0 DC PWL( (0 0.0) (2 0.0) (2.0000000001 1.0) (3 1.0)
|
||||
+ (3.5000000001 0.0) (4 0.0) )
|
||||
*
|
||||
*
|
||||
vdata2 200 0 DC PWL( (0 0.0) (1.0 0.0) (1.0000000001 1.0) (2 1.0)
|
||||
+ (2.0000000001 0.0) (3 0.0) (3.0000000001 1.0) (4 1.0) )
|
||||
*
|
||||
*
|
||||
vclk 300 0 DC PWL( (0 0.0) (0.5 0.0) (0.50000000001 1.0)
|
||||
+ (1.0 1.0) (1.00000000001 0.0)
|
||||
+ (1.5 0.0) (1.50000000001 1.0)
|
||||
+ (2.0 1.0) (2.00000000001 0.0)
|
||||
+ (2.5 0.0) (2.50000000001 1.0)
|
||||
+ (3.0 1.0) (3.00000000001 0.0)
|
||||
+ (3.5 0.0) (3.50000000001 1.0)
|
||||
+ (4.0 1.0) (4.00000000001 0.0)
|
||||
+ (4.5 0.0) (4.50000000001 1.0)
|
||||
+ (5.0 1.0) (5.00000000001 0.0)
|
||||
+ (5.5 0.0) (5.50000000001 1.0)
|
||||
+ (6.0 1.0) (6.00000000001 0.0)
|
||||
+ (6.5 0.0) (6.50000000001 1.0)
|
||||
+ (7.0 1.0) (7.00000000001 0.0)
|
||||
+ (7.5 0.0) (7.50000000001 1.0) (4.0 1.0) )
|
||||
*
|
||||
vaddr1 400 0 DC 0
|
||||
*
|
||||
*
|
||||
vaddr2 500 0 DC PWL( (0 0.0) (0.6 0.0) (0.60000000001 1.0)
|
||||
+ (0.9 1.0) (0.90000000001 0.0)
|
||||
+ (2.6 0.0) (2.60000000001 1.0)
|
||||
+ (2.9 1.0) (2.90000000001 0.0) (3.0 0.0) )
|
||||
*
|
||||
*
|
||||
*
|
||||
vselect 600 0 DC PWL( (0 0.0) (1.0 0.0) (2.0000000001 1.0) (2 1.0) )
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** adc_bridge block ***
|
||||
aconverter [100 200 300 400 500 600] [1 2 3 4 5 6] adc_bridge1
|
||||
.model adc_bridge1 adc_bridge (in_low=0.1 in_high=0.9
|
||||
+ rise_delay=1.0e-12 fall_delay=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** state machine block ***
|
||||
a1 [1 2] 3 4 [10 11] d_state1
|
||||
.model d_state1 d_state (clk_delay=1.0e-6 reset_delay=2.0e-6
|
||||
+ state_file=state.txt reset_state=0
|
||||
+ input_load=1.0e-12 clk_load=1.0e-12
|
||||
+ reset_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*** RAM block ***
|
||||
a2 [1 2] [20 21] [3 4] 5 [6] d_ram1
|
||||
.model d_ram1 d_ram (select_value=1 ic=0
|
||||
+ read_delay=1.0e-6 data_load=1.0e-12
|
||||
+ address_load=1.0e-12 select_load=1.0e-12
|
||||
+ enable_load=1.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 100 0 10k
|
||||
r2 200 0 10k
|
||||
r3 300 0 10k
|
||||
r4 400 0 10k
|
||||
r5 500 0 10k
|
||||
r6 600 0 10k
|
||||
*
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
Model card reference
|
||||
*
|
||||
* This circuit contains simple gain blocks that share a
|
||||
* single .model card.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 gain_block
|
||||
r2 2 0 1k
|
||||
*
|
||||
a2 1 3 gain_block
|
||||
r3 3 0 1k
|
||||
*
|
||||
.model gain_block gain (in_offset = 1 gain=10)
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
Code Model Test - DC: d_osc, dac_bridge, adc_bridge
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** d_osc block ***
|
||||
a1 1 10 d_osc1
|
||||
.model d_osc1 d_osc (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[100 100 1000 1000]
|
||||
+ duty_cycle=0.5 init_phase=0.0
|
||||
+ rise_delay=1.0e-6 fall_delay=2.0e-6)
|
||||
*
|
||||
*** dac_bridge block ***
|
||||
a2 [10] [20] dac_bridge1
|
||||
.model dac_bridge1 dac_bridge (out_low=0.5 out_high=4.5 out_undef=1.8
|
||||
+ input_load=1.0e-12
|
||||
+ t_rise=1.0e-6 t_fall=2.0e-6)
|
||||
*
|
||||
*
|
||||
*** adc_bridge block ***
|
||||
a3 [2] [30] adc_bridge1
|
||||
.model adc_bridge1 adc_bridge (in_low=0.7 in_high=2.4
|
||||
+ rise_delay=1.0e-12 fall_delay=2.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
*
|
||||
r20 20 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
Code Model Test - Transient: d_osc, dac_bridge, adc_bridge
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .01s 1s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 DC PWL( (0 0.0) (1 1.0) )
|
||||
*
|
||||
v2 2 0 DC PWL( (0 0.0) (1 5.0) )
|
||||
*
|
||||
*
|
||||
*** d_osc block ***
|
||||
a1 1 10 d_osc1
|
||||
.model d_osc1 d_osc (cntl_array=[-1.0 0.0 1.0 2.0]
|
||||
+ freq_array=[1.0 1.0 8.0 8.0]
|
||||
+ duty_cycle=0.5 init_phase=0.0
|
||||
+ rise_delay=1.0e-6 fall_delay=2.0e-6)
|
||||
*
|
||||
*** dac_bridge block ***
|
||||
a2 [10] [20] dac_bridge1
|
||||
.model dac_bridge1 dac_bridge (out_low=0.5 out_high=4.5 out_undef=1.8
|
||||
+ input_load=1.0e-12
|
||||
+ t_rise=1.0e-6 t_fall=2.0e-6)
|
||||
*
|
||||
*
|
||||
*** adc_bridge block ***
|
||||
a3 [2] [30] adc_bridge1
|
||||
.model adc_bridge1 adc_bridge (in_low=0.7 in_high=2.4
|
||||
+ rise_delay=1.0e-12 fall_delay=2.0e-12)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
*
|
||||
r20 20 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
Capacitor and inductor with natural initial conditions
|
||||
*
|
||||
* This circuit contains a capacitor and an inductor with
|
||||
* initial conditions on them. Each of the components
|
||||
* has a parallel resistor so that an exponential decay
|
||||
* of the initial condition occurs with a time constant of
|
||||
* 1 second.
|
||||
*
|
||||
.tran 0.1 5
|
||||
*
|
||||
a1 1 0 cap
|
||||
.model cap capacitor (c=1000uf ic=1)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a2 2 0 ind
|
||||
.model ind inductor (l=1H ic=1)
|
||||
r2 2 0 1.0
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
IO ordering
|
||||
*
|
||||
* This circuit contains a simple gain block. The order of
|
||||
* the nodes listed on the instance line follows the order
|
||||
* of the connections defined in the 'ifspec.ifs' file for
|
||||
* the model. Refer to /atesse-su/src/cml/gain/ifspec.ifs .
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 gain_block
|
||||
.model gain_block gain (gain=10)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
IO types
|
||||
*
|
||||
* This circuit contains a mix of input output types including
|
||||
* voltages, currents, digital signals, and user defined
|
||||
* signals.
|
||||
*
|
||||
.tran 1e-6 1e-4
|
||||
*
|
||||
v1 1 0 0.0 pulse(0 1 2e-5)
|
||||
r1 1 0 1k
|
||||
*
|
||||
abridge1 [1] [enable] node_bridge1
|
||||
.model node_bridge1 adc_bridge
|
||||
*
|
||||
aclk [enable clk] clk nand
|
||||
.model nand d_nand (rise_delay=1e-5 fall_delay=1e-5)
|
||||
*
|
||||
abridge2 clk enable real_node1 node_bridge2
|
||||
.model node_bridge2 d_to_real (zero=-1 one=1)
|
||||
*
|
||||
again real_node1 real_node2 times10
|
||||
.model times10 real_gain (gain=10)
|
||||
*
|
||||
abridge3 real_node2 analog_node node_bridge3
|
||||
.model node_bridge3 real_to_v
|
||||
*
|
||||
rout analog_node 0 1k
|
||||
*
|
||||
again %vnam v1 %i i_out gain_block
|
||||
.model gain_block gain (gain=10)
|
||||
ri_out i_out 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
Long names
|
||||
*
|
||||
* This circuit contains a sine wave source followed by a
|
||||
* gain block code model with a gain of 10. Long names
|
||||
* are used for instances, models, and nodes.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1_123456789_123456789_1234 1 0 0.0 sin(0 1 2k)
|
||||
*
|
||||
r1_123456789_123456789_1234 1 0 1k
|
||||
*
|
||||
a1_123456789_123456789_1234 1 out_123456789_123456789_1234
|
||||
+ gain_block_123456789_123456789_1234
|
||||
*
|
||||
.model gain_block_123456789_123456789_1234 gain (gain=10)
|
||||
r2_123456789_123456789_1234 out_123456789_123456789_1234 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
MiXeD CaSe
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator deck parsing code is case-insensitive.
|
||||
*
|
||||
.TrAn 1E-5 1e-3
|
||||
*
|
||||
V1 1 0 0.0 sIn(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
A1 1 2 GaIn_BlOcK
|
||||
.MODel gAiN_bLoCk GAin (gaIN=10)
|
||||
r2 2 0 1K
|
||||
*
|
||||
.eNd
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
Mixed IO sizes
|
||||
*
|
||||
* This circuit contains a collection of digital and analog
|
||||
* models with saclar and vector inputs of varying sizes.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 pulse(0 1 1e-4)
|
||||
r1 1 0 1k
|
||||
*
|
||||
v2 2 0 0.0 sin(0 1 2k)
|
||||
r2 2 0 1k
|
||||
*
|
||||
abridge1 [1] [enable] atod
|
||||
.model atod adc_bridge
|
||||
*
|
||||
aosc [enable clk] clk nand
|
||||
.model nand d_nand (rise_delay=1e-4 fall_delay=1e-4)
|
||||
*
|
||||
ainv clk clk_bar inv
|
||||
.model inv d_inverter (rise_delay=1e-5 fall_delay=1e-5)
|
||||
*
|
||||
adac [clk clk_bar] [3 4] dac
|
||||
.model dac dac_bridge (t_rise=1e-5 t_fall=1e-5)
|
||||
*
|
||||
asum [1 2 3 4] 5 sum
|
||||
.model sum summer
|
||||
*
|
||||
r3 3 0 1k
|
||||
r4 4 0 1k
|
||||
r5 5 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
Mixed IO types
|
||||
*
|
||||
* This circuit contains a mixture of IO types, including
|
||||
* analog, digital, user-defined (real), and 'null'.
|
||||
*
|
||||
* The circuit demonstrates the use of the digital and
|
||||
* user-defined node capability to model system-level designs
|
||||
* such as sampled-data filters. The simulated circuit
|
||||
* contains a digital oscillator enabled after 100us. The
|
||||
* square wave oscillator output is divided by 8 with a
|
||||
* ripple counter. The result is passed through a digital
|
||||
* filter to convert it to a sine wave.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 pulse(0 1 1e-4 1e-6)
|
||||
r1 1 0 1k
|
||||
*
|
||||
abridge1 [1] [enable] atod
|
||||
.model atod adc_bridge
|
||||
*
|
||||
aclk [enable clk] clk nand
|
||||
.model nand d_nand (rise_delay=1e-5 fall_delay=1e-5)
|
||||
*
|
||||
adiv2 div2_out clk NULL NULL NULL div2_out dff
|
||||
adiv4 div4_out div2_out NULL NULL NULL div4_out dff
|
||||
adiv8 div8_out div4_out NULL NULL NULL div8_out dff
|
||||
.model dff d_dff
|
||||
*
|
||||
abridge2 div8_out enable filt_in node_bridge2
|
||||
.model node_bridge2 d_to_real (zero=-1 one=1)
|
||||
*
|
||||
xfilter filt_in clk filt_out dig_filter
|
||||
*
|
||||
abridge3 filt_out a_out node_bridge3
|
||||
.model node_bridge3 real_to_v
|
||||
*
|
||||
rlpf1 a_out oa_minus 10k
|
||||
*
|
||||
xlpf 0 oa_minus lpf_out opamp
|
||||
*
|
||||
rlpf2 oa_minus lpf_out 10k
|
||||
clpf lpf_out oa_minus 0.01uF
|
||||
*
|
||||
*
|
||||
.subckt dig_filter filt_in clk filt_out
|
||||
*
|
||||
.model n0 real_gain (gain=1.0)
|
||||
.model n1 real_gain (gain=2.0)
|
||||
.model n2 real_gain (gain=1.0)
|
||||
.model g1 real_gain (gain=0.125)
|
||||
.model zm1 real_delay
|
||||
.model d0a real_gain (gain=-0.75)
|
||||
.model d1a real_gain (gain=0.5625)
|
||||
.model d0b real_gain (gain=-0.3438)
|
||||
.model d1b real_gain (gain=1.0)
|
||||
*
|
||||
an0a filt_in x0a n0
|
||||
an1a filt_in x1a n1
|
||||
an2a filt_in x2a n2
|
||||
*
|
||||
az0a x0a clk x1a zm1
|
||||
az1a x1a clk x2a zm1
|
||||
*
|
||||
ad0a x2a x0a d0a
|
||||
ad1a x2a x1a d1a
|
||||
*
|
||||
az2a x2a filt1_out g1
|
||||
az3a filt1_out clk filt2_in zm1
|
||||
*
|
||||
an0b filt2_in x0b n0
|
||||
an1b filt2_in x1b n1
|
||||
an2b filt2_in x2b n2
|
||||
*
|
||||
az0b x0b clk x1b zm1
|
||||
az1b x1b clk x2b zm1
|
||||
*
|
||||
ad0 x2b x0b d0b
|
||||
ad1 x2b x1b d1b
|
||||
*
|
||||
az2b x2b clk filt_out zm1
|
||||
*
|
||||
.ends dig_filter
|
||||
*
|
||||
*
|
||||
.subckt opamp plus minus out
|
||||
*
|
||||
r1 plus minus 300k
|
||||
a1 %vd (plus minus) outint lim
|
||||
.model lim limit (out_lower_limit = -12 out_upper_limit = 12
|
||||
+ fraction = true limit_range = 0.2 gain=300e3)
|
||||
r3 outint out 50.0
|
||||
r2 out 0 1e12
|
||||
*
|
||||
.ends opamp
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Mixed references
|
||||
*
|
||||
* This circuit demonstrates the use of single-ended and
|
||||
* differential inputs and outputs.
|
||||
*
|
||||
* Note that digital models reference a single node for
|
||||
* their inputs and output (i.e. they are single-ended)
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 5k)
|
||||
v2 2 0 0.0 sin(0 1 1k)
|
||||
*
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
*
|
||||
*
|
||||
a1 %v 1 %i 10 times10
|
||||
r10 10 0 1k
|
||||
*
|
||||
*
|
||||
a2 %vd (1 2) %id(11 12) times10
|
||||
r11 11 0 1k
|
||||
r12 12 0 1k
|
||||
r11_12 11 12 1.0
|
||||
*
|
||||
*
|
||||
r3 2 3 1k
|
||||
a3 %i 3 %v 13 times10
|
||||
r13 13 0 1k
|
||||
*
|
||||
a4 [1] [digital_node1] adc
|
||||
.model adc adc_bridge
|
||||
*
|
||||
a5 digital_node1 digital_node2 inv
|
||||
.model inv d_inverter
|
||||
*
|
||||
*
|
||||
.model times10 gain (gain=10)
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
mosamp2 - mos amplifier - transient
|
||||
.options acct abstol=10n vntol=10n
|
||||
.tran 0.1us 10us
|
||||
m1 15 15 1 32 m w=88.9u l=25.4u
|
||||
m2 1 1 2 32 m w=12.7u l=266.7u
|
||||
m3 2 2 30 32 m w=88.9u l=25.4u
|
||||
m4 15 5 4 32 m w=12.7u l=106.7u
|
||||
m5 4 4 30 32 m w=88.9u l=12.7u
|
||||
m6 15 15 5 32 m w=44.5u l=25.4u
|
||||
m7 5 20 8 32 m w=482.6u l=12.7u
|
||||
m8 8 2 30 32 m w=88.9u l=25.4u
|
||||
m9 15 15 6 32 m w=44.5u l=25.4u
|
||||
m10 6 21 8 32 m w=482.6u l=12.7u
|
||||
m11 15 6 7 32 m w=12.7u l=106.7u
|
||||
m12 7 4 30 32 m w=88.9u l=12.7u
|
||||
m13 15 10 9 32 m w=139.7u l=12.7u
|
||||
m14 9 11 30 32 m w=139.7u l=12.7u
|
||||
m15 15 15 12 32 m w=12.7u l=207.8u
|
||||
m16 12 12 11 32 m w=54.1u l=12.7u
|
||||
m17 11 11 30 32 m w=54.1u l=12.7u
|
||||
m18 15 15 10 32 m w=12.7u l=45.2u
|
||||
m19 10 12 13 32 m w=270.5u l=12.7u
|
||||
m20 13 7 30 32 m w=270.5u l=12.7u
|
||||
m21 15 10 14 32 m w=254u l=12.7u
|
||||
m22 14 11 30 32 m w=241.3u l=12.7u
|
||||
m23 15 20 16 32 m w=19u l=38.1u
|
||||
m24 16 14 30 32 m w=406.4u l=12.7u
|
||||
m25 15 15 20 32 m w=38.1u l=42.7u
|
||||
m26 20 16 30 32 m w=381u l=25.4u
|
||||
m27 20 15 66 32 m w=22.9u l=7.6u
|
||||
cc 7 9 40pf
|
||||
cl 66 0 70pf
|
||||
vin 21 0 pulse(0 5 1ns 1ns 1ns 5us 10us)
|
||||
vccp 15 0 dc +15
|
||||
vddn 30 0 dc -15
|
||||
vb 32 0 dc -20
|
||||
.model m nmos(nsub=2.2e15 uo=575 ucrit=49k uexp=0.1 tox=0.11u xj=2.95u
|
||||
+ level=2 cgso=1.5n cgdo=1.5n cbd=4.5f cbs=4.5f ld=2.4485u nss=3.2e10
|
||||
+ kp=2e-5 phi=0.6 )
|
||||
.print tran v(20) v(66)
|
||||
.plot tran v(20) v(66)
|
||||
.end
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
mosmem - mos memory cell
|
||||
.width in=72
|
||||
.opt abstol=1u
|
||||
.opt acct list node
|
||||
.tran 20ns 2us
|
||||
vdd 9 0 dc 5
|
||||
vs 7 0 pulse(2 0 520ns 20ns 20ns 500ns 2000ns)
|
||||
vw 1 0 pulse(0 2 20ns 20ns 500ns 200ns)
|
||||
vwb 2 0 pulse(2 0 20ns 20ns 20ns 2000ns 2000ns)
|
||||
m1 3 1 0 0 mod w=250u l=5u
|
||||
m2 4 2 0 0 mod w=250u l=5u
|
||||
m3 9 9 3 0 mod w=5u l=5u
|
||||
m4 9 9 4 0 mod w=5u l=5u
|
||||
m5 5 7 3 0 mod w=50u l=5u
|
||||
m6 6 7 4 0 mod w=50u l=5u
|
||||
m7 5 6 0 0 mod w=250u l=5u
|
||||
m8 6 5 0 0 mod w=250u l=5u
|
||||
m9 9 9 5 0 mod w=5u l=5u
|
||||
m10 9 9 6 0 mod w=5u l=5u
|
||||
m11 8 4 0 0 mod w=250u l=5u
|
||||
m12 9 9 8 0 mod w=5u l=5u
|
||||
.model mod nmos(vto=0.5 phi=0.7 kp=1.0e-6 gamma=1.83 lambda=0.115
|
||||
+ level=1 cgso=1u cgdo=1u cbd=50p cbs=50p)
|
||||
.print dc v(5) v(6)
|
||||
.plot dc v(6)
|
||||
.plot tran v(6) v(5) v(7) v(1) v(2)
|
||||
.end
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# $Id$
|
||||
#
|
||||
# Makefile for Code Model directories
|
||||
#
|
||||
|
||||
# Include global XSPICE selections for CC and other macros
|
||||
include /usr/local/xspice-1-0/include/make.include
|
||||
|
||||
INCLUDE = -I. -I$(ROOT)/include/sim
|
||||
|
||||
CFLAGS = -g
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Edit the following definition to specify the object files that comprise
|
||||
# your code model. If your code model is completely specified in the
|
||||
# cfunc.mod file, there is no need to edit this definition.
|
||||
# DO NOT include the ifspec.o file.
|
||||
|
||||
CODE_MODEL_OBJECTS = cfunc.o
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# DO NOT MODIFY THE FOLLOWING DEFINITIONS:
|
||||
|
||||
.SUFFIXES: $(SUFFIXES) .mod .ifs
|
||||
|
||||
.mod.c:
|
||||
$(BINDIR)/cmpp -mod $<
|
||||
|
||||
.ifs.c:
|
||||
$(BINDIR)/cmpp -ifs
|
||||
|
||||
.c.o: $*.c
|
||||
${CC} ${CFLAGS} ${INCLUDE} -c $*.c
|
||||
|
||||
all : ifspec.o $(CODE_MODEL_OBJECTS)
|
||||
|
||||
cfunc.o : cfunc.c
|
||||
ifspec.o : ifspec.c
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/* $Id$ */
|
||||
|
||||
void *malloc(unsigned);
|
||||
|
||||
#define OUT_STATE 0
|
||||
#define NXT_TIME 1
|
||||
#define NUM_NOTES 128
|
||||
|
||||
|
||||
/* A numerically controlled oscillator. Output frequencies */
|
||||
/* are determined according to the MIDI note number at input */
|
||||
|
||||
void ucm_nco (ARGS)
|
||||
{
|
||||
|
||||
double *freq;
|
||||
|
||||
int *output_state;
|
||||
double *next_time;
|
||||
|
||||
int i;
|
||||
int index;
|
||||
int scale_factor;
|
||||
|
||||
double half_period;
|
||||
|
||||
|
||||
if(INIT) {
|
||||
|
||||
/* Setup storage for the toggled output state */
|
||||
output_state = (int *) cm_event_alloc(OUT_STATE, sizeof(int));
|
||||
next_time = (double *) cm_event_alloc(NXT_TIME, sizeof(double));
|
||||
|
||||
/* Allocate storage for frequencies */
|
||||
STATIC_VAR(freq) = malloc(NUM_NOTES * sizeof(double));
|
||||
freq = STATIC_VAR(freq);
|
||||
|
||||
/* Initialize the frequency array */
|
||||
for(i = 0; i < NUM_NOTES; i++) {
|
||||
if(i == 0)
|
||||
freq[0] = 8.17578 * PARAM(mult_factor);
|
||||
else
|
||||
freq[i] = freq[i-1] * 1.059463094;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
/* Get old output state */
|
||||
output_state = (int *) cm_event_get_ptr(OUT_STATE, 0);
|
||||
next_time = (double *) cm_event_get_ptr(NXT_TIME, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Convert the input bits to an integer */
|
||||
index = 0;
|
||||
scale_factor = 64;
|
||||
for(i = 0; i < 7; i++) {
|
||||
if(INPUT_STATE(in[i]) == ONE)
|
||||
index += scale_factor;
|
||||
scale_factor /= 2;
|
||||
}
|
||||
|
||||
/* Look up the frequency and compute half its period */
|
||||
freq = STATIC_VAR(freq);
|
||||
half_period = 1.0 / freq[index];
|
||||
|
||||
|
||||
/* Queue up events and output the new state */
|
||||
if(TIME == 0.0) {
|
||||
*next_time = half_period;
|
||||
cm_event_queue(*next_time);
|
||||
OUTPUT_STATE(out) = *output_state;
|
||||
}
|
||||
else {
|
||||
if(TIME == *next_time) {
|
||||
*next_time = TIME + half_period;
|
||||
cm_event_queue(*next_time);
|
||||
*output_state = 1 - *output_state;
|
||||
OUTPUT_STATE(out) = *output_state;
|
||||
OUTPUT_DELAY(out) = PARAM(delay);
|
||||
}
|
||||
else
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* $Id$ */
|
||||
|
||||
NAME_TABLE:
|
||||
|
||||
Spice_Model_Name: nco
|
||||
C_Function_Name: ucm_nco
|
||||
Description: "A simple MIDI numerically controlled oscillator"
|
||||
|
||||
|
||||
PORT_TABLE:
|
||||
|
||||
Port_Name: in out
|
||||
Description: "program input" "oscillator output"
|
||||
Direction: in out
|
||||
Default_Type: d d
|
||||
Allowed_Types: [d] [d]
|
||||
Vector: yes no
|
||||
Vector_Bounds: [7 7] -
|
||||
Null_Allowed: no no
|
||||
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: delay mult_factor
|
||||
Description: "output delay" "freq multiplier"
|
||||
Data_Type: real real
|
||||
Default_Value: 1e-9 1
|
||||
Limits: [1e-15 -] [1e-9 -]
|
||||
Vector: no no
|
||||
Vector_Bounds: - -
|
||||
Null_Allowed: yes yes
|
||||
|
||||
|
||||
STATIC_VAR_TABLE:
|
||||
|
||||
Static_Var_Name: freq
|
||||
Data_Type: pointer
|
||||
Description: "frequencies of notes"
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Parameter defaults
|
||||
*
|
||||
* This circuit contains a code model with
|
||||
* parameters of various types, which are all defaulted,
|
||||
* and prints the default values.
|
||||
*
|
||||
.op
|
||||
*
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 1 2 1k
|
||||
*
|
||||
a1 [1 2] mod
|
||||
.model mod print_param_types
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
Parameter types
|
||||
*
|
||||
* This circuit contains a code model which accepts several
|
||||
* parameters of various types and prints them.
|
||||
*
|
||||
.op
|
||||
*
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 1 2 1k
|
||||
*
|
||||
a1 [1 2] mod
|
||||
.model mod print_param_types
|
||||
+ integer=2
|
||||
+ real=3.0
|
||||
+ complex=<4.0 5.0>
|
||||
+ string=six
|
||||
+ integer_array=[7 8]
|
||||
+ real_array=[9.0 10.0]
|
||||
+ complex_array=[< 11.0 12.0 > < 13.0 14.0 >]
|
||||
+ string_array=[fifteen sixteen]
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Parsing
|
||||
*
|
||||
* This circuit contains a simple gain block to demonstrate
|
||||
* that the simulator parses the syntax used to reference
|
||||
* code models.
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
r1 1 0 1k
|
||||
*
|
||||
a1 1 2 gain_block
|
||||
.model gain_block gain (gain=10)
|
||||
r2 2 0 1k
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
Polarity of voltages and currents
|
||||
*
|
||||
* This circuit contains a set of gain blocks to evaluate
|
||||
* the polarity of voltages and currents on code models
|
||||
*
|
||||
.tran 1e-5 1e-3
|
||||
*
|
||||
v1 1 0 0.0 sin(0 1 1k)
|
||||
*
|
||||
r1 1 0 1k
|
||||
*
|
||||
*
|
||||
a1 %v 1 %v 10 times10
|
||||
r10 10 0 1k
|
||||
*
|
||||
r1_2 1 2 1k
|
||||
a2 %i 2 %v 11 times10
|
||||
r11 11 0 1k
|
||||
*
|
||||
a3 1 %i 12 times10
|
||||
r12 12 0 1k
|
||||
*
|
||||
*
|
||||
.model times10 gain (gain=10)
|
||||
*
|
||||
.end
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# $Id$
|
||||
#
|
||||
# Makefile for Code Model directories
|
||||
#
|
||||
|
||||
# Include global XSPICE selections for CC and other macros
|
||||
include /usr/local/xspice-1-0/include/make.include
|
||||
|
||||
INCLUDE = -I. -I$(ROOT)/include/sim
|
||||
|
||||
CFLAGS = -g
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Edit the following definition to specify the object files that comprise
|
||||
# your code model. If your code model is completely specified in the
|
||||
# cfunc.mod file, there is no need to edit this definition.
|
||||
# DO NOT include the ifspec.o file.
|
||||
|
||||
CODE_MODEL_OBJECTS = cfunc.o
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# DO NOT MODIFY THE FOLLOWING DEFINITIONS:
|
||||
|
||||
.SUFFIXES: $(SUFFIXES) .mod .ifs
|
||||
|
||||
.mod.c:
|
||||
$(BINDIR)/cmpp -mod $<
|
||||
|
||||
.ifs.c:
|
||||
$(BINDIR)/cmpp -ifs
|
||||
|
||||
.c.o: $*.c
|
||||
${CC} ${CFLAGS} ${INCLUDE} -c $*.c
|
||||
|
||||
all : ifspec.o $(CODE_MODEL_OBJECTS)
|
||||
|
||||
cfunc.o : cfunc.c
|
||||
ifspec.o : ifspec.c
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* $Id$ */
|
||||
|
||||
void ucm_print_param_types (ARGS)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(INIT) {
|
||||
/* Print scalar parameters */
|
||||
printf("\nScalar parameters\n\n");
|
||||
printf("integer = %d\n", PARAM(integer));
|
||||
printf("real = %e\n", PARAM(real));
|
||||
printf("complex = <%e %e>\n", PARAM(complex).real,
|
||||
PARAM(complex).imag);
|
||||
printf("string = %s\n", PARAM(string));
|
||||
|
||||
/* Print vector parameters */
|
||||
printf("\nVector parameters\n\n");
|
||||
for(i = 0; i < PARAM_SIZE(integer_array); i++)
|
||||
printf("integer = %d\n", PARAM(integer_array[i]));
|
||||
for(i = 0; i < PARAM_SIZE(real_array); i++)
|
||||
printf("real = %e\n", PARAM(real_array[i]));
|
||||
for(i = 0; i < PARAM_SIZE(complex_array); i++)
|
||||
printf("complex = <%e %e>\n", PARAM(complex_array[i]).real,
|
||||
PARAM(complex_array[i]).imag);
|
||||
for(i = 0; i < PARAM_SIZE(string_array); i++)
|
||||
printf("string = %s\n", PARAM(string_array[i]));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/* $Id$ */
|
||||
|
||||
NAME_TABLE:
|
||||
|
||||
Spice_Model_Name: print_param_types
|
||||
C_Function_Name: ucm_print_param_types
|
||||
Description: "ignores its input, but prints its parameters"
|
||||
|
||||
|
||||
PORT_TABLE:
|
||||
|
||||
|
||||
Port_Name: in
|
||||
Description: "input"
|
||||
Direction: in
|
||||
Default_Type: v
|
||||
Allowed_Types: [v,vd,i,id,vnam]
|
||||
Vector: yes
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: no
|
||||
|
||||
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: integer
|
||||
Description: "integer parameter"
|
||||
Data_Type: int
|
||||
Default_Value: 1
|
||||
Limits: -
|
||||
Vector: no
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: real
|
||||
Description: "real parameter"
|
||||
Data_Type: real
|
||||
Default_Value: 1
|
||||
Limits: -
|
||||
Vector: no
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: complex
|
||||
Description: "complex parameter"
|
||||
Data_Type: complex
|
||||
Default_Value: <1.0, 1.0>
|
||||
Limits: -
|
||||
Vector: no
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: string
|
||||
Description: "string parameter"
|
||||
Data_Type: string
|
||||
Default_Value: "one"
|
||||
Limits: -
|
||||
Vector: no
|
||||
Vector_Bounds: -
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: integer_array
|
||||
Description: "integer array parameter"
|
||||
Data_Type: int
|
||||
Default_Value: 1
|
||||
Limits: -
|
||||
Vector: yes
|
||||
Vector_Bounds: in
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: real_array
|
||||
Description: "real array parameter"
|
||||
Data_Type: real
|
||||
Default_Value: 1
|
||||
Limits: -
|
||||
Vector: yes
|
||||
Vector_Bounds: in
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: complex_array
|
||||
Description: "complex array parameter"
|
||||
Data_Type: complex
|
||||
Default_Value: <1.0 1.0>
|
||||
Limits: -
|
||||
Vector: yes
|
||||
Vector_Bounds: in
|
||||
Null_Allowed: yes
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: string_array
|
||||
Description: "string array parameter"
|
||||
Data_Type: string
|
||||
Default_Value: "one"
|
||||
Limits: -
|
||||
Vector: yes
|
||||
Vector_Bounds: in
|
||||
Null_Allowed: yes
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
rca3040 ckt - rca 3040 wideband amplifier
|
||||
.ac dec 10 1 10ghz
|
||||
.dc vin -0.25 0.25 0.005
|
||||
.tran 2.0ns 200ns
|
||||
vin 1 0 sin(0 0.1 50meg 0.5ns) ac 1
|
||||
vcc 2 0 15.0
|
||||
vee 3 0 -15.0
|
||||
rs1 30 1 1k
|
||||
rs2 31 0 1k
|
||||
r1 5 3 4.8k
|
||||
r2 6 3 4.8k
|
||||
r3 9 3 811
|
||||
r4 8 3 2.17k
|
||||
r5 8 0 820
|
||||
r6 2 14 1.32k
|
||||
r7 2 12 4.5k
|
||||
r8 2 15 1.32k
|
||||
r9 16 0 5.25k
|
||||
r10 17 0 5.25k
|
||||
q1 2 30 5 qnl
|
||||
q2 2 31 6 qnl
|
||||
q3 10 5 7 qnl
|
||||
q4 11 6 7 qnl
|
||||
q5 14 12 10 qnl
|
||||
q6 15 12 11 qnl
|
||||
q7 12 12 13 qnl
|
||||
q8 13 13 0 qnl
|
||||
q9 7 8 9 qnl
|
||||
q10 2 15 16 qnl
|
||||
q11 2 14 17 qnl
|
||||
.model qnl npn bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf
|
||||
+ cjc=2pf va 50
|
||||
.end
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# $Id$
|
||||
#
|
||||
# Makefile for Code Model directories
|
||||
#
|
||||
|
||||
# Include global XSPICE selections for CC and other macros
|
||||
include /usr/local/xspice-1-0/include/make.include
|
||||
|
||||
INCLUDE = -I. -I$(ROOT)/include/sim
|
||||
|
||||
CFLAGS = -g
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Edit the following definition to specify the object files that comprise
|
||||
# your code model. If your code model is completely specified in the
|
||||
# cfunc.mod file, there is no need to edit this definition.
|
||||
# DO NOT include the ifspec.o file.
|
||||
|
||||
CODE_MODEL_OBJECTS = cfunc.o
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# DO NOT MODIFY THE FOLLOWING DEFINITIONS:
|
||||
|
||||
.SUFFIXES: $(SUFFIXES) .mod .ifs
|
||||
|
||||
.mod.c:
|
||||
$(BINDIR)/cmpp -mod $<
|
||||
|
||||
.ifs.c:
|
||||
$(BINDIR)/cmpp -ifs
|
||||
|
||||
.c.o: $*.c
|
||||
${CC} ${CFLAGS} ${INCLUDE} -c $*.c
|
||||
|
||||
all : ifspec.o $(CODE_MODEL_OBJECTS)
|
||||
|
||||
cfunc.o : cfunc.c
|
||||
ifspec.o : ifspec.c
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/* $Id$ */
|
||||
|
||||
|
||||
#define CLK_STATE 0
|
||||
|
||||
|
||||
void ucm_real_delay (ARGS)
|
||||
{
|
||||
|
||||
double *in;
|
||||
double *out;
|
||||
|
||||
Digital_State_t *state;
|
||||
Digital_State_t *old_state;
|
||||
|
||||
|
||||
if(INIT) {
|
||||
state = (void *) cm_event_alloc(CLK_STATE, sizeof(Digital_State_t));
|
||||
old_state = state;
|
||||
*state = INPUT_STATE(clk);
|
||||
}
|
||||
else {
|
||||
state = (void *) cm_event_get_ptr(CLK_STATE, 0);
|
||||
old_state = (void *) cm_event_get_ptr(CLK_STATE, 1);
|
||||
}
|
||||
|
||||
if(ANALYSIS != TRANSIENT)
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
else {
|
||||
*state = INPUT_STATE(clk);
|
||||
if(*state == *old_state)
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
else if(*state != ONE)
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
else {
|
||||
in = INPUT(in);
|
||||
out = OUTPUT(out);
|
||||
*out = *in;
|
||||
OUTPUT_DELAY(out) = PARAM(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue