Initial revision

This commit is contained in:
stefanjones 2002-11-26 10:11:59 +00:00
parent a7e1405208
commit d2ae47441b
201 changed files with 34791 additions and 0 deletions

24
src/frontend/com_dl.c Executable file
View File

@ -0,0 +1,24 @@
#include <ngspice.h> /* for wl */
#include "ftedefs.h"
#include <devdefs.h> /* solve deps in dev.h*/
#include <../spicelib/devices/dev.h> /*for load library commands*/
#ifdef XSPICE
void com_codemodel(wordlist *wl){
wordlist *ww;
for(ww = wl;ww;ww = ww->wl_next)
if(load_opus(wl->wl_word))
fprintf(cp_err,"Error: Library %s couldn't be loaded!\n",ww->wl_word);
return;
}
#endif
#ifdef DEVLIB
void com_use(wordlist *wl){
wordlist *ww;
for(ww = wl;ww;ww = ww->wl_next)
if(load_dev(wl->wl_word))
fprintf(cp_err,"Error: Library %s couldn't be loaded!\n",ww->wl_word);
return;
}
#endif

12
src/frontend/com_dl.h Executable file
View File

@ -0,0 +1,12 @@
#ifndef _COM_DL_H
#define _COM_DL_H 1
#ifdef XSPICE
void com_codemodel(wordlist *wl);
#endif
#ifdef DEVLIB
void com_use(wordlist *wl);
#endif
#endif

24
src/include/cluster.h Executable file
View File

@ -0,0 +1,24 @@
#ifndef _CLUSTER_H_
#define _CLUSTER_H_
#include <cktdefs.h>
/* Cluster definitions */
#define PORT 1234
#define TIME_PORT 1235
#define DOMAIN_NAME "cluster.multigig"
#define CLUSTER_WIDTH 4
#define TIME_HOST "time.cluster.multigig"
/* does all the setups */
extern int CLUsetup(CKTcircuit *ckt);
/* reads input pipes and sets voltages*/
/* call each time the present time is changed, ie just before NIinter*/
extern int CLUinput(CKTcircuit *ckt);
/* call after each accepted timestep, ie CKTdump */
extern int CLUoutput(CKTcircuit *ckt);
/* the time step control */
extern int CLUsync(double time,double *delta, int error);
#endif

49
src/include/cm.h Executable file
View File

@ -0,0 +1,49 @@
#ifndef CM_DEFINED
#define CM_DEFINED
/* ===========================================================================
FILE CM.h
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 is includes all include data in the CM package.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "cmtypes.h"
#include "cmconstants.h" // K.A. wrong name
//#include "Cmconsta.h"
#include "cmproto.h"
#include "mifcmdat.h"
#endif /* CM_DEFINED */

57
src/include/cmconstants.h Executable file
View File

@ -0,0 +1,57 @@
#ifndef CMCONSTANTS_DEFINED
#define CMCONSTANTS_DEFINED
/* ===========================================================================
FILE CMconstants.h
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 constants used by code models.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h"
/***** Define Constants *******************************************/
#define FALSE 0
#define TRUE 1
#define DC MIF_DC
#define AC MIF_AC
#define TRANSIENT MIF_TRAN
#define ANALOG MIF_ANALOG
#define EVENT MIF_EVENT_DRIVEN
#endif /* CMCONSTANTS_DEFINED */

95
src/include/cmproto.h Executable file
View File

@ -0,0 +1,95 @@
#ifndef CMPROTO_DEFINED
#define CMPROTO_DEFINED
/* ===========================================================================
FILE CMproto.h
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, Bill Kuhn
MODIFICATIONS
<date> <person name> <nature of modifications>
SUMMARY
This file contains ANSI C function prototypes for cm_xxx functions
called by code models.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
/* Prototypes for functions used by internal code models */
/* The actual functions reside in ../ICM/CMutil.c */
/* 12/17/90 */
#include "cmtypes.h"
void cm_climit_fcn(double in, double in_offset, double cntl_upper,
double cntl_lower, double lower_delta,
double upper_delta, double limit_range,
double gain, int percent, double *out_final,
double *pout_pin_final, double *pout_pcntl_lower_final,
double *pout_pcntl_upper_final);
void cm_smooth_corner(double x_input, double x_center, double y_center,
double domain, double lower_slope, double upper_slope,
double *y_output, double *dy_dx);
void cm_smooth_discontinuity(double x_input, double x_lower, double y_lower,
double x_upper, double y_upper,
double *y_output, double *dy_dx);
double cm_smooth_pwl(double x_input, double *x, double *y, int size,
double input_domain, double *dout_din);
double cm_analog_ramp_factor(void);
void *cm_analog_alloc(int tag, int bytes);
void *cm_analog_get_ptr(int tag, int timepoint);
int cm_analog_integrate(double integrand, double *integral, double *partial);
int cm_analog_converge(double *state);
int cm_analog_set_temp_bkpt(double time);
int cm_analog_set_perm_bkpt(double time);
void cm_analog_not_converged(void);
void cm_analog_auto_partial(void);
void *cm_event_alloc(int tag, int bytes);
void *cm_event_get_ptr(int tag, int timepoint);
int cm_event_queue(double time);
char *cm_message_get_errmsg(void);
int cm_message_send(char *msg);
double cm_netlist_get_c(void);
double cm_netlist_get_l(void);
Complex_t cm_complex_set(double real, double imag);
Complex_t cm_complex_add(Complex_t x, Complex_t y);
Complex_t cm_complex_subtract(Complex_t x, Complex_t y);
Complex_t cm_complex_multiply(Complex_t x, Complex_t y);
Complex_t cm_complex_divide(Complex_t x, Complex_t y);
#endif /* CMPROTO_DEFINED */

71
src/include/cmtypes.h Executable file
View File

@ -0,0 +1,71 @@
#ifndef CMTYPES_DEFINED
#define CMTYPES_DEFINED
/* ===========================================================================
FILE CMtypes.h
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, Bill Kuhn
MODIFICATIONS
<date> <person name> <nature of modifications>
SUMMARY
This file contains type definitions used by code models.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h"
/***** Define Typedefs ********************************************/
typedef int Boolean_t;
typedef Mif_Complex_t Complex_t;
typedef enum {
ZERO, /* Normally referenced as 0 */
ONE, /* Normally referenced as 1 */
UNKNOWN, /* Unknown */
} Digital_State_t;
typedef enum {
STRONG, /* strong */
RESISTIVE, /* resistive */
HI_IMPEDANCE, /* high impedance */
UNDETERMINED, /* unknown strength */
} Digital_Strength_t;
typedef struct {
Digital_State_t state;
Digital_Strength_t strength;
} Digital_t;
#endif /* CMTYPES_DEFINED */

79
src/include/dllitf.h Executable file
View File

@ -0,0 +1,79 @@
/*
DLL load interface
(c)2000 Arpad Buermen
*/
#ifndef __DLLITF_H
#define __DLLITF_H
#include "mifproto.h"
#include "cmproto.h"
// This structure contains pointers to core SPICE OPUS functions used in CMs and UDNs.
// A pointer to this structure is passed to the dll when the dll is loaded.
struct coreInfo_t {
// MIF stuff
void ((*dllitf_MIF_INP2A)(void *, INPtables *, card *));
char * ((*dllitf_MIFgetMod)(void *, char *, INPmodel **, INPtables *));
IFvalue * ((*dllitf_MIFgetValue)(void *, char **, int, INPtables *, char **));
int ((*dllitf_MIFsetup)(SMPmatrix *, GENmodel *, CKTcircuit *, int *));
int ((*dllitf_MIFunsetup)(GENmodel *, CKTcircuit *));
int ((*dllitf_MIFload)(GENmodel *, CKTcircuit *));
int ((*dllitf_MIFmParam)(int, IFvalue *, GENmodel *));
int ((*dllitf_MIFask)(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *));
int ((*dllitf_MIFmAsk)(CKTcircuit *, GENmodel *, int, IFvalue *));
int ((*dllitf_MIFtrunc)(GENmodel *, CKTcircuit *, double *));
int ((*dllitf_MIFconvTest)(GENmodel *, CKTcircuit *));
int ((*dllitf_MIFdelete)(GENmodel *, IFuid, GENinstance **));
int ((*dllitf_MIFmDelete)(GENmodel **, IFuid, GENmodel *));
void ((*dllitf_MIFdestroy)(GENmodel **));
char * ((*dllitf_MIFgettok)(char **));
char * ((*dllitf_MIFget_token)(char **, Mif_Token_Type_t *));
Mif_Cntl_Src_Type_t ((*dllitf_MIFget_cntl_src_type)(Mif_Port_Type_t, Mif_Port_Type_t));
char * ((*dllitf_MIFcopy)(char *));
// CM stuff
void ((*dllitf_cm_climit_fcn)(double, double, double, double, double, double,
double, double, int, double *, double *, double *,
double *));
void ((*dllitf_cm_smooth_corner)(double, double, double, double, double, double,
double *, double *));
void ((*dllitf_cm_smooth_discontinuity)(double, double, double, double, double,
double *, double *));
double ((*dllitf_cm_smooth_pwl)(double, double *, double *, int, double, double *));
double ((*dllitf_cm_analog_ramp_factor)(void));
void * ((*dllitf_cm_analog_alloc)(int, int));
void * ((*dllitf_cm_analog_get_ptr)(int, int));
int ((*dllitf_cm_analog_integrate)(double, double *, double *));
int ((*dllitf_cm_analog_converge)(double *));
int ((*dllitf_cm_analog_set_temp_bkpt)(double));
int ((*dllitf_cm_analog_set_perm_bkpt)(double));
void ((*dllitf_cm_analog_not_converged)(void));
void ((*dllitf_cm_analog_auto_partial)(void));
void * ((*dllitf_cm_event_alloc)(int, int));
void * ((*dllitf_cm_event_get_ptr)(int, int));
int ((*dllitf_cm_event_queue)(double));
char * ((*dllitf_cm_message_get_errmsg)(void));
int ((*dllitf_cm_message_send)(char *));
double ((*dllitf_cm_netlist_get_c)(void));
double ((*dllitf_cm_netlist_get_l)(void));
Complex_t ((*dllitf_cm_complex_set)(double, double));
Complex_t ((*dllitf_cm_complex_add)(Complex_t, Complex_t));
Complex_t ((*dllitf_cm_complex_subtract)(Complex_t, Complex_t));
Complex_t ((*dllitf_cm_complex_multiply)(Complex_t, Complex_t));
Complex_t ((*dllitf_cm_complex_divide)(Complex_t, Complex_t));
FILE * ((*dllitf_cm_stream_out)(void));
FILE * ((*dllitf_cm_stream_in)(void));
FILE * ((*dllitf_cm_stream_err)(void));
/*Other stuff*/
void * ((*dllitf_malloc_pj)(size_t));
void * ((*dllitf_calloc_pj)(size_t, size_t));
void * ((*dllitf_realloc_pj)(void *, size_t));
void ((*dllitf_free_pj)(void *));
char * ((*dllitf_tmalloc)(int));
char * ((*dllitf_trealloc)(char *, int));
void ((*dllitf_txfree)(char *));
};
#endif

109
src/include/enh.h Executable file
View File

@ -0,0 +1,109 @@
#ifndef ENH_HEADER
#define ENH_HEADER x
/* ===========================================================================
FILE ENH.h
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 typedefs used by the event-driven algorithm.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h"
#include "fteinp.h"
/*
The following data is used in implementing various enhancements made to the
simulator. The main struct is dynamically allocated in ckt so that incremental additions
can be made more easily without the need to recompile multiple modules.
Allocation and initialization is done in CKTinit.c which should be the only
module needed to recompile after additions are made here.
*/
typedef enum {
ENH_ANALOG_NODE, /* An analog node */
ENH_EVENT_NODE, /* An event-driven node */
ENH_ANALOG_BRANCH, /* A branch current */
ENH_ANALOG_INSTANCE, /* An analog instance */
ENH_EVENT_INSTANCE, /* An event-driven instance */
ENH_HYBRID_INSTANCE, /* A hybrid (analog/event-driven) instance */
} Enh_Conv_Source_t;
typedef struct {
double current; /* The current dynamic breakpoint time */
double last; /* The last used dynamic breakpoint time */
} Enh_Bkpt_t;
typedef struct {
double ramptime; /* supply ramping time specified on .options */
} Enh_Ramp_t;
typedef struct {
Mif_Boolean_t last_NIiter_call; /* True if this is the last call to NIiter() */
Mif_Boolean_t report_conv_probs; /* True if conv test functions should send debug info */
} Enh_Conv_Debug_t;
typedef struct {
Mif_Boolean_t enabled; /* True if convergence limiting enabled on code models */
double abs_step; /* Minimum limiting step size */
double step; /* Fractional step amount */
} Enh_Conv_Limit_t;
typedef struct {
Mif_Boolean_t enabled; /* True if rshunt option used */
double gshunt; /* 1.0 / rshunt */
int num_nodes; /* Number of nodes in matrix */
double **diag; /* Pointers to matrix diagonals */
} Enh_Rshunt_t;
typedef struct {
Enh_Bkpt_t breakpoint; /* Data used by dynamic breakpoints */
Enh_Ramp_t ramp; /* New options added to simulator */
Enh_Conv_Debug_t conv_debug; /* Convergence debug info dumping data */
Enh_Conv_Limit_t conv_limit; /* Convergence limiting info */
Enh_Rshunt_t rshunt_data; /* Shunt conductance from nodes to ground */
} Enh_Ckt_Data_t;
void ENHreport_conv_prob(Enh_Conv_Source_t type, char *name, char *msg);
struct line *ENHtranslate_poly(struct line *deck);
#endif /* ENH_HEADER */

371
src/include/evt.h Executable file
View File

@ -0,0 +1,371 @@
#ifndef EVT_HEADER
#define EVT_HEADER x
/* ===========================================================================
FILE EVT.h
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 the definition of the evt data structure and all
its substructures. The single evt structure is housed inside of
the main 3C1 circuit structure 'ckt' and contains virtually all
information about the event-driven simulation.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "mifdefs.h"
#include "mifcmdat.h"
#include "miftypes.h"
/* ************** */
/* Info structure */
/* ************** */
typedef struct Evt_Output_Info_s {
struct Evt_Output_Info_s *next; /* the next in the linked list */
int node_index; /* index into node info struct for this output */
int output_subindex; /* index into output data in node data struct */
int inst_index; /* Index of instance the port is on */
int port_index; /* Index of port the output corresponds to */
} Evt_Output_Info_t;
typedef struct Evt_Port_Info_s {
struct Evt_Port_Info_s *next; /* the next in the linked list of node info */
int inst_index; /* Index of instance the port is on */
int node_index; /* index of node the port is connected to */
char *node_name; /* name of node port is connected to */
char *inst_name; /* instance name */
char *conn_name; /* connection name on instance */
int port_num; /* port number of instance connector */
} Evt_Port_Info_t;
typedef struct Evt_Inst_Index_s {
struct Evt_Inst_Index_s *next; /* the next in the linked list */
int index; /* the value of the index */
} Evt_Inst_Index_t;
typedef struct Evt_Node_Info_s {
struct Evt_Node_Info_s *next; /* the next in the linked list */
char *name; /* Name of node in deck */
int udn_index; /* Index of the node type */
Mif_Boolean_t invert; /* True if need to make inverted copy */
int num_ports; /* Number of ports connected to this node */
int num_outputs; /* Number of outputs connected to this node */
int num_insts; /* The number of insts receiving node as input */
Evt_Inst_Index_t *inst_list; /* Linked list of indexes of these instances */
} Evt_Node_Info_t;
typedef struct Evt_Inst_Info_s {
struct Evt_Inst_Info_s *next; /* the next in the linked list of node info */
MIFinstance *inst_ptr; /* Pointer to MIFinstance struct for this instance */
} Evt_Inst_Info_t;
typedef struct {
Evt_Inst_Info_t *inst_list; /* static info about event/hybrid instances */
Evt_Node_Info_t *node_list; /* static info about event nodes */
Evt_Port_Info_t *port_list; /* static info about event ports */
Evt_Output_Info_t *output_list; /* static info about event outputs */
int *hybrid_index; /* vector of inst indexs for hybrids */
Evt_Inst_Info_t **inst_table; /* vector of pointers to elements in inst_list */
Evt_Node_Info_t **node_table; /* vector of pointers to elements in node_list */
Evt_Port_Info_t **port_table; /* vector of pointers to elements in port_list */
Evt_Output_Info_t **output_table; /* vector of pointers to elements in output_list */
} Evt_Info_t;
/* *************** */
/* Queue structure */
/* *************** */
typedef struct Evt_Inst_Event_s {
struct Evt_Inst_Event_s *next; /* the next in the linked list */
double event_time; /* Time for this event to happen */
double posted_time; /* Time at which event was entered in queue */
} Evt_Inst_Event_t;
typedef struct {
Evt_Inst_Event_t **head; /* Beginning of linked lists */
Evt_Inst_Event_t ***current; /* Beginning of pending events */
Evt_Inst_Event_t ***last_step; /* Values of 'current' at last accepted timepoint */
Evt_Inst_Event_t **free; /* Linked lists of items freed by backups */
double last_time; /* Time at which last_step was set */
double next_time; /* Earliest next event time in queue */
int num_modified; /* Number modified since last accepted timepoint */
int *modified_index; /* Indexes of modified instances */
Mif_Boolean_t *modified; /* Flags used to prevent multiple entries */
int num_pending; /* Count of number of pending events in lists */
int *pending_index; /* Indexes of pending events */
Mif_Boolean_t *pending; /* Flags used to prevent multiple entries */
int num_to_call; /* Count of number of instances that need to be called */
int *to_call_index; /* Indexes of instances to be called */
Mif_Boolean_t *to_call; /* Flags used to prevent multiple entries */
} Evt_Inst_Queue_t;
typedef struct {
int num_to_eval; /* Count of number of nodes that need to be evaluated */
int *to_eval_index; /* Indexes of nodes to be evaluated */
Mif_Boolean_t *to_eval; /* Flags used to prevent multiple entries */
int num_changed; /* Count of number of nodes that changed */
int *changed_index; /* Indexes of nodes that changed */
Mif_Boolean_t *changed; /* Flags used to prevent multiple entries */
} Evt_Node_Queue_t;
typedef struct Evt_Output_Event_s {
struct Evt_Output_Event_s *next; /* the next in the linked list */
double event_time; /* Time for this event to happen */
double posted_time; /* Time at which event was entered in queue */
Mif_Boolean_t removed; /* True if event has been deactivated */
double removed_time; /* Time at which event was deactivated */
void *value; /* The delayed value sent to this output */
} Evt_Output_Event_t;
typedef struct {
Evt_Output_Event_t **head; /* Beginning of linked lists */
Evt_Output_Event_t ***current; /* Beginning of pending events */
Evt_Output_Event_t ***last_step; /* Values of 'current' at last accepted timepoint */
Evt_Output_Event_t **free; /* Linked lists of items freed by backups */
double last_time; /* Time at which last_step was set */
double next_time; /* Earliest next event time in queue */
int num_modified; /* Number modified since last accepted timepoint */
int *modified_index; /* Indexes of modified outputs */
Mif_Boolean_t *modified; /* Flags used to prevent multiple entries */
int num_pending; /* Count of number of pending events in lists */
int *pending_index; /* Indexes of pending events */
Mif_Boolean_t *pending; /* Flags used to prevent multiple entries */
int num_changed; /* Count of number of outputs that changed */
int *changed_index; /* Indexes of outputs that changed */
Mif_Boolean_t *changed; /* Flags used to prevent multiple entries */
} Evt_Output_Queue_t;
typedef struct {
Evt_Inst_Queue_t inst; /* dynamic queue for instances */
Evt_Node_Queue_t node; /* dynamic queue of changing nodes */
Evt_Output_Queue_t output; /* dynamic queue of delayed outputs */
} Evt_Queue_t;
/* ************** */
/* Data structure */
/* ************** */
typedef struct Evt_Node_s {
struct Evt_Node_s *next; /* pointer to next in linked list */
Mif_Boolean_t op; /* true if computed from op analysis */
double step; /* DC step or time at which data was computed */
void **output_value; /* Array of outputs posted to this node */
void *node_value; /* Resultant computed from output values */
void *inverted_value; /* Inverted copy of node_value */
} Evt_Node_t;
typedef struct {
Evt_Node_t **head; /* Beginning of linked lists */
Evt_Node_t ***tail; /* Location of last item added to list */
Evt_Node_t ***last_step; /* 'tail' at last accepted timepoint */
Evt_Node_t **free; /* Linked lists of items freed by backups */
int num_modified; /* Number modified since last accepted timepoint */
int *modified_index; /* Indexes of modified nodes */
Mif_Boolean_t *modified; /* Flags used to prevent multiple entries */
Evt_Node_t *rhs; /* Location where model outputs are placed */
Evt_Node_t *rhsold; /* Location where model inputs are retrieved */
double *total_load; /* Location where total load inputs are retrieved */
} Evt_Node_Data_t;
typedef struct Evt_State_s {
struct Evt_State_s *next; /* Pointer to next state */
struct Evt_State_s *prev; /* Pointer to previous state */
double step; /* Time at which state was assigned (0 for DC) */
void *block; /* Block of memory holding all states on inst */
} Evt_State_t;
typedef struct Evt_State_Desc_s {
struct Evt_State_Desc_s *next; /* Pointer to next description */
int tag; /* Tag for this state */
int size; /* Size of this state */
int offset; /* Offset of this state into the state block */
} Evt_State_Desc_t;
typedef struct {
Evt_State_t **head; /* Beginning of linked lists */
Evt_State_t ***tail; /* Location of last item added to list */
Evt_State_t ***last_step; /* 'tail' at last accepted timepoint */
Evt_State_t **free; /* Linked lists of items freed by backups */
int num_modified; /* Number modified since last accepted timepoint */
int *modified_index; /* List of indexes modified */
Mif_Boolean_t *modified; /* Flags used to prevent multiple entries */
int *total_size; /* Total bytes for all states allocated */
Evt_State_Desc_t **desc; /* Lists of description structures */
} Evt_State_Data_t;
typedef struct Evt_Msg_s {
struct Evt_Msg_s *next; /* Pointer to next state */
Mif_Boolean_t op; /* true if output from op analysis */
double step; /* DC step or time at which message was output */
char *text; /* The value of the message text */
int port_index; /* The index of the port from which the message came */
} Evt_Msg_t;
typedef struct {
Evt_Msg_t **head; /* Beginning of linked lists */
Evt_Msg_t ***tail; /* Location of last item added to list */
Evt_Msg_t ***last_step; /* 'tail' at last accepted timepoint */
Evt_Msg_t **free; /* Linked lists of items freed by backups */
int num_modified; /* Number modified since last accepted timepoint */
int *modified_index; /* List of indexes modified */
Mif_Boolean_t *modified; /* Flags used to prevent multiple entries */
} Evt_Msg_Data_t;
typedef struct {
int op_alternations; /* Total alternations between event and analog */
int op_load_calls; /* Total load calls in DCOP analysis */
int op_event_passes; /* Total passes through event iteration loop */
int tran_load_calls; /* Total inst calls in transient analysis */
int tran_time_backups; /* Number of transient timestep cuts */
} Evt_Statistic_t;
typedef struct {
Evt_Node_Data_t *node; /* dynamic event solution vector */
Evt_State_Data_t *state; /* dynamic event instance state data */
Evt_Msg_Data_t *msg; /* dynamic event message data */
Evt_Statistic_t *statistics; /* Statistics for events, etc. */
} Evt_Data_t;
/* **************** */
/* Counts structure */
/* **************** */
typedef struct {
int num_insts; /* number of event/hybrid instances parsed */
int num_hybrids; /* number of hybrids parsed */
int num_hybrid_outputs; /* number of outputs on all hybrids parsed */
int num_nodes; /* number of event nodes parsed */
int num_ports; /* number of event ports parsed */
int num_outputs; /* number of event outputs parsed */
} Evt_Count_t;
/* **************** */
/* Limits structure */
/* **************** */
typedef struct {
int max_event_passes; /* maximum loops in attempting convergence of event nodes */
int max_op_alternations; /* maximum loops through event/analog alternation */
} Evt_Limit_t;
/* ************** */
/* Jobs structure */
/* ************** */
typedef struct {
int num_jobs; /* Number of jobs run */
char **job_name; /* Names of different jobs */
Evt_Node_Data_t **node_data; /* node_data for different jobs */
Evt_State_Data_t **state_data; /* state_data for different jobs */
Evt_Msg_Data_t **msg_data; /* messages for different jobs */
Evt_Statistic_t **statistics; /* Statistics for different jobs */
} Evt_Job_t;
/* ***************** */
/* Options structure */
/* ***************** */
typedef struct {
Mif_Boolean_t op_alternate; /* Alternate analog/event solutions in OP analysis */
} Evt_Option_t;
/* ****************** */
/* Main evt structure */
/* ****************** */
typedef struct {
Evt_Count_t counts; /* Number of insts, nodes, etc. */
Evt_Info_t info; /* Static info about insts, etc. */
Evt_Queue_t queue; /* Dynamic queued events */
Evt_Data_t data; /* Results and state data */
Evt_Limit_t limits; /* Iteration limits, etc. */
Evt_Job_t jobs; /* Data held from multiple job runs */
Evt_Option_t options; /* Data input on .options cards */
} Evt_Ckt_Data_t;
#endif /* EVT_HEADER */

124
src/include/evtproto.h Executable file
View File

@ -0,0 +1,124 @@
#ifndef EVTPROTO_HEADER
#define EVTPROTO_HEADER x
/* ===========================================================================
FILE EVTproto.h
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 ANSI C function prototypes for functions
in the event-driven simulation algorithm package.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "cktdefs.h"
#include "cpstd.h"
#include "mifdefs.h"
#include "ipc.h"
/* ******************* */
/* Function Prototypes */
/* ******************* */
int EVTinit(CKTcircuit *ckt);
/*int EVTinit2(CKTcircuit *ckt);*/
void EVTtermInsert(
CKTcircuit *ckt,
MIFinstance *fast,
char *node_name,
char *type_name,
int conn_num,
int port_num,
char **err_msg);
int EVTsetup(CKTcircuit *ckt);
int EVTiter(CKTcircuit *ckt);
void EVTbackup(CKTcircuit *ckt, double new_time);
double EVTnext_time(CKTcircuit *ckt);
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);
void EVTdequeue(CKTcircuit *ckt, double time);
int EVTload(CKTcircuit *ckt, int inst_index);
void EVTprint(wordlist *wl);
int EVTop(
CKTcircuit *ckt,
long firstmode,
long continuemode,
int max_iter,
Mif_Boolean_t first_call);
void EVTop_save(
CKTcircuit *ckt,
Mif_Boolean_t op,
double step);
void EVTnode_copy(
CKTcircuit *ckt,
int node_index,
Evt_Node_t *from,
Evt_Node_t **to);
void EVTcall_hybrids(CKTcircuit *ckt);
void EVTdump(
CKTcircuit *ckt,
Ipc_Anal_t mode,
double step);
void EVTaccept(
CKTcircuit *ckt, /* main circuit struct */
double time); /* time at which analog soln was accepted */
#endif /* EVTPROTO_HEADER */

123
src/include/evtudn.h Executable file
View File

@ -0,0 +1,123 @@
#ifndef EVTUDN_HEADER
#define EVTUDN_HEADER x
/* ===========================================================================
FILE EVTudn.h
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 the definition of "User-Defined Nodes".
These nodes are integrated into the simulator similar to the
way models are tied into SPICE 3C1, so that new node types
can be relatively easily added. The functions (required and
optional) are listed below. For optional functions, the
function can be left undefined and the pointer placed into the
Evt_Udn_Info_t structure can be specified as NULL.
Required functions:
create - allocate data structure used as inputs and outputs to code models
initialize - set structure to appropriate initial value for first use as model input
copy - make a copy of the contents into created but possibly uninitialized structure
compare - determine if two structures are equal in value
Optional functions:
dismantle - free allocations _inside_ structure (but not structure itself)
invert - invert logical value of structure
resolve - determine the resultant when multiple outputs are connected to a node
plot_val - output a real value for specified structure component for plotting purposes
print_val - output a string value for specified structure component for printing
ipc_val - output a binary data structure and size of the structure for IPC
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h" /* for Mif_Boolean_t used in udn_..._compare */
#define MALLOCED_PTR (*evt_struct_ptr)
#define STRUCT_PTR evt_struct_ptr
#define STRUCT_PTR_1 evt_struct_ptr_1
#define STRUCT_PTR_2 evt_struct_ptr_2
#define EQUAL (*evt_equal)
#define INPUT_STRUCT_PTR evt_input_struct_ptr
#define OUTPUT_STRUCT_PTR evt_output_struct_ptr
#define INPUT_STRUCT_PTR_ARRAY evt_input_struct_ptr_array
#define INPUT_STRUCT_PTR_ARRAY_SIZE evt_input_struct_ptr_array_size
#define STRUCT_MEMBER_ID evt_struct_member_id
#define PLOT_VAL (*evt_plot_val)
#define PRINT_VAL (*evt_print_val)
#define IPC_VAL (*evt_ipc_val)
#define IPC_VAL_SIZE (*evt_ipc_val_size)
#define CREATE_ARGS void **evt_struct_ptr
#define INITIALIZE_ARGS void *evt_struct_ptr
#define COMPARE_ARGS void *evt_struct_ptr_1, \
void *evt_struct_ptr_2, \
Mif_Boolean_t *evt_equal
#define COPY_ARGS void *evt_input_struct_ptr, \
void *evt_output_struct_ptr
#define DISMANTLE_ARGS void *evt_struct_ptr
#define INVERT_ARGS void *evt_struct_ptr
#define RESOLVE_ARGS int evt_input_struct_ptr_array_size, \
void **evt_input_struct_ptr_array, \
void *evt_output_struct_ptr
#define PLOT_VAL_ARGS void *evt_struct_ptr, \
char *evt_struct_member_id, \
double *evt_plot_val
#define PRINT_VAL_ARGS void *evt_struct_ptr, \
char *evt_struct_member_id, \
char **evt_print_val
#define IPC_VAL_ARGS void *evt_struct_ptr, \
void **evt_ipc_val, \
int *evt_ipc_val_size
typedef struct {
char *name;
char *description;
void ((*create)(CREATE_ARGS));
void ((*dismantle)(DISMANTLE_ARGS));
void ((*initialize)(INITIALIZE_ARGS));
void ((*invert)(INVERT_ARGS));
void ((*copy)(COPY_ARGS));
void ((*resolve)(RESOLVE_ARGS));
void ((*compare)(COMPARE_ARGS));
void ((*plot_val)(PLOT_VAL_ARGS));
void ((*print_val)(PRINT_VAL_ARGS));
void ((*ipc_val)(IPC_VAL_ARGS));
} Evt_Udn_Info_t;
extern int g_evt_num_udn_types;
extern Evt_Udn_Info_t **g_evt_udn_info;
#endif /* EVTUDN_HEADER */

122
src/include/ipc.h Executable file
View File

@ -0,0 +1,122 @@
/* $Id$
*
*/
/*============================================================================
FILE IPC.h
MEMBER OF process XSPICE
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
Provides compatibility for the new SPICE simulator to both the MSPICE user
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE
v.2 Simulator Interface and BCP (via Bsd Sockets).
INTERFACES
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
============================================================================*/
#ifndef IPC_DEFINED
#define IPC_DEFINED
#define IPC_MAX_LINE_LEN 80
#define IPC_MAX_PATH_LEN 2048
/* Known socket port for server and client to communicate: */
#define SOCKET_PORT 1064
/* Recognition character for Beginning Of Line of message: */
#define BOL_CHAR '\\'
/* Length (in bytes) of a socket message header: */
#define SOCK_MSG_HDR_LEN 5
typedef int Ipc_Boolean_t;
#define IPC_FALSE 0
#define IPC_TRUE 1
typedef struct { /* Don't change this type! It is cast elsewhere */
double real;
double imag;
} Ipc_Complex_t;
/*---------------------------------------------------------------------------*/
typedef enum {
IPC_STATUS_OK,
IPC_STATUS_NO_DATA,
IPC_STATUS_END_OF_DECK,
IPC_STATUS_EOF,
IPC_STATUS_ERROR,
} Ipc_Status_t;
#if 0
/*---------------------------------------------------------------------------*/
typedef void* Ipc_Connection_t;
/*
* A connection is an `opaque' type - the user has no access to the details of
* the implementation. Indeed the details are different depending on whether
* underlying transport mechanism is AEGIS Mailboxes or Bsd Sockets (or
* something else...)
*/
#endif
/*---------------------------------------------------------------------------*/
typedef enum {
IPC_WAIT,
IPC_NO_WAIT,
} Ipc_Wait_t;
/*---------------------------------------------------------------------------*/
typedef enum {
IPC_PROTOCOL_V1, /* >DATAB records in ATESSE v.1 format
* Handles v.1 style logfile name passing protocol
*/
IPC_PROTOCOL_V2, /* >DATAB records in ATESSE v.2 format
*/
} Ipc_Protocol_t;
/*---------------------------------------------------------------------------*/
typedef enum {
IPC_MODE_BATCH,
IPC_MODE_INTERACTIVE,
} Ipc_Mode_t;
/*---------------------------------------------------------------------------*/
typedef enum {
IPC_ANAL_DCOP,
IPC_ANAL_DCTRCURVE,
IPC_ANAL_AC,
IPC_ANAL_TRAN,
} Ipc_Anal_t;
#endif /* IPC_DEFINED */

52
src/include/ipcproto.h Executable file
View File

@ -0,0 +1,52 @@
/* IPC.c */
Ipc_Boolean_t kw_match (char *keyword , char *str );
Ipc_Status_t ipc_initialize_server (char *server_name , Ipc_Mode_t m , Ipc_Protocol_t p );
Ipc_Status_t ipc_terminate_server (void );
Ipc_Status_t ipc_get_line (char *str , int *len , Ipc_Wait_t wait );
Ipc_Status_t ipc_flush (void );
Ipc_Status_t ipc_send_line_binary (char *str , int len );
Ipc_Status_t ipc_send_line (char *str );
Ipc_Status_t ipc_send_data_prefix (double time );
Ipc_Status_t ipc_send_dcop_prefix (void );
Ipc_Status_t ipc_send_data_suffix (void );
Ipc_Status_t ipc_send_dcop_suffix (void );
Ipc_Status_t ipc_send_errchk (void );
Ipc_Status_t ipc_send_end (void );
int stuff_binary_v1 (double d1 , double d2 , int n , char *buf , int pos );
Ipc_Status_t ipc_send_double (char *tag , double value );
Ipc_Status_t ipc_send_complex (char *tag , Ipc_Complex_t value );
Ipc_Status_t ipc_send_int (char *tag , int value );
Ipc_Status_t ipc_send_boolean (char *tag , Ipc_Boolean_t value );
Ipc_Status_t ipc_send_string (char *tag , char *value );
Ipc_Status_t ipc_send_int_array (char *tag , int array_len , int *value );
Ipc_Status_t ipc_send_double_array (char *tag , int array_len , double *value );
Ipc_Status_t ipc_send_complex_array (char *tag , int array_len , Ipc_Complex_t *value );
Ipc_Status_t ipc_send_boolean_array (char *tag , int array_len , Ipc_Boolean_t *value );
Ipc_Status_t ipc_send_string_array (char *tag , int array_len , char **value );
Ipc_Status_t ipc_send_evtdict_prefix ();
Ipc_Status_t ipc_send_evtdict_suffix ();
Ipc_Status_t ipc_send_evtdata_prefix ();
Ipc_Status_t ipc_send_evtdata_suffix ();
Ipc_Status_t ipc_send_event(int, double, double, char *, void *, int);
/* IPCtiein.c */
void ipc_handle_stop (void );
void ipc_handle_returni (void );
void ipc_handle_mintime (double time );
void ipc_handle_vtrans (char *vsrc , char *dev );
void ipc_send_stdout (void );
void ipc_send_stderr (void );
Ipc_Status_t ipc_send_std_files (void );
Ipc_Boolean_t ipc_screen_name (char *name , char *mapped_name );
int ipc_get_devices (void *circuit , char *device , char ***names , double **modtypes );
void ipc_free_devices (int num_items , char **names , double *modtypes );
void ipc_check_pause_stop (void );
/* IPCaegis.c */
Ipc_Status_t ipc_transport_initialize_server (char *server_name , Ipc_Mode_t m , Ipc_Protocol_t p , char *batch_filename );
Ipc_Status_t extract_msg (char *str , int *len );
Ipc_Status_t ipc_transport_get_line (char *str , int *len , Ipc_Wait_t wait );
Ipc_Status_t ipc_transport_terminate_server (void );
Ipc_Status_t ipc_transport_send_line (char *str , int len );

96
src/include/ipctiein.h Executable file
View File

@ -0,0 +1,96 @@
/*============================================================================
FILE IPCtiein.h
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
Provides a protocol independent interface between the simulator
and the IPC method used to interface to CAE packages.
INTERFACES
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
============================================================================*/
#ifndef IPC_TIEIN_DEFINED
#define IPC_TIEIN_DEFINED
#include "ipc.h"
#include "ipcproto.h"
#define IPC_STDOUT_FILE_NAME "/usr/tmp/atesse_xspice.out"
#define IPC_STDERR_FILE_NAME "/usr/tmp/atesse_xspice.err"
/*
Ipc_Vtrans_t is used by functions that return results to translate
voltage source names to the names of the devices they monitor.
This table is built from #VTRANS cards in the incoming deck and
is provided for ATESSE 1.0 compatibility.
*/
typedef struct {
int size; /* Size of arrays */
char **vsrc_name; /* Array of voltage source name prefixes */
char **device_name; /* Array of device names the vsources map to */
} Ipc_Vtrans_t;
/*
Ipc_Tiein_t is used by the SPICE mods that take care of interprocess communications
activities.
*/
typedef struct {
Ipc_Boolean_t enabled; /* True if we are using IPC */
Ipc_Mode_t mode; /* INTERACTIVE or BATCH mode */
Ipc_Anal_t anal_type; /* DCOP, AC, ... mode */
Ipc_Boolean_t syntax_error; /* True if error occurred during parsing */
Ipc_Boolean_t run_error; /* True if error occurred during simulation */
Ipc_Boolean_t errchk_sent; /* True if #ERRCHK has been sent */
Ipc_Boolean_t returni; /* True if simulator should return currents */
double mintime; /* Minimum time between timepoints returned */
double last_time; /* Last timepoint returned */
double cpu_time; /* CPU time used during simulation */
Ipc_Boolean_t *send; /* Used by OUTinterface to determine what to send */
char *log_file; /* Path to write log file */
Ipc_Vtrans_t vtrans; /* Used by OUTinterface to translate v sources */
Ipc_Boolean_t stop_analysis; /* True if analysis should be terminated */
} Ipc_Tiein_t;
extern Ipc_Tiein_t g_ipc;
#endif /* IPC_TIEIN_DEFINED */

84
src/include/mif.h Executable file
View File

@ -0,0 +1,84 @@
#ifndef MIF
#define MIF
/* ===========================================================================
FILE MIF.h
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 structure definitions global data used with the MIF package.
The global data structure is used to circumvent the need to modify
argument lists in existing SPICE 3C1 functions.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h"
#include "mifdefs.h"
#include "cktdefs.h"
typedef struct {
Mif_Boolean_t init; /* TRUE if first call to model */
Mif_Boolean_t anal_init; /* TRUE if first call for this analysis type */
Mif_Analysis_t anal_type; /* The type of analysis being performed */
Mif_Call_Type_t call_type; /* Type of call to code model - analog or event-driven */
double evt_step; /* The current DC step or time in event analysis */
} Mif_Circuit_Info_t;
typedef struct {
double current; /* The current dynamic breakpoint time */
double last; /* The last used dynamic breakpoint time */
} Mif_Bkpt_Info_t;
typedef struct {
Mif_Boolean_t global; /* Set by .option to force all models to use auto */
Mif_Boolean_t local; /* Set by individual model to request auto partials */
} Mif_Auto_Partial_t;
typedef struct {
Mif_Circuit_Info_t circuit; /* Circuit data that will be needed by MIFload */
MIFinstance *instance; /* Current instance struct */
CKTcircuit *ckt; /* The ckt struct for the circuit */
char *errmsg; /* An error msg from a cm_... function */
Mif_Bkpt_Info_t breakpoint; /* Data used by dynamic breakpoints */
Mif_Auto_Partial_t auto_partial; /* Flags to enable auto partial computations */
} Mif_Info_t;
extern Mif_Info_t g_mif_info;
#endif /* MIF */

373
src/include/mifcmdat.h Executable file
View File

@ -0,0 +1,373 @@
#ifndef MIFCMDAT
#define MIFCMDAT
/* ===========================================================================
FILE MIFcmdat.h
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 the data structure definitions used by
code model and the associated MIF package.
A special preprocessor (cmpp) is used on models written by a
user to turn items like INPUT(<name>) into the appropriate structure
reference.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h"
/* ************************************************************************** */
/*
* Pointers into matrix for a voltage input, voltage output partial
*/
typedef struct Mif_E_Ptr_s {
double *branch_poscntl; /* Branch row, positive controlling column */
double *branch_negcntl; /* Branch row, negative controlling column */
} Mif_E_Ptr_t;
/*
* Pointers into matrix for a current input, current output partial
*/
typedef struct Mif_F_Ptr_s {
double *pos_ibranchcntl; /* Positive row, controlling branch column */
double *neg_ibranchcntl; /* Negative row, controlling branch column */
} Mif_F_Ptr_t;
/*
* Pointers into matrix for a voltage input, current output partial
*/
typedef struct Mif_G_Ptr_s {
double *pos_poscntl; /* Positive row, positive controlling column */
double *pos_negcntl; /* Positive row, negative controlling column */
double *neg_poscntl; /* Negative row, positive controlling column */
double *neg_negcntl; /* Negative row, negative controlling column */
} Mif_G_Ptr_t;
/*
* Pointers into matrix for a current input, voltage output partial
*/
typedef struct Mif_H_Ptr_s {
double *branch_ibranchcntl; /* Branch row, controlling branch column */
} Mif_H_Ptr_t;
/*
* Matrix pointers associated with a particular port (of a particular type)
*/
typedef union Mif_Port_Ptr_u {
Mif_E_Ptr_t e; /* Pointers for voltage input, voltage output */
Mif_F_Ptr_t f; /* Pointers for current input, current output */
Mif_G_Ptr_t g; /* Pointers for voltage input, current output */
Mif_H_Ptr_t h; /* Pointers for current input, voltage output */
} Mif_Port_Ptr_t;
/*
* Array of matrix data pointers for particular ports in a connection
*/
typedef struct Mif_Conn_Ptr_s {
Mif_Port_Ptr_t *port; /* Data for a particular port */
} Mif_Conn_Ptr_t;
/*
* Row numbers and matrix entry pointers for loading the matrix and RHS with
* data appropriate for the particular output port and input ports.
*/
typedef struct Mif_Smp_Ptr_s {
/* Data at this level is for this connection. The Mif_Conn_Ptr_t */
/* subtree is used only if this connection is an output. It supplies */
/* the matrix pointers required for loading the partials from each */
/* input. */
/* node connection equation numbers */
int pos_node; /* Row associated with positive node */
int neg_node; /* Row associated with negative node */
/* V source branch equation numbers */
int branch; /* Row associated with V output branch */
int ibranch; /* Row associated with I input branch */
/* matrix pointers for V source output */
double *pos_branch; /* Positive node row, branch column */
double *neg_branch; /* Negative node row, branch column */
double *branch_pos; /* Branch row, positive node column */
double *branch_neg; /* Branch row, negative node column */
/* matrix pointers for the zero-valued V source associated with an I input */
double *pos_ibranch; /* Positive node row, branch column */
double *neg_ibranch; /* Negative node row, branch column */
double *ibranch_pos; /* Branch row, positive node column */
double *ibranch_neg; /* Branch row, negative node column */
/* array of pointer info required for putting partials into the matrix */
Mif_Conn_Ptr_t *input; /* Matrix pointers associated with inputs */
} Mif_Smp_Ptr_t;
/* ******************************************************************** */
/*
* Partial derivatives wrt ports of a particular input connection
*/
typedef struct Mif_Partial_s {
double *port; /* Partial wrt this port */
} Mif_Partial_t;
/*
* AC gains wrt ports of a particular input connection
*/
typedef struct Mif_AC_Gain_s {
Mif_Complex_t *port; /* AC gain wrt this port */
} Mif_AC_Gain_t;
/*
* Data used to access information in event struct in CKTcircuit struct ckt
*/
typedef struct {
int node_index; /* Index of node in event-driven structures */
int output_subindex; /* Subindex of output on node */
int port_index; /* Index of port in event-driven structures */
int output_index; /* Index of output in event-driven structures */
} Mif_Evt_Data_t;
/*
* Information about individual port(s) of a connection.
*/
typedef struct Mif_Port_Data_s {
Mif_Port_Type_t type; /* Port type - e.g. MIF_VOLTAGE, ... */
char *type_str; /* Port type in string form */
char *pos_node_str; /* Positive node identifier */
char *neg_node_str; /* Negative node identifier */
char *vsource_str; /* Voltage source identifier */
Mif_Boolean_t is_null; /* Set to true if null in SPICE deck */
Mif_Value_t input; /* The input value */
Mif_Value_t output; /* The output value */
Mif_Partial_t *partial; /* Partials for this port wrt inputs */
Mif_AC_Gain_t *ac_gain; /* AC gains for this port wrt inputs */
int old_input; /* Index into CKTstate for old input */
Mif_Boolean_t invert; /* True if state should be inverted */
Mif_Boolean_t changed; /* A new output has been assigned */
double load; /* Load factor output to this port */
double total_load; /* Total load for this port */
double delay; /* Digital delay for this output port */
char *msg; /* Message string output to port */
Mif_Smp_Ptr_t smp_data; /* Pointers used to load matrix/rhs */
Mif_Evt_Data_t evt_data; /* Data used to access evt struct */
double nominal_output; /* Saved output when doing auto partial */
} Mif_Port_Data_t;
/* ******************************************************************** */
/*
* Information in MIFinstance struct used by cm_.. support functions.
*/
typedef struct Mif_State_s { /* for cm_analog_alloc() */
int tag; /* Tag identifying this particular state */
int index; /* Index into ckt->CKTstate[i] vector */
int doubles; /* Number of doubles allocated for this state */
int bytes; /* Actual number of bytes requested by cm_analog_alloc() */
} Mif_State_t;
typedef struct Mif_Intgr_s { /* for cm_analog_integrate() */
int byte_index; /* Byte offset into state array */
} Mif_Intgr_t;
typedef struct Mif_Conv_s { /* for cm_analog_converge() */
int byte_index; /* Byte offset into state array */
double last_value; /* Value at last iteration */
} Mif_Conv_t;
/* ******************************************************************** */
/*
* Information about the circuit in which this model is simulating.
*/
typedef struct Mif_Circ_Data_s {
Mif_Boolean_t init; /* True if first call to model - a setup pass */
Mif_Analysis_t anal_type; /* Current analysis type */
Mif_Boolean_t anal_init; /* True if first call in this analysis type */
Mif_Call_Type_t call_type; /* Analog or event type call */
double time; /* Current analysis time */
double frequency; /* Current analysis frequency */
double temperature; /* Current analysis temperature */
double t[8]; /* History of last 8 analysis times t[0]=time */
} Mif_Circ_Data_t;
/*
* The structure associated with a named "connection" on the model.
*/
typedef struct Mif_Conn_Data_s {
char *name; /* Name of this connection - currently unused */
char *description; /* Description of this connection - unused */
Mif_Boolean_t is_null; /* Set to true if null in SPICE deck */
Mif_Boolean_t is_input; /* Set to true if connection is an input */
Mif_Boolean_t is_output; /* Set to true if connection is an output */
int size; /* The size of an array (1 if scalar) */
Mif_Port_Data_t **port; /* Pointer(s) to port(s) for this connection */
} Mif_Conn_Data_t;
/*
* Values for model parameters
*/
typedef struct Mif_Param_Data_s {
Mif_Boolean_t is_null; /* True if no value given on .model card */
int size; /* Size of array (1 if scalar) */
Mif_Value_t *element; /* Value of parameter(s) */
} Mif_Param_Data_t;
/*
* Values for instance variables
*/
typedef struct Mif_Inst_Var_Data_s {
int size; /* Size of array (1 if scalar) */
Mif_Value_t *element; /* Value of instance variables(s) */
} Mif_Inst_Var_Data_t;
/* ************************************************************************* */
/*
* HERE IT IS!!!
* The top level data structure passed to code models.
*/
typedef struct Mif_Private_s {
Mif_Circ_Data_t circuit; /* Information about the circuit */
int num_conn; /* Number of connections on this model */
Mif_Conn_Data_t **conn; /* Information about each connection */
int num_param; /* Number of parameters on this model */
Mif_Param_Data_t **param; /* Information about each parameter */
int num_inst_var; /* Number of instance variables */
Mif_Inst_Var_Data_t **inst_var; /* Information about each inst variable */
} Mif_Private_t;
#endif /* MIFCMDAT */

111
src/include/mifdefs.h Executable file
View File

@ -0,0 +1,111 @@
#ifndef MIFDEFS
#define MIFDEFS
/* ===========================================================================
FILE MIFdefs.h
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 (augmented) SPICE 3C1 compatible typedefs for use
with code models. These typedefs define the data structures that are
used internally to describe instances and models in the circuit
description linked lists.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "mifcmdat.h"
#include "ifsim.h"
/* The per-instance data structure */
typedef struct sMIFinstance {
struct sMIFmodel *MIFmodPtr; /* backpointer to model */
struct sMIFinstance *MIFnextInstance; /* pointer to next instance of current model */
IFuid MIFname; /* pointer to character string naming this instance */
int num_conn; /* number of connections on the code model */
Mif_Conn_Data_t **conn; /* array of data structures for each connection */
int num_inst_var; /* number of instance variables on the code model */
Mif_Inst_Var_Data_t **inst_var; /* array of structs for each instance var */
int num_param; /* number of parameters on the code model */
Mif_Param_Data_t **param; /* array of structs for each parameter */
int num_state; /* Number of state tags used for this inst */
Mif_State_t *state; /* Info about states */
int num_intgr; /* Number of integrals */
Mif_Intgr_t *intgr; /* Info for integrals */
int num_conv; /* Number of things to be converged */
Mif_Conv_t *conv; /* Info for convergence things */
Mif_Boolean_t initialized; /* True if model called once already */
Mif_Boolean_t analog; /* true if this inst is analog or hybrid type */
Mif_Boolean_t event_driven; /* true if this inst is event-driven or hybrid type */
int inst_index; /* Index into inst_table in evt struct in ckt */
} MIFinstance ;
/* The per model data structure */
typedef struct sMIFmodel {
int MIFmodType; /* type index of this device type */
struct sMIFmodel *MIFnextModel; /* pointer to next possible model in linked list */
MIFinstance *MIFinstances; /* pointer to list of instances that have this model */
IFuid MIFmodName; /* pointer to character string naming this model */
int num_param; /* number of parameters on the code model */
Mif_Param_Data_t **param; /* array of structs for each parameter */
Mif_Boolean_t analog; /* true if this model is analog or hybrid type */
Mif_Boolean_t event_driven; /* true if this model is event-driven or hybrid type */
} MIFmodel;
/* NOTE: There are no device parameter tags, since the ask, mAsk, ... */
/* functions for code models work out of the generic code model structure */
#endif /* MIFDEFS */

120
src/include/mifparse.h Executable file
View File

@ -0,0 +1,120 @@
#ifndef MIFPARSE
#define MIFPARSE
/* ===========================================================================
FILE MIFparse.h
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 the information structure definitions used by the
code model parser to check for valid connections and parameters.
Structures of these types are created by the code model preprocessor
(cmpp) from the user created ifspec.ifs file.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "miftypes.h"
/*
* Information about a connection used by the parser to error check input
*/
typedef struct Mif_Conn_Info_s {
char *name; /* Name of this connection */
char *description; /* Description of this connection */
Mif_Dir_t direction; /* Is this connection an input, output, or both? */
Mif_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 */
Mif_Port_Type_t *allowed_type; /* The allowed types */
char **allowed_type_str; /* The allowed types in string form */
Mif_Boolean_t is_array; /* True if connection is an array */
Mif_Boolean_t has_lower_bound; /* True if there is an array size lower bound */
int lower_bound; /* Array size lower bound */
Mif_Boolean_t has_upper_bound; /* True if there is an array size upper bound */
int upper_bound; /* Array size upper bound */
Mif_Boolean_t null_allowed; /* True if null is allowed for this connection */
} Mif_Conn_Info_t;
/*
* Information about a parameter used by the parser to error check input
*/
typedef struct Mif_Param_Info_s {
char *name; /* Name of this parameter */
char *description; /* Description of this parameter */
Mif_Data_Type_t type; /* Is this a real, boolean, string, ... */
Mif_Boolean_t has_default; /* True if there is a default value */
Mif_Parse_Value_t default_value; /* The default value */
Mif_Boolean_t has_lower_limit; /* True if there is a lower limit */
Mif_Parse_Value_t lower_limit; /* The lower limit for this parameter */
Mif_Boolean_t has_upper_limit; /* True if there is a upper limit */
Mif_Parse_Value_t upper_limit; /* The upper limit for this parameter */
Mif_Boolean_t is_array; /* True if parameter is an array */
Mif_Boolean_t has_conn_ref; /* True if parameter is associated with a connector */
int conn_ref; /* The subscript of the associated connector */
Mif_Boolean_t has_lower_bound; /* True if there is an array size lower bound */
int lower_bound; /* Array size lower bound */
Mif_Boolean_t has_upper_bound; /* True if there is an array size upper bound */
int upper_bound; /* Array size upper bound */
Mif_Boolean_t null_allowed; /* True if null is allowed for this parameter */
} Mif_Param_Info_t;
/*
* Information about an instance parameter used by the parser to error check input
*/
typedef struct Mif_Inst_Var_Info_s {
char *name; /* Name of this instance var */
char *description; /* Description of this instance var */
Mif_Data_Type_t type; /* Is this a real, boolean, string, ... */
Mif_Boolean_t is_array; /* True if instance var is an array */
} Mif_Inst_Var_Info_t;
#endif /* MIFPARSE */

157
src/include/mifproto.h Executable file
View File

@ -0,0 +1,157 @@
#ifndef MIFPROTO
#define MIFPROTO
/* ===========================================================================
FILE MIFproto.h
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 ANSI C function prototypes for functions in the
MIF package.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
#include "ifsim.h"
#include "inpdefs.h"
#include "smpdefs.h"
#include "cktdefs.h"
#include "miftypes.h"
extern void MIF_INP2A(
void *ckt, /* circuit structure to put mod/inst structs in */
INPtables *tab, /* symbol table for node names, etc. */
card *current /* the card we are to parse */
);
extern char * MIFgetMod(
void *ckt,
char *name,
INPmodel **model,
INPtables *tab
);
extern IFvalue * MIFgetValue(
void *ckt,
char **line,
int type,
INPtables *tab,
char **err
);
extern int MIFsetup(
SMPmatrix *matrix,
GENmodel *inModel,
CKTcircuit *ckt,
int *state
);
extern int MIFload(
GENmodel *inModel,
CKTcircuit *ckt
);
extern int MIFmParam(
int param_index,
IFvalue *value,
GENmodel *inModel
);
extern int MIFask(
CKTcircuit *ckt,
GENinstance *inst,
int param_index,
IFvalue *value,
IFvalue *select
);
extern int MIFmAsk(
CKTcircuit *ckt,
GENmodel *inModel,
int param_index,
IFvalue *value
);
extern int MIFtrunc(
GENmodel *inModel,
CKTcircuit *ckt,
double *timeStep
);
extern int MIFconvTest(
GENmodel *inModel,
CKTcircuit *ckt
);
extern int MIFdelete(
GENmodel *inModel,
IFuid name,
GENinstance **inst
);
extern int MIFmDelete(
GENmodel **inModel,
IFuid modname,
GENmodel *model
);
extern void MIFdestroy(
GENmodel **inModel
);
extern char *MIFgettok(
char **s
);
extern char *MIFget_token(
char **s,
Mif_Token_Type_t *type
);
extern Mif_Cntl_Src_Type_t MIFget_cntl_src_type(
Mif_Port_Type_t in_port_type,
Mif_Port_Type_t out_port_type
);
extern char *MIFcopy(char *);
#endif /* MIFPROTO */

226
src/include/miftypes.h Executable file
View File

@ -0,0 +1,226 @@
#ifndef MIFTYPES
#define MIFTYPES
/* ===========================================================================
FILE MIFtypes.h
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 typedefs shared by several header files in
the MIF package.
INTERFACES
None.
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
=========================================================================== */
/* ***************************************************************************** */
typedef int Mif_Boolean_t;
#define MIF_FALSE 0
#define MIF_TRUE 1
typedef int Mif_Status_t;
#define MIF_OK 0
#define MIF_ERROR 1
/*
typedef enum {
MIF_OK,
MIF_ERROR,
} Mif_Status_t;
*/
/* ***************************************************************************** */
/*
* The type of call to a code model - analog or event-driven
*/
typedef enum {
MIF_ANALOG, /* Analog call */
MIF_EVENT_DRIVEN, /* Event-driven call */
} Mif_Call_Type_t;
/*
* Analysis type enumerations
*/
typedef enum {
MIF_DC, /* A DC or DCOP analysis */
MIF_AC, /* A swept AC analysis */
MIF_TRAN, /* A transient analysis */
} Mif_Analysis_t;
/*
* Port type enumerations
*/
typedef enum {
MIF_VOLTAGE, /* v - Single-ended voltage */
MIF_DIFF_VOLTAGE, /* vd - Differential voltage */
MIF_CURRENT, /* i - Single-ended current */
MIF_DIFF_CURRENT, /* id - Differential current */
MIF_VSOURCE_CURRENT, /* vnam - Voltage source current */
MIF_CONDUCTANCE, /* g - Single-ended VCIS */
MIF_DIFF_CONDUCTANCE, /* gd - Differential VCIS */
MIF_RESISTANCE, /* h - Single-ended ICVS */
MIF_DIFF_RESISTANCE, /* hd - Differential ICVS */
MIF_DIGITAL, /* d - Digital */
MIF_USER_DEFINED, /* <identifier> - Any user defined type */
} Mif_Port_Type_t;
/*
* The direction of a connector
*/
typedef enum {
MIF_IN, /* Input only */
MIF_OUT, /* Output only */
MIF_INOUT, /* Input and output (e.g. g or h type) */
} Mif_Dir_t;
/*
* The type of a parameter
*/
typedef enum {
MIF_BOOLEAN,
MIF_INTEGER,
MIF_REAL,
MIF_COMPLEX,
MIF_STRING,
} Mif_Data_Type_t;
/*
* The type of a token
*/
typedef enum {
MIF_LARRAY_TOK,
MIF_RARRAY_TOK,
MIF_LCOMPLEX_TOK,
MIF_RCOMPLEX_TOK,
MIF_PERCENT_TOK,
MIF_TILDE_TOK,
MIF_STRING_TOK,
MIF_NULL_TOK,
MIF_NO_TOK,
} Mif_Token_Type_t;
/*
* Type of controlled source
*/
typedef enum {
MIF_VCVS,
MIF_VCIS,
MIF_ICVS,
MIF_ICIS,
} Mif_Cntl_Src_Type_t;
/* ***************************************************************************** */
/*
* Complex numbers
*/
typedef struct {
double real;
double imag;
} Mif_Complex_t;
/*
* Values of different types used by the load, ... routines
*/
typedef union {
Mif_Boolean_t bvalue; /* For digital node value */
int ivalue; /* For integer parameters */
double rvalue; /* For spice node values and real parameters */
Mif_Complex_t cvalue; /* For complex parameters */
char *svalue; /* For string parameters */
void *pvalue; /* For user defined nodes */
} Mif_Value_t;
/*
* Values of different types used by the parser. Note that this is a structure
* instead of a union because we need to do initializations in the ifspec.c files for
* the models and unions cannot be initialized in any useful way in C
*
*/
typedef struct {
Mif_Boolean_t bvalue; /* For boolean values */
int ivalue; /* For integer values */
double rvalue; /* For real values */
Mif_Complex_t cvalue; /* For complex values */
char *svalue; /* For string values */
} Mif_Parse_Value_t;
#endif /* MIFTYPES */

66
src/include/multi_line.h Normal file
View File

@ -0,0 +1,66 @@
/*
* project.h
*
* Diagonalization by Successive Rotations Method
* (The Jacobi Method)
*
* Date: October 4, 1991
*
* Author: Shen Lin
*
* Copyright (C) University of California, Berkeley
*
*/
/************************************************************
*
* Macros
*
************************************************************/
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#endif
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
#ifndef ABS
#define ABS(x) ((x) >= 0 ? (x) : (-(x)))
#endif
#ifndef SGN
#define SGN(x) ((x) >= 0 ? (1.0) : (-1.0))
#endif
/************************************************************
*
* Defines
*
************************************************************/
#define MAX_DIM 16
#define Title "Diagonalization of a Symmetric matrix A (A = S^-1 D S)\n"
#define Left_deg 7 /* should be greater than or equal to 6 */
#define Right_deg 2
/************************************************************
*
* Data Structure Definitions
*
************************************************************/
typedef struct linked_list_of_max_entry{
struct linked_list_of_max_entry *next;
int row, col;
float value;
} MAXE, *MAXE_PTR;
typedef struct {
double *Poly[MAX_DIM];
double C_0[MAX_DIM];
} Mult_Out;
typedef struct {
double *Poly;
double C_0;
} Single_Out;

396
src/include/swec.h Normal file
View File

@ -0,0 +1,396 @@
/*
* project.h
*
* Timing Simulator (ESWEC)
*
* Date: October 5, 1990
*
* Author: Shen Lin
*
* Copyright (C) University of California, Berkeley
*
*/
#ifndef _SWEC_H_
#define _SWEC_H_
/************************************************************
*
* Defines
*
************************************************************/
#define MainTitle " Timing Simulator\n"
#define MAXDEVICE 4
#define MAXMOS 31500 /* suggested value */
#define MAXDD 256 /* suggested value */
#define MAXVCCS 128 /* suggested value */
#define MAXTIME 1000000
#define MAXNODE 136
#define TAB_SIZE 8192 /* originally 2048 */
#define NUM_STEPS_PER_MICRON 10 /* 0.1 micron is the smallest step */
#define MAX_FET_SIZE 80 /* largest fet in microns */
#define Vol_Step 1.0e-3 /* voltage resolution */
#define SCL 1000.0 /* voltage scaler (1V/3mv) */
#define MAX_CP_TX_LINES 4 /* max number of coupled lines in
a multiconductor line system */
/************************************************************
*
* Macro
*
************************************************************/
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#endif
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
#ifndef ABS
#define ABS(x) ((x) >= 0 ? (x) : (-(x)))
#endif
/************************************************************
*
* Data Structure Definitions
*
************************************************************/
typedef struct reglist REGLIST;
typedef struct node NODE;
typedef struct mosfet MOSFET;
typedef struct emosfet EMOSFET;
typedef struct diode DIODE;
typedef struct ediode EDIODE;
typedef struct vccs VCCS;
typedef struct evccs EVCCS;
typedef struct i_cap I_CAP;
typedef struct ei_cap EI_CAP;
typedef struct resistor RESISTOR;
typedef struct eresistor ERESISTOR;
typedef struct rline RLINE;
typedef struct erline ERLINE;
typedef struct txline TXLine;
typedef struct etxline ETXLine;
typedef struct cpline CPLine;
typedef struct ecpline ECPLine;
typedef struct bqueue BQUEUE;
typedef struct pqueue PQUEUE;
typedef struct ms_device MS_DEVICE;
typedef struct bp_device BP_DEVICE;
typedef struct dd_device DD_DEVICE;
struct mosfet{
int type; /* 1 : NMOS, 2 : PMOS */
MS_DEVICE *device; /* NULL if the nominal device model */
NODE *out_node;
NODE *in_node;
float Cs, Cd;
MOSFET *nx;
int time; /* instantaneous information */
float voltage, dvg; /* instantaneous information */
float vgN_1; /* gate voltage at previous event point */
float G; /* effective conductance at t(n) */
float effective; /* W over effective L */
int tabW; /* width in ns/um */
REGLIST *region; /* region associated with this mos */
/* NULL if driven by the node of the same region */
};
struct diode{
float Is; /* saturation current */
float Vj; /* junction potential */
double G;
NODE *in_node;
NODE *out_node;
DIODE *nx;
};
struct vccs{
float Is; /* saturation current */
NODE *in_node;
NODE *out_node;
NODE *pcv_node;
NODE *ncv_node;
DIODE *nx;
};
typedef struct {
char name[10]; /* device name */
int type; /* 1 : NMOS, 2 : PMOS */
int device_id; /* device id */
} DEVICENAME;
struct ms_device{
char name[10];
int used; /* device used in circuit flag */
float rho; /* device vsat denom param */
float alpha; /* device vsat denom vgg param */
float vt; /* device zero bias threshold voltage in mv*/
float gamma; /* device backgate bias vt param */
float fermi; /* device fermi potential in mv */
float theta; /* device backgate bias vt width param */
float mu; /* device vt width param */
float eta; /* device saturation slope */
float eta5; /* eta - 0.5 */
int pzld; /* positive lambda */
float lambda; /* channel-length modulation */
float kp; /* device conductance parameter */
float cgs0; /* gate-source overlap capacitance
per meter channel width */
float cgd0; /* gate-drain overlap capacitance
per meter channel width */
float cox; /* oxide-field capacitance
per square meter of gate area */
float cjsw; /* zero-biased junction sidewall capacitace
per meter of junction perimeter */
float cj0; /* zero-biased junction bottom capacitace
per square meter of junction area */
float keq; /* abrupt junction parameter */
float ld; /* lateral diffusion */
float *thresh;
float *sat;
float *dsat;
float *body;
float *gammod;
};
struct bp_device{
char name[10];
int type; /* 1 : NPN; 2 : PNP */
float rc; /* collector resistance */
float re; /* emitter resistance */
float rb; /* zero bias base resistance */
float Is; /* transport saturation current */
float Af; /* ideal maximum forward alpha */
float Ar; /* ideal maximum reverse alpha */
float Vje; /* B-E built-in potential */
float Vjc; /* B-C built-in potential */
};
struct dd_device{
char name[10];
float Is; /* saturation current */
float rs; /* ohmic resistance */
float Vj; /* junction potential */
};
typedef struct linked_lists_of_Bpoint{
struct linked_lists_of_Bpoint *next;
int time;
float voltage;
float slope;
} BPOINT, *BPOINTPTR;
typedef struct linked_lists_of_nodeName{
char id[24];
struct linked_lists_of_nodeName *left, *right;
NODE *nd;
} NDname, *NDnamePt;
struct node {
NDnamePt name;
EMOSFET *mptr; /* pointer to head of src/drn MOSFET list */
EMOSFET *gptr; /* pointer to head of gate MOSFET list */
EI_CAP *cptr; /* pointer to head of internodal cap list */
ERESISTOR *rptr; /* pointer to head of internodal resistor list */
ERLINE *rlptr; /* pointer to head of internodal TX line list */
ETXLine *tptr; /* pointer to head of transmission line list */
ECPLine *cplptr; /* pointer to head of coupled lines list */
EDIODE *ddptr; /* pointer to head of diode list */
EVCCS *vccsptr; /* pointer to head of VCCS list */
EVCCS *cvccsptr;/* pointer to head of controlled VCCS list */
NODE *next; /* pointer to next node */
REGLIST *region; /* region associated with this node */
NODE *base_ptr; /* group src/drn nodes into region */
/* charles 2,2 1/18/93
float V;
float dv; voltage at t(n-1) and slope at t(n)
*/
double V;
double dv;
float CL; /* grounded capacitance in F */
double gsum; /*^ sum of the equivalent conductance */
double cgsum; /*^ sum of the constant conductance */
double is; /*^ equivalent Is */
int tag; /* -2 : Vdd, -3 : Vss, -1 : initial value */
int flag; /*^ flag to show some features of the node */
PQUEUE *qptr; /*^ pointer to the entry in the queue or waiting list */
FILE *ofile; /* output file for the signal at this node */
/* NULL if not for print */
int dvtag;
};
struct reglist{
REGLIST *rnxt; /* pointer to next region */
NODE *nlist; /* node list */
MOSFET *mos;
I_CAP *cap;
RESISTOR *res;
TXLine *txl;
CPLine *cpl;
struct linked_lists_of_Bpoint *Bpoint; /* break points at primary inputs */
struct linked_lists_of_Bpoint *head; /* header of the break points at primary inputs */
int eTime; /* time when this region previously evaluated */
int DCvalue;
/* 1, 0, 2 : unknown, 3 : unchangeable 1, 4 : unchangeable 0 */
BQUEUE *prediction;
};
struct bqueue{
int key; /* time for the event to be fired, or DC weight */
BQUEUE *left;
BQUEUE *right;
BQUEUE *pred;
BQUEUE *pool;
REGLIST *region; /* region id */
};
struct pqueue {
NODE *node;
PQUEUE *next;
PQUEUE *prev;
};
struct i_cap {
NODE *in_node;
NODE *out_node;
float cap;
I_CAP *nx;
};
struct resistor {
NODE *in_node;
NODE *out_node;
float g; /* conductance */
int ifF; /* whether floating */
float g1; /* conductance for floating resistor */
RESISTOR *nx;
};
struct rline {
NODE *in_node;
NODE *out_node;
float g; /* conductance */
RLINE *nx;
};
typedef struct linked_lists_of_vi_txl{
struct linked_lists_of_vi_txl *next;
struct linked_lists_of_vi_txl *pool;
int time;
/* charles 2,2
float v_i, v_o;
float i_i, i_o;
*/
double v_i, v_o;
double i_i, i_o;
} VI_list_txl;
typedef struct linked_lists_of_vi{
struct linked_lists_of_vi *next;
struct linked_lists_of_vi *pool;
int time;
float v_i[MAX_CP_TX_LINES], v_o[MAX_CP_TX_LINES];
float i_i[MAX_CP_TX_LINES], i_o[MAX_CP_TX_LINES];
} VI_list;
typedef struct {
double c, x;
double cnv_i, cnv_o;
} TERM;
typedef struct {
int ifImg;
double aten;
TERM tm[3];
} TMS;
struct cpline {
int noL;
int ext;
float ratio[MAX_CP_TX_LINES];
float taul[MAX_CP_TX_LINES];
TMS *h1t[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
TMS *h2t[MAX_CP_TX_LINES][MAX_CP_TX_LINES][MAX_CP_TX_LINES];
TMS *h3t[MAX_CP_TX_LINES][MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double h1C[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double h2C[MAX_CP_TX_LINES][MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double h3C[MAX_CP_TX_LINES][MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double h1e[MAX_CP_TX_LINES][MAX_CP_TX_LINES][3];
NODE *in_node[MAX_CP_TX_LINES];
NODE *out_node[MAX_CP_TX_LINES];
int tag_i[MAX_CP_TX_LINES], tag_o[MAX_CP_TX_LINES];
CPLine *nx;
struct linked_lists_of_vi *vi_head;
struct linked_lists_of_vi *vi_tail;
float dc1[MAX_CP_TX_LINES], dc2[MAX_CP_TX_LINES];
};
struct txline {
int lsl; /* 1 if the line is lossless, otherwise 0 */
int ext; /* a flag, set if time step is greater than tau */
float ratio;
float taul;
double sqtCdL;
double h2_aten;
double h3_aten;
double h1C;
double h1e[3];
int ifImg;
NODE *in_node;
NODE *out_node;
int tag_i, tag_o;
TERM h1_term[3];
TERM h2_term[3];
TERM h3_term[6];
TXLine *nx;
struct linked_lists_of_vi_txl *vi_head;
struct linked_lists_of_vi_txl *vi_tail;
float dc1, dc2;
int newtp; /* flag indicating new time point */
};
struct evccs {
VCCS *vccs;
EVCCS *link;
};
struct ediode {
DIODE *dd;
EDIODE *link;
};
struct emosfet {
MOSFET *mos;
EMOSFET *link;
};
struct ei_cap {
I_CAP *cap;
EI_CAP *link;
};
struct eresistor {
RESISTOR *res;
ERESISTOR *link;
};
struct erline {
RLINE *rl;
ERLINE *link;
};
struct etxline {
TXLine *line;
ETXLine *link;
};
struct ecpline {
CPLine *line;
ECPLine *link;
};
#endif

33
src/include/tclspice.h Executable file
View File

@ -0,0 +1,33 @@
/*Include file to allow spice to export certain data */
#ifndef TCLSPICE_H
#define TCLSPICE_H
extern int steps_completed;
extern void blt_init(void *run);
extern void blt_add(int index,double value);
extern void blt_relink(int index, void* v);
extern void blt_lockvec(int index);
/* For things to do per loop */
int Tcl_ExecutePerLoop();
/* For tk ploting */
extern int sp_Tk_Init(void);
#include <graph.h>
extern int sp_Tk_NewViewport(GRAPH *graph);
extern int sp_Tk_Close(void);
extern int sp_Tk_Clear(void);
extern int sp_Tk_DrawLine(int x1, int y1, int x2, int y2);
extern int sp_Tk_Arc(int x0, int y0, int radius, double theta1, double theta2);
extern int sp_Tk_Text(char *text, int x, int y);
extern int sp_Tk_DefineColor(int colorid, double red, double green, double blue);
extern int sp_Tk_DefineLinestyle(int linestyleid, int mask);
extern int sp_Tk_SetLinestyle(int linestyleid);
extern int sp_Tk_SetColor(int colorid);
extern int sp_Tk_Update(void);
/* The blt callback method */
#include <dvec.h>
extern int blt_plot(struct dvec *y,struct dvec *x);
#endif

3028
src/pkgIndex.tcl.in Executable file

File diff suppressed because it is too large Load Diff

426
src/spicelib/analysis/cluster.c Executable file
View File

@ -0,0 +1,426 @@
/* Spice hooks */
#include <ngspice.h>
#ifdef CLUSTER
#include <inpdefs.h>
#include "cluster.h"
#include <cktdefs.h>
#include <gendefs.h>
/* Misc stuff */
#include <pthread.h>
#include <string.h>
/*Network stuff*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
struct input_pipe {
/*the names of the local and remote nodes*/
char remote[32];
char local[32];
int fd;
FILE *stream;
/* the data recieved */
double time;
double data;
/*resistance of this link*/
double res;
/* The value controled */
double *currentPtr;
/*The output it is linked to*/
struct output_pipe *link;
struct input_pipe *next;
};
struct output_pipe {
int fd;
FILE *stream;
/*the names of the local and remote nodes*/
char local[32];
char remote[32];
/* The index of the local node value in the ckt->CKTrhsOld array */
int outIndex;
/*Last values sent*/
double time,data;
struct input_pipe *link;
struct output_pipe *next;
};
static double lastTimeSent=0;
static int time_sock=0;
static FILE *time_outfile=NULL;
static FILE *time_infile=NULL;
static struct input_pipe* input_pipes=NULL;
static struct output_pipe* output_pipes=NULL;
/* sets up deamon which waits for connections
*and sets up input pipes as it recieves them */
static void *start_listener(void *);
/* Setup the output pipes*/
static int setup_output(CKTcircuit *ckt);
static int setup_input(CKTcircuit *ckt);
static int setup_time();
int CLUsetup(CKTcircuit *ckt){
pthread_t tid;
struct input_pipe *curr;
int i, connections=0;
GENmodel *mod;
GENinstance *inst;
/* count the number of connections expected */
i = INPtypelook("Isource");
for(mod = (GENmodel *)ckt->CKThead[i];
mod != NULL;
mod = mod->GENnextModel)
for (inst = mod->GENinstances;
inst != NULL;
inst = inst->GENnextInstance)
if(strncmp("ipcx",inst->GENname,4) == 0)
connections++;
/* allocate the input connections */
for(i=0;i<connections;i++) {
curr = (struct input_pipe *)tmalloc(sizeof(struct input_pipe));
if(input_pipes)
curr->next = input_pipes;
else
curr->next = NULL;
input_pipes = curr;
}
pthread_create(&tid,NULL,start_listener,(void *)&connections);
setup_output(ckt);
pthread_join(tid,NULL);
setup_input(ckt);
setup_time();
return 0;
}
#include "../devices/isrc/isrcdefs.h"
/*Connect to remote machine and find the data*/
static int setup_output(CKTcircuit *ckt){
int type;
GENmodel *mod;
GENinstance *inst;
char hostname[64];
lastTimeSent = 0;
type = INPtypelook("Isource");
for(mod = (GENmodel *)ckt->CKThead[type];
mod != NULL;
mod = mod->GENnextModel)
for (inst = mod->GENinstances;
inst != NULL;
inst = inst->GENnextInstance)
if(strncmp("ipcx",inst->GENname,4) == 0){
ISRCinstance *isrc = (ISRCinstance *)inst;
CKTnode *node;
struct output_pipe *curr;
struct sockaddr_in address;
struct hostent *host=NULL;
int sock,nodeNum,i;
/*Create the struct*/
curr = (struct output_pipe *)tmalloc(sizeof(struct output_pipe));
if(output_pipes)
curr->next = output_pipes;
else
curr->next = NULL;
output_pipes = curr;
/* The node names */
strcpy(curr->local,CKTnodName(ckt,isrc->ISRCnegNode));/*weird*/
strcpy(curr->remote,isrc->ISRCname);
/* extract remote node number */
nodeNum = /*Xcoord*/(curr->remote[4] - '0') * CLUSTER_WIDTH
+ /*Ycoord*/(curr->remote[9] - '0');
sprintf(hostname,"n%d."DOMAIN_NAME,nodeNum);
/* network stuff */
host = gethostbyname(hostname);
if(!host){
printf("Host not found in setup_output\n");
exit(0);
}
if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
printf("Socket open in setup_output\n");
exit(0);
}
address.sin_family = AF_INET;
address.sin_port = htons(PORT);
memcpy(&address.sin_addr,host->h_addr_list[0],
sizeof(address.sin_addr));
printf("connecting to %s ...... ",hostname);
fflush(stdout);
while(connect(sock,(struct sockaddr *)&address,sizeof(address))){
usleep(500);/*wait for the sever to start*/
}
printf("connected\n");
curr->fd = sock;
/* send stuff */
/* buffer */
i = (strlen(curr->remote) + strlen(curr->local) + 2)*sizeof(char);
setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i));
curr->stream = fdopen(curr->fd,"w");
fwrite(curr->remote,sizeof(char),strlen(curr->remote),curr->stream);
fputc('\0',curr->stream);
fwrite(curr->local,sizeof(char),strlen(curr->local),curr->stream);
fputc('\0',curr->stream);
fflush(curr->stream);
/* buffer, what is done per time point */
i = sizeof(double)*2;
setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i));
/* find the index in ckt->rhsOld which contains the local node */
i = 0;
for(node = ckt->CKTnodes->next;node;node = node->next){
i++;
if(strcmp(node->name,curr->local)==0){
curr->outIndex = i;
goto next;
}
}
printf("Local node %s not found\n",curr->local);
exit(0);
next:
}
return 0;
}
/*Processes the connections recieved by start_listener*/
static int setup_input(CKTcircuit *ckt){
int type;
GENmodel *mod;
GENinstance *inst;
struct input_pipe *input;
type = INPtypelook("Isource");
for(input = input_pipes;input;input = input->next){
int i;
input->stream = fdopen(input->fd,"r");
/*Get the local and remote node names*/
i=0;
do {
while(fread(&input->local[i],sizeof(char),1,input->stream) != 1);
}while(input->local[i++] != '\0');
i=0;
do {
while(fread(&input->remote[i],sizeof(char),1,input->stream) != 1);
}while(input->remote[i++] != '\0');
/* initilise */
input->time = -1;
/*Find the Isource to control*/
for(mod = (GENmodel *)ckt->CKThead[type];
mod != NULL;
mod = mod->GENnextModel)
for (inst = mod->GENinstances;
inst != NULL;
inst = inst->GENnextInstance)
if(strcmp(input->remote,&inst->GENname[11]) == 0){
ISRCinstance *isrc = (ISRCinstance *)inst;
input->res = isrc->ISRCdcValue;
isrc->ISRCdcValue = 0;
input->currentPtr = &isrc->ISRCdcValue;
goto next;
}
/* We get here if no Isource matches */
printf("Current source %s not found\n",input->remote);
exit(0);
next:
/* Now find the corresponding output */
{
struct output_pipe *output;
for(output = output_pipes;output;output = output->next)
if(strcmp(&input->local[11],output->local)==0){
input->link = output;
output->link = input;
goto next2;
}
printf("Parent to %s not found\n",&input->local[11]);
exit(0);
next2:
}
}
return 0;
}
/* This starts a server and waits for connections, number given by argument*/
static void *start_listener(void *v){
int *connections = (int *)v;
int count=0;
struct sockaddr_in address;
int sock, conn,i;
size_t addrLength = sizeof(struct sockaddr_in);
struct input_pipe *curr;
if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
printf("socket in start_listener\n");
exit(0);
}
/* Allow reuse of the socket */
i = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
/* port, inferface ..*/
address.sin_family = AF_INET;
address.sin_port = htons(PORT);
memset(&address.sin_addr,0,sizeof(address.sin_addr));
if(bind(sock, (struct sockaddr *)&address,sizeof(address))){
printf("bind in start_listener\n");
exit(0);
}
if(listen(sock,5)){
printf("listen in start_listener\n");
exit(0);
}
/* Loop till recieved all connections */
curr = input_pipes;
while (count < *connections){
if((conn = accept(sock, (struct sockaddr *)&address,&addrLength)) < 0){
printf("accept in start_listener\n");
exit(0);
}
curr->fd = conn;
/* will fill rest of structure later in setup_input*/
count ++;
curr = curr->next;
}
close(sock);
return NULL;
}
/*Writes data to remote computer*/
int CLUoutput(CKTcircuit *ckt){
struct output_pipe *output;
lastTimeSent = ckt->CKTtime;
for(output = output_pipes;
output;
output = output->next){
output->time = ckt->CKTtime;
output->data = ckt->CKTrhsOld[output->outIndex];
fwrite(&output->time,sizeof(double),1,output->stream);
fwrite(&output->data,
sizeof(double),1,output->stream);
fflush(output->stream);
}
return 0;
}
/*Maniputates the local circuit based on the links*/
int CLUinput(CKTcircuit *ckt){
struct input_pipe *input;
double tmp;
for(input= input_pipes;input;input = input->next){
/*recieve data till we get a good time point*/
while (input->time < lastTimeSent){
while(fread(&input->time, sizeof(double), 1, input->stream) != 1){}
while(fread(&input->data, sizeof(double), 1, input->stream) != 1){}
}
tmp = (input->link->data - input->data) / input->res;
/*dampen out large currents*/
if(tmp > 0)
*input->currentPtr = 0.2 * (1 - exp(-tmp/0.2));
else
*input->currentPtr = -0.2 * (1 - exp(tmp/0.2));
/*GND is the posNode, local node is the negNode*/
}
return 0;
}
static int setup_time(){
struct sockaddr_in address;
struct hostent *host=NULL;
char *hostname = TIME_HOST;
int sock,i;
/* network stuff */
host = gethostbyname(hostname);
if(!host){
printf("Host not found in setup_time\n");
exit(0);
}
if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
printf("Socket open in setup_time\n");
exit(0);
}
i = sizeof(double)*2;
setsockopt(sock,SOL_SOCKET,SO_SNDBUF ,&i,sizeof(i));
address.sin_family = AF_INET;
address.sin_port = htons(TIME_PORT);
memcpy(&address.sin_addr,host->h_addr_list[0],
sizeof(address.sin_addr));
while(connect(sock,(struct sockaddr *)&address,sizeof(address))){
usleep(500);/*wait for the sever to start*/
}
time_sock=sock;
time_outfile=fdopen(sock,"w");
time_infile=fdopen(sock,"r");
return 0;
}
int CLUsync(double time,double *delta, int error){
double tmp;
if(error)
tmp = *delta * (-1);
else
tmp = *delta;
fwrite(&time,sizeof(double),1,time_outfile);
fwrite(&tmp,sizeof(double),1,time_outfile);
fflush(time_outfile);
while(fread(&tmp,sizeof(double),1,time_infile) != 1);
if(tmp < 0){
*delta = -tmp;
return 0;
} else {
*delta = tmp;
return 1;
}
}
#endif

View File

@ -0,0 +1,18 @@
## Process this file with automake to produce Makefile.in
pkglib_LTLIBRARIES = libcpl.la
libcpl_la_SOURCES = \
cpl.c \
cpldest.c \
cplmdel.c \
cplparam.c \
cpldel.c \
cplload.c \
cplmpar.c \
cplsetup.c \
cplinit.c
INCLUDES = -I$(top_srcdir)/src/include
MAINTAINERCLEANFILES = Makefile.in

View File

@ -0,0 +1,39 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cpldefs.h"
#include "devdefs.h"
#include "ifsim.h"
#include "suffix.h"
IFparm CPLpTable[] = {
IOP("pos_nodes", CPL_POS_NODE, IF_VECTOR|IF_STRING, "in nodes"),
IOP("neg_nodes", CPL_NEG_NODE, IF_VECTOR|IF_STRING, "out nodes"),
IOP("dimension", CPL_DIM, IF_INTEGER, "number of coupled lines"),
IOP("length", CPL_LENGTH, IF_REAL, "length of lines"),
};
IFparm CPLmPTable[] = { /* model parameters */
IOP( "r", CPL_R, IF_REALVEC,"resistance per length"),
IOP( "l", CPL_L, IF_REALVEC,"inductance per length"),
IOP( "c", CPL_C, IF_REALVEC,"capacitance per length"),
IOP( "g", CPL_G, IF_REALVEC,"conductance per length"),
IOP( "length", CPL_length, IF_REAL,"length"),
IP( "cpl", CPL_MOD_R, IF_FLAG,"Device is a cpl model"),
};
char *CPLnames[] = {
"P+",
"P-"
};
int CPLnSize = NUMELEMS(CPLnames);
int CPLiSize = sizeof(CPLinstance);
int CPLmSize = sizeof(CPLmodel);
int CPLmPTSize = NUMELEMS(CPLmPTable);
int CPLpTSize = NUMELEMS(CPLpTable);

View File

@ -0,0 +1,97 @@
#ifndef CPL
#define CPL
#include "ifsim.h"
#include "cktdefs.h"
#include "gendefs.h"
#include "complex.h"
#include "noisedef.h"
#include "swec.h"
/* information used to describe a single instance */
typedef struct sCPLinstance {
struct sCPLmodel *CPLmodPtr; /* backpointer to model */
struct sCPLinstance *CPLnextInstance; /* pointer to next instance of
* current model*/
IFuid CPLname; /* pointer to character string naming this instance */
int dimension;
int *CPLposNodes;
int *CPLnegNodes;
double CPLlength;
int *CPLibr1;
int *CPLibr2;
CPLine *cplines; /* pointer to SWEC cplines type */
CPLine *cplines2; /* temporary pointer to SWEC cplines type */
char **in_node_names;
char **out_node_names;
double **CPLibr1Ibr1;
double **CPLibr2Ibr2;
double **CPLposIbr1;
double **CPLnegIbr2;
/* trial */
double **CPLposPos;
double **CPLnegNeg;
double **CPLposNeg;
double **CPLnegPos;
double ***CPLibr1Pos;
double ***CPLibr2Neg;
double ***CPLibr1Neg;
double ***CPLibr2Pos;
double ***CPLibr1Ibr2;
double ***CPLibr2Ibr1;
unsigned CPLibr1Given : 1;
unsigned CPLibr2Given : 1;
unsigned CPLdcGiven : 1;
unsigned CPLlengthgiven : 1;
} CPLinstance ;
/* per model data */
typedef struct sCPLmodel { /* model structure for a cpl */
int CPLmodType; /* type index of this device type */
struct sCPLmodel *CPLnextModel; /* pointer to next possible model in
* linked list */
CPLinstance * CPLinstances; /* pointer to list of instances that have this
* model */
IFuid CPLmodName; /* pointer to character string naming this model */
double *Rm;
double *Gm;
double *Lm;
double *Cm;
double length;
unsigned Rmgiven : 1;
unsigned Lmgiven : 1;
unsigned Gmgiven : 1;
unsigned Cmgiven : 1;
unsigned lengthgiven : 1;
} CPLmodel;
/* instance parameters */
#define CPL_POS_NODE 1
#define CPL_NEG_NODE 2
#define CPL_DIM 3
#define CPL_LENGTH 4
/* model parameters */
#define CPL_R 101
#define CPL_C 102
#define CPL_G 103
#define CPL_L 104
#define CPL_length 105
#define CPL_MOD_R 106
#include "cplext.h"
extern VI_list *pool_vi;
#endif /*CPL*/

View File

@ -0,0 +1,38 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cpldefs.h"
#include "sperror.h"
#include "suffix.h"
int
CPLdelete(inModel,name,inst)
GENmodel *inModel;
IFuid name;
GENinstance **inst;
{
CPLmodel *model = (CPLmodel *)inModel;
CPLinstance **fast = (CPLinstance **)inst;
CPLinstance **prev = NULL;
CPLinstance *here;
for( ; model ; model = model->CPLnextModel) {
prev = &(model->CPLinstances);
for(here = *prev; here ; here = *prev) {
if(here->CPLname == name || (fast && here==*fast) ) {
*prev= here->CPLnextInstance;
FREE(here);
return(OK);
}
prev = &(here->CPLnextInstance);
}
}
return(E_NODEV);
}

View File

@ -0,0 +1,34 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cpldefs.h"
#include "suffix.h"
void
CPLdestroy(inModel)
GENmodel **inModel;
{
CPLmodel **model = (CPLmodel **)inModel;
CPLinstance *here;
CPLinstance *prev = NULL;
CPLmodel *mod = *model;
CPLmodel *oldmod = NULL;
for( ; mod ; mod = mod->CPLnextModel) {
if(oldmod) FREE(oldmod);
oldmod = mod;
prev = (CPLinstance *)NULL;
for(here = mod->CPLinstances ; here ; here = here->CPLnextInstance) {
if(prev) FREE(prev);
prev = here;
}
if(prev) FREE(prev);
}
if(oldmod) FREE(oldmod);
*model = NULL;
}

View File

@ -0,0 +1,19 @@
#ifdef __STDC__
/* extern int CPLaccept(CKTcircuit*,GENmodel*); */
extern int CPLdelete(GENmodel*,IFuid,GENinstance**);
extern void CPLdestroy(GENmodel**);
extern int CPLload(GENmodel*,CKTcircuit*);
extern int CPLmDelete(GENmodel**,IFuid,GENmodel*);
extern int CPLmParam(int,IFvalue*,GENmodel*);
extern int CPLparam(int,IFvalue*,GENinstance*,IFvalue*);
extern int CPLsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*);
#else /* stdc */
/* extern int CPLaccept(); */
extern int CPLdelete();
extern void CPLdestroy();
extern int CPLload();
extern int CPLmDelete();
extern int CPLmParam();
extern int CPLparam();
extern int CPLsetup();
#endif /* stdc */

View File

@ -0,0 +1,68 @@
#include <config.h>
#include <devdefs.h>
#include "cplitf.h"
#include "cplext.h"
#include "cplinit.h"
SPICEdev CPLinfo = {
{
"CplLines",
"Simple Coupled Multiconductor Lines",
&CPLnSize,
&CPLnSize,
CPLnames,
&CPLpTSize,
CPLpTable,
&CPLmPTSize,
CPLmPTable,
0
},
CPLparam,
CPLmParam,
CPLload,
CPLsetup,
NULL,
NULL,
NULL,
NULL,
NULL, /* CPLfindBranch, */
NULL,
NULL,
CPLdestroy,
#ifdef DELETES
CPLmDelete,
CPLdelete,
#else /* DELETES */
NULL,
NULL,
#endif /* DELETES */
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&CPLiSize,
&CPLmSize
};
SPICEdev *
get_cpl_info(void)
{
return &CPLinfo;
}

View File

@ -0,0 +1,13 @@
#ifndef _CPLINIT_H
#define _CPLINIT_H
extern IFparm CPLpTable[ ];
extern IFparm CPLmPTable[ ];
extern int CPLmPTSize;
extern int CPLpTSize;
extern char *CPLnames[ ];
extern int CPLiSize;
extern int CPLmSize;
extern int CPLnSize;
#endif

View File

@ -0,0 +1,6 @@
#ifndef DEV_CPL
#define DEV_CPL
SPICEdev *get_cpl_info(void);
#endif

View File

@ -0,0 +1,890 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cpldefs.h"
#include "sperror.h"
#include "suffix.h"
VI_list *pool_vi;
static double ratio[MAX_CP_TX_LINES];
static VI_list *new_vi();
static void free_vi();
static int get_pvs_vi();
static int update_cnv();
static int add_new_vi();
static int right_consts();
static int update_delayed_cnv();
static int multC();
static int expC();
static int divC();
static void update_cnv_a();
static void copy_cp();
/*ARGSUSED*/
int
CPLload(inModel,ckt)
GENmodel *inModel;
CKTcircuit *ckt;
{
register CPLmodel *model = (CPLmodel *)inModel;
register CPLinstance *here;
CPLine *cp, *cp2;
int *k, *l;
int time, time2;
double h, h1, f;
int hint;
float hf;
NODE *nd;
double v, v1, g;
int cond1, i;
int noL, m, p, q;
CKTnode *node;
VI_list *vi, *vi_before;
int before, delta;
int resindex;
h = ckt->CKTdelta;
h1 = 0.5 * h;
time2 = (int) (ckt->CKTtime * 1e12);
hint = (int)(h * 1e12);
hf = (float)(h * 1e12);
time = (int) ((ckt->CKTtime - ckt->CKTdelta) * 1e12);
cond1= ckt->CKTmode & MODEDC;
for( ; model != NULL; model = model->CPLnextModel ) {
for (here = model->CPLinstances; here != NULL ;
here=here->CPLnextInstance) {
cp = here->cplines;
if (cond1 || cp->vi_head == NULL) continue;
noL = cp->noL = here->dimension;
if (cp->vi_tail->time > time) {
time = cp->vi_tail->time;
hint = time2 - time;
}
before = cp->vi_tail->time;
vi_before = cp->vi_tail;
if (time > cp->vi_tail->time) {
copy_cp(cp, here->cplines2);
add_new_vi(here, ckt, time);
delta = time - before;
for (m = 0; m < noL; m++) {
nd = cp->in_node[m];
v = vi_before->v_i[m];
v1 = nd->V = cp->vi_tail->v_i[m];
nd->dv = (v1 - v) / delta;
}
for (m = 0; m < noL; m++) {
nd = cp->out_node[m];
v = vi_before->v_o[m];
v1 = nd->V = cp->vi_tail->v_o[m];
nd->dv = (v1 - v) / delta;
}
update_cnv(cp, (float)delta);
if (cp->ext) update_delayed_cnv(cp, (float)delta);
}
}
}
model = (CPLmodel *)inModel;
/* loop through all the models */
for( ; model != NULL; model = model->CPLnextModel ) {
/* loop through all the instances of the model */
for (here = model->CPLinstances; here != NULL ;
here=here->CPLnextInstance) {
double mintaul = 123456789.0;
cp = here->cplines;
cp2 = here->cplines2;
for (i = 0; i < cp->noL; i++) {
if (mintaul > cp->taul[i]) mintaul = cp->taul[i];
}
if (mintaul < hf) {
fprintf(stderr, "your time step is too large for tau.\n");
fprintf(stderr, "please decrease max time step in .tran card.\n");
fprintf(stderr, ".tran tstep tstop tstart tmax.\n");
fprintf(stderr, "make tmax smaller than %e and try again.\n",
mintaul * 1e-12);
return (1111);
}
noL = cp->noL = here->dimension;
if (cond1) {
resindex = 0;
for (m = 0; m < noL; m++) {
if (here->CPLlengthgiven)
g = model->Rm[resindex] * here->CPLlength;
else g = model->Rm[resindex] * here->CPLmodPtr->length;
*(here->CPLposIbr1[m]) += 1.0;
*(here->CPLnegIbr2[m]) += 1.0;
*(here->CPLibr1Ibr1[m]) += 1.0;
*(here->CPLibr1Ibr2[m][m]) += 1.0;
*(here->CPLibr2Pos[m][m]) += 1.0;
*(here->CPLibr2Neg[m][m]) -= 1.0;
*(here->CPLibr2Ibr1[m][m]) -= g;
resindex = resindex + noL - m;
}
continue;
}
/* dc setup */
if (here->CPLdcGiven == 0 && !cond1) {
for (i = 0; i < cp->noL; i++) {
nd = cp->in_node[i];
for(node = ckt->CKTnodes;node; node = node->next) {
if (strcmp(nd->name->id, node->name) == 0) {
cp->dc1[i] = ckt->CKTrhsOld[node->number];
cp2->dc1[i] = nd->V = cp->dc1[i];
break;
}
}
nd = cp->out_node[i];
for(node = ckt->CKTnodes;node; node = node->next) {
if (strcmp(nd->name->id, node->name) == 0) {
cp->dc2[i] = ckt->CKTrhsOld[node->number];
cp2->dc2[i] = nd->V = cp->dc2[i];
break;
}
}
}
here->CPLdcGiven = 1;
vi = new_vi();
vi->time = 0;
{
int i, j, k, l;
for (i = 0; i < cp->noL; i++) {
for (j = 0; j < cp->noL; j++) {
TMS *tms;
double a, b;
tms = cp->h1t[i][j];
if (tms->ifImg) {
tms->tm[0].cnv_i = - cp->dc1[j] *
tms->tm[0].c / tms->tm[0].x;
tms->tm[0].cnv_o = - cp->dc2[j] *
tms->tm[0].c / tms->tm[0].x;
divC(tms->tm[1].c, tms->tm[2].c,
tms->tm[1].x, tms->tm[2].x, &a, &b);
tms->tm[1].cnv_i = - cp->dc1[j] * a;
tms->tm[1].cnv_o = - cp->dc2[j] * a;
tms->tm[2].cnv_i = - cp->dc1[j] * b;
tms->tm[2].cnv_o = - cp->dc2[j] * b;
} else
for (k = 0; k < 3; k++) {
tms->tm[k].cnv_i = - cp->dc1[j] *
tms->tm[k].c / tms->tm[k].x;
tms->tm[k].cnv_o = - cp->dc2[j] *
tms->tm[k].c / tms->tm[k].x;
}
for (l = 0; l < cp->noL; l++) {
tms = cp->h2t[i][j][l];
for (k = 0; k < 3; k++) {
tms->tm[k].cnv_i = 0.0;
tms->tm[k].cnv_o = 0.0;
}
}
for (l = 0; l < cp->noL; l++) {
tms = cp->h3t[i][j][l];
if (tms->ifImg) {
tms->tm[0].cnv_i = - cp->dc1[j] *
tms->tm[0].c / tms->tm[0].x;
tms->tm[0].cnv_o = - cp->dc2[j] *
tms->tm[0].c / tms->tm[0].x;
divC(tms->tm[1].c, tms->tm[2].c,
tms->tm[1].x, tms->tm[2].x, &a, &b);
tms->tm[1].cnv_i = - cp->dc1[j] * a;
tms->tm[1].cnv_o = - cp->dc2[j] * a;
tms->tm[2].cnv_i = - cp->dc1[j] * b;
tms->tm[2].cnv_o = - cp->dc2[j] * b;
} else
for (k = 0; k < 3; k++) {
tms->tm[k].cnv_i = - cp->dc1[j] *
tms->tm[k].c / tms->tm[k].x;
tms->tm[k].cnv_o = - cp->dc2[j] *
tms->tm[k].c / tms->tm[k].x;
}
}
}
for (i = 0; i < cp->noL; i++) {
vi->i_i[i] = vi->i_o[i] = 0.0;
vi->v_i[i] = cp->dc1[i];
vi->v_o[i] = cp->dc2[i];
}
}
vi->next = NULL;
cp->vi_tail = vi;
cp->vi_head = vi;
cp2->vi_tail = vi;
cp2->vi_head = vi;
}
}
for (m = 0; m < noL; m++) {
*(here->CPLibr1Ibr1[m]) = -1.0;
*(here->CPLibr2Ibr2[m]) = -1.0;
}
for (m = 0; m < noL; m++) {
*(here->CPLposIbr1[m]) = 1.0;
*(here->CPLnegIbr2[m]) = 1.0;
}
for (m = 0; m < noL; m++) {
for (p = 0; p < noL; p++) {
*(here->CPLibr1Pos[m][p]) =
cp->h1t[m][p]->aten + h1 * cp->h1C[m][p];
*(here->CPLibr2Neg[m][p]) =
cp->h1t[m][p]->aten + h1 * cp->h1C[m][p];
}
}
k = here->CPLibr1;
l = here->CPLibr2;
copy_cp(cp2, cp);
if (right_consts(here,cp2, time,time2,h,h1,k,l,ckt)) {
cp2->ext = 1;
for (q = 0; q < noL; q++) {
cp->ratio[q] = ratio[q];
if (ratio[q] > 0.0) {
for (m = 0; m < noL; m++) {
for (p = 0; p < noL; p++) {
if (cp->h3t[m][p][q]) {
f = ratio[q] * (h1 * cp->h3C[m][p][q] +
cp->h3t[m][p][q]->aten);
*(here->CPLibr1Neg[m][p]) = -f;
*(here->CPLibr2Pos[m][p]) = -f;
}
if (cp->h2t[m][p][q]) {
f = ratio[q] * (h1 * cp->h2C[m][p][q] +
cp->h2t[m][p][q]->aten);
*(here->CPLibr1Ibr2[m][p]) = -f;
*(here->CPLibr2Ibr1[m][p]) = -f;
}
}
}
}
}
}
else cp->ext = 0;
}
}
return(OK);
}
static void
copy_cp(new, old)
CPLine *new, *old;
{
int i, j, k, l, m;
VI_list *temp;
new->noL = m = old->noL;
new->ext = old->ext;
for (i = 0; i < m; i++) {
new->ratio[i] = old->ratio[i];
new->taul[i] = old->taul[i];
for (j = 0; j < m; j++) {
if (new->h1t[i][j] == NULL)
new->h1t[i][j] = (TMS *) malloc(sizeof (TMS));
new->h1t[i][j]->ifImg = old->h1t[i][j]->ifImg;
new->h1t[i][j]->aten = old->h1t[i][j]->aten;
new->h1C[i][j] = old->h1C[i][j];
for (k = 0; k < 3; k++) {
new->h1t[i][j]->tm[k].c = old->h1t[i][j]->tm[k].c;
new->h1t[i][j]->tm[k].x = old->h1t[i][j]->tm[k].x;
new->h1t[i][j]->tm[k].cnv_i = old->h1t[i][j]->tm[k].cnv_i;
new->h1t[i][j]->tm[k].cnv_o = old->h1t[i][j]->tm[k].cnv_o;
new->h1e[i][j][k] = old->h1e[i][j][k];
}
for (l = 0; l < m; l++) {
if (new->h2t[i][j][l] == NULL)
new->h2t[i][j][l] = (TMS *) malloc(sizeof (TMS));
new->h2t[i][j][l]->ifImg = old->h2t[i][j][l]->ifImg;
new->h2t[i][j][l]->aten = old->h2t[i][j][l]->aten;
new->h2C[i][j][l] = old->h2C[i][j][l];
new->h3C[i][j][l] = old->h3C[i][j][l];
for (k = 0; k < 3; k++) {
new->h2t[i][j][l]->tm[k].c = old->h2t[i][j][l]->tm[k].c;
new->h2t[i][j][l]->tm[k].x = old->h2t[i][j][l]->tm[k].x;
new->h2t[i][j][l]->tm[k].cnv_i
= old->h2t[i][j][l]->tm[k].cnv_i;
new->h2t[i][j][l]->tm[k].cnv_o
= old->h2t[i][j][l]->tm[k].cnv_o;
}
if (new->h3t[i][j][l] == NULL)
new->h3t[i][j][l] = (TMS *) malloc(sizeof (TMS));
new->h3t[i][j][l]->ifImg = old->h3t[i][j][l]->ifImg;
new->h3t[i][j][l]->aten = old->h3t[i][j][l]->aten;
for (k = 0; k < 3; k++) {
new->h3t[i][j][l]->tm[k].c = old->h3t[i][j][l]->tm[k].c;
new->h3t[i][j][l]->tm[k].x = old->h3t[i][j][l]->tm[k].x;
new->h3t[i][j][l]->tm[k].cnv_i
= old->h3t[i][j][l]->tm[k].cnv_i;
new->h3t[i][j][l]->tm[k].cnv_o
= old->h3t[i][j][l]->tm[k].cnv_o;
}
}
}
}
while (new->vi_head->time < old->vi_head->time) {
temp = new->vi_head;
new->vi_head = new->vi_head->next;
free_vi(temp);
}
}
static int
right_consts(here, cp, t, time, h, h1, l1, l2, ckt)
CPLinstance *here;
CPLine *cp;
int t, time;
double h, h1;
int *l1, *l2;
CKTcircuit *ckt;
{
int i, j, k, l;
double e;
double ff[MAX_CP_TX_LINES], gg[MAX_CP_TX_LINES];
double v1_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double v2_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i1_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i2_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double v1_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double v2_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i1_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i2_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
int ext;
register int noL;
noL = cp->noL;
for (j = 0; j < noL; j++) {
register double ff1;
ff[j] = 0.0;
gg[j] = 0.0;
for (k = 0; k < noL; k++)
if (cp->h1t[j][k]) {
if (cp->h1t[j][k]->ifImg) {
double er, ei, a, b, a1, b1;
TMS *tms;
tms = cp->h1t[j][k];
cp->h1e[j][k][0] = e = exp((double) tms->tm[0].x * h);
expC(tms->tm[1].x, tms->tm[2].x, h, &er, &ei);
cp->h1e[j][k][1] = er;
cp->h1e[j][k][2] = ei;
ff1 = tms->tm[0].c * e * h1;
ff[j] -= tms->tm[0].cnv_i * e;
gg[j] -= tms->tm[0].cnv_o * e;
ff[j] -= ff1 * cp->in_node[k]->V;
gg[j] -= ff1 * cp->out_node[k]->V;
multC(tms->tm[1].c, tms->tm[2].c, er, ei, &a1, &b1);
multC(tms->tm[1].cnv_i, tms->tm[2].cnv_i, er, ei, &a, &b);
ff[j] -= 2.0 * (a1 * h1 * cp->in_node[k]->V + a);
multC(tms->tm[1].cnv_o, tms->tm[2].cnv_o, er, ei, &a, &b);
gg[j] -= 2.0 * (a1 * h1 * cp->out_node[k]->V + a);
} else {
ff1 = 0.0;
for (i = 0; i < 3; i++) {
cp->h1e[j][k][i] = e = exp((double) cp->h1t[j][k]->tm[i].x * h);
ff1 -= cp->h1t[j][k]->tm[i].c * e;
ff[j] -= cp->h1t[j][k]->tm[i].cnv_i * e;
gg[j] -= cp->h1t[j][k]->tm[i].cnv_o * e;
}
ff[j] += ff1 * h1 * cp->in_node[k]->V;
gg[j] += ff1 * h1 * cp->out_node[k]->V;
}
}
}
ext = get_pvs_vi(t, time, cp, v1_i, v2_i, i1_i, i2_i,
v1_o, v2_o, i1_o, i2_o);
for (j = 0; j < noL; j++) { /** current eqn **/
register TERM *tm;
for (k = 0; k < noL; k++) /** node voltage **/
for (l = 0; l < noL; l++) /** different mode **/
if (cp->h3t[j][k][l]) {
if (cp->h3t[j][k][l]->ifImg) {
double er, ei, a, b, a1, b1, a2, b2;
register TMS *tms;
tms = cp->h3t[j][k][l];
expC(tms->tm[1].x, tms->tm[2].x, h, &er, &ei);
a2 = h1 * tms->tm[1].c;
b2 = h1 * tms->tm[2].c;
a = tms->tm[1].cnv_i;
b = tms->tm[2].cnv_i;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, (double) v1_i[l][k] * er + v2_i[l][k], (double) v1_i[l][k] * ei, &a1, &b1);
tms->tm[1].cnv_i = a + a1;
tms->tm[2].cnv_i = b + b1;
a = tms->tm[1].cnv_o;
b = tms->tm[2].cnv_o;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, (double) v1_o[l][k] * er + v2_o[l][k], (double) v1_o[l][k] * ei, &a1, &b1);
tms->tm[1].cnv_o = a + a1;
tms->tm[2].cnv_o = b + b1;
tm = &(tms->tm[0]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c *
(v1_i[l][k] * e + v2_i[l][k]);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c *
(v1_o[l][k] * e + v2_o[l][k]);
ff[j] += tms->aten * v2_o[l][k] + tm->cnv_o +
2.0 * tms->tm[1].cnv_o;
gg[j] += tms->aten * v2_i[l][k] + tm->cnv_i +
2.0 * tms->tm[1].cnv_i;
} else {
for (i = 0; i < 3; i++) { /** 3 poles **/
tm = &(cp->h3t[j][k][l]->tm[i]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c * (v1_i[l][k] * e + v2_i[l][k]);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c * (v1_o[l][k] * e + v2_o[l][k]);
ff[j] += tm->cnv_o;
gg[j] += tm->cnv_i;
}
ff[j] += cp->h3t[j][k][l]->aten * v2_o[l][k];
gg[j] += cp->h3t[j][k][l]->aten * v2_i[l][k];
}
}
for (k = 0; k < noL; k++) /** line current **/
for (l = 0; l < noL; l++) /** different mode **/
if (cp->h2t[j][k][l]) {
if (cp->h2t[j][k][l]->ifImg) {
double er, ei, a, b, a1, b1, a2, b2;
register TMS *tms;
tms = cp->h2t[j][k][l];
expC(tms->tm[1].x, tms->tm[2].x, h, &er, &ei);
a2 = h1 * tms->tm[1].c;
b2 = h1 * tms->tm[2].c;
a = tms->tm[1].cnv_i;
b = tms->tm[2].cnv_i;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, (double) i1_i[l][k] * er + i2_i[l][k], (double) i1_i[l][k] * ei, &a1, &b1);
tms->tm[1].cnv_i = a + a1;
tms->tm[2].cnv_i = b + b1;
a = tms->tm[1].cnv_o;
b = tms->tm[2].cnv_o;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, (double) i1_o[l][k] * er + i2_o[l][k], (double) i1_o[l][k] * ei, &a1, &b1);
tms->tm[1].cnv_o = a + a1;
tms->tm[2].cnv_o = b + b1;
tm = &(tms->tm[0]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c *
(i1_i[l][k] * e + i2_i[l][k]);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c *
(i1_o[l][k] * e + i2_o[l][k]);
ff[j] += tms->aten * i2_o[l][k] + tm->cnv_o +
2.0 * tms->tm[1].cnv_o;
gg[j] += tms->aten * i2_i[l][k] + tm->cnv_i +
2.0 * tms->tm[1].cnv_i;
} else {
for (i = 0; i < 3; i++) { /** 3 poles **/
tm = &(cp->h2t[j][k][l]->tm[i]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c * (i1_i[l][k] * e + i2_i[l][k]);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c * (i1_o[l][k] * e + i2_o[l][k]);
ff[j] += tm->cnv_o;
gg[j] += tm->cnv_i;
}
ff[j] += cp->h2t[j][k][l]->aten * i2_o[l][k];
gg[j] += cp->h2t[j][k][l]->aten * i2_i[l][k];
}
}
}
for (i = 0; i < noL; i++) {
*(ckt->CKTrhs + l1[i]) = ff[i];
*(ckt->CKTrhs + l2[i]) = gg[i];
}
return(ext);
}
static int
update_cnv(cp, h)
CPLine *cp;
float h;
{
int i, j, k;
register int noL;
double ai, bi, ao, bo;
double e, t;
register TMS *tms;
register TERM *tm;
noL = cp->noL;
for (j = 0; j < noL; j++)
for (k = 0; k < noL; k++) {
ai = cp->in_node[k]->V;
ao = cp->out_node[k]->V;
bi = cp->in_node[k]->dv;
bo = cp->out_node[k]->dv;
if (cp->h1t[j][k]) {
if (cp->h1t[j][k]->ifImg) {
tms = cp->h1t[j][k];
if (tms == NULL)
continue;
tm = &(tms->tm[0]);
e = cp->h1e[j][k][0];
t = tm->c / tm->x;
update_cnv_a(tms, h, ai, ao, ai - bi * h, ao - bo * h,
cp->h1e[j][k][1], cp->h1e[j][k][2]);
bi *= t;
bo *= t;
tm->cnv_i = (tm->cnv_i - bi*h) * e + (e - 1.0)*(ai*t +
1.0e+12*bi/tm->x);
tm->cnv_o = (tm->cnv_o - bo*h) * e + (e - 1.0)*(ao*t +
1.0e+12*bo/tm->x);
} else
for (i = 0; i < 3; i++) {
tm = &(cp->h1t[j][k]->tm[i]);
e = cp->h1e[j][k][i];
t = tm->c / tm->x;
bi *= t;
bo *= t;
tm->cnv_i = (tm->cnv_i - bi*h) * e + (e - 1.0)*(ai*t + 1.0e+12*bi/tm->x);
tm->cnv_o = (tm->cnv_o - bo*h) * e + (e - 1.0)*(ao*t + 1.0e+12*bo/tm->x);
}
}
}
return 0;
}
static VI_list
*new_vi()
{
VI_list *q;
if (pool_vi) {
q = pool_vi;
pool_vi = pool_vi->pool;
return(q);
} else return((VI_list *) malloc (sizeof (VI_list)));
}
static void
free_vi(q)
VI_list *q;
{
q->pool = pool_vi;
pool_vi = q;
}
static int
add_new_vi(here, ckt, time)
CPLinstance *here;
CKTcircuit *ckt;
int time;
{
VI_list *vi;
register int i, noL;
CPLine *cp, *cp2;
cp = here->cplines;
cp2 = here->cplines2;
vi = new_vi();
vi->time = time;
noL = cp->noL;
for (i = 0; i < noL; i++) {
/*
vi->v_i[i] = cp->in_node[i]->V;
vi->v_o[i] = cp->out_node[i]->V;
*/
vi->v_i[i] = *(ckt->CKTrhsOld + here->CPLposNodes[i]);
vi->v_o[i] = *(ckt->CKTrhsOld + here->CPLnegNodes[i]);
vi->i_i[i] = *(ckt->CKTrhsOld + here->CPLibr1[i]);
vi->i_o[i] = *(ckt->CKTrhsOld + here->CPLibr2[i]);
}
cp->vi_tail->next = vi;
cp2->vi_tail->next = vi;
vi->next = NULL;
cp->vi_tail = vi;
cp2->vi_tail = vi;
return(1);
}
static int
get_pvs_vi(t1, t2, cp, v1_i, v2_i, i1_i, i2_i, v1_o, v2_o, i1_o, i2_o)
CPLine *cp;
int t1, t2;
double v1_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double v2_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i1_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i2_i[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double v1_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double v2_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i1_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
double i2_o[MAX_CP_TX_LINES][MAX_CP_TX_LINES];
{
double ta[MAX_CP_TX_LINES], tb[MAX_CP_TX_LINES];
register VI_list *vi, *vi1;
register double f;
register int i, j;
int mini = -1;
double minta = 123456789.0;
int ext = 0;
register int noL;
noL = cp->noL;
for (i = 0; i < noL; i++) {
ta[i] = t1 - cp->taul[i];
tb[i] = t2 - cp->taul[i];
if (ta[i] < minta) {
minta = ta[i];
mini = i;
}
}
for (i = 0; i < noL; i++) {
ratio[i] = 0.0;
if (tb[i] <= 0) {
for (j = 0; j < noL; j++) {
i1_i[i][j] = i2_i[i][j] = i1_o[i][j] = i2_o[i][j] = 0.0;
v1_i[i][j] = v2_i[i][j] = cp->dc1[j];
v1_o[i][j] = v2_o[i][j] = cp->dc2[j];
}
} else {
if (ta[i] <= 0) {
for (j = 0; j < noL; j++) {
i1_i[i][j] = i1_o[i][j] = 0.0;
v1_i[i][j] = cp->dc1[j];
v1_o[i][j] = cp->dc2[j];
}
vi1 = cp->vi_head;
vi = vi1->next;
} else {
vi1 = cp->vi_head;
for (vi = vi1->next; vi->time < ta[i]; ) {
/* if (i == mini)
free_vi(vi1); */
vi1 = vi;
/* new */
vi = vi->next;
if (vi == NULL) goto errordetect;
}
f = (ta[i] - vi1->time) / (vi->time - vi1->time);
for (j = 0; j < noL; j++) {
v1_i[i][j] = vi1->v_i[j] + f * (vi->v_i[j] - vi1->v_i[j]);
v1_o[i][j] = vi1->v_o[j] + f * (vi->v_o[j] - vi1->v_o[j]);
i1_i[i][j] = vi1->i_i[j] + f * (vi->i_i[j] - vi1->i_i[j]);
i1_o[i][j] = vi1->i_o[j] + f * (vi->i_o[j] - vi1->i_o[j]);
}
if (i == mini)
cp->vi_head = vi1;
}
if (tb[i] > t1) {
/*
fprintf(stderr, "pvs: time = %d\n", t2);
*/
ext = 1;
ratio[i] = f = (tb[i] - t1) / (t2 - t1);
if (vi)
for (; vi->next; vi = vi->next);
else
vi = vi1;
f = 1 - f;
for (j = 0; j < noL; j++) {
v2_i[i][j] = vi->v_i[j] * f;
v2_o[i][j] = vi->v_o[j] * f;
i2_i[i][j] = vi->i_i[j] * f;
i2_o[i][j] = vi->i_o[j] * f;
}
} else {
for (; vi->time < tb[i];) {
vi1 = vi;
/* new */
vi = vi->next;
if (vi == NULL) goto errordetect;
}
f = (tb[i] - vi1->time) / (vi->time - vi1->time);
for (j = 0; j < noL; j++) {
v2_i[i][j] = vi1->v_i[j] + f * (vi->v_i[j] - vi1->v_i[j]);
v2_o[i][j] = vi1->v_o[j] + f * (vi->v_o[j] - vi1->v_o[j]);
i2_i[i][j] = vi1->i_i[j] + f * (vi->i_i[j] - vi1->i_i[j]);
i2_o[i][j] = vi1->i_o[j] + f * (vi->i_o[j] - vi1->i_o[j]);
}
}
}
}
return(ext);
errordetect:
fprintf(stderr, "your maximum time step is too large for tau.\n");
fprintf(stderr, "decrease max time step in .tran card and try again\n");
exit(0);
}
static int
update_delayed_cnv(cp, h)
CPLine *cp;
float h;
{
int i, j, k;
float *ratio;
register double f;
register VI_list *vi;
register TMS *tms;
register int noL;
h *= 0.5e-12;
ratio = cp->ratio;
vi = cp->vi_tail;
noL = cp->noL;
for (k = 0; k < noL; k++) /* mode */
if (ratio[k] > 0.0)
for (i = 0; i < noL; i++) /* current eqn */
for (j = 0; j < noL; j++) {
tms = cp->h3t[i][j][k];
if (tms == NULL)
continue;
f = h * ratio[k] * vi->v_i[j];
tms->tm[0].cnv_i += f * tms->tm[0].c;
tms->tm[1].cnv_i += f * tms->tm[1].c;
tms->tm[2].cnv_i += f * tms->tm[2].c;
f = h * ratio[k] * vi->v_o[j];
tms->tm[0].cnv_o += f * tms->tm[0].c;
tms->tm[1].cnv_o += f * tms->tm[1].c;
tms->tm[2].cnv_o += f * tms->tm[2].c;
tms = cp->h2t[i][j][k];
f = h * ratio[k] * vi->i_i[j];
tms->tm[0].cnv_i += f * tms->tm[0].c;
tms->tm[1].cnv_i += f * tms->tm[1].c;
tms->tm[2].cnv_i += f * tms->tm[2].c;
f = h * ratio[k] * vi->i_o[j];
tms->tm[0].cnv_o += f * tms->tm[0].c;
tms->tm[1].cnv_o += f * tms->tm[1].c;
tms->tm[2].cnv_o += f * tms->tm[2].c;
}
return(1);
}
static int expC(ar, ai, h, cr, ci)
double ar, ai, *cr, *ci;
double h;
{
double e, cs, si;
e = exp((double) ar * h);
cs = cos((double) ai * h);
si = sin((double) ai * h);
*cr = e * cs;
*ci = e * si;
return(1);
}
static int multC(ar, ai, br, bi, cr, ci)
double ar, ai, br, bi;
double *cr, *ci;
{
register double tp;
tp = ar*br - ai*bi;
*ci = ar*bi+ai*br;
*cr = tp;
return (1);
}
static void
update_cnv_a(tms, h, ai, ao, bi, bo, er, ei)
TMS *tms;
float h;
double ai, bi, ao, bo;
double er, ei;
{
double a, b, a1, b1;
h *= 0.5e-12;
multC(tms->tm[1].c, tms->tm[2].c, er, ei, &a1, &b1);
multC(tms->tm[1].cnv_i, tms->tm[2].cnv_i, er, ei, &a, &b);
tms->tm[1].cnv_i = a + h * (a1 * bi + ai * tms->tm[1].c);
tms->tm[2].cnv_i = b + h * (b1 * bi + ai * tms->tm[2].c);
multC(tms->tm[1].cnv_o, tms->tm[2].cnv_o, er, ei, &a, &b);
tms->tm[1].cnv_o = a + h * (a1 * bo + ao * tms->tm[1].c);
tms->tm[2].cnv_o = b + h * (b1 * bo + ao * tms->tm[2].c);
}
static int divC(ar, ai, br, bi, cr, ci)
double ar, ai, br, bi;
double *cr, *ci;
{
double t;
t = br*br + bi*bi;
*cr = (ar*br + ai*bi) / t;
*ci = (ai*br - ar*bi) / t;
return(1);
}

View File

@ -0,0 +1,45 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cpldefs.h"
#include "sperror.h"
#include "suffix.h"
int
CPLmDelete(inModel,modname,kill)
GENmodel **inModel;
IFuid modname;
GENmodel *kill;
{
CPLmodel **model = (CPLmodel **)inModel;
CPLmodel *modfast = (CPLmodel *)kill;
CPLinstance *here;
CPLinstance *prev = NULL;
CPLmodel **oldmod;
oldmod = model;
for( ; *model ; model = &((*model)->CPLnextModel)) {
if( (*model)->CPLmodName == modname ||
(modfast && *model == modfast) ) goto delgot;
oldmod = model;
}
return(E_NOMOD);
delgot:
*oldmod = (*model)->CPLnextModel; /* cut deleted device out of list */
for(here = (*model)->CPLinstances ; here ; here = here->CPLnextInstance) {
if(prev) FREE(prev);
prev = here;
}
if(prev) FREE(prev);
FREE(*model);
return(OK);
}

View File

@ -0,0 +1,51 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "const.h"
#include "ifsim.h"
#include "cpldefs.h"
#include "sperror.h"
#include "suffix.h"
int
CPLmParam(param,value,inModel)
int param;
IFvalue *value;
GENmodel *inModel;
{
register CPLmodel *model = (CPLmodel *)inModel;
switch(param) {
case CPL_R:
model->Rm = value->v.vec.rVec;
model->Rmgiven = TRUE;
break;
case CPL_L:
model->Lm = value->v.vec.rVec;
model->Lmgiven = TRUE;
break;
case CPL_G:
model->Gm = value->v.vec.rVec;
model->Gmgiven = TRUE;
break;
case CPL_C:
model->Cm = value->v.vec.rVec;
model->Cmgiven = TRUE;
break;
case CPL_length:
model->length = value->rValue;
model->lengthgiven = TRUE;
break;
case CPL_MOD_R:
break;
default:
return(E_BADPARM);
}
return(OK);
}

View File

@ -0,0 +1,45 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "const.h"
#include "ifsim.h"
#include "cpldefs.h"
#include "sperror.h"
#include "suffix.h"
/* ARGSUSED */
int
CPLparam(param,value,inst,select)
int param;
IFvalue *value;
GENinstance *inst;
IFvalue *select;
{
CPLinstance *here = (CPLinstance *)inst;
switch(param) {
case CPL_POS_NODE:
here->in_node_names = value->v.vec.sVec;
break;
case CPL_NEG_NODE:
here->out_node_names = value->v.vec.sVec;
break;
case CPL_DIM:
here->dimension = value->iValue;
break;
case CPL_LENGTH:
here->CPLlength = value->rValue;
here->CPLlengthgiven = TRUE;
break;
default:
return(E_BADPARM);
}
return(OK);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
## Process this file with automake to produce Makefile.in
pkglib_LTLIBRARIES = libtxl.la
libtxl_la_SOURCES = \
txl.c \
txlask.c \
txldest.c \
txlload.c \
txlmdel.c \
txlparam.c \
txlacct.c \
txldel.c \
txlmask.c \
txlmpar.c \
txlsetup.c \
txlinit.c
INCLUDES = -I$(top_srcdir)/src/include
MAINTAINERCLEANFILES = Makefile.in

View File

@ -0,0 +1,38 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "txldefs.h"
#include "devdefs.h"
#include "ifsim.h"
#include "suffix.h"
IFparm TXLpTable[] = {
IP("pos_node", TXL_IN_NODE, IF_INTEGER,"Positive node of txl"),
IP("neg_node", TXL_OUT_NODE, IF_INTEGER,"Negative node of txl"),
IOP("length", TXL_LENGTH, IF_REAL,"length of line"),
};
IFparm TXLmPTable[] = { /* model parameters */
IOP( "r", TXL_R, IF_REAL,"resistance per length"),
IOP( "l", TXL_L, IF_REAL,"inductance per length"),
IOP( "c", TXL_C, IF_REAL,"capacitance per length"),
IOP( "g", TXL_G, IF_REAL,"conductance per length"),
IOP( "length", TXL_length, IF_REAL,"length"),
IP( "txl", TXL_MOD_R, IF_FLAG,"Device is a txl model"),
};
char *TXLnames[] = {
"Y+",
"Y-"
};
int TXLnSize = NUMELEMS(TXLnames);
int TXLiSize = sizeof(TXLinstance);
int TXLmSize = sizeof(TXLmodel);
int TXLmPTSize = NUMELEMS(TXLmPTable);
int TXLpTSize = NUMELEMS(TXLpTable);

View File

@ -0,0 +1,76 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include <math.h>
#include "cktdefs.h"
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
int
TXLaccept(ckt,inModel)
register CKTcircuit *ckt;
GENmodel *inModel;
/* set up the breakpoint table.
*/
{
register TXLmodel *model = (TXLmodel *)inModel;
register TXLinstance *here;
int hint;
double h, v, v1;
NODE *nd;
TXLine *tx;
/* loop through all the voltage source models */
for( ; model != NULL; model = model->TXLnextModel ) {
/* loop through all the instances of the model */
for (here = model->TXLinstances; here != NULL ;
here=here->TXLnextInstance) {
h = ckt->CKTdelta;
hint = (int) (h * 1e12);
if (hint != 0) {
tx = here->txline;
nd = tx->in_node;
if (nd->dvtag == 0) {
v = nd->V;
v1 = nd->V = *(ckt->CKTrhs + here->TXLposNode);
nd->dv = (v1 - v) / hint;
nd->dvtag = 1;
}
nd = tx->out_node;
if (nd->dvtag == 0) {
v = nd->V;
v1 = nd->V = *(ckt->CKTrhs + here->TXLnegNode);
nd->dv = (v1 - v) / hint;
nd->dvtag = 1;
}
}
else {
/* can't happen. */
printf("zero h detected\n");
exit(1);
}
}
}
model = (TXLmodel *)inModel;
for( ; model != NULL; model = model->TXLnextModel ) {
for (here = model->TXLinstances; here != NULL ;
here=here->TXLnextInstance) {
nd = here->txline->in_node;
nd->dvtag = 0;
nd = here->txline->out_node;
nd->dvtag = 0;
}
}
return(OK);
}

View File

@ -0,0 +1,43 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include <math.h>
#include "const.h"
#include "txldefs.h"
#include "ifsim.h"
#include "cktdefs.h"
#include "sperror.h"
#include "suffix.h"
/*ARGSUSED*/
int
TXLask(ckt,inst,which,value,select)
CKTcircuit *ckt;
GENinstance *inst;
int which;
IFvalue *value;
IFvalue *select;
{
TXLinstance *fast = (TXLinstance *)inst;
switch(which) {
case TXL_OUT_NODE:
value->iValue = fast->TXLnegNode;
return(OK);
case TXL_IN_NODE:
value->iValue = fast->TXLposNode;
return(OK);
case TXL_LENGTH:
value->rValue = fast->TXLlength;
return(OK);
default:
return(E_BADPARM);
}
/* NOTREACHED */
}

View File

@ -0,0 +1,92 @@
#ifndef TXL
#define TXL
#include "ifsim.h"
#include "cktdefs.h"
#include "gendefs.h"
#include "complex.h"
#include "noisedef.h"
#include "swec.h"
/* information used to describe a single instance */
typedef struct sTXLinstance {
struct sTXLmodel *TXLmodPtr; /* backpointer to model */
struct sTXLinstance *TXLnextInstance; /* pointer to next instance of
* current model*/
IFuid TXLname; /* pointer to character string naming this instance */
int TXLposNode;
int TXLnegNode;
double TXLlength;
int TXLibr1;
int TXLibr2;
TXLine *txline; /* pointer to SWEC txline type */
TXLine *txline2; /* pointer to SWEC txline type. temporary storage */
char *in_node_name;
char *out_node_name;
double *TXLposPosptr;
double *TXLposNegptr;
double *TXLnegPosptr;
double *TXLnegNegptr;
double *TXLibr1Posptr;
double *TXLibr2Negptr;
double *TXLposIbr1ptr;
double *TXLnegIbr2ptr;
double *TXLibr1Negptr;
double *TXLibr2Posptr;
double *TXLibr1Ibr1ptr;
double *TXLibr2Ibr2ptr;
double *TXLibr1Ibr2ptr;
double *TXLibr2Ibr1ptr;
unsigned TXLibr1Given : 1;
unsigned TXLibr2Given : 1;
unsigned TXLdcGiven : 1;
unsigned TXLlengthgiven : 1; /* flag to indicate C was specified */
} TXLinstance ;
/* per model data */
typedef struct sTXLmodel { /* model structure for a txl */
int TXLmodType; /* type index of this device type */
struct sTXLmodel *TXLnextModel; /* pointer to next possible model in
* linked list */
TXLinstance * TXLinstances; /* pointer to list of instances that have this
* model */
IFuid TXLmodName; /* pointer to character string naming this model */
double R;
double L;
double G;
double C;
double length;
unsigned Rgiven : 1; /* flag to indicate R was specified */
unsigned Lgiven : 1; /* flag to indicate L was specified */
unsigned Ggiven : 1; /* flag to indicate G was specified */
unsigned Cgiven : 1; /* flag to indicate C was specified */
unsigned lengthgiven : 1; /* flag to indicate C was specified */
} TXLmodel;
/* instance parameters */
#define TXL_IN_NODE 1
#define TXL_OUT_NODE 2
#define TXL_LENGTH 3
/* model parameters */
#define TXL_R 101
#define TXL_C 102
#define TXL_G 103
#define TXL_L 104
#define TXL_length 105
#define TXL_MOD_R 106
#include "txlext.h"
extern VI_list_txl *pool_vi_txl;
#endif /*TXL*/

View File

@ -0,0 +1,38 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
int
TXLdelete(inModel,name,inst)
GENmodel *inModel;
IFuid name;
GENinstance **inst;
{
TXLmodel *model = (TXLmodel *)inModel;
TXLinstance **fast = (TXLinstance **)inst;
TXLinstance **prev = NULL;
TXLinstance *here;
for( ; model ; model = model->TXLnextModel) {
prev = &(model->TXLinstances);
for(here = *prev; here ; here = *prev) {
if(here->TXLname == name || (fast && here==*fast) ) {
*prev= here->TXLnextInstance;
FREE(here);
return(OK);
}
prev = &(here->TXLnextInstance);
}
}
return(E_NODEV);
}

View File

@ -0,0 +1,36 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "txldefs.h"
#include "suffix.h"
void
TXLdestroy(inModel)
GENmodel **inModel;
{
TXLmodel **model = (TXLmodel **)inModel;
TXLinstance *here;
TXLinstance *prev = NULL;
TXLmodel *mod = *model;
TXLmodel *oldmod = NULL;
for( ; mod ; mod = mod->TXLnextModel) {
if(oldmod) FREE(oldmod);
oldmod = mod;
prev = (TXLinstance *)NULL;
for(here = mod->TXLinstances ; here ; here = here->TXLnextInstance) {
if(prev) FREE(prev);
prev = here;
}
if(prev) FREE(prev);
}
if(oldmod) FREE(oldmod);
*model = NULL;
}

View File

@ -0,0 +1,19 @@
#ifdef __STDC__
/* extern int TXLaccept(CKTcircuit*,GENmodel*); */
extern int TXLdelete(GENmodel*,IFuid,GENinstance**);
extern void TXLdestroy(GENmodel**);
extern int TXLload(GENmodel*,CKTcircuit*);
extern int TXLmDelete(GENmodel**,IFuid,GENmodel*);
extern int TXLmParam(int,IFvalue*,GENmodel*);
extern int TXLparam(int,IFvalue*,GENinstance*,IFvalue*);
extern int TXLsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*);
#else /* stdc */
/* extern int TXLaccept(); */
extern int TXLdelete();
extern void TXLdestroy();
extern int TXLload();
extern int TXLmDelete();
extern int TXLmParam();
extern int TXLparam();
extern int TXLsetup();
#endif /* stdc */

View File

@ -0,0 +1,41 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "cktdefs.h"
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
int
TXLfindBr(ckt,inModel,name)
register CKTcircuit *ckt;
GENmodel *inModel;
register IFuid name;
{
register TXLmodel *model = (TXLmodel *)inModel;
register TXLinstance *here;
int error;
CKTnode *tmp;
for( ; model != NULL; model = model->TXLnextModel) {
for (here = model->TXLinstances; here != NULL;
here = here->TXLnextInstance) {
if(here->TXLname == name) {
if(here->TXLbranch == 0) {
error = CKTmkCur(ckt,&tmp,here->TXLname,"branch");
if(error) return(error);
here->TXLbranch = tmp->number;
}
return(here->TXLbranch);
}
}
}
return(0);
}

View File

@ -0,0 +1,73 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include <config.h>
#include <devdefs.h>
#include "txlitf.h"
#include "txlext.h"
#include "txlinit.h"
SPICEdev TXLinfo = {
{
"TransLine",
"Simple Lossy Transmission Line",
&TXLnSize,
&TXLnSize,
TXLnames,
&TXLpTSize,
TXLpTable,
&TXLmPTSize,
TXLmPTable,
},
TXLparam,
TXLmParam,
TXLload,
TXLsetup,
NULL,
NULL,
NULL,
NULL,
NULL, /* TXLfindBranch, */
TXLload, /* ac load */
NULL,
TXLdestroy,
#ifdef DELETES
TXLmDelete,
TXLdelete,
#else /* DELETES */
NULL,
NULL,
#endif /* DELETES */
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&TXLiSize,
&TXLmSize
};
SPICEdev *
get_txl_info(void)
{
return &TXLinfo;
}

View File

@ -0,0 +1,18 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#ifndef _TXLINIT_H
#define _TXLINIT_H
extern IFparm TXLpTable[ ];
extern IFparm TXLmPTable[ ];
extern int TXLmPTSize;
extern int TXLpTSize;
extern char *TXLnames[ ];
extern int TXLiSize;
extern int TXLmSize;
extern int TXLnSize;
#endif

View File

@ -0,0 +1,12 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#ifndef DEV_TXL
#define DEV_TXL
SPICEdev *get_txl_info(void);
#endif

View File

@ -0,0 +1,689 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
VI_list_txl *pool_vi_txl;
static double ratio[MAX_CP_TX_LINES];
static int update_cnv_txl();
static VI_list_txl *new_vi_txl();
static void free_vi_txl();
static int add_new_vi_txl();
static int get_pvs_vi_txl();
static int right_consts_txl();
static int update_delayed_cnv_txl();
static int multC();
static int expC();
static void copy_tx();
/*static char *message = "tau of txl line is larger than max time step";*/
/*ARGSUSED*/
int
TXLload(inModel,ckt)
GENmodel *inModel;
CKTcircuit *ckt;
{
register TXLmodel *model = (TXLmodel *)inModel;
register TXLinstance *here;
TXLine *tx, *tx2;
int k, l;
int time, time2;
double h, h1, f;
int hint;
float hf;
NODE *nd;
double v, v1, g;
int cond1;
CKTnode *node;
VI_list_txl *vi, *vi_before;
int i, before, delta;
/* debug
printf("before txlload\n");
SMPprint(ckt->CKTmatrix, stdout);
*/
h = ckt->CKTdelta;
h1 = 0.5 * h;
time2 = (int) (ckt->CKTtime * 1e12);
hint = (int)(h * 1e12);
hf = (float)(h * 1e12);
time = (int) ((ckt->CKTtime - ckt->CKTdelta) * 1e12);
cond1= ckt->CKTmode & MODEDC;
for( ; model != NULL; model = model->TXLnextModel ) {
for (here = model->TXLinstances; here != NULL ;
here=here->TXLnextInstance) {
tx = here->txline;
if (cond1 || tx->vi_head == NULL) continue;
if (time < tx->vi_tail->time) {
time = tx->vi_tail->time;
hint = time2 - time;
}
vi_before = tx->vi_tail;
before = tx->vi_tail->time;
if (time > tx->vi_tail->time) {
copy_tx(tx, here->txline2);
add_new_vi_txl(here, ckt, time);
delta = time - before;
nd = tx->in_node;
v = vi_before->v_i;
nd->V = tx->vi_tail->v_i;
v1 = nd->V;
nd->dv = (v1 - v) / delta;
nd = tx->out_node;
v = vi_before->v_o;
v1 = nd->V = tx->vi_tail->v_o;
nd->dv = (v1 - v) / delta;
if (tx->lsl) continue;
update_cnv_txl(tx, (float) delta);
if (tx->ext) update_delayed_cnv_txl(tx, (float) delta);
}
}
}
model = (TXLmodel *)inModel;
for( ; model != NULL; model = model->TXLnextModel ) {
for (here = model->TXLinstances; here != NULL ;
here=here->TXLnextInstance) {
tx = here->txline;
tx2 = here->txline2;
if (!tx->lsl && hf > tx->taul) {
fprintf(stderr, "your time step is too large for tau.\n");
fprintf(stderr, "please decrease max time step in .tran card.\n");
fprintf(stderr, ".tran tstep tstop tstart tmax.\n");
fprintf(stderr, "make tmax smaller than %e and try again.\n",
tx->taul * 1e-12);
return (1111);
}
if (cond1) {
if (here->TXLlengthgiven)
g = model->R * here->TXLlength;
else g = model->R * here->TXLmodPtr->length;
*(here->TXLposIbr1ptr) += 1.0;
*(here->TXLnegIbr2ptr) += 1.0;
*(here->TXLibr1Ibr1ptr) += 1.0;
*(here->TXLibr1Ibr2ptr) += 1.0;
*(here->TXLibr2Posptr) += 1.0;
*(here->TXLibr2Negptr) -= 1.0;
*(here->TXLibr2Ibr1ptr) -= g;
continue;
}
/* dc setup */
if (here->TXLdcGiven == 0 && !cond1) {
nd = tx->in_node;
for (node = ckt->CKTnodes;node; node = node->next) {
if (strcmp(nd->name->id, node->name) == 0) {
tx->dc1 = tx2->dc1 = ckt->CKTrhsOld[node->number];
nd->V = tx->dc1;
break;
}
}
nd = tx->out_node;
for (node = ckt->CKTnodes;node; node = node->next) {
if (strcmp(nd->name->id, node->name) == 0) {
tx->dc2 = tx2->dc2 = ckt->CKTrhsOld[node->number];
nd->V = tx->dc2;
break;
}
}
here->TXLdcGiven = 1;
vi = new_vi_txl();
vi->time = 0;
vi->i_i = *(ckt->CKTrhsOld + here->TXLibr1);
vi->i_o = *(ckt->CKTrhsOld + here->TXLibr2);
vi->v_i = tx->dc1;
vi->v_o = tx->dc2;
for (i = 0; i < 3; i++) {
tx->h1_term[i].cnv_i =
- tx->dc1 * tx->h1_term[i].c / tx->h1_term[i].x;
tx->h1_term[i].cnv_o =
- tx->dc2 * tx->h1_term[i].c / tx->h1_term[i].x;
}
for (i = 0; i < 3; i++) {
tx->h2_term[i].cnv_i = 0.0;
tx->h2_term[i].cnv_o = 0.0;
}
for (i = 0; i < 6; i++) {
tx->h3_term[i].cnv_i =
- tx->dc1 * tx->h3_term[i].c / tx->h3_term[i].x;
tx->h3_term[i].cnv_o =
- tx->dc2 * tx->h3_term[i].c / tx->h3_term[i].x;
}
vi->next = NULL;
tx->vi_tail = vi;
tx->vi_head = vi;
here->txline2->vi_tail = vi;
here->txline2->vi_head = vi;
}
/* change 6,6 1/18/93
*(here->TXLibr1Ibr1ptr) -= 1.0;
*(here->TXLibr2Ibr2ptr) -= 1.0;
*(here->TXLposIbr1ptr) += 1.0;
*(here->TXLnegIbr2ptr) += 1.0;
*(here->TXLibr1Posptr) += tx->sqtCdL + h1 * tx->h1C;
*(here->TXLibr2Negptr) += tx->sqtCdL + h1 * tx->h1C;
*/
*(here->TXLibr1Ibr1ptr) = -1.0;
*(here->TXLibr2Ibr2ptr) = -1.0;
*(here->TXLposIbr1ptr) = 1.0;
*(here->TXLnegIbr2ptr) = 1.0;
*(here->TXLibr1Posptr) = tx->sqtCdL + h1 * tx->h1C;
*(here->TXLibr2Negptr) = tx->sqtCdL + h1 * tx->h1C;
k = here->TXLibr1;
l = here->TXLibr2;
copy_tx(tx2, tx);
if (right_consts_txl(tx2, time, time2, h, h1, k, l, ckt)) {
if (tx->lsl) {
f = ratio[0] * tx->h3_aten;
*(here->TXLibr1Negptr) = -f;
*(here->TXLibr2Posptr) = -f;
f = ratio[0] * tx->h2_aten;
*(here->TXLibr1Ibr2ptr) = -f;
*(here->TXLibr2Ibr1ptr) = -f;
}
else {
tx->ext = 1;
tx->ratio = ratio[0];
if (ratio[0] > 0.0) {
f = ratio[0] * (h1 * (tx->h3_term[0].c
+ tx->h3_term[1].c + tx->h3_term[2].c
+ tx->h3_term[3].c + tx->h3_term[4].c
+ tx->h3_term[5].c ) + tx->h3_aten);
*(here->TXLibr1Negptr) = -f;
*(here->TXLibr2Posptr) = -f;
f = ratio[0] * (h1 * ( tx->h2_term[0].c
+ tx->h2_term[1].c + tx->h2_term[2].c )
+ tx->h2_aten);
*(here->TXLibr1Ibr2ptr) = -f;
*(here->TXLibr2Ibr1ptr) = -f;
}
}
}
else tx->ext = 0;
}
}
if (cond1) return (OK);
/* debug
printf("after txlload\n");
SMPprint(ckt->CKTmatrix, stdout);
*/
return(OK);
}
static void copy_tx(new, old)
TXLine *new, *old;
{
int i;
VI_list_txl *temp;
new->lsl = old->lsl;
new->ext = old->ext;
new->ratio = old->ratio;
new->taul = old->taul;
new->sqtCdL = old->sqtCdL;
new->h2_aten = old->h2_aten;
new->h3_aten = old->h3_aten;
new->h1C = old->h1C;
for (i= 0; i < 3; i++) {
new->h1e[i] = old->h1e[i];
new->h1_term[i].c = old->h1_term[i].c;
new->h1_term[i].x = old->h1_term[i].x;
new->h1_term[i].cnv_i = old->h1_term[i].cnv_i;
new->h1_term[i].cnv_o = old->h1_term[i].cnv_o;
new->h2_term[i].c = old->h2_term[i].c;
new->h2_term[i].x = old->h2_term[i].x;
new->h2_term[i].cnv_i = old->h2_term[i].cnv_i;
new->h2_term[i].cnv_o = old->h2_term[i].cnv_o;
}
for (i= 0; i < 6; i++) {
new->h3_term[i].c = old->h3_term[i].c;
new->h3_term[i].x = old->h3_term[i].x;
new->h3_term[i].cnv_i = old->h3_term[i].cnv_i;
new->h3_term[i].cnv_o = old->h3_term[i].cnv_o;
}
new->ifImg = old->ifImg;
if (new->vi_tail != old->vi_tail) {
/* someting wrong */
exit (0);
}
while (new->vi_head->time < old->vi_head->time) {
temp = new->vi_head;
new->vi_head = new->vi_head->next;
free_vi_txl(temp);
}
}
static int update_cnv_txl(tx, h)
TXLine *tx;
float h;
{
int i;
double ai, bi, ao, bo;
register double e, t;
ai = tx->in_node->V;
ao = tx->out_node->V;
bi = tx->in_node->dv;
bo = tx->out_node->dv;
for (i = 0; i < 3; i++) {
register TERM *tm;
tm = &(tx->h1_term[i]);
e = tx->h1e[i];
t = tm->c / tm->x;
bi *= t;
bo *= t;
tm->cnv_i = (tm->cnv_i - bi*h) * e + (e - 1.0)*(ai*t + 1.0e+12*bi/tm->x);
tm->cnv_o = (tm->cnv_o - bo*h) * e + (e - 1.0)*(ao*t + 1.0e+12*bo/tm->x);
}
return (1);
}
static VI_list_txl
*new_vi_txl()
{
VI_list_txl *q;
if (pool_vi_txl) {
q = pool_vi_txl;
pool_vi_txl = pool_vi_txl->pool;
return(q);
} else
return((VI_list_txl *) malloc (sizeof (VI_list_txl)));
}
static void
free_vi_txl(q)
VI_list_txl *q;
{
q->pool = pool_vi_txl;
pool_vi_txl = q;
}
static int add_new_vi_txl(here, ckt, time)
TXLinstance *here;
CKTcircuit *ckt;
int time;
{
VI_list_txl *vi;
TXLine *tx, *tx2;
tx = here->txline;
tx2 = here->txline2;
vi = new_vi_txl();
vi->time = time;
tx->vi_tail->next = vi;
tx2->vi_tail->next = vi;
vi->next = NULL;
tx->vi_tail = vi;
tx2->vi_tail = vi;
vi->v_i = *(ckt->CKTrhsOld + here->TXLposNode);
vi->v_o = *(ckt->CKTrhsOld + here->TXLnegNode);
vi->i_i = *(ckt->CKTrhsOld + here->TXLibr1);
vi->i_o = *(ckt->CKTrhsOld + here->TXLibr2);
return(1);
}
static int
get_pvs_vi_txl(t1, t2, tx, v1_i, v2_i, i1_i, i2_i, v1_o, v2_o, i1_o, i2_o)
TXLine *tx;
int t1, t2;
double *v1_i, *v2_i, *i1_i, *i2_i, *v1_o, *v2_o, *i1_o, *i2_o;
{
double ta, tb;
register VI_list_txl *vi, *vi1;
register double f;
int ext = 0;
ta = t1 - tx->taul;
tb = t2 - tx->taul;
if (tb <= 0) {
*v1_i = *v2_i = tx->dc1;
*v2_o = *v1_o = tx->dc2;
*i1_i = *i2_i = *i1_o = *i2_o = 0;
return(ext);
}
if (ta <= 0) {
*i1_i = *i1_o = 0.0;
*v1_i = tx->dc1;
*v1_o = tx->dc2;
vi1 = tx->vi_head;
vi = vi1->next;
} else {
vi1 = tx->vi_head;
for (vi = vi1->next; vi->time < ta; vi = vi->next) {
/* free_vi_txl(vi1); */
vi1 = vi;
}
f = (ta - vi1->time) / (vi->time - vi1->time);
*v1_i = vi1->v_i + f * (vi->v_i - vi1->v_i);
*v1_o = vi1->v_o + f * (vi->v_o - vi1->v_o);
*i1_i = vi1->i_i + f * (vi->i_i - vi1->i_i);
*i1_o = vi1->i_o + f * (vi->i_o - vi1->i_o);
tx->vi_head = vi1;
}
if (tb > t1) {
/* fprintf(stderr, "pvs: time = %d\n", t2); */
ext = 1;
/*
f = tb - t1;
*v2_i = tx->in_node->V + tx->in_node->dv * f;
*v2_o = tx->out_node->V + tx->out_node->dv * f;
if (vi) {
for (; vi->time != t1; vi = vi->next)
vi1 = vi;
f /= (double) (t1 - vi1->time);
*i2_i = vi->i_i + f * (vi->i_i - vi1->i_i);
*i2_o = vi->i_o + f * (vi->i_o - vi1->i_o);
} else {
*i2_i = vi1->i_i;
*i2_o = vi1->i_o;
}
*/
ratio[0] = f = (tb - t1) / (t2 - t1);
if (vi)
for (; vi->time != t1; vi = vi->next);
else
vi = vi1;
f = 1 - f;
*v2_i = vi->v_i * f;
*v2_o = vi->v_o * f;
*i2_i = vi->i_i * f;
*i2_o = vi->i_o * f;
} else {
for (; vi->time < tb; vi = vi->next)
vi1 = vi;
f = (tb - vi1->time) / (vi->time - vi1->time);
*v2_i = vi1->v_i + f * (vi->v_i - vi1->v_i);
*v2_o = vi1->v_o + f * (vi->v_o - vi1->v_o);
*i2_i = vi1->i_i + f * (vi->i_i - vi1->i_i);
*i2_o = vi1->i_o + f * (vi->i_o - vi1->i_o);
}
return(ext);
}
static int
right_consts_txl(tx, t, time, h, h1, l1, l2, ckt)
TXLine *tx;
int t, time;
double h, h1; /*** h1 = 0.5 * h ***/
int l1, l2;
CKTcircuit *ckt;
{
int i;
register double ff=0.0, gg=0.0, e;
double v1_i, v2_i, i1_i, i2_i;
double v1_o, v2_o, i1_o, i2_o;
int ext;
if (! tx->lsl) {
register double ff1=0.0;
for (i = 0; i < 3; i++) {
tx->h1e[i] = e = exp((double) tx->h1_term[i].x * h);
ff1 -= tx->h1_term[i].c * e;
ff -= tx->h1_term[i].cnv_i * e;
gg -= tx->h1_term[i].cnv_o * e;
}
ff += ff1 * h1 * tx->in_node->V;
gg += ff1 * h1 * tx->out_node->V;
}
ext = get_pvs_vi_txl(t, time, tx, &v1_i, &v2_i, &i1_i, &i2_i, &v1_o, &v2_o, &i1_o, &i2_o);
if (tx->lsl) {
ff = tx->h3_aten * v2_o + tx->h2_aten * i2_o;
gg = tx->h3_aten * v2_i + tx->h2_aten * i2_i;
} else {
if (tx->ifImg) {
double a, b, er, ei, a1, b1, a2, b2;
for (i = 0; i < 4; i++) {
register TERM *tm;
tm = &(tx->h3_term[i]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c * (v1_i * e + v2_i);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c * (v1_o * e + v2_o);
}
expC(tx->h3_term[4].x, tx->h3_term[5].x, h, &er, &ei);
a2 = h1 * tx->h3_term[4].c;
b2 = h1 * tx->h3_term[5].c;
a = tx->h3_term[4].cnv_i;
b = tx->h3_term[5].cnv_i;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, v1_i * er + v2_i, v1_i * ei, &a1, &b1);
tx->h3_term[4].cnv_i = a + a1;
tx->h3_term[5].cnv_i = b + b1;
a = tx->h3_term[4].cnv_o;
b = tx->h3_term[5].cnv_o;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, v1_o * er + v2_o, v1_o * ei, &a1, &b1);
tx->h3_term[4].cnv_o = a + a1;
tx->h3_term[5].cnv_o = b + b1;
ff += tx->h3_aten * v2_o;
gg += tx->h3_aten * v2_i;
for (i = 0; i < 5; i++) {
ff += tx->h3_term[i].cnv_o;
gg += tx->h3_term[i].cnv_i;
}
ff += tx->h3_term[4].cnv_o;
gg += tx->h3_term[4].cnv_i;
{
register TERM *tm;
tm = &(tx->h2_term[0]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c * (i1_i * e + i2_i);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c * (i1_o * e + i2_o);
}
expC(tx->h2_term[1].x, tx->h2_term[2].x, h, &er, &ei);
a2 = h1 * tx->h2_term[1].c;
b2 = h1 * tx->h2_term[2].c;
a = tx->h2_term[1].cnv_i;
b = tx->h2_term[2].cnv_i;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, i1_i * er + i2_i, i1_i * ei, &a1, &b1);
tx->h2_term[1].cnv_i = a + a1;
tx->h2_term[2].cnv_i = b + b1;
a = tx->h2_term[1].cnv_o;
b = tx->h2_term[2].cnv_o;
multC(a, b, er, ei, &a, &b);
multC(a2, b2, i1_o * er + i2_o, i1_o * ei, &a1, &b1);
tx->h2_term[1].cnv_o = a + a1;
tx->h2_term[2].cnv_o = b + b1;
ff += tx->h2_aten * i2_o + tx->h2_term[0].cnv_o +
2.0 * tx->h2_term[1].cnv_o;
gg += tx->h2_aten * i2_i + tx->h2_term[0].cnv_i +
2.0 * tx->h2_term[1].cnv_i;
} else {
for (i = 0; i < 6; i++) {
register TERM *tm;
tm = &(tx->h3_term[i]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c * (v1_i * e + v2_i);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c * (v1_o * e + v2_o);
}
ff += tx->h3_aten * v2_o;
gg += tx->h3_aten * v2_i;
for (i = 0; i < 6; i++) {
ff += tx->h3_term[i].cnv_o;
gg += tx->h3_term[i].cnv_i;
}
for (i = 0; i < 3; i++) {
register TERM *tm;
tm = &(tx->h2_term[i]);
e = exp((double) tm->x * h);
tm->cnv_i = tm->cnv_i * e + h1 * tm->c * (i1_i * e + i2_i);
tm->cnv_o = tm->cnv_o * e + h1 * tm->c * (i1_o * e + i2_o);
}
ff += tx->h2_aten * i2_o;
gg += tx->h2_aten * i2_i;
for (i = 0; i < 3; i++) {
ff += tx->h2_term[i].cnv_o;
gg += tx->h2_term[i].cnv_i;
}
}
}
*(ckt->CKTrhs + l1) = ff;
*(ckt->CKTrhs + l2) = gg;
return(ext);
}
static int
update_delayed_cnv_txl(tx, h)
TXLine *tx;
float h;
{
float ratio;
register double f;
register VI_list_txl *vi;
register TERM *tms;
h *= 0.5e-12;
ratio = tx->ratio;
vi = tx->vi_tail;
if (ratio > 0.0) {
tms = tx->h3_term;
f = h * ratio * vi->v_i;
tms[0].cnv_i += f * tms[0].c;
tms[1].cnv_i += f * tms[1].c;
tms[2].cnv_i += f * tms[2].c;
tms[3].cnv_i += f * tms[3].c;
tms[4].cnv_i += f * tms[4].c;
tms[5].cnv_i += f * tms[5].c;
f = h * ratio * vi->v_o;
tms[0].cnv_o += f * tms[0].c;
tms[1].cnv_o += f * tms[1].c;
tms[2].cnv_o += f * tms[2].c;
tms[3].cnv_o += f * tms[3].c;
tms[4].cnv_o += f * tms[4].c;
tms[5].cnv_o += f * tms[5].c;
tms = tx->h2_term;
f = h * ratio * vi->i_i;
tms[0].cnv_i += f * tms[0].c;
tms[1].cnv_i += f * tms[1].c;
tms[2].cnv_i += f * tms[2].c;
f = h * ratio * vi->i_o;
tms[0].cnv_o += f * tms[0].c;
tms[1].cnv_o += f * tms[1].c;
tms[2].cnv_o += f * tms[2].c;
}
return(1);
}
static int expC(ar, ai, h, cr, ci)
double ar, ai, *cr, *ci;
float h;
{
double e, cs, si;
e = exp((double) ar * h);
cs = cos((double) ai * h);
si = sin((double) ai * h);
*cr = e * cs;
*ci = e * si;
return(1);
}
static int multC(ar, ai, br, bi, cr, ci)
double ar, ai, br, bi;
double *cr, *ci;
{
register double tp;
tp = ar*br - ai*bi;
*ci = ar*bi + ai*br;
*cr = tp;
return (1);
}

View File

@ -0,0 +1,49 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "const.h"
#include "cktdefs.h"
#include "ifsim.h"
#include "txldefs.h"
#include "sperror.h"
#include "devdefs.h"
#include "suffix.h"
#include "swec.h"
/* ARGSUSED */
int
TXLmodAsk(ckt,inModel,which,value)
CKTcircuit *ckt;
GENmodel *inModel;
int which;
IFvalue *value;
{
TXLmodel *model = (TXLmodel *)inModel;
switch(which) {
case TXL_R:
value->rValue = model->R;
return(OK);
case TXL_C:
value->rValue = model->C;
return(OK);
case TXL_G:
value->rValue = model->G;
return(OK);
case TXL_L:
value->rValue = model->L;
return(OK);
case TXL_length:
value->rValue = model->length;
return(OK);
default:
return(E_BADPARM);
}
}

View File

@ -0,0 +1,45 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
int
TXLmDelete(inModel,modname,kill)
GENmodel **inModel;
IFuid modname;
GENmodel *kill;
{
TXLmodel **model = (TXLmodel **)inModel;
TXLmodel *modfast = (TXLmodel *)kill;
TXLinstance *here;
TXLinstance *prev = NULL;
TXLmodel **oldmod;
oldmod = model;
for( ; *model ; model = &((*model)->TXLnextModel)) {
if( (*model)->TXLmodName == modname ||
(modfast && *model == modfast) ) goto delgot;
oldmod = model;
}
return(E_NOMOD);
delgot:
*oldmod = (*model)->TXLnextModel; /* cut deleted device out of list */
for(here = (*model)->TXLinstances ; here ; here = here->TXLnextInstance) {
if(prev) FREE(prev);
prev = here;
}
if(prev) FREE(prev);
FREE(*model);
return(OK);
}

View File

@ -0,0 +1,51 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "const.h"
#include "ifsim.h"
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
int
TXLmParam(param,value,inModel)
int param;
IFvalue *value;
GENmodel *inModel;
{
register TXLmodel *model = (TXLmodel *)inModel;
switch(param) {
case TXL_R:
model->R = value->rValue;
model->Rgiven = TRUE;
break;
case TXL_L:
model->L = value->rValue;
model->Lgiven = TRUE;
break;
case TXL_G:
model->G = value->rValue;
model->Ggiven = TRUE;
break;
case TXL_C:
model->C = value->rValue;
model->Cgiven = TRUE;
break;
case TXL_length:
model->length = value->rValue;
model->lengthgiven = TRUE;
break;
case TXL_MOD_R:
break;
default:
return(E_BADPARM);
}
return(OK);
}

View File

@ -0,0 +1,40 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "const.h"
#include "ifsim.h"
#include "txldefs.h"
#include "sperror.h"
#include "suffix.h"
/* ARGSUSED */
int
TXLparam(param,value,inst,select)
int param;
IFvalue *value;
GENinstance *inst;
IFvalue *select;
{
TXLinstance *here = (TXLinstance *)inst;
switch(param) {
case TXL_IN_NODE:
here->TXLposNode = value->iValue;
break;
case TXL_OUT_NODE:
here->TXLnegNode = value->iValue;
break;
case TXL_LENGTH:
here->TXLlength = value->rValue;
here->TXLlengthgiven = TRUE;
break;
default:
return(E_BADPARM);
}
return(OK);
}

File diff suppressed because it is too large Load Diff

131
src/spicelib/parser/inp2p.c Normal file
View File

@ -0,0 +1,131 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "ifsim.h"
#include "inpdefs.h"
#include "inpmacs.h"
#include "fteext.h"
#include "inp.h"
void
INP2P(ckt,tab,current)
void *ckt;
INPtables *tab;
card *current;
{
int mytype; /* the type we determine cpls are */
int type; /* the type the model says it is */
char *line; /* the part of the current line left to parse */
char *name, *tempname; /* the cpl's name */
char *model; /* the name of the cpl's model */
char **nname1; /* the first node's name */
char **nname2; /* the second node's name */
char *ground;
void **node1; /* the first node's node pointer */
void **node2; /* the second node's node pointer */
void *groundnode;
int error; /* error code temporary */
int error1; /* secondary error code temporary */
INPmodel *thismodel; /* pointer to model structure describing our model */
void *mdfast; /* pointer to the actual model */
void *fast; /* pointer to the actual instance */
IFvalue ptemp; /* a value structure to package cpl into */
IFuid uid; /* uid for default model */
double lenval = 0;
int lenvalgiven = 0;
int num, i;
mytype = INPtypelook("CplLines");
if(mytype < 0 ) {
LITERR("Device type CplLines not supported by this binary\n")
return;
}
line = current->line;
INPgetTok(&line,&name,1);
INPinsert(&name,tab);
/* num = (int) INPevaluate(&line,&error1,1); */
num = 0;
/* first pass to determine the dimension */
while (*line != '\0') {
INPgetTok(&line, &tempname,1);
if (strcmp(tempname, "len") == 0) break;
num ++;
}
num = (num - 2) / 2;
line = current->line;
INPgetTok(&line,&name,1);
nname1 = (char **) malloc(num * sizeof(char *));
nname2 = (char **) malloc(num * sizeof(char *));
node1 = (void **) malloc(num * sizeof(void *));
node2 = (void **) malloc(num * sizeof(void *));
for (i = 0; i < num; i++) {
INPgetTok(&line,&(nname1[i]),1);
INPtermInsert(ckt,&(nname1[i]),tab,&(node1[i]));
}
INPgetTok(&line,&ground,1);
INPtermInsert(ckt,&ground,tab,&groundnode);
for (i = 0; i < num; i++) {
INPgetTok(&line,&(nname2[i]),1);
INPtermInsert(ckt,&(nname2[i]),tab,&(node2[i]));
}
INPgetTok(&line,&ground,1);
INPtermInsert(ckt,&ground,tab,&groundnode);
INPgetTok(&line,&model,1);
if (strcmp(model, "len") == 0) {
lenval = INPevaluate(&line,&error1,1);
lenvalgiven = 1;
INPgetTok(&line,&model,1);
}
if(*model) { /* token isn't null */
INPinsert(&model,tab);
thismodel = (INPmodel *)NULL;
current->error = INPgetMod(ckt,model,&thismodel,tab);
if(thismodel != NULL) {
if(mytype != thismodel->INPmodType) {
LITERR("incorrect model type")
return;
}
mdfast = thismodel->INPmodfast;
type = thismodel->INPmodType;
} else {
type = mytype;
if(!tab->defPmod) {
/* create default P model */
IFnewUid(ckt,&uid,(IFuid)NULL,"P",UID_MODEL,(void**)NULL);
IFC(newModel, (ckt,type,&(tab->defPmod),uid))
}
mdfast = tab->defPmod;
}
IFC(newInstance,(ckt,mdfast,&fast,name))
} else {
LITERR("model name is not found")
return;
}
/* IFC(bindNode,(ckt,fast,1,fakename)) */
ptemp.iValue = num;
GCA(INPpName,("dimension", &ptemp,ckt,type,fast))
ptemp.v.vec.sVec = nname1;
GCA(INPpName,("pos_nodes", &ptemp,ckt,type,fast))
ptemp.v.vec.sVec = nname2;
GCA(INPpName,("neg_nodes", &ptemp,ckt,type,fast))
if (error1 == 0 && lenvalgiven) {
ptemp.rValue = lenval;
GCA(INPpName,("length",&ptemp,ckt,type,fast))
}
return;
}

236
src/spicelib/parser/inp2y.c Normal file
View File

@ -0,0 +1,236 @@
/**********
Copyright 1992 Regents of the University of California. All rights
reserved.
Author: 1992 Charles Hough
**********/
#include "ngspice.h"
#include <stdio.h>
#include "ifsim.h"
#include "inpdefs.h"
#include "inpmacs.h"
#include "fteext.h"
#include "inp.h"
void
INP2Y(ckt,tab,current)
void *ckt;
INPtables *tab;
card *current;
{
/* parse a txl card */
/* Yxxxx node1 node2 name */
int mytype; /* the type to determine txl */
int mytype2; /* the type to determine cpl */
int type; /* the type the model says it is */
char *line; /* the part of the current line left to parse */
char *name; /* the resistor's name */
char *buf; /* temporary buffer for parsing */
char *model; /* the name of the resistor's model */
char *nname1; /* the first node's name */
char *nname2; /* the second node's name */
char rname1[10], rname2[10], rname3[10];
char cname1[10], cname2[10], cname3[10], cname4[10];
char *internal1, *internal2;
char *ground1, *ground2;
void *node1; /* the first node's node pointer */
void *node2; /* the second node's node pointer */
void *gnode1, *gnode2, *inode1, *inode2;
int error; /* error code temporary */
int error1; /* secondary error code temporary */
INPmodel *thismodel; /* pointer to model structure describing our model */
void *mdfast; /* pointer to the actual model */
void *fast; /* pointer to the actual instance */
void *mdfast2, *mdfast3, *mdfast4, *mdfast5, *mdfast6;
void *fast2, *fast3, *fast4, *fast5, *fast6;
IFuid uid; /* uid for default model */
GENinstance *txl;
IFvalue ptemp; /* a value structure to package into */
double lval=0, rval=0, cval=0, lenval=0;
int lenvalgiven = 0;
mytype = INPtypelook("TransLine");
mytype2 = INPtypelook("CplLines");
if(mytype < 0 ) {
LITERR("Device type TransLine not supported by this binary\n")
return;
}
line = current->line;
INPgetTok(&line,&name,1);
INPinsert(&name,tab);
INPgetTok(&line,&nname1,1);
INPtermInsert(ckt,&nname1,tab,&node1);
INPgetTok(&line,&ground1,1);
INPtermInsert(ckt,&ground1,tab,&gnode1);
INPgetTok(&line,&nname2,1);
INPtermInsert(ckt,&nname2,tab,&node2);
INPgetTok(&line,&ground2,1);
INPtermInsert(ckt,&ground2,tab,&gnode2);
INPgetTok(&line,&model,1);
if (strcmp(model, "len") == 0) {
lenval = INPevaluate(&line,&error1,1);
lenvalgiven = 1;
INPgetTok(&line,&model,1);
}
if(*model) { /* token isn't null */
INPinsert(&model,tab);
thismodel = (INPmodel *)NULL;
current->error = INPgetMod(ckt,model,&thismodel,tab);
if(thismodel != NULL) {
if (thismodel->INPmodType == mytype2) {
INP2P(ckt,tab,current);
return;
}
else if (mytype != thismodel->INPmodType) {
LITERR("incorrect model type")
return;
}
line = thismodel->INPmodLine->line;
INPgetTok(&line,&buf,1); /* throw out .model */
INPgetTok(&line,&buf,1); /* throw out model name */
INPgetTok(&line,&buf,1); /* throw out txl */
INPgetTok(&line,&buf,1);
while (*line != '\0') {
if (*buf == 'R' || *buf == 'r') {
INPgetTok(&line,&buf,1);
rval = atof(buf);
}
if ((strcmp(buf,"L") == 0) || (strcmp(buf,"l") == 0)) {
INPgetTok(&line,&buf,1);
lval = atof(buf);
}
if ((strcmp(buf,"C") == 0) || (strcmp(buf,"c") == 0)) {
INPgetTok(&line,&buf,1);
cval = atof(buf);
}
if (lenvalgiven == 0) {
if (strcmp(buf,"length")== 0) {
INPgetTok(&line,&buf,1);
lenval = atof(buf);
}
}
INPgetTok(&line,&buf,1);
}
if (lenval && rval && lval && rval/lval > 1.6e10) {
/* use 3-pi model */
rval = 3.0 / (rval * lenval);
cval = cval * lenval / 6.0;
type = INPtypelook("Resistor");
/* resistor between node1 and internal1 */
internal1 = (char *) malloc (10);
strcpy(internal1, "txlnd1");
INPtermInsert(ckt, &internal1, tab, &inode1);
if(!tab->defRmod) {
/* create default R model */
IFnewUid(ckt,&uid,(IFuid)NULL,"R",UID_MODEL,(void**)NULL);
IFC(newModel, (ckt,type,&(tab->defRmod),uid))
}
mdfast = tab->defRmod;
strcpy(rname1, "txlres1");
IFC(newInstance,(ckt,mdfast,&fast,rname1))
IFC(bindNode,(ckt,fast,1,node1))
IFC(bindNode,(ckt,fast,2,inode1))
ptemp.rValue = rval;
GCA(INPpName,("resistance",&ptemp,ckt,type,fast))
/* resistor between internal1 and internal2 */
internal2 = (char *) malloc (10);
strcpy(internal2, "txlnd2");
INPtermInsert(ckt, &internal2, tab, &inode2);
strcpy(rname2, "txlres2");
mdfast2 = tab->defRmod;
IFC(newInstance,(ckt,mdfast2,&fast2,rname2))
IFC(bindNode,(ckt,fast2,1,inode1))
IFC(bindNode,(ckt,fast2,2,inode2))
ptemp.rValue = rval;
GCA(INPpName,("resistance",&ptemp,ckt,type,fast2))
/* resistor between internal2 and node2 */
strcpy(rname3, "txlres3");
mdfast3 = tab->defRmod;
IFC(newInstance,(ckt,mdfast3,&fast3,rname3))
IFC(bindNode,(ckt,fast3,1,inode2))
IFC(bindNode,(ckt,fast3,2,node2))
ptemp.rValue = rval;
GCA(INPpName,("resistance",&ptemp,ckt,type,fast3))
/* capacitor on node1 */
type = INPtypelook("Capacitor");
if(!tab->defCmod) {
IFnewUid(ckt,&uid,(IFuid)NULL,"C",UID_MODEL,(void**)NULL);
IFC(newModel,(ckt,type,&(tab->defCmod),uid))
}
mdfast4 = tab->defCmod;
strcpy(cname1, "txlcap1");
IFC(newInstance,(ckt,mdfast4,&fast4,cname1))
IFC(bindNode,(ckt,fast4,1,node1))
IFC(bindNode,(ckt,fast4,2,gnode1))
ptemp.rValue = cval;
GCA(INPpName,("capacitance",&ptemp,ckt,type,fast4))
/* capacitor on internal1 */
strcpy(cname2, "txlcap2");
mdfast4 = tab->defCmod;
IFC(newInstance,(ckt,mdfast4,&fast4,cname2))
IFC(bindNode,(ckt,fast4,1,inode1))
IFC(bindNode,(ckt,fast4,2,gnode1))
ptemp.rValue = cval * 2;
GCA(INPpName,("capacitance",&ptemp,ckt,type,fast4))
/* capacitor on internal2 */
strcpy(cname3, "txlcap3");
mdfast5 = tab->defCmod;
IFC(newInstance,(ckt,mdfast5,&fast5,cname3))
IFC(bindNode,(ckt,fast5,1,inode2))
IFC(bindNode,(ckt,fast5,2,gnode1))
ptemp.rValue = cval * 2;
GCA(INPpName,("capacitance",&ptemp,ckt,type,fast5))
/* capacitor on node2 */
strcpy(cname4, "txlcap4");
mdfast6 = tab->defCmod;
IFC(newInstance,(ckt,mdfast6,&fast6,cname4))
IFC(bindNode,(ckt,fast6,1,node2))
IFC(bindNode,(ckt,fast6,2,gnode1))
ptemp.rValue = cval;
GCA(INPpName,("capacitance",&ptemp,ckt,type,fast6))
return;
}
/* use regular txl model */
mdfast = thismodel->INPmodfast;
type = thismodel->INPmodType;
} else {
type = mytype;
if(!tab->defYmod) {
/* create default Y model */
IFnewUid(ckt,&uid,(IFuid)NULL,"Y",UID_MODEL,(void**)NULL);
IFC(newModel, (ckt,type,&(tab->defYmod),uid))
}
mdfast = tab->defYmod;
}
IFC(newInstance,(ckt,mdfast,&fast,name))
} else {
LITERR("model name is not found")
return;
}
if (error1 == 0 && lenvalgiven) {
ptemp.rValue = lenval;
GCA(INPpName,("length",&ptemp,ckt,type,fast))
}
IFC(bindNode,(ckt,fast,1,node1))
IFC(bindNode,(ckt,fast,2,node2))
txl = (GENinstance *)fast;
return;
}

34
src/tcl/ChangeLog Executable file
View File

@ -0,0 +1,34 @@
25/07/2002:
* Modified configure/Makefiles so use --enable-tcl to make module
* Added option --enable-cluster to configure for cluster version
* Swig no longer needed to compile
23/07/2002:
* Added display device Tk plot
* Added function bltplot
17/04/2002:
* Merged a version of cluster spice.
26/03/2002:
* New TCL function lastVector.
19/02/2002:
* User nodes and codemodels now work in DCtrans analysis,
calculated results are now correct.
* Fixed bug where the first timestep always seems to fail to converge
after a resume or a step, thus cutting delta.
30/01/2002:
* Precompiled Opus/XSpice models are now supported with
--enable-xspice flag, load them using codemodel "opus spice module"
22/01/2002:
* Fixed parameters being ignored when mosfet model is not found
16/01/2002:
* Fixed crash when a mosfet model is not found
In the mists of time:
* Changed spicelib/parser/inpgtok.c to allow / * ^ in node names (/ needed for ext2spice)
* Modifed files in
spicelib/analysis/(acan.c, dctran.c, dctrcurv.c, noisean.c), frontend/outitf.c,
frontend/runcoms.c, frontend/runcoms2.c
so rawfiles continue to be written to after a pause then a resume
* Small modification to main.c to make the struct nutmeginfo global, so tclspice can use it.
* Added ifdefed code to frontend/outitf.c which links output to tclspice.
* Modified main.c and frontend/inp.c so .save lines are always processed
* ifdefed code in misc/alloc.c so the functions use Tcl_Mutex to stop memory allocation conflicts.
* Fixed crash in com_resume() when run without circuit loaded

170
src/tcl/README Executable file
View File

@ -0,0 +1,170 @@
Spice Tcl module
$Id$
DESCRIPTION
Contained in this package is the source code for a spice tcl module and ng-spice-rework-14.
It allows you run spice commands in tcl and run the spice simulator in the background
so you can manipulate the results while spice is running.
THANKS:
Ng-Spice at http://ngspice.sourceforge.net for the spice simulator
ScriptEDA ( http://www-cad.eecs.berkeley.edu/~pinhong/scriptEDA ) for the idea and examples.
INSTALLATION
Requirements:
ngspice, included (only tested with ng-spice-rework-13 and 14, should work with all rework versions)
tcl WITH thread support compiled in (tested with tcl-8.3.3-65 and tcl8.3.4)
BTL for tcl (tested with blt2.4y)
pthreads (most modern OS's have this)
Installation:
This package contains the ng-spice-rework-14 source code, which has been slightly modifed, and the tcl module source.
The spice source is contained in the ng-spice-rework directory.
Tcl modules's documentation is in the ng-spice-rework/src/tcl directory
Please hide libgc.so (the garbage collector library), if you have it. You can put it back afterwards!
This is because you don't want tclspice to compile with it included!
Also if you want to run spice in the background you need to recompile
tcl and tk to enable thread support if they haven't got it enabled already (redhat packages haven't).
If you don't then tclspice will crash frequently!!!!
The install commands are:
From the root directory of the source:
./configure --enable-tcl --enable-experimental --enable-xspice --disable-shared
make tcl
And as root:
make tcl_install
USAGE
example:
$tclsh
%package require spice
(to load the module)
Then you can run commands either by typing spice command directly or by typing spice <spice command>
For example:
%spice::version
%spice::source ./example.cir
%spice::bg run
%spice::halt
%spice::show
%spice::plot_nvars 0
%spice::plot_variables 0
%spice::plot_datapoints 0
%spice::bg resume
%spice::halt
%exit
Commands availiabe:
spice has it's own namespace (spice::) which can be imported.
Although there are a few conflicts, so not all commands are imported.
spice::spice <command>
runs the spicified spice command in the foreground
spice::bg <command>
runs the spice command in the background
All spice commands should be recognised
spice::halt
Stops(or attempts to) a spice background command (like run) (it simulates a ^C)
spice::running
returns 1 if a background process is running, 0 otherwise
spice::get_output script ?stderr?
runs the tcl script "script", catching std_out and maping it to the return value.
It can also catch the std_err and put it into the stderr variable.
spice::get_param device param
Returns the parameter of the device
spice::spice_data
Returns the names and types of avaliable spice
variables
{name type} {name type} ... {name type}
spice::spice_header
Returns the current run's title, analysis name, date, and the number of signals as follows:
{title ??} {name ???} {date ????} {variables ???}
spice::delta ?value?
Sets the value of delta to the given value, if given.
It returns the current setting of delta
spice::maxstep ?value?
Same as spice::delta but for the maximum stepsize allowed
variables:
spice::steps_completed
The number of simulation steps done so far.
The following concern the BLT vectors generated;
functions:
spice::spicetoblt vecName signal ?start? ?end?
Sets the blt vector vecName with the contents of the spice signal, signal,
using the optional start and end index.
spice::lastVector vecName
Sets the blt vector vecName to contain the last spice state vector
variables:
spice::blt_vnum
The number of signals avalible
The following only work if there is a plot stored;
spice::plot_variables plot
returns a list of variables in plot "plot"
plot is from 0-numofplots, newest plot being 0.
spice::plot_get_value name plot index
returns value of varable "name" in plot "plot", at position "index"
spice::plot_datapoints plot
returns number of time steps saved so far
spice::plot_title plot
returns plot title
spice::plot_date plot
returns date string
spice::plot_name plot
returns plot name
spice::plot_nvars plot
returns number of variables in the plot
Plotting functions;
spice::plot
The standard plot function has been wrapped to a Tk canvas ".c" See Tcl source in
pkgIndex.tcl The callback functions are named gr_*, modify/override at will.
spice::bltplot
Instead of plotting: For each pair of vectors to plot spice::gr_Plot is called,
"proc spice_gr_Plot { Xname Xtype Xunits Yname Ytype Yunits }" which you can override
With the static Blt vectors "spice::X_Data" and "spice::Y_Data" containing the plot data.
WARNING:
If any of the Tcl callback functions cause an error then a crash may occour as tcl
overwrites random data in the spice code. Not sure why.
TODO & BUGS
1) plot and iplot don't work: window opens then tclsh stops, Xserver doesn't respond to spice requests
They aren't really needed anymore, as you now have the blt vectors to play with,
and the Tk plot output and bltplot output.
2) Spice prints to stdout, unavoidable, sorry if it mucks up your commandline
3) tclreadline doesn't like this module very much
Stefan Jones
<stefan.jones@multigig.com>

587
src/tcl/example.cir Executable file
View File

@ -0,0 +1,587 @@
TITLE: proj1.cir.cir - Rotary Traveling Wave Oscillator
.control
set filetype=ascii
.endc
VDD0 VDD0 VDD DC 0
VSS0 VSS0 0 DC 0
VDD_A0 VDD_A0 VDD0 DC 0
VSS_A0 VSS_A0 VSS0 DC 0
VDD_B0 VDD_B0 VDD0 DC 0
VSS_B0 VSS_B0 VSS0 DC 0
LA0 A0 LCA0 3.69030941553353e-11
RA0 LCA0 A1 0.266535044422507
LB0 B0 LCB0 3.69030941553353e-11
RB0 LCB0 B1 0.266535044422507
C0 A1 B1 2.50418376625721e-14
MNA0 B0 A0 VSS_B0 VSS_B0 Nmod L=2.53696435353243e-07 W=
+4.24857778403814e-05 AD=3.125e-11 AS=3.125e-11 PD=
+8.49715556807627e-05 PS=8.49715556807627e-05 NQSMOD=1
MPA0 B0 A0 VDD_B0 VDD_B0 Pmod L=2.55343565546106e-07 W=
+0.000101772203908557 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000203544407817114 PS=0.000203544407817114 NQSMOD=1
MNB0 A0 B0 VSS_A0 VSS_A0 Nmod L=2.53941602497219e-07 W=
+4.10652659629401e-05 AD=3.125e-11 AS=3.125e-11 PD=
+8.21305319258802e-05 PS=8.21305319258802e-05 NQSMOD=1
MPB0 A0 B0 VDD_A0 VDD_A0 Pmod L=2.52010168145607e-07 W=
+0.000103533977891464 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000207067955782928 PS=0.000207067955782928 NQSMOD=1
LA1 A1 LCA1 3.69030941553353e-11
RA1 LCA1 A2 0.266535044422507
LB1 B1 LCB1 3.69030941553353e-11
RB1 LCB1 B2 0.266535044422507
C1 A2 B2 2.50418376625721e-14
MNA1 B1 A1 0 0 Nmod L=2.52370578161099e-07 W=4.12246995102289e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.24493990204578e-05 PS=
+8.24493990204578e-05 NQSMOD=1
MPA1 B1 A1 VDD VDD Pmod L=2.45709468983316e-07 W=0.000103710764679465
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000207421529358929 PS=
+0.000207421529358929 NQSMOD=1
MNB1 A1 B1 0 0 Nmod L=2.48115895523017e-07 W=4.26306134285554e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.52612268571108e-05 PS=
+8.52612268571108e-05 NQSMOD=1
MPB1 A1 B1 VDD VDD Pmod L=2.55265156192223e-07 W=0.000102043840486507
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000204087680973014 PS=
+0.000204087680973014 NQSMOD=1
LA2 A2 LCA2 3.69030941553353e-11
RA2 LCA2 A3 0.266535044422507
LB2 B2 LCB2 3.69030941553353e-11
RB2 LCB2 B3 0.266535044422507
C2 A3 B3 2.50418376625721e-14
MNA2 B2 A2 0 0 Nmod L=2.53484220592882e-07 W=4.16915225420459e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.33830450840917e-05 PS=
+8.33830450840917e-05 NQSMOD=1
MPA2 B2 A2 VDD VDD Pmod L=2.44256748076514e-07 W=0.00010549295960702
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000210985919214039 PS=
+0.000210985919214039 NQSMOD=1
MNB2 A2 B2 0 0 Nmod L=2.48805892712811e-07 W=4.15734692647458e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.31469385294916e-05 PS=
+8.31469385294916e-05 NQSMOD=1
MPB2 A2 B2 VDD VDD Pmod L=2.54004987710956e-07 W=0.00010229621219808
+AD=7.8125e-11 AS=7.8125e-11 PD=0.00020459242439616 PS=
+0.00020459242439616 NQSMOD=1
LA3 A3 LCA3 3.69030941553353e-11
RA3 LCA3 A4 0.266535044422507
LB3 B3 LCB3 3.69030941553353e-11
RB3 LCB3 B4 0.266535044422507
C3 A4 B4 2.50418376625721e-14
MNA3 B3 A3 0 0 Nmod L=2.54307430347219e-07 W=4.11339076756089e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.22678153512179e-05 PS=
+8.22678153512179e-05 NQSMOD=1
MPA3 B3 A3 VDD VDD Pmod L=2.52369109463781e-07 W=0.000103371681055656
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000206743362111311 PS=
+0.000206743362111311 NQSMOD=1
MNB3 A3 B3 0 0 Nmod L=2.4960708801709e-07 W=4.21794611046917e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.43589222093833e-05 PS=
+8.43589222093833e-05 NQSMOD=1
MPB3 A3 B3 VDD VDD Pmod L=2.53834779766428e-07 W=0.000105556314711602
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000211112629423204 PS=
+0.000211112629423204 NQSMOD=1
LA4 A4 LCA4 3.69030941553353e-11
RA4 LCA4 A5 0.266535044422507
LB4 B4 LCB4 3.69030941553353e-11
RB4 LCB4 B5 0.266535044422507
C4 A5 B5 2.50418376625721e-14
MNA4 B4 A4 0 0 Nmod L=2.48091656083177e-07 W=4.11207568141106e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.22415136282211e-05 PS=
+8.22415136282211e-05 NQSMOD=1
MPA4 B4 A4 VDD VDD Pmod L=2.47723605289033e-07 W=0.000103463392309261
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000206926784618522 PS=
+0.000206926784618522 NQSMOD=1
MNB4 A4 B4 0 0 Nmod L=2.49254771880382e-07 W=4.25122425012226e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.50244850024452e-05 PS=
+8.50244850024452e-05 NQSMOD=1
MPB4 A4 B4 VDD VDD Pmod L=2.49689766979065e-07 W=0.000103227993619608
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000206455987239216 PS=
+0.000206455987239216 NQSMOD=1
LA5 A5 LCA5 3.69030941553353e-11
RA5 LCA5 A6 0.266535044422507
LB5 B5 LCB5 3.69030941553353e-11
RB5 LCB5 B6 0.266535044422507
C5 A6 B6 2.50418376625721e-14
MNA5 B5 A5 0 0 Nmod L=2.53960031106522e-07 W=4.1129961792588e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.22599235851759e-05 PS=
+8.22599235851759e-05 NQSMOD=1
MPA5 B5 A5 VDD VDD Pmod L=2.47418707088064e-07 W=0.000101621693062467
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000203243386124935 PS=
+0.000203243386124935 NQSMOD=1
MNB5 A5 B5 0 0 Nmod L=2.49659687529522e-07 W=4.2524931640785e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.50498632815701e-05 PS=
+8.50498632815701e-05 NQSMOD=1
MPB5 A5 B5 VDD VDD Pmod L=2.46328059754468e-07 W=0.000102061546065548
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000204123092131096 PS=
+0.000204123092131096 NQSMOD=1
LA6 A6 LCA6 3.69030941553353e-11
RA6 LCA6 A7 0.266535044422507
LB6 B6 LCB6 3.69030941553353e-11
RB6 LCB6 B7 0.266535044422507
C6 A7 B7 2.50418376625721e-14
MNA6 B6 A6 0 0 Nmod L=2.54326804653788e-07 W=4.17332976706085e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.34665953412171e-05 PS=
+8.34665953412171e-05 NQSMOD=1
MPA6 B6 A6 VDD VDD Pmod L=2.48727427835127e-07 W=0.000103244611103459
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000206489222206918 PS=
+0.000206489222206918 NQSMOD=1
MNB6 A6 B6 0 0 Nmod L=2.49697035135609e-07 W=4.23570035518e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.47140071036001e-05 PS=
+8.47140071036001e-05 NQSMOD=1
MPB6 A6 B6 VDD VDD Pmod L=2.48995485890626e-07 W=0.000103695454759978
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000207390909519956 PS=
+0.000207390909519956 NQSMOD=1
LA7 A7 LCA7 3.69030941553353e-11
RA7 LCA7 A8 0.266535044422507
LB7 B7 LCB7 3.69030941553353e-11
RB7 LCB7 B8 0.266535044422507
C7 A8 B8 2.50418376625721e-14
MNA7 B7 A7 0 0 Nmod L=2.53418975114981e-07 W=4.06421756574473e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.12843513148946e-05 PS=
+8.12843513148946e-05 NQSMOD=1
MPA7 B7 A7 VDD VDD Pmod L=2.4471861043622e-07 W=0.000104600862141835
+AD=7.8125e-11 AS=7.8125e-11 PD=0.00020920172428367 PS=
+0.00020920172428367 NQSMOD=1
MNB7 A7 B7 0 0 Nmod L=2.50159056393584e-07 W=4.06845582724173e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.13691165448345e-05 PS=
+8.13691165448345e-05 NQSMOD=1
MPB7 A7 B7 VDD VDD Pmod L=2.55032245177227e-07 W=0.000106482118141681
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000212964236283363 PS=
+0.000212964236283363 NQSMOD=1
LA8 A8 LCA8 3.69030941553353e-11
RA8 LCA8 A9 0.266535044422507
LB8 B8 LCB8 3.69030941553353e-11
RB8 LCB8 B9 0.266535044422507
C8 A9 B9 2.50418376625721e-14
MNA8 B8 A8 0 0 Nmod L=2.45729547191971e-07 W=4.18266198665335e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.3653239733067e-05 PS=8.3653239733067e-05
+NQSMOD=1
MPA8 B8 A8 VDD VDD Pmod L=2.45156004861421e-07 W=0.000101593205477244
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000203186410954489 PS=
+0.000203186410954489 NQSMOD=1
MNB8 A8 B8 0 0 Nmod L=2.49014342219656e-07 W=4.14314219478801e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.28628438957603e-05 PS=
+8.28628438957603e-05 NQSMOD=1
MPB8 A8 B8 VDD VDD Pmod L=2.50396673007567e-07 W=0.000103029640740115
+AD=7.8125e-11 AS=7.8125e-11 PD=0.00020605928148023 PS=
+0.00020605928148023 NQSMOD=1
LA9 A9 LCA9 3.69030941553353e-11
RA9 LCA9 A10 0.266535044422507
LB9 B9 LCB9 3.69030941553353e-11
RB9 LCB9 B10 0.266535044422507
C9 A10 B10 2.50418376625721e-14
MNA9 B9 A9 0 0 Nmod L=2.51066307645916e-07 W=4.17044186844862e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.34088373689724e-05 PS=
+8.34088373689724e-05 NQSMOD=1
MPA9 B9 A9 VDD VDD Pmod L=2.4945438501494e-07 W=0.000104601836030031
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000209203672060063 PS=
+0.000209203672060063 NQSMOD=1
MNB9 A9 B9 0 0 Nmod L=2.56178041422984e-07 W=4.17990098329256e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.35980196658511e-05 PS=
+8.35980196658511e-05 NQSMOD=1
MPB9 A9 B9 VDD VDD Pmod L=2.5274010042983e-07 W=0.000103578149162769
+AD=7.8125e-11 AS=7.8125e-11 PD=0.000207156298325537 PS=
+0.000207156298325537 NQSMOD=1
LA10 A10 LCA10 3.69030941553353e-11
RA10 LCA10 A11 0.266535044422507
LB10 B10 LCB10 3.69030941553353e-11
RB10 LCB10 B11 0.266535044422507
C10 A11 B11 2.50418376625721e-14
MNA10 B10 A10 0 0 Nmod L=2.45772611943267e-07 W=4.24345922952649e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.48691845905299e-05 PS=
+8.48691845905299e-05 NQSMOD=1
MPA10 B10 A10 VDD VDD Pmod L=2.55544710347746e-07 W=
+0.000105625826497323 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000211251652994645 PS=0.000211251652994645 NQSMOD=1
MNB10 A10 B10 0 0 Nmod L=2.55886308364338e-07 W=4.0850956346516e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.17019126930321e-05 PS=
+8.17019126930321e-05 NQSMOD=1
MPB10 A10 B10 VDD VDD Pmod L=2.44778614470725e-07 W=
+0.000105511594248206 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000211023188496411 PS=0.000211023188496411 NQSMOD=1
LA11 A11 LCA11 3.69030941553353e-11
RA11 LCA11 A12 0.266535044422507
LB11 B11 LCB11 3.69030941553353e-11
RB11 LCB11 B12 0.266535044422507
C11 A12 B12 2.50418376625721e-14
MNA11 B11 A11 0 0 Nmod L=2.4768739676619e-07 W=4.14724461551725e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.29448923103449e-05 PS=
+8.29448923103449e-05 NQSMOD=1
MPA11 B11 A11 VDD VDD Pmod L=2.46276216123912e-07 W=
+0.000101782633723501 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000203565267447002 PS=0.000203565267447002 NQSMOD=1
MNB11 A11 B11 0 0 Nmod L=2.54985612770668e-07 W=4.24608643314108e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.49217286628216e-05 PS=
+8.49217286628216e-05 NQSMOD=1
MPB11 A11 B11 VDD VDD Pmod L=2.45772463970764e-07 W=
+0.000106109588792745 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.00021221917758549 PS=0.00021221917758549 NQSMOD=1
LA12 A12 LCA12 3.69030941553353e-11
RA12 LCA12 A13 0.266535044422507
LB12 B12 LCB12 3.69030941553353e-11
RB12 LCB12 B13 0.266535044422507
C12 A13 B13 2.50418376625721e-14
MNA12 B12 A12 0 0 Nmod L=2.45480481009462e-07 W=4.20858793029857e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.41717586059714e-05 PS=
+8.41717586059714e-05 NQSMOD=1
MPA12 B12 A12 VDD VDD Pmod L=2.48462320158069e-07 W=
+0.00010650127744954 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.00021300255489908 PS=0.00021300255489908 NQSMOD=1
MNB12 A12 B12 0 0 Nmod L=2.51992945030792e-07 W=4.17981435096244e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.35962870192489e-05 PS=
+8.35962870192489e-05 NQSMOD=1
MPB12 A12 B12 VDD VDD Pmod L=2.49941922576661e-07 W=
+0.0001044851795426 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000208970359085199 PS=0.000208970359085199 NQSMOD=1
LA13 A13 LCA13 3.69030941553353e-11
RA13 LCA13 A14 0.266535044422507
LB13 B13 LCB13 3.69030941553353e-11
RB13 LCB13 B14 0.266535044422507
C13 A14 B14 2.50418376625721e-14
MNA13 B13 A13 0 0 Nmod L=2.51146190542173e-07 W=4.23276196447018e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.46552392894035e-05 PS=
+8.46552392894035e-05 NQSMOD=1
MPA13 B13 A13 VDD VDD Pmod L=2.46359362747576e-07 W=
+0.00010249565409785 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.0002049913081957 PS=0.0002049913081957 NQSMOD=1
MNB13 A13 B13 0 0 Nmod L=2.44656485453628e-07 W=4.11044634633624e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.22089269267248e-05 PS=
+8.22089269267248e-05 NQSMOD=1
MPB13 A13 B13 VDD VDD Pmod L=2.56119611942636e-07 W=
+0.0001064085618438 AD=7.8125e-11 AS=7.8125e-11 PD=0.0002128171236876
+PS=0.0002128171236876 NQSMOD=1
LA14 A14 LCA14 3.69030941553353e-11
RA14 LCA14 A15 0.266535044422507
LB14 B14 LCB14 3.69030941553353e-11
RB14 LCB14 B15 0.266535044422507
C14 A15 B15 2.50418376625721e-14
MNA14 B14 A14 0 0 Nmod L=2.47663439668801e-07 W=4.20889991075918e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.41779982151835e-05 PS=
+8.41779982151835e-05 NQSMOD=1
MPA14 B14 A14 VDD VDD Pmod L=2.51252450429323e-07 W=
+0.000103622229824819 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000207244459649638 PS=0.000207244459649638 NQSMOD=1
MNB14 A14 B14 0 0 Nmod L=2.5044796612668e-07 W=4.24685059762319e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.49370119524638e-05 PS=
+8.49370119524638e-05 NQSMOD=1
MPB14 A14 B14 VDD VDD Pmod L=2.4786360459861e-07 W=
+0.000104258615459431 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000208517230918863 PS=0.000208517230918863 NQSMOD=1
LA15 A15 LCA15 3.69030941553353e-11
RA15 LCA15 A16 0.266535044422507
LB15 B15 LCB15 3.69030941553353e-11
RB15 LCB15 B16 0.266535044422507
C15 A16 B16 2.50418376625721e-14
MNA15 B15 A15 0 0 Nmod L=2.5213362488047e-07 W=4.26610931467994e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.53221862935989e-05 PS=
+8.53221862935989e-05 NQSMOD=1
MPA15 B15 A15 VDD VDD Pmod L=2.44411053097269e-07 W=
+0.000104344399065411 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000208688798130821 PS=0.000208688798130821 NQSMOD=1
MNB15 A15 B15 0 0 Nmod L=2.44947739168727e-07 W=4.18061319080677e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.36122638161354e-05 PS=
+8.36122638161354e-05 NQSMOD=1
MPB15 A15 B15 VDD VDD Pmod L=2.45133067349567e-07 W=
+0.000103673770597555 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.00020734754119511 PS=0.00020734754119511 NQSMOD=1
LA16 A16 LCA16 3.69030941553353e-11
RA16 LCA16 A17 0.266535044422507
LB16 B16 LCB16 3.69030941553353e-11
RB16 LCB16 B17 0.266535044422507
C16 A17 B17 2.50418376625721e-14
MNA16 B16 A16 0 0 Nmod L=2.5558903414348e-07 W=4.23651981762607e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.47303963525215e-05 PS=
+8.47303963525215e-05 NQSMOD=1
MPA16 B16 A16 VDD VDD Pmod L=2.46968507923118e-07 W=
+0.000101577430536373 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000203154861072746 PS=0.000203154861072746 NQSMOD=1
MNB16 A16 B16 0 0 Nmod L=2.52441475326891e-07 W=4.0963445615255e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.192689123051e-05 PS=
+8.192689123051e-05 NQSMOD=1
MPB16 A16 B16 VDD VDD Pmod L=2.49958772476576e-07 W=
+0.000102341104143712 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000204682208287424 PS=0.000204682208287424 NQSMOD=1
LA17 A17 LCA17 3.69030941553353e-11
RA17 LCA17 A18 0.266535044422507
LB17 B17 LCB17 3.69030941553353e-11
RB17 LCB17 B18 0.266535044422507
C17 A18 B18 2.50418376625721e-14
MNA17 B17 A17 0 0 Nmod L=2.46623947628415e-07 W=4.07033737509309e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.14067475018618e-05 PS=
+8.14067475018618e-05 NQSMOD=1
MPA17 B17 A17 VDD VDD Pmod L=2.52274212428759e-07 W=
+0.000105423152156798 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000210846304313596 PS=0.000210846304313596 NQSMOD=1
MNB17 A17 B17 0 0 Nmod L=2.51233452024547e-07 W=4.12815452669714e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.25630905339429e-05 PS=
+8.25630905339429e-05 NQSMOD=1
MPB17 A17 B17 VDD VDD Pmod L=2.49324495416238e-07 W=
+0.000104142717459091 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000208285434918183 PS=0.000208285434918183 NQSMOD=1
LA18 A18 LCA18 3.69030941553353e-11
RA18 LCA18 A19 0.266535044422507
LB18 B18 LCB18 3.69030941553353e-11
RB18 LCB18 B19 0.266535044422507
C18 A19 B19 2.50418376625721e-14
MNA18 B18 A18 0 0 Nmod L=2.52038203439398e-07 W=4.17044670825126e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.34089341650252e-05 PS=
+8.34089341650252e-05 NQSMOD=1
MPA18 B18 A18 VDD VDD Pmod L=2.46465042965348e-07 W=
+0.000102305682920291 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000204611365840582 PS=0.000204611365840582 NQSMOD=1
MNB18 A18 B18 0 0 Nmod L=2.45695550122768e-07 W=4.2510656912981e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.50213138259621e-05 PS=
+8.50213138259621e-05 NQSMOD=1
MPB18 A18 B18 VDD VDD Pmod L=2.56212134001568e-07 W=
+0.000101696358889307 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000203392717778614 PS=0.000203392717778614 NQSMOD=1
LA19 A19 LCA19 3.69030941553353e-11
RA19 LCA19 A20 0.266535044422507
LB19 B19 LCB19 3.69030941553353e-11
RB19 LCB19 B20 0.266535044422507
C19 A20 B20 2.50418376625721e-14
MNA19 B19 A19 0 0 Nmod L=2.46298724559332e-07 W=4.26183323927543e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.52366647855085e-05 PS=
+8.52366647855085e-05 NQSMOD=1
MPA19 B19 A19 VDD VDD Pmod L=2.53903413760174e-07 W=
+0.000103580270078538 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000207160540157077 PS=0.000207160540157077 NQSMOD=1
MNB19 A19 B19 0 0 Nmod L=2.4541336381424e-07 W=4.1471197163819e-05 AD=
+3.125e-11 AS=3.125e-11 PD=8.2942394327638e-05 PS=8.2942394327638e-05
+NQSMOD=1
MPB19 A19 B19 VDD VDD Pmod L=2.51953325753565e-07 W=
+0.0001019745929959 AD=7.8125e-11 AS=7.8125e-11 PD=0.0002039491859918
+PS=0.0002039491859918 NQSMOD=1
LA20 A20 LCA20 3.69030941553353e-11
RA20 LCA20 A21 0.266535044422507
LB20 B20 LCB20 3.69030941553353e-11
RB20 LCB20 B21 0.266535044422507
C20 A21 B21 2.50418376625721e-14
MNA20 B20 A20 0 0 Nmod L=2.55318350883171e-07 W=4.2257523363596e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.4515046727192e-05 PS=
+8.4515046727192e-05 NQSMOD=1
MPA20 B20 A20 VDD VDD Pmod L=2.50733395598687e-07 W=
+0.000105848300738233 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000211696601476467 PS=0.000211696601476467 NQSMOD=1
MNB20 A20 B20 0 0 Nmod L=2.53961238224852e-07 W=4.07467605160825e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.1493521032165e-05 PS=
+8.1493521032165e-05 NQSMOD=1
MPB20 A20 B20 VDD VDD Pmod L=2.52173406118976e-07 W=
+0.000104205251139887 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000208410502279773 PS=0.000208410502279773 NQSMOD=1
LA21 A21 LCA21 3.69030941553353e-11
RA21 LCA21 A22 0.266535044422507
LB21 B21 LCB21 3.69030941553353e-11
RB21 LCB21 B22 0.266535044422507
C21 A22 B22 2.50418376625721e-14
MNA21 B21 A21 0 0 Nmod L=2.46323292867561e-07 W=4.1601573531982e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.32031470639639e-05 PS=
+8.32031470639639e-05 NQSMOD=1
MPA21 B21 A21 VDD VDD Pmod L=2.54613442115316e-07 W=
+0.000104931161465525 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.00020986232293105 PS=0.00020986232293105 NQSMOD=1
MNB21 A21 B21 0 0 Nmod L=2.55836584454404e-07 W=4.10424160274173e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.20848320548346e-05 PS=
+8.20848320548346e-05 NQSMOD=1
MPB21 A21 B21 VDD VDD Pmod L=2.54709741956022e-07 W=
+0.000102062091080516 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000204124182161031 PS=0.000204124182161031 NQSMOD=1
LA22 A22 LCA22 3.69030941553353e-11
RA22 LCA22 A23 0.266535044422507
LB22 B22 LCB22 3.69030941553353e-11
RB22 LCB22 B23 0.266535044422507
C22 A23 B23 2.50418376625721e-14
MNA22 B22 A22 0 0 Nmod L=2.54430620981417e-07 W=4.19307535657001e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.38615071314001e-05 PS=
+8.38615071314001e-05 NQSMOD=1
MPA22 B22 A22 VDD VDD Pmod L=2.46694525572975e-07 W=
+0.000103108817734331 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000206217635468663 PS=0.000206217635468663 NQSMOD=1
MNB22 A22 B22 0 0 Nmod L=2.4991048194413e-07 W=4.12343575509987e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.24687151019974e-05 PS=
+8.24687151019974e-05 NQSMOD=1
MPB22 A22 B22 VDD VDD Pmod L=2.53435790976082e-07 W=
+0.000105540213369592 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000211080426739185 PS=0.000211080426739185 NQSMOD=1
LA23 A23 LCA23 3.69030941553353e-11
RA23 LCA23 A24 0.266535044422507
LB23 B23 LCB23 3.69030941553353e-11
RB23 LCB23 B24 0.266535044422507
C23 A24 B24 2.50418376625721e-14
MNA23 B23 A23 0 0 Nmod L=2.47985427798248e-07 W=4.14939059451511e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.29878118903023e-05 PS=
+8.29878118903023e-05 NQSMOD=1
MPA23 B23 A23 VDD VDD Pmod L=2.50625862917368e-07 W=
+0.000104857443713713 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000209714887427425 PS=0.000209714887427425 NQSMOD=1
MNB23 A23 B23 0 0 Nmod L=2.48906363214973e-07 W=4.09072154111792e-05
+AD=3.125e-11 AS=3.125e-11 PD=8.18144308223583e-05 PS=
+8.18144308223583e-05 NQSMOD=1
MPB23 A23 B23 VDD VDD Pmod L=2.544246792556e-07 W=
+0.000106667496188909 AD=7.8125e-11 AS=7.8125e-11 PD=
+0.000213334992377817 PS=0.000213334992377817 NQSMOD=1
RCROSS1 A0 B24 0.001
RCROSS2 B0 A24 0.001
.SAVE VDD0
.SAVE VSS0
.SAVE VDD_A0
.SAVE VSS_A0
.SAVE VDD_B0
.SAVE VSS_B0
.SAVE A0 B0 LA0#branch LB0#branch A1 B1 LA1#branch LB1#branch A2 B2
+LA2#branch LB2#branch A3 B3 LA3#branch LB3#branch A4 B4 LA4#branch
+LB4#branch A5 B5 LA5#branch LB5#branch A6 B6 LA6#branch LB6#branch
+A7 B7 LA7#branch LB7#branch A8 B8 LA8#branch LB8#branch A9 B9
+LA9#branch LB9#branch A10 B10 LA10#branch LB10#branch A11 B11
+LA11#branch LB11#branch A12 B12 LA12#branch LB12#branch A13 B13
+LA13#branch LB13#branch A14 B14 LA14#branch LB14#branch A15 B15
+LA15#branch LB15#branch A16 B16 LA16#branch LB16#branch A17 B17
+LA17#branch LB17#branch A18 B18 LA18#branch LB18#branch A19 B19
+LA19#branch LB19#branch A20 B20 LA20#branch LB20#branch A21 B21
+LA21#branch LB21#branch A22 B22 LA22#branch LB22#branch A23 B23
+LA23#branch LB23#branch
**
**INCLUDING FILE: ./proj1/process.models....
*
* Typical N Typical P - from process corners (taken from tsmc025_corners.bsim3 fron NCSU)
*
* TSMC 0.25u 5M 1P process. 2.5V transistor models
.MODEL Nmod NMOS LEVEL=8
+TNOM = 25
+VERSION = 3.2.2 TOX = 5.8e-9
+XJ = 1E-07 NCH = 2.354946E+17 LLN = 1
+LWN = 1 WLN = 1 WWN = 1
+LINT = 1.76E-08 WINT = 6.75E-09 MOBMOD = 1
+BINUNIT = 2 DWG = 0 DWB = 0
+VTH0 = 0.4321336 LVTH0 = 2.081814E-08 WVTH0 = -5.470342E-11
+PVTH0 = -6.721795E-16 K1 = 0.3281252 LK1 = 9.238362E-08
+WK1 = 2.878255E-08 PK1 = -2.426481E-14 K2 = 0.0402824
+LK2 = -3.208392E-08 WK2 = -1.154091E-08 PK2 = 9.192045E-15
+K3 = 0 DVT0 = 0 DVT1 = 0
+DVT2 = 0 DVT0W = 0 DVT1W = 0
+DVT2W = 0 NLX = 0 W0 = 0
+K3B = 0 VSAT = 7.586954E+04 LVSAT = 3.094656E-03
+WVSAT = -1.747416E-03 PVSAT = 8.820956E-10 UA = 8.924498E-10
+LUA = -1.511745E-16 WUA = -3.509821E-17 PUA = -3.08778E-23
+UB = 8.928832E-21 LUB = -1.655745E-27 WUB = -2.03282E-27
+PUB = 3.4578E-34 UC = -1.364265E-11 LUC = 1.170473E-17
+WUC = -1.256705E-18 PUC = -6.249644E-24 RDSW = 447.8871
+PRWB = 0 PRWG = 0 WR = 0.99
+U0 = 0.06005258 LU0 = -6.31976E-09 WU0 = -8.819531E-09
+PU0 = 3.57209E-15 A0 = -1.468837 LA0 = 6.419548E-07
+WA0 = 5.512414E-07 PA0 = -9.222928E-14 KETA = -0.04922795
+LKETA = 2.360844E-08 WKETA = 1.560385E-08 PKETA = -5.98377E-15
+A1 = 0.02659908 LA1 = -6.511454E-09 A2 = 1
+AGS = -4.01637 LAGS = 1.090294E-06 WAGS = 1.162021E-06
+PAGS = -3.108579E-13 B0 = 0 B1 = 0
+VOFF = -0.1829426 LVOFF = 9.941631E-09 WVOFF = 1.568082E-08
+PVOFF = -2.832958E-15 NFACTOR = 0.6790636 LNFACTOR= 3.454948E-08
+WNFACTOR= 1.501016E-07 PNFACTOR= -2.955591E-14 CIT = 2.218499E-04
+LCIT = -1.076934E-10 WCIT = -3.286884E-10 PCIT = 1.658928E-16
+CDSC = 0 CDSCB = 0 CDSCD = 0
+ETA0 = 1.215578E-04 LETA0 = -1.037758E-11 WETA0 = -3.030225E-11
+PETA0 = 1.529658E-17 ETAB = 3.548681E-03 LETAB = -1.791374E-09
+WETAB = -6.897268E-10 PETAB = 3.481742E-16 DSUB = 0
+PCLM = 3.583838 PDIBLC1 = 0 PDIBLC2 = 5.379674E-03
+LPDIBLC2= 7.808481E-09 WPDIBLC2= 5.516945E-10 PPDIBLC2= -2.784957E-16
+PDIBLCB = -0.1229374 LPDIBLCB= 4.956215E-08 WPDIBLCB= 3.299946E-08
+PPDIBLCB= -9.624918E-15 DROUT = 0 PSCBE1 = 4.472639E+08
+LPSCBE1 = 28.64041 WPSCBE1 = 15.7154 PPSCBE1 = -7.933138E-06
+PSCBE2 = 1.842585E-06 LPSCBE2 = 2.871008E-12 WPSCBE2 = 2.579183E-12
+PPSCBE2 = -1.301972E-18 PVAG = -2.015254E-03 LPVAG = 1.017757E-09
+WPVAG = 3.07622E-10 PPVAG = -1.55418E-16 DELTA = -0.02862256
+LDELTA = 1.492454E-08 WDELTA = -6.71663E-09 PDELTA = 3.407521E-15
+ALPHA0 = 0 BETA0 = 30 KT1 = -0.2579945
+LKT1 = -1.664895E-08 WKT1 = -1.633463E-08 PKT1 = 3.755864E-15
+KT2 = -0.05347481 LKT2 = 8.244731E-09 WKT2 = 1.13705E-09
+PKT2 = -1.240924E-15 AT = -1.132632E+04 LAT = 6.469047E-03
+WAT = 6.829220E-04 PAT = -4.154249E-10 UTE = -2.309089
+LUTE = 1.662427E-07 WUTE = 1.244801E-07 PUTE = -5.627924E-14
+UA1 = -3.461758E-10 LUA1 = 1.747495E-16 WUA1 = -1.42065E-16
+PUA1 = 7.171442E-23 UB1 = 0 UC1 = -2.38157E-12
+LUC1 = -2.895726E-18 WUC1 = -1.990052E-17 PUC1 = 1.004497E-23
+KT1L = 0 PRT = -1E-18 CJ = 2.024128E-3
+MJ = 0.4960069 PB = 0.9173808 CJSW = 2.751528E-10
+MJSW = 0.443145 PBSW = 0.9173808 CJSWG = 2.135064E-10
+MJSWG = 0.443145 PBSWG = 0.9173808
+RSH = 4.5
+XTI = 3
+CGDO = 3.11E-10 CGSO = 3.11E-10 CAPMOD = 2
+XPART = 1 CF = 0
+JS = 1E-06
+JSW = 5E-11
.MODEL Pmod PMOS LEVEL=8
+VERSION = 3.2.2
+TNOM = 25 TOX = 5.8e-9
+XJ = 1E-7 NCH = 4.1589E17
+LLN = 1 LWN = 1 WLN = 1
+WWN = 1 LINT = 1.2365E-8 WINT = 7.8E-9
+MOBMOD = 1 BINUNIT = 2 DWG = 0
+DWB = 0 VTH0 = -0.6236538 LVTH0 = 2.649834E-8
+WVTH0 = 3.214189E-8 PVTH0 = -3.22268E-15 K1 = 0.4198155
+LK1 = 5.770498E-8 WK1 = 5.577151E-8 PK1 = -2.81684E-14
+K2 = 0.0429467 LK2 = -2.296405E-8 WK2 = -1.355302E-8
+PK2 = 6.848271E-15 K3 = 0 DVT0 = 0
+DVT1 = 0 DVT2 = 0 DVT0W = 0
+DVT1W = 0 DVT2W = 0 NLX = 0
+W0 = 0 K3B = 0 VSAT = 1.443912E5
+LVSAT = -7.688012E-4 WVSAT = -6.083648E-3 PVSAT = 2.186471E-10
+UA = 1.846811E-9 LUA = -3.27694E-16 WUA = -2.82106E-16
+PUA = 7.180233E-23 UB = -7.84535E-19 LUB = 4.772849E-25
+WUB = 2.599205E-25 PUB = -1.46530E-31 UC = -1.75560E-10
+LUC = 3.360832E-17 WUC = 1.504425E-17 PUC = -1.30556E-23
+RDSW = 1.03E3 PRWB = 0 PRWG = 0
+WR = 1 U0 = 0.0136443 LU0 = -7.22084E-10
+WU0 = -1.088554E-9 PU0 = 2.730854E-16 A0 = 0.1071803
+LA0 = 4.64252E-7 WA0 = 5.383179E-7 PA0 = -1.32033E-13
+KETA = -4.943762E-3 LKETA = -3.565304E-9 WKETA = -5.226247E-9
+PKETA = 2.640665E-15 A1 = 0 A2 = 0.4
+AGS = 0.1664005 LAGS = 1.19106E-7 WAGS = 5.29237E-8
+PAGS = -2.67304E-14 B0 = 0 B1 = 0
+VOFF = -0.0592623 LVOFF = -1.96686E-8 WVOFF = -1.486398E-8
+PVOFF = 7.510321E-15 NFACTOR = 0.8588103 LNFACTOR= -1.158881E-7
+WNFACTOR= 1.210664E-8 PNFACTOR= -6.11712E-15 CIT = 6.439495E-5
+LCIT = 2.916437E-10 WCIT = -3.11284E-11 PCIT = 1.572825E-17
+CDSC = 0 CDSCB = 0 CDSCD = 0
+ETA0 = -3.819468E-3 LETA0 = 2.155422E-9 WETA0 = 8.235612E-10
+PETA0 = -4.16037E-16 ETAB = 1.334637E-3 LETAB = -7.93631E-10
+WETAB = 5.284657E-11 PETAB = -2.68353E-17 DSUB = 0
+PCLM = 0.1098002 LPCLM = 6.874263E-7 WPCLM = 6.724724E-7
+PPCLM = -1.97766E-13 PDIBLC1 = 0 PDIBLC2 = 5.801323E-3
+LPDIBLC2= -1.81964E-9 WPDIBLC2= -5.853396E-9 PPDIBLC2= 2.957545E-15
+PDIBLCB = 0.1921199 DROUT = 0 PSCBE1 = 7.19E8
+PSCBE2 = 1E-20 PVAG = 0 DELTA = 0.01
+ALPHA0 = 0 BETA0 = 30 KT1 = -0.3248987
+LKT1 = -1.160393E-8 WKT1 = 4.153356E-8 PKT1 = -4.62347E-15
+KT2 = -0.0367632 AT = 1E4 UTE = -1.04
+UA1 = 3.992421E-10 UB1 = -9.23294E-19 LUB1 = -5.28718E-26
+WUB1 = -6.13069E-26 PUB1 = 1.503674E-32 UC1 = -1.00699E-12
+KT1L = 0 PRT = 0 CJ = 1.931092e-3
+MJ = 0.4812153 PB = 0.9134669 CJSW = 2.232277e-10
+MJSW = 0.3237595 PBSW = 0.9134669 CJSWG = 1.607088e-10
+MJSWG = 0.3237595 PBSWG = 0.9134669
+RSH = 3.5
+CGDO = 2.68e-10 CGSO = 2.68e-10
+CAPMOD = 2
+XPART = 1
+CF = 0 XTI = 3
+JS = 3E-7
+JSW = 5E-12
**.... FINISHED INCLUDING: ./proj1/process.models
**
.OPTIONS TEMP=25
VSLEW_CONTROL VSLEW 0 (PULSE 0 1 0 1e-09)
EVLOGIC VRAMP 0 VSLEW 0 2.5
VDDPOWER VDD VRAMP DC 0
VARACTOR_V VARACTOR_V 0 DC 2.5
.SAVE vddpower#branch
.SAVE vdd
.SAVE varactor_v
.TRAN 0.02n 3000n 0n 0.5n
.END

12
src/tcl/plot.tcl Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# WishFix \
exec wish -f "$0" ${1+"$@"}
###
package require spice
spice::source example.cir
spice::step 100
spice::plot a0 vs b0
spice::bltplot a0

50
src/tcl/vector_test.tcl Executable file
View File

@ -0,0 +1,50 @@
#!/bin/sh
# WishFix \
exec wish -f "$0" ${1+"$@"}
###
package require BLT
namespace import blt::*
package require spice
wm title . "Vector Test script"
wm geometry . 800x600+40+40
pack propagate . false
stripchart .chart
pack .chart -side top -fill both -expand true
.chart axis configure x -title "Time"
# Create a vector (and call it $vector)
#vector create v1
spice::source example.cir
spice::bg run
after 1000
vector create a0
vector create b0
vector create a1
vector create b1
vector create stime
proc bltupdate {} {
spice::spicetoblt a0 a0
spice::spicetoblt b0 b0
spice::spicetoblt a1 a1
spice::spicetoblt b1 b1
spice::spicetoblt time stime
#puts $spice::lastitercount
after 100 bltupdate
}
bltupdate
.chart element create a0 -color red -xdata stime -ydata a0
.chart element create b0 -color blue -xdata stime -ydata b0
.chart element create a1 -color yellow -xdata stime -ydata a1
.chart element create b1 -color black -xdata stime -ydata b1

1323
src/tclspice.c Executable file

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,16 @@
# Process this file with automake
CFLAGS = -g -O2 -Wall
CC = gcc
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
EXTRA_DIST = README
SUBDIRS = mif cm enh evt ipc idn
INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)
MAINTAINERCLEANFILES = Makefile.in
all: xspice.o
xspice.o:
$(COMPILE) -c xspice.c

24
src/xspice/README Executable file
View File

@ -0,0 +1,24 @@
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

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

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

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

@ -0,0 +1,437 @@
/* ===========================================================================
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 *translate(char *orig_card, char **inst_card,
char **mod_card);
static int get_poly_dimension(char *card);
// added as a quick bug fix, a lot of standard models have a linear poly(1) which
// fails in this code, Kevin Aylward April 15th 2000
char * (*FPConvertSpicePoly1ToBsource)(char *card); // this is so I can use the MFC class libary
/*
ENHtranslate_poly()
Translate all 2G6 style polynomial controlled sources in the deck
to new polynomial controlled source code model syntax.
*/
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;
int poly_dimension;
char *buff;
/* Iterate through each card in the deck and translate as needed */
for(d = deck; d; d = d->li_next)
{
/* If doesn't need to be translated, continue to next card */
if(! needs_translating(d->li_line))
continue;
// Start added as a quick fix to a xspice translation bug in poly(1) code
// Kevin Aylward April 15th 2000, fuck knows where it is
poly_dimension = get_poly_dimension(d->li_line);
if(poly_dimension == 1)//
{
buff = (FPConvertSpicePoly1ToBsource)(d->li_line);
if(buff)
{
FREE(d->li_line);
d->li_line = buff;
}
continue;
}
// End added as a quick fix to a xspice translation bug in poly(1) code
// Kevin Aylward April 15th 2000
/* 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 = 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;
/* 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 */
{
switch(*card) {
case 'e':
case 'g':
if(count_tokens(card) <=6)
return(0);
else
return(1);
case 'f':
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 */
/*
translate()
Do the syntax translation of the 2G6 source to the new code model syntax.
*/
static char *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 *name;
char **out_conn;
char **in_conn;
char **coef;
char *card;
/* Get 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 */
dim = get_poly_dimension(orig_card);
if(dim <= 0)
return("ERROR - Argument to poly() is not an integer\n");
/* Compute number of input connections based on type and dimension */
switch(type) {
case 'e':
case 'g':
num_conns = 2 * dim;
break;
default:
num_conns = dim;
}
/* Compute number of coefficients. Return error if less than one. */
if(dim == 1)
num_coefs = num_tokens - num_conns - 3;
else
num_coefs = num_tokens - num_conns - 5;
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);
out_conn = (void *) MALLOC(2 * sizeof(char *));
for(i = 0; i < 2; i++)
out_conn[i] = MIFgettok(&card);
if(dim > 1)
for(i = 0; i < 2; i++)
txfree(MIFgettok(&card));
in_conn = (void *) MALLOC(num_conns * sizeof(char *));
for(i = 0; i < num_conns; i++)
in_conn[i] = MIFgettok(&card);
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 = 50;
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 = 50;
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);
if((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), "] ");
if((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), "a$poly$%s", name);
sprintf(*mod_card, ".model a$poly$%s poly coef = [ ", name);
for(i = 0; i < num_coefs; i++)
sprintf(*mod_card + strlen(*mod_card), "%s ", coef[i]);
sprintf(*mod_card + strlen(*mod_card), "]");
/* 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);
} /* translate */
/*
get_poly_dimension()
Get the poly source dimension from the token immediately following
the 'poly' if any. If 'poly' is not present, return 1. If poly is
present and token following is a valid integer, return it. Else
return 0.
*/
static int get_poly_dimension(
char *card) /* the card text */
{
int i;
int dim;
char *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 a dimension of 1 */
tok = MIFgettok(&card);
if(strcmp(tok, "poly"))
{
FREE(tok);
tok = NULL;
return(1);
}
FREE(tok);
/* Must have been "poly", so next line must be a number */
/* Try to convert it. If successful, return the number */
/* else, return 0 to indicate an error... */
tok = MIFgettok(&card);
dim = atoi(tok);
FREE(tok);
return(dim);
} /* 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

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