First batch of added file.

This commit is contained in:
pnenzi 2003-07-23 19:59:53 +00:00
parent 8362dec274
commit 9317355c0c
159 changed files with 27058 additions and 0 deletions

20
src/xspice/Makefile.am Executable file
View File

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

41
src/xspice/README Executable file
View File

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

17
src/xspice/cm/Makefile.am Executable file
View File

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

701
src/xspice/cm/cm.c Executable file
View File

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

267
src/xspice/cm/cmevt.c Executable file
View File

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

314
src/xspice/cm/cmmeters.c Executable file
View File

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

523
src/xspice/cm/cmutil.c Executable file
View File

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

36
src/xspice/cmpp/Makefile Executable file
View File

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

285
src/xspice/cmpp/cmpp.h Executable file
View File

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

179
src/xspice/cmpp/ifs_lex.l Executable file
View File

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

81
src/xspice/cmpp/ifs_yacc.h Executable file
View File

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

901
src/xspice/cmpp/ifs_yacc.y Executable file
View File

@ -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, &param->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, &param->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;}
;
%%

125
src/xspice/cmpp/main.c Executable file
View File

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

107
src/xspice/cmpp/mod_lex.l Executable file
View File

@ -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;}
%%

49
src/xspice/cmpp/mod_yacc.h Executable file
View File

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

559
src/xspice/cmpp/mod_yacc.y Executable file
View File

@ -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);}
;
%%

88
src/xspice/cmpp/pp_ifs.c Executable file
View File

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

File diff suppressed because it is too large Load Diff

181
src/xspice/cmpp/pp_mod.c Executable file
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);
}

175
src/xspice/cmpp/read_ifs.c Executable file
View File

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

87
src/xspice/cmpp/util.c Executable file
View File

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

File diff suppressed because it is too large Load Diff

13
src/xspice/enh/Makefile.am Executable file
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

99
src/xspice/enh/enh.c Executable file
View File

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

536
src/xspice/enh/enhtrans.c Executable file
View File

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

27
src/xspice/evt/Makefile.am Executable file
View File

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

170
src/xspice/evt/evtaccept.c Executable file
View File

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

645
src/xspice/evt/evtbackup.c Executable file
View File

@ -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++;
}
}
}

View File

@ -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]);
}

366
src/xspice/evt/evtdeque.c Executable file
View File

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

350
src/xspice/evt/evtdump.c Executable file
View File

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

437
src/xspice/evt/evtinit.c Executable file
View File

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

300
src/xspice/evt/evtiter.c Executable file
View File

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

613
src/xspice/evt/evtload.c Executable file
View File

@ -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 */
}

93
src/xspice/evt/evtnext_time.c Executable file
View File

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

159
src/xspice/evt/evtnode_copy.c Executable file
View File

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

321
src/xspice/evt/evtop.c Executable file
View File

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

218
src/xspice/evt/evtplot.c Executable file
View File

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

369
src/xspice/evt/evtprint.c Executable file
View File

@ -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");
}

252
src/xspice/evt/evtqueue.c Executable file
View File

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

578
src/xspice/evt/evtsetup.c Executable file
View File

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

512
src/xspice/evt/evttermi.c Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

17
src/xspice/examples/bad_io.deck Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

28
src/xspice/examples/diffpair.in Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

42
src/xspice/examples/mosamp2.in Executable file
View File

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

27
src/xspice/examples/mosmem.in Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]));
}
}

View File

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

33
src/xspice/examples/rca3040.in Executable file
View File

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

View File

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

View File

@ -0,0 +1,46 @@
/* $Id$ */
#define CLK_STATE 0
void ucm_real_delay (ARGS)
{
double *in;
double *out;
Digital_State_t *state;
Digital_State_t *old_state;
if(INIT) {
state = (void *) cm_event_alloc(CLK_STATE, sizeof(Digital_State_t));
old_state = state;
*state = INPUT_STATE(clk);
}
else {
state = (void *) cm_event_get_ptr(CLK_STATE, 0);
old_state = (void *) cm_event_get_ptr(CLK_STATE, 1);
}
if(ANALYSIS != TRANSIENT)
OUTPUT_CHANGED(out) = FALSE;
else {
*state = INPUT_STATE(clk);
if(*state == *old_state)
OUTPUT_CHANGED(out) = FALSE;
else if(*state != ONE)
OUTPUT_CHANGED(out) = FALSE;
else {
in = INPUT(in);
out = OUTPUT(out);
*out = *in;
OUTPUT_DELAY(out) = PARAM(delay);
}
}
}

Some files were not shown because too many files have changed in this diff Show More