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