159 changed files with 27058 additions and 0 deletions
-
20src/xspice/Makefile.am
-
41src/xspice/README
-
17src/xspice/cm/Makefile.am
-
701src/xspice/cm/cm.c
-
267src/xspice/cm/cmevt.c
-
314src/xspice/cm/cmmeters.c
-
523src/xspice/cm/cmutil.c
-
36src/xspice/cmpp/Makefile
-
285src/xspice/cmpp/cmpp.h
-
179src/xspice/cmpp/ifs_lex.l
-
81src/xspice/cmpp/ifs_yacc.h
-
901src/xspice/cmpp/ifs_yacc.y
-
125src/xspice/cmpp/main.c
-
107src/xspice/cmpp/mod_lex.l
-
49src/xspice/cmpp/mod_yacc.h
-
559src/xspice/cmpp/mod_yacc.y
-
88src/xspice/cmpp/pp_ifs.c
-
1082src/xspice/cmpp/pp_lst.c
-
181src/xspice/cmpp/pp_mod.c
-
175src/xspice/cmpp/read_ifs.c
-
87src/xspice/cmpp/util.c
-
1304src/xspice/cmpp/writ_ifs.c
-
13src/xspice/enh/Makefile.am
-
99src/xspice/enh/enh.c
-
536src/xspice/enh/enhtrans.c
-
27src/xspice/evt/Makefile.am
-
170src/xspice/evt/evtaccept.c
-
645src/xspice/evt/evtbackup.c
-
78src/xspice/evt/evtcall_hybrids.c
-
366src/xspice/evt/evtdeque.c
-
350src/xspice/evt/evtdump.c
-
437src/xspice/evt/evtinit.c
-
300src/xspice/evt/evtiter.c
-
613src/xspice/evt/evtload.c
-
93src/xspice/evt/evtnext_time.c
-
159src/xspice/evt/evtnode_copy.c
-
321src/xspice/evt/evtop.c
-
218src/xspice/evt/evtplot.c
-
369src/xspice/evt/evtprint.c
-
252src/xspice/evt/evtqueue.c
-
578src/xspice/evt/evtsetup.c
-
512src/xspice/evt/evttermi.c
-
67src/xspice/examples/analog_models1_ac.deck
-
61src/xspice/examples/analog_models1_dc.deck
-
61src/xspice/examples/analog_models1_swept_dc.deck
-
62src/xspice/examples/analog_models1_transient.deck
-
66src/xspice/examples/analog_models2_ac.deck
-
63src/xspice/examples/analog_models2_dc.deck
-
64src/xspice/examples/analog_models2_swept_dc.deck
-
67src/xspice/examples/analog_models2_transient.deck
-
81src/xspice/examples/analog_models3_ac.deck
-
79src/xspice/examples/analog_models3_dc.deck
-
79src/xspice/examples/analog_models3_swept_dc.deck
-
80src/xspice/examples/analog_models3_transient.deck
-
78src/xspice/examples/analog_models4_ac.deck
-
74src/xspice/examples/analog_models4_dc.deck
-
72src/xspice/examples/analog_models4_swept_dc.deck
-
76src/xspice/examples/analog_models4_transient.deck
-
17src/xspice/examples/arbitrary_phase.deck
-
17src/xspice/examples/bad_io.deck
-
25src/xspice/examples/bad_io_type.deck
-
16src/xspice/examples/bad_name.deck
-
16src/xspice/examples/bad_param.deck
-
16src/xspice/examples/bad_param_type.deck
-
40src/xspice/examples/d_to_real/Makefile
-
43src/xspice/examples/d_to_real/cfunc.mod
-
32src/xspice/examples/d_to_real/ifspec.ifs
-
28src/xspice/examples/diffpair.in
-
23src/xspice/examples/digital_invert.deck
-
20src/xspice/examples/digital_models.deck
-
77src/xspice/examples/digital_models1.deck
-
91src/xspice/examples/digital_models2.deck
-
92src/xspice/examples/digital_models3.deck
-
91src/xspice/examples/digital_models4.deck
-
19src/xspice/examples/dot_model_ref.deck
-
46src/xspice/examples/hybrid_models1_dc.deck
-
48src/xspice/examples/hybrid_models1_transient.deck
-
19src/xspice/examples/initial_conditions.deck
-
17src/xspice/examples/io_ordering.deck
-
34src/xspice/examples/io_types.deck
-
19src/xspice/examples/long_names.deck
-
15src/xspice/examples/mixed_case.deck
-
33src/xspice/examples/mixed_io_size.deck
-
98src/xspice/examples/mixed_mode.deck
-
41src/xspice/examples/mixed_ref.deck
-
42src/xspice/examples/mosamp2.in
-
27src/xspice/examples/mosmem.in
-
40src/xspice/examples/nco/Makefile
-
90src/xspice/examples/nco/cfunc.mod
-
38src/xspice/examples/nco/ifspec.ifs
-
16src/xspice/examples/param_defaults.deck
-
23src/xspice/examples/param_types.deck
-
16src/xspice/examples/parsing.deck
-
26src/xspice/examples/polarity.deck
-
40src/xspice/examples/print_param_types/Makefile
-
33src/xspice/examples/print_param_types/cfunc.mod
-
112src/xspice/examples/print_param_types/ifspec.ifs
-
33src/xspice/examples/rca3040.in
-
40src/xspice/examples/real_delay/Makefile
-
46src/xspice/examples/real_delay/cfunc.mod
@ -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); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
1082
src/xspice/cmpp/pp_lst.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -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); |
||||
|
} |
||||
|
|
||||
|
|
||||
1304
src/xspice/cmpp/writ_ifs.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -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 changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue