Initial revision
This commit is contained in:
parent
a7e1405208
commit
d2ae47441b
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 );
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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*/
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef DEV_CPL
|
||||
#define DEV_CPL
|
||||
|
||||
SPICEdev *get_cpl_info(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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*/
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LIBRARIES = libcmxsp.a
|
||||
|
||||
libcmxsp_a_SOURCES = \
|
||||
cm.c \
|
||||
cmevt.c \
|
||||
cmmeters.c \
|
||||
cmutil.c
|
||||
|
||||
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,701 @@
|
|||
/* ===========================================================================
|
||||
FILE CM.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from user code models.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_analog_alloc()
|
||||
cm_analog_get_ptr()
|
||||
cm_analog_integrate()
|
||||
cm_analog_converge()
|
||||
cm_analog_set_temp_bkpt()
|
||||
cm_analog_set_perm_bkpt()
|
||||
cm_analog_ramp_factor()
|
||||
cm_analog_not_converged()
|
||||
cm_analog_auto_partial()
|
||||
|
||||
cm_message_get_errmsg()
|
||||
cm_message_send()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
#include "ngspice.h"
|
||||
#include "cm.h"
|
||||
#include "mif.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void cm_static_integrate(int byte_index,
|
||||
double integrand,
|
||||
double *integral,
|
||||
double *partial);
|
||||
|
||||
/*
|
||||
|
||||
cm_analog_alloc()
|
||||
|
||||
This function is called from code model C functions to allocate
|
||||
state storage for a particular instance. It computes the number
|
||||
of doubles that need to be allocated in SPICE's state storage
|
||||
vectors from the number of bytes specified in it's argument and
|
||||
then allocates space for the states. An index into the SPICE
|
||||
state-vectors is stored in the instance's data structure along
|
||||
with a ``tag'' variable supplied by the caller so that the location
|
||||
of the state storage area can be found by cm_analog_get_ptr().
|
||||
|
||||
*/
|
||||
|
||||
void *cm_analog_alloc(
|
||||
int tag, /* The user-specified tag for this block of memory */
|
||||
int bytes) /* The number of bytes to allocate */
|
||||
{
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_State_t *state;
|
||||
|
||||
int doubles_needed;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Scan states in instance struct and see if tag has already been used */
|
||||
for(i = 0; i < here->num_state; i++) {
|
||||
if(tag == here->state[i].tag) {
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_alloc() - Tag already used in previous call\n";
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute number of doubles needed and allocate space in ckt->CKTstates[i] */
|
||||
doubles_needed = bytes / sizeof(double) + 1;
|
||||
|
||||
/* Allocate space in instance struct for this state descriptor */
|
||||
if(here->num_state == 0) {
|
||||
here->num_state = 1;
|
||||
here->state = (void *) MALLOC(sizeof(Mif_State_t));
|
||||
}
|
||||
else {
|
||||
here->num_state++;
|
||||
here->state = (void *) REALLOC(here->state,
|
||||
here->num_state * sizeof(Mif_State_t));
|
||||
}
|
||||
|
||||
/* Fill in the members of the state descriptor struct */
|
||||
state = &(here->state[here->num_state - 1]);
|
||||
state->tag = tag;
|
||||
state->index = ckt->CKTnumStates;
|
||||
state->doubles = doubles_needed;
|
||||
state->bytes = bytes;
|
||||
|
||||
|
||||
/* Add the states to the ckt->CKTstates vectors */
|
||||
ckt->CKTnumStates += doubles_needed;
|
||||
for(i=0;i<=ckt->CKTmaxOrder+1;i++) {
|
||||
if(ckt->CKTnumStates == doubles_needed)
|
||||
ckt->CKTstates[i] = (double *) MALLOC(ckt->CKTnumStates * sizeof(double));
|
||||
else
|
||||
ckt->CKTstates[i] = (double *) REALLOC(ckt->CKTstates[i],
|
||||
ckt->CKTnumStates * sizeof(double));
|
||||
}
|
||||
|
||||
/* Return pointer to the allocated space in state 0 */
|
||||
return( (void *) (ckt->CKTstates[0] + (ckt->CKTnumStates - doubles_needed)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_get_ptr()
|
||||
|
||||
This function is called from code model C functions to return a
|
||||
pointer to state storage allocated with cm_analog_alloc(). A tag
|
||||
specified in its argument list is used to locate the state in
|
||||
question. A second argument specifies whether the desired state
|
||||
is for the current timestep or from a preceding timestep. The
|
||||
location of the state in memory is then computed and returned.
|
||||
*/
|
||||
|
||||
void *cm_analog_get_ptr(
|
||||
int tag, /* The user-specified tag for this block of memory */
|
||||
int timepoint) /* The timepoint of interest - 0=current 1=previous */
|
||||
{
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_State_t *state=NULL;
|
||||
|
||||
Mif_Boolean_t got_tag;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Scan states in instance struct and see if tag exists */
|
||||
for(got_tag = MIF_FALSE, i = 0; i < here->num_state; i++) {
|
||||
if(tag == here->state[i].tag) {
|
||||
state = &(here->state[i]);
|
||||
got_tag = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return error if tag not found */
|
||||
if(! got_tag) {
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_get_ptr() - Bad tag\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Return error if timepoint is not 0 or 1 */
|
||||
if((timepoint < 0) || (timepoint > 1)) {
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_get_ptr() - Bad timepoint\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Return address of requested state in ckt->CKTstates[timepoint] vector */
|
||||
return( (void *) (ckt->CKTstates[timepoint] + state->index) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_integrate()
|
||||
|
||||
This function performs a numerical integration on the state
|
||||
supplied in its argument list according to the integrand also
|
||||
supplied in the argument list. The next value of the integral
|
||||
and the partial derivative with respect to the integrand input is
|
||||
returned. The integral argument must be a pointer to memory
|
||||
previously allocated through a call to cm_analog_alloc(). If this is
|
||||
the first call to cm_analog_integrate(), information is entered into the
|
||||
instance structure to mark that the integral should be processed
|
||||
by MIFtrunc and MIFconvTest.
|
||||
*/
|
||||
|
||||
int cm_analog_integrate(
|
||||
double integrand, /* The integrand */
|
||||
double *integral, /* The current and returned value of integral */
|
||||
double *partial) /* The partial derivative of integral wrt integrand */
|
||||
{
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_Intgr_t *intgr;
|
||||
Mif_Boolean_t got_index;
|
||||
|
||||
char *char_state0;
|
||||
char *char_state;
|
||||
|
||||
int byte_index;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Check to be sure we're in transient analysis */
|
||||
if(g_mif_info.circuit.anal_type != MIF_TRAN) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - Called in non-transient analysis\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Preliminary check to be sure argument was allocated by cm_analog_alloc() */
|
||||
if(ckt->CKTnumStates <= 0) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - Integral must be memory allocated by cm_analog_alloc()\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Compute byte offset from start of state0 vector */
|
||||
char_state0 = (char *) ckt->CKTstate0;
|
||||
char_state = (char *) integral;
|
||||
byte_index = char_state - char_state0;
|
||||
|
||||
/* Check to be sure argument address is in range of state0 vector */
|
||||
if((byte_index < 0) ||
|
||||
(byte_index > ((ckt->CKTnumStates - 1) * sizeof(double)) ) ) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - Argument must be in state vector 0\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Scan the intgr array in the instance struct to see if already exists */
|
||||
for(got_index = MIF_FALSE, i = 0; i < here->num_intgr; i++) {
|
||||
if(here->intgr[i].byte_index == byte_index) {
|
||||
got_index = MIF_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report error if not found and this is not the first load pass in tran analysis */
|
||||
if((! got_index) && (! g_mif_info.circuit.anal_init)) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_integrate() - New integral and not initialization pass\n";
|
||||
*partial = 0.0;
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* If new integral state, allocate space in instance */
|
||||
/* struct for this intgr descriptor and register it with */
|
||||
/* the cm_analog_converge() function */
|
||||
if(! got_index) {
|
||||
if(here->num_intgr == 0) {
|
||||
here->num_intgr = 1;
|
||||
here->intgr = (void *) MALLOC(sizeof(Mif_Intgr_t));
|
||||
}
|
||||
else {
|
||||
here->num_intgr++;
|
||||
here->intgr = (void *) REALLOC(here->intgr,
|
||||
here->num_intgr * sizeof(Mif_Intgr_t));
|
||||
}
|
||||
intgr = &(here->intgr[here->num_intgr - 1]);
|
||||
intgr->byte_index = byte_index;
|
||||
if(cm_analog_converge(integral)) {
|
||||
printf("%s\n",g_mif_info.errmsg);
|
||||
g_mif_info.errmsg = "ERROR - cm_analog_integrate() - Failure in cm_analog_converge() call\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the new integral and the partial */
|
||||
cm_static_integrate(byte_index, integrand, integral, partial);
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_converge()
|
||||
|
||||
This function registers a state variable allocated with
|
||||
cm_analog_alloc() to be subjected to a convergence test at the end of
|
||||
each iteration. The state variable must be a double.
|
||||
Information is entered into the instance structure to mark that
|
||||
the state variable should be processed by MIFconvTest.
|
||||
*/
|
||||
|
||||
int cm_analog_converge(
|
||||
double *state) /* The state to be converged */
|
||||
{
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Mif_Conv_t *conv;
|
||||
|
||||
char *char_state0;
|
||||
char *char_state;
|
||||
|
||||
int byte_index;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Preliminary check to be sure argument was allocated by cm_analog_alloc() */
|
||||
if(ckt->CKTnumStates <= 0) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_converge() - Argument must be memory allocated by cm_analog_alloc()\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Compute byte offset from start of state0 vector */
|
||||
char_state0 = (char *) ckt->CKTstate0;
|
||||
char_state = (char *) state;
|
||||
byte_index = char_state - char_state0;
|
||||
|
||||
/* Check to be sure argument address is in range of state0 vector */
|
||||
if((byte_index < 0) ||
|
||||
(byte_index > ((ckt->CKTnumStates - 1) * sizeof(double)) ) ) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_converge() - Argument must be in state vector 0\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Scan the conv array in the instance struct to see if already registered */
|
||||
/* If so, do nothing, just return */
|
||||
for(i = 0; i < here->num_conv; i++) {
|
||||
if(here->conv[i].byte_index == byte_index)
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
/* Allocate space in instance struct for this conv descriptor */
|
||||
if(here->num_conv == 0) {
|
||||
here->num_conv = 1;
|
||||
here->conv = (void *) MALLOC(sizeof(Mif_Conv_t));
|
||||
}
|
||||
else {
|
||||
here->num_conv++;
|
||||
here->conv = (void *) REALLOC(here->conv,
|
||||
here->num_conv * sizeof(Mif_Conv_t));
|
||||
}
|
||||
|
||||
/* Fill in the conv descriptor data */
|
||||
conv = &(here->conv[here->num_conv - 1]);
|
||||
conv->byte_index = byte_index;
|
||||
conv->last_value = 1.0e30; /* There should be a better way ... */
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_message_get_errmsg()
|
||||
|
||||
This function returns the address of an error message string set
|
||||
by a call to some code model support function.
|
||||
*/
|
||||
|
||||
char *cm_message_get_errmsg(void)
|
||||
{
|
||||
return(g_mif_info.errmsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_set_temp_bkpt()
|
||||
|
||||
This function is called by a code model C function to set a
|
||||
temporary breakpoint. These temporary breakpoints remain in
|
||||
effect only until the next timestep is taken. A temporary
|
||||
breakpoint added with a time less than the current time, but
|
||||
greater than the last successful timestep causes the simulator to
|
||||
abandon the current timestep and decrease the timestep to hit the
|
||||
breakpoint. A temporary breakpoint with a time greater than the
|
||||
current time causes the simulator to make the breakpoint the next
|
||||
timepoint if the next timestep would produce a time greater than
|
||||
that of the breakpoint.
|
||||
*/
|
||||
|
||||
|
||||
int cm_analog_set_temp_bkpt(
|
||||
double time) /* The time of the breakpoint to be set */
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Make sure breakpoint is not prior to last accepted timepoint */
|
||||
if(time < ((ckt->CKTtime - ckt->CKTdelta) + ckt->CKTminBreak)) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_analog_set_temp_bkpt() - Time < last accepted timepoint\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* If too close to a permanent breakpoint or the current time, discard it */
|
||||
if( (fabs(time - ckt->CKTbreaks[0]) < ckt->CKTminBreak) ||
|
||||
(fabs(time - ckt->CKTbreaks[1]) < ckt->CKTminBreak) ||
|
||||
(fabs(time - ckt->CKTtime) < ckt->CKTminBreak) )
|
||||
return(MIF_OK);
|
||||
|
||||
/* If < current dynamic breakpoint, make it the current breakpoint */
|
||||
if( time < g_mif_info.breakpoint.current)
|
||||
g_mif_info.breakpoint.current = time;
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_set_perm_bkpt()
|
||||
|
||||
This function is called by a code model C function to set a
|
||||
permanent breakpoint. These permanent breakpoints remain in
|
||||
effect from the time they are introduced until the simulation
|
||||
time equals or exceeds the breakpoint time. A permanent
|
||||
breakpoint added with a time less than the current time, but
|
||||
greater than the last successful timestep causes the simulator to
|
||||
abandon the current timestep and decrease the timestep to hit the
|
||||
breakpoint. A permanent breakpoint with a time greater than the
|
||||
current time causes the simulator to make the breakpoint the next
|
||||
timepoint if the next timestep would produce a time greater than
|
||||
that of the breakpoint.
|
||||
*/
|
||||
|
||||
|
||||
int cm_analog_set_perm_bkpt(
|
||||
double time) /* The time of the breakpoint to be set */
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Call cm_analog_set_temp_bkpt() to force backup if less than current time */
|
||||
if(time < (ckt->CKTtime + ckt->CKTminBreak))
|
||||
return(cm_analog_set_temp_bkpt(time));
|
||||
else
|
||||
CKTsetBreak(ckt,time);
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_ramp_factor()
|
||||
|
||||
This function returns the current value of the ramp factor
|
||||
associated with the ``ramptime'' option. For this option
|
||||
to work best, models with analog outputs that may be non-zero at
|
||||
time zero should call this function and scale their outputs
|
||||
and partials by the ramp factor.
|
||||
*/
|
||||
|
||||
|
||||
double cm_analog_ramp_factor(void)
|
||||
{
|
||||
|
||||
CKTcircuit *ckt;
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
||||
/* if ramptime == 0.0, no ramptime option given, so return 1.0 */
|
||||
/* this is the most common case, so it goes first */
|
||||
if(ckt->enh->ramp.ramptime == 0.0)
|
||||
return(1.0);
|
||||
|
||||
/* else if not transient analysis, return 1.0 */
|
||||
else if( (!(ckt->CKTmode & MODETRANOP)) && (!(ckt->CKTmode & MODETRAN)) )
|
||||
return(1.0);
|
||||
|
||||
/* else if time >= ramptime, return 1.0 */
|
||||
else if(ckt->CKTtime >= ckt->enh->ramp.ramptime)
|
||||
return(1.0);
|
||||
|
||||
/* else time < end of ramp, so compute and return factor based on time */
|
||||
else
|
||||
return(ckt->CKTtime / ckt->enh->ramp.ramptime);
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************ */
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985 Thomas L. Quarles
|
||||
*
|
||||
* This is a modified version of the function NIintegrate()
|
||||
*
|
||||
* Modifications are Copyright 1991 Georgia Tech Research Institute
|
||||
*
|
||||
*/
|
||||
|
||||
static void cm_static_integrate(int byte_index,
|
||||
double integrand,
|
||||
double *integral,
|
||||
double *partial)
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
double intgr[7];
|
||||
double cur=0;
|
||||
double *double_ptr;
|
||||
|
||||
double ceq;
|
||||
double geq;
|
||||
|
||||
char *char_ptr;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the address of the ckt struct from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* Get integral values from current and previous timesteps */
|
||||
for(i = 0; i <= ckt->CKTorder; i++) {
|
||||
char_ptr = (char *) ckt->CKTstates[i];
|
||||
char_ptr += byte_index;
|
||||
double_ptr = (double *) char_ptr;
|
||||
intgr[i] = *double_ptr;
|
||||
}
|
||||
|
||||
|
||||
/* Do what SPICE3C1 does for its implicit integration */
|
||||
|
||||
switch(ckt->CKTintegrateMethod) {
|
||||
|
||||
case TRAPEZOIDAL:
|
||||
|
||||
switch(ckt->CKTorder) {
|
||||
|
||||
case 1:
|
||||
cur = ckt->CKTag[1] * intgr[1];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* WARNING - This code needs to be redone. */
|
||||
/* The correct code should rely on one previous value */
|
||||
/* of cur as done in NIintegrate() */
|
||||
cur = -0.5 * ckt->CKTag[0] * intgr[1];
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GEAR:
|
||||
cur = 0.0;
|
||||
|
||||
switch(ckt->CKTorder) {
|
||||
|
||||
case 6:
|
||||
cur += ckt->CKTag[6] * intgr[6];
|
||||
/* fall through */
|
||||
case 5:
|
||||
cur += ckt->CKTag[5] * intgr[5];
|
||||
/* fall through */
|
||||
case 4:
|
||||
cur += ckt->CKTag[4] * intgr[4];
|
||||
/* fall through */
|
||||
case 3:
|
||||
cur += ckt->CKTag[3] * intgr[3];
|
||||
/* fall through */
|
||||
case 2:
|
||||
cur += ckt->CKTag[2] * intgr[2];
|
||||
/* fall through */
|
||||
case 1:
|
||||
cur += ckt->CKTag[1] * intgr[1];
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ceq = cur;
|
||||
geq = ckt->CKTag[0];
|
||||
|
||||
/* WARNING: Take this out when the case 2: above is fixed */
|
||||
if((ckt->CKTintegrateMethod == TRAPEZOIDAL) &&
|
||||
(ckt->CKTorder == 2))
|
||||
geq *= 0.5;
|
||||
|
||||
|
||||
/* The following code is equivalent to */
|
||||
/* the solution of one matrix iteration to produce the */
|
||||
/* integral value. */
|
||||
|
||||
*integral = (integrand - ceq) / geq;
|
||||
*partial = 1.0 / geq;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_not_converged()
|
||||
|
||||
This function tells the simulator not to allow the current
|
||||
iteration to be the final iteration. It is called when
|
||||
a code model performs internal limiting on one or more of
|
||||
its inputs to assist convergence.
|
||||
*/
|
||||
|
||||
void cm_analog_not_converged(void)
|
||||
{
|
||||
(g_mif_info.ckt->CKTnoncon)++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_message_send()
|
||||
|
||||
This function prints a message output from a code model, prepending
|
||||
the instance name.
|
||||
*/
|
||||
|
||||
|
||||
int cm_message_send(
|
||||
char *msg) /* The message to output. */
|
||||
{
|
||||
MIFinstance *here;
|
||||
|
||||
/* Get the address of the instance struct from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
|
||||
/* Print the name of the instance and the message */
|
||||
printf("\nInstance: %s Message: %s\n", (char *) here->MIFname, msg);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_auto_partial()
|
||||
|
||||
This function tells the simulator to automatically compute
|
||||
approximations of partial derivatives of analog outputs
|
||||
with respect to analog inputs. When called from a code
|
||||
model, it sets a flag in the g_mif_info structure
|
||||
which tells function MIFload() and it's associated
|
||||
MIFauto_partial() function to perform the necessary
|
||||
calculations.
|
||||
*/
|
||||
|
||||
|
||||
void cm_analog_auto_partial(void)
|
||||
{
|
||||
g_mif_info.auto_partial.local = MIF_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
/* ===========================================================================
|
||||
FILE CMevt.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from user code models
|
||||
that are associated with the event-driven algorithm.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_event_alloc()
|
||||
cm_event_get_ptr()
|
||||
cm_event_queue()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "cm.h"
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_event_alloc()
|
||||
|
||||
This function is called from code model C functions to allocate
|
||||
state storage for a particular event-driven
|
||||
instance. It is similar to the
|
||||
function cm_analog_alloc() used by analog models, but allocates states
|
||||
that are rotated during event-driven 'timesteps' instead of analog
|
||||
timesteps.
|
||||
*/
|
||||
|
||||
|
||||
void *cm_event_alloc(
|
||||
int tag, /* The user-specified tag for the memory block */
|
||||
int bytes) /* The number of bytes to be allocated */
|
||||
{
|
||||
|
||||
int inst_index;
|
||||
int num_tags;
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
void *ptr;
|
||||
|
||||
Evt_State_Desc_t **desc_ptr;
|
||||
Evt_State_Desc_t *desc;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_State_t *state;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
||||
/* If not initialization pass, return error */
|
||||
if(here->initialized) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_alloc() - Cannot alloc when not initialization pass\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_index = here->inst_index;
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
|
||||
/* Scan state descriptor list to determine if tag is present and to */
|
||||
/* find the end of the list. Report error if duplicate tag */
|
||||
desc_ptr = &(state_data->desc[inst_index]);
|
||||
desc = *desc_ptr;
|
||||
num_tags = 1;
|
||||
while(desc) {
|
||||
if(desc->tag == tag) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_alloc() - Duplicate tag\n";
|
||||
return(NULL);
|
||||
}
|
||||
desc_ptr = &(desc->next);
|
||||
desc = *desc_ptr;
|
||||
num_tags++;
|
||||
}
|
||||
|
||||
/* Create a new state description structure at end of list */
|
||||
/* and fill in the data and update the total size */
|
||||
*desc_ptr = (void *) MALLOC(sizeof(Evt_State_Desc_t));
|
||||
desc = *desc_ptr;
|
||||
desc->tag = tag;
|
||||
desc->size = bytes;
|
||||
desc->offset = state_data->total_size[inst_index];
|
||||
state_data->total_size[inst_index] += bytes;
|
||||
|
||||
/* Create a new state structure if list starting at head is null */
|
||||
state = state_data->head[inst_index];
|
||||
if(state == NULL) {
|
||||
state = (void *) MALLOC(sizeof(Evt_State_t));
|
||||
state_data->head[inst_index] = state;
|
||||
}
|
||||
|
||||
/* Create or enlarge the block and set the time */
|
||||
if(num_tags == 1)
|
||||
state->block = MALLOC(state_data->total_size[inst_index]);
|
||||
else
|
||||
state->block = REALLOC(state->block,
|
||||
state_data->total_size[inst_index]);
|
||||
|
||||
state->step = g_mif_info.circuit.evt_step;
|
||||
|
||||
|
||||
/* Return allocated memory */
|
||||
ptr = ((char *)state->block) + desc->offset;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_event_get_ptr()
|
||||
|
||||
This function is called from code model C functions to return a
|
||||
pointer to state storage allocated with cm_event_alloc(). A tag
|
||||
specified in its argument list is used to locate the state in
|
||||
question. A second argument specifies whether the desired state
|
||||
is for the current timestep or from a preceding timestep. The
|
||||
location of the state in memory is then computed and returned.
|
||||
*/
|
||||
|
||||
|
||||
void *cm_event_get_ptr(
|
||||
int tag, /* The user-specified tag for the memory block */
|
||||
int timepoint) /* The timepoint - 0=current, 1=previous */
|
||||
{
|
||||
|
||||
int i;
|
||||
int inst_index;
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
void *ptr;
|
||||
|
||||
Evt_State_Desc_t *desc;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_State_t *state;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
||||
/* If initialization pass, return error */
|
||||
if((! here->initialized) && (timepoint > 0)) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_get_ptr() - Cannot get_ptr(tag,1) during initialization pass\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_index = here->inst_index;
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
/* Scan state descriptor list to find the descriptor for this tag. */
|
||||
/* Report error if tag not found */
|
||||
desc = state_data->desc[inst_index];
|
||||
while(desc) {
|
||||
if(desc->tag == tag)
|
||||
break;
|
||||
desc = desc->next;
|
||||
}
|
||||
|
||||
if(desc == NULL) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_get_ptr() - Specified tag not found\n";
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Get the state pointer from the current array */
|
||||
state = *(state_data->tail[inst_index]);
|
||||
|
||||
/* Backup the specified number of timesteps */
|
||||
for(i = 0; i < timepoint; i++)
|
||||
if(state->prev)
|
||||
state = state->prev;
|
||||
|
||||
/* Return pointer */
|
||||
ptr = ((char *) state->block) + desc->offset;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_event_queue()
|
||||
|
||||
This function queues an event for an instance participating
|
||||
in the event-driven algorithm.
|
||||
*/
|
||||
|
||||
|
||||
int cm_event_queue(
|
||||
double time) /* The time of the event to be queued */
|
||||
{
|
||||
|
||||
MIFinstance *here;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
here = g_mif_info.instance;
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
/* If breakpoint time <= current event time, return error */
|
||||
if(time <= g_mif_info.circuit.evt_step) {
|
||||
g_mif_info.errmsg =
|
||||
"ERROR - cm_event_queue() - Event time cannot be <= current time\n";
|
||||
return(MIF_ERROR);
|
||||
}
|
||||
|
||||
/* Add the event time to the inst queue */
|
||||
EVTqueue_inst(ckt, here->inst_index, g_mif_info.circuit.evt_step,
|
||||
time);
|
||||
|
||||
return(MIF_OK);
|
||||
}
|
||||
|
|
@ -0,0 +1,314 @@
|
|||
/* ===========================================================================
|
||||
FILE CMmeters.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from code models.
|
||||
These functions are primarily designed for use by the
|
||||
"cmeter" and "lmeter" models provided in the XSPICE
|
||||
code model library.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_netlist_get_c()
|
||||
cm_netlist_get_l()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
#include "ngspice.h"
|
||||
#include "cm.h"
|
||||
#include "mif.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
|
||||
#include "mifdefs.h"
|
||||
#include "cap/capdefs.h"
|
||||
#include "ind/inddefs.h"
|
||||
#include "vsrc/vsrcdefs.h"
|
||||
#include "inpdefs.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_netlist_get_c()
|
||||
|
||||
This is a special function designed for use with the c_meter
|
||||
model. It returns the parallel combination of the capacitance
|
||||
connected to the first port on the instance.
|
||||
*/
|
||||
|
||||
double cm_netlist_get_c()
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
MIFinstance *cmeter_inst;
|
||||
CAPinstance *cap_inst;
|
||||
VSRCinstance *vsrc_inst;
|
||||
|
||||
CAPmodel *cap_head;
|
||||
CAPmodel *cap_model;
|
||||
VSRCmodel *vsrc_head;
|
||||
VSRCmodel *vsrc_model;
|
||||
|
||||
int cap_type;
|
||||
int vsrc_type;
|
||||
|
||||
int cmeter_node;
|
||||
int vsrc_node;
|
||||
|
||||
double c;
|
||||
|
||||
|
||||
/* Get the circuit data structure and current instance */
|
||||
ckt = g_mif_info.ckt;
|
||||
cmeter_inst = g_mif_info.instance;
|
||||
|
||||
/* Get internal node number for positive node of cmeter input */
|
||||
cmeter_node = cmeter_inst->conn[0]->port[0]->smp_data.pos_node;
|
||||
|
||||
/* Initialize total capacitance value to zero */
|
||||
c = 0.0;
|
||||
|
||||
|
||||
/* ****************************************************** */
|
||||
/* Look for capacitors connected directly to cmeter input */
|
||||
/* ****************************************************** */
|
||||
|
||||
/* Get the head of the list of capacitor models in the circuit */
|
||||
cap_type = INPtypelook("Capacitor");
|
||||
if(cap_type < 0) {
|
||||
printf("\nERROR - Capacitor type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
cap_head = (CAPmodel *) ckt->CKThead[cap_type];
|
||||
|
||||
/* Scan through all capacitor instances and add in values */
|
||||
/* of any capacitors connected to cmeter input */
|
||||
|
||||
for(cap_model = cap_head; cap_model; cap_model = cap_model->CAPnextModel) {
|
||||
for(cap_inst = cap_model->CAPinstances;
|
||||
cap_inst;
|
||||
cap_inst = cap_inst->CAPnextInstance) {
|
||||
if((cmeter_node == cap_inst->CAPposNode) ||
|
||||
(cmeter_node == cap_inst->CAPnegNode)) {
|
||||
c += cap_inst->CAPcapac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ***************************************************************** */
|
||||
/* Look for capacitors connected through zero-valued voltage sources */
|
||||
/* ***************************************************************** */
|
||||
|
||||
/* Get the head of the list of voltage source models in the circuit */
|
||||
vsrc_type = INPtypelook("Vsource");
|
||||
if(vsrc_type < 0) {
|
||||
printf("\nERROR - Vsource type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
vsrc_head = (VSRCmodel *) ckt->CKThead[vsrc_type];
|
||||
|
||||
/* Scan through all voltage source instances and add in values */
|
||||
/* of any capacitors connected to cmeter input through voltage source */
|
||||
|
||||
for(vsrc_model = vsrc_head; vsrc_model; vsrc_model = vsrc_model->VSRCnextModel) {
|
||||
for(vsrc_inst = vsrc_model->VSRCinstances;
|
||||
vsrc_inst;
|
||||
vsrc_inst = vsrc_inst->VSRCnextInstance) {
|
||||
|
||||
/* Skip to next if not DC source with value = 0.0 */
|
||||
if((vsrc_inst->VSRCfunctionType != 0) ||
|
||||
(vsrc_inst->VSRCdcValue != 0.0))
|
||||
continue;
|
||||
|
||||
/* See if voltage source is connected to cmeter input */
|
||||
/* If so, get other node voltage source is connected to */
|
||||
/* If not, skip to next source */
|
||||
if(cmeter_node == vsrc_inst->VSRCposNode)
|
||||
vsrc_node = vsrc_inst->VSRCnegNode;
|
||||
else if(cmeter_node == vsrc_inst->VSRCnegNode)
|
||||
vsrc_node = vsrc_inst->VSRCposNode;
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
/* Scan through all capacitor instances and add in values */
|
||||
/* of any capacitors connected to the voltage source node */
|
||||
|
||||
for(cap_model = cap_head; cap_model; cap_model = cap_model->CAPnextModel) {
|
||||
for(cap_inst = cap_model->CAPinstances;
|
||||
cap_inst;
|
||||
cap_inst = cap_inst->CAPnextInstance) {
|
||||
if((vsrc_node == cap_inst->CAPposNode) ||
|
||||
(vsrc_node == cap_inst->CAPnegNode)) {
|
||||
c += cap_inst->CAPcapac;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* end for all vsrc instances */
|
||||
} /* end for all vsrc models */
|
||||
|
||||
|
||||
/* Return the total capacitance value */
|
||||
return(c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_netlist_get_l()
|
||||
|
||||
This is a special function designed for use with the l_meter
|
||||
model. It returns the equivalent value of inductance
|
||||
connected to the first port on the instance.
|
||||
*/
|
||||
|
||||
|
||||
double cm_netlist_get_l()
|
||||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
MIFinstance *lmeter_inst;
|
||||
INDinstance *ind_inst;
|
||||
VSRCinstance *vsrc_inst;
|
||||
|
||||
INDmodel *ind_head;
|
||||
INDmodel *ind_model;
|
||||
VSRCmodel *vsrc_head;
|
||||
VSRCmodel *vsrc_model;
|
||||
|
||||
int ind_type;
|
||||
int vsrc_type;
|
||||
|
||||
int lmeter_node;
|
||||
int vsrc_node;
|
||||
|
||||
double l;
|
||||
|
||||
|
||||
/* Get the circuit data structure and current instance */
|
||||
ckt = g_mif_info.ckt;
|
||||
lmeter_inst = g_mif_info.instance;
|
||||
|
||||
/* Get internal node number for positive node of lmeter input */
|
||||
lmeter_node = lmeter_inst->conn[0]->port[0]->smp_data.pos_node;
|
||||
|
||||
/* Initialize total inductance to infinity */
|
||||
l = 1.0e12;
|
||||
|
||||
|
||||
/* ****************************************************** */
|
||||
/* Look for inductors connected directly to lmeter input */
|
||||
/* ****************************************************** */
|
||||
|
||||
/* Get the head of the list of inductor models in the circuit */
|
||||
ind_type = INPtypelook("Inductor");
|
||||
if(ind_type < 0) {
|
||||
printf("\nERROR - Inductor type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
ind_head = (INDmodel *) ckt->CKThead[ind_type];
|
||||
|
||||
/* Scan through all inductor instances and add in values */
|
||||
/* of any inductors connected to lmeter input */
|
||||
|
||||
for(ind_model = ind_head; ind_model; ind_model = ind_model->INDnextModel) {
|
||||
for(ind_inst = ind_model->INDinstances;
|
||||
ind_inst;
|
||||
ind_inst = ind_inst->INDnextInstance) {
|
||||
if((lmeter_node == ind_inst->INDposNode) ||
|
||||
(lmeter_node == ind_inst->INDnegNode)) {
|
||||
l = 1.0 / ( (1.0 / l) + (1.0 / ind_inst->INDinduct) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ***************************************************************** */
|
||||
/* Look for inductors connected through zero-valued voltage sources */
|
||||
/* ***************************************************************** */
|
||||
|
||||
/* Get the head of the list of voltage source models in the circuit */
|
||||
vsrc_type = INPtypelook("Vsource");
|
||||
if(vsrc_type < 0) {
|
||||
printf("\nERROR - Vsource type not supported in this binary\n");
|
||||
return(0);
|
||||
}
|
||||
vsrc_head = (VSRCmodel *) ckt->CKThead[vsrc_type];
|
||||
|
||||
/* Scan through all voltage source instances and add in values */
|
||||
/* of any inductors connected to lmeter input through voltage source */
|
||||
|
||||
for(vsrc_model = vsrc_head; vsrc_model; vsrc_model = vsrc_model->VSRCnextModel) {
|
||||
for(vsrc_inst = vsrc_model->VSRCinstances;
|
||||
vsrc_inst;
|
||||
vsrc_inst = vsrc_inst->VSRCnextInstance) {
|
||||
|
||||
/* Skip to next if not DC source with value = 0.0 */
|
||||
if((vsrc_inst->VSRCfunctionType != 0) ||
|
||||
(vsrc_inst->VSRCdcValue != 0.0))
|
||||
continue;
|
||||
|
||||
/* See if voltage source is connected to lmeter input */
|
||||
/* If so, get other node voltage source is connected to */
|
||||
/* If not, skip to next source */
|
||||
if(lmeter_node == vsrc_inst->VSRCposNode)
|
||||
vsrc_node = vsrc_inst->VSRCnegNode;
|
||||
else if(lmeter_node == vsrc_inst->VSRCnegNode)
|
||||
vsrc_node = vsrc_inst->VSRCposNode;
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
/* Scan through all inductor instances and add in values */
|
||||
/* of any inductors connected to the voltage source node */
|
||||
|
||||
for(ind_model = ind_head; ind_model; ind_model = ind_model->INDnextModel) {
|
||||
for(ind_inst = ind_model->INDinstances;
|
||||
ind_inst;
|
||||
ind_inst = ind_inst->INDnextInstance) {
|
||||
if((vsrc_node == ind_inst->INDposNode) ||
|
||||
(vsrc_node == ind_inst->INDnegNode)) {
|
||||
l = 1.0 / ( (1.0 / l) + (1.0 / ind_inst->INDinduct) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* end for all vsrc instances */
|
||||
} /* end for all vsrc models */
|
||||
|
||||
|
||||
/* Return the total capacitance value */
|
||||
return(l);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
/* ===========================================================================
|
||||
FILE CMutil.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Jeff Murray
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions callable from user code models.
|
||||
These functions were written to support code models in the
|
||||
XSPICE library, but may be useful in general.
|
||||
|
||||
INTERFACES
|
||||
|
||||
cm_smooth_corner()
|
||||
cm_smooth_discontinuity()
|
||||
cm_smooth_pwl()
|
||||
|
||||
cm_climit_fcn()
|
||||
|
||||
cm_complex_set()
|
||||
cm_complex_add()
|
||||
cm_complex_subtract()
|
||||
cm_complex_multiply()
|
||||
cm_complex_divide()
|
||||
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
=========================================================================== */
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "cm.h"
|
||||
|
||||
/* Corner Smoothing Function ************************************
|
||||
* *
|
||||
* The following function smooths the transition between two *
|
||||
* slopes into a quadratic (parabolic) curve. The calling *
|
||||
* function passes an x,y coordinate representing the *
|
||||
* "breakpoint", a smoothing domain value (d), and the slopes at *
|
||||
* both endpoints, and the x value itself. The situation is *
|
||||
* shown below: B C *
|
||||
* A |<-d->| ^ y *
|
||||
* ---------*-----* | | *
|
||||
* lower_slope-^ |<-d->|\ | | *
|
||||
* \ | | *
|
||||
* \ | *------>x *
|
||||
* At A<x<C, cm_smooth_corner \ | *
|
||||
* returns a "y" value which \| *
|
||||
* smoothly transitions from *__ *
|
||||
* f(A) to f(C) in a parabolic \ | upper_slope *
|
||||
* fashion...the slope of the new \| *
|
||||
* function is also returned. \ *
|
||||
* *
|
||||
*****************************************************************/
|
||||
|
||||
void cm_smooth_corner(
|
||||
double x_input, /* The value of the x input */
|
||||
double x_center, /* The x intercept of the two slopes */
|
||||
double y_center, /* The y intercept of the two slopes */
|
||||
double domain, /* The smoothing domain */
|
||||
double lower_slope, /* The lower slope */
|
||||
double upper_slope, /* The upper slope */
|
||||
double *y_output, /* The smoothed y output */
|
||||
double *dy_dx) /* The partial of y wrt x */
|
||||
{
|
||||
double x_upper,y_upper,a,b,c,dy_dx_temp;
|
||||
|
||||
/* Set up parabolic constants */
|
||||
|
||||
x_upper = x_center + domain;
|
||||
y_upper = y_center + (upper_slope * domain);
|
||||
a = ((upper_slope - lower_slope) / 4.0) * (1 / domain);
|
||||
b = upper_slope - (2.0 * a * x_upper);
|
||||
c = y_upper - (a * x_upper * x_upper) - (b * x_upper);
|
||||
|
||||
/* Calculate y value & derivative */
|
||||
|
||||
dy_dx_temp = 2.0*a*x_input + b; /* Prevents reassignment problems */
|
||||
/* for x-limiting cases. */
|
||||
|
||||
*y_output = a*x_input*x_input + b*x_input + c;
|
||||
*dy_dx = dy_dx_temp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Discontinuity Smoothing Function *****************************
|
||||
* *
|
||||
* The following function smooths the transition between two *
|
||||
* values using an x^2 function. The calling function *
|
||||
* function passes an x1,y1 coordinate representing the *
|
||||
* starting point, an x2,y2 coordinate representing an ending *
|
||||
* point, and the x value itself. The situation is shown below: *
|
||||
* *
|
||||
* ^ y (xu,yu) *
|
||||
* | ---*----------- *
|
||||
* | --- | *
|
||||
* | -- *
|
||||
* | - | *
|
||||
* | - *
|
||||
* | - | *
|
||||
* | -- *
|
||||
* | (xl,yl) --- | *
|
||||
* ----|----*--- *
|
||||
* | | | *
|
||||
* O------------------------------------->x *
|
||||
*****************************************************************/
|
||||
|
||||
void cm_smooth_discontinuity(
|
||||
double x_input, /* The x value at which to compute y */
|
||||
double x_lower, /* The x value of the lower corner */
|
||||
double y_lower, /* The y value of the lower corner */
|
||||
double x_upper, /* The x value of the upper corner */
|
||||
double y_upper, /* The y value of the upper corner */
|
||||
double *y_output, /* The computed smoothed y value */
|
||||
double *dy_dx) /* The partial of y wrt x */
|
||||
{
|
||||
double x_center,y_center,a,b,c,center_slope;
|
||||
|
||||
|
||||
/* Derive x_center, y_center & center_slope values */
|
||||
x_center = (x_upper + x_lower) / 2.0;
|
||||
y_center = (y_upper + y_lower) / 2.0;
|
||||
center_slope = 2.0 * (y_upper - y_lower) / (x_upper - x_lower);
|
||||
|
||||
|
||||
if (x_input < x_lower) { /* x_input @ lower level */
|
||||
*y_output = y_lower;
|
||||
*dy_dx = 0.0;
|
||||
}
|
||||
else {
|
||||
if (x_input < x_center) { /* x_input in lower transition */
|
||||
a = center_slope / (x_upper - x_lower);
|
||||
b = center_slope - 2.0 * a * x_center;
|
||||
c = y_center - a * x_center * x_center - b * x_center;
|
||||
*y_output = a * x_input * x_input + b * x_input + c;
|
||||
*dy_dx = 2.0 * a * x_input + b;
|
||||
}
|
||||
else { /* x_input in upper transition */
|
||||
if (x_input < x_upper) {
|
||||
a = -center_slope / (x_upper - x_lower);
|
||||
b = -2.0 * a * x_upper;
|
||||
c = y_upper - a * x_upper * x_upper - b * x_upper;
|
||||
*y_output = a * x_input * x_input + b * x_input + c;
|
||||
*dy_dx = 2.0 * a * x_input + b;
|
||||
}
|
||||
else { /* x_input @ upper level */
|
||||
*y_output = y_upper;
|
||||
*dy_dx = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Controlled Limiter Function (modified CLIMIT) */
|
||||
|
||||
/*
|
||||
This is a special function created for use with the CLIMIT
|
||||
controlled limiter model.
|
||||
*/
|
||||
|
||||
void cm_climit_fcn(
|
||||
double in, /* The input value */
|
||||
double in_offset, /* The input offset */
|
||||
double cntl_upper, /* The upper control input value */
|
||||
double cntl_lower, /* The lower control input value */
|
||||
double lower_delta, /* The delta from control to limit value */
|
||||
double upper_delta, /* The delta from control to limit value */
|
||||
double limit_range, /* The limiting range */
|
||||
double gain, /* The gain from input to output */
|
||||
int percent, /* The fraction vs. absolute range flag */
|
||||
double *out_final, /* The output value */
|
||||
double *pout_pin_final, /* The partial of output wrt input */
|
||||
double *pout_pcntl_lower_final, /* The partial of output wrt lower control input */
|
||||
double *pout_pcntl_upper_final) /* The partial of output wrt upper control input */
|
||||
{
|
||||
|
||||
/* Define error message string constants */
|
||||
|
||||
char *climit_range_error = "\n**** ERROR ****\n* CLIMIT function linear range less than zero. *\n";
|
||||
|
||||
|
||||
double threshold_upper,threshold_lower,linear_range,
|
||||
out_lower_limit,out_upper_limit,limited_out,
|
||||
out,pout_pin,pout_pcntl_lower,pout_pcntl_upper,junk;
|
||||
|
||||
/* Find Upper & Lower Limits */
|
||||
|
||||
out_lower_limit = cntl_lower + lower_delta;
|
||||
out_upper_limit = cntl_upper - upper_delta;
|
||||
|
||||
|
||||
if (percent == TRUE) /* Set range to absolute value */
|
||||
limit_range = limit_range *
|
||||
(out_upper_limit - out_lower_limit);
|
||||
|
||||
|
||||
|
||||
threshold_upper = out_upper_limit - /* Set Upper Threshold */
|
||||
limit_range;
|
||||
threshold_lower = out_lower_limit + /* Set Lower Threshold */
|
||||
limit_range;
|
||||
linear_range = threshold_upper - threshold_lower;
|
||||
|
||||
|
||||
/* Test the linear region & make sure there IS one... */
|
||||
if (linear_range < 0.0) {
|
||||
printf("%s\n",climit_range_error);
|
||||
/* limited_out = 0.0;
|
||||
pout_pin = 0.0;
|
||||
pout_pcntl_lower = 0.0;
|
||||
pout_pcntl_upper = 0.0;
|
||||
return;
|
||||
*/ }
|
||||
|
||||
/* Compute Un-Limited Output */
|
||||
out = gain * (in_offset + in);
|
||||
|
||||
|
||||
if (out < threshold_lower) { /* Limit Out @ Lower Bound */
|
||||
|
||||
pout_pcntl_upper= 0.0;
|
||||
|
||||
if (out > (out_lower_limit - limit_range)) { /* Parabolic */
|
||||
cm_smooth_corner(out,out_lower_limit,out_lower_limit,
|
||||
limit_range,0.0,1.0,&limited_out,
|
||||
&pout_pin);
|
||||
pout_pin = gain * pout_pin;
|
||||
cm_smooth_discontinuity(out,out_lower_limit,1.0,threshold_lower,
|
||||
0.0,&pout_pcntl_lower,&junk);
|
||||
}
|
||||
else { /* Hard-Limited Region */
|
||||
limited_out = out_lower_limit;
|
||||
pout_pin = 0.0;
|
||||
pout_pcntl_lower = 1.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (out > threshold_upper) { /* Limit Out @ Upper Bound */
|
||||
|
||||
pout_pcntl_lower= 0.0;
|
||||
|
||||
if (out < (out_upper_limit+limit_range)) { /* Parabolic */
|
||||
cm_smooth_corner(out,out_upper_limit,out_upper_limit,
|
||||
limit_range,1.0,0.0,&limited_out,
|
||||
&pout_pin);
|
||||
pout_pin = gain * pout_pin;
|
||||
cm_smooth_discontinuity(out,threshold_upper,0.0,out_upper_limit,
|
||||
1.0,&pout_pcntl_upper,&junk);
|
||||
}
|
||||
else { /* Hard-Limited Region */
|
||||
limited_out = out_upper_limit;
|
||||
pout_pin = 0.0;
|
||||
pout_pcntl_upper = 1.0;
|
||||
}
|
||||
}
|
||||
else { /* No Limiting Needed */
|
||||
limited_out = out;
|
||||
pout_pin = gain;
|
||||
pout_pcntl_lower = 0.0;
|
||||
pout_pcntl_upper = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*out_final = limited_out;
|
||||
*pout_pin_final = pout_pin;
|
||||
*pout_pcntl_lower_final = pout_pcntl_lower;
|
||||
*pout_pcntl_upper_final = pout_pcntl_upper;
|
||||
|
||||
}
|
||||
|
||||
/**** End Controlled Limiter Function ****/
|
||||
|
||||
/*=============================================================================*/
|
||||
|
||||
|
||||
/* Piecewise Linear Smoothing Function *********************
|
||||
* The following is a transfer curve function which *
|
||||
* accepts as input an "x" value, and returns a "y" *
|
||||
* value. The transfer characteristic is a smoothed *
|
||||
* piece-wise linear curve described by *x and *y array *
|
||||
* coordinate pairs. *
|
||||
* *
|
||||
* Created 8/14/91 *
|
||||
* Last Modified 8/14/91 J.P.Murray *
|
||||
***********************************************************/
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* ^ x[4] *
|
||||
* x[1] | * *
|
||||
* | midpoint /|\ *
|
||||
* | | / \ *
|
||||
* | V | / | \ *
|
||||
* *----*----* \ *
|
||||
* midpoint /| | | \ *
|
||||
* | / || * <- midpoint *
|
||||
* V/ | |x[3] \ *
|
||||
* <-----------*------------O------------\-------------> *
|
||||
* | / | \ | | *
|
||||
* / | \ *
|
||||
* |/ | \| | *
|
||||
* * | *-----*---> *
|
||||
* /| | x[5] x[6] *
|
||||
* / | *
|
||||
* / x[0] | *
|
||||
* / | *
|
||||
* / | *
|
||||
* / | *
|
||||
* V *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* Note that for the cm_smooth_pwl function, the arguments *
|
||||
* are as listed below: *
|
||||
* *
|
||||
* *
|
||||
* double x_input; input * *
|
||||
* double *x; pointer to the x-coordinate *
|
||||
* array * *
|
||||
* double *y; pointer to the y-coordinate *
|
||||
* array * *
|
||||
* int size; size of the arrays *
|
||||
* *
|
||||
* double input_domain; smoothing range * *
|
||||
* double dout_din; partial derivative of the *
|
||||
* output w.r.t. the input * *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
|
||||
double cm_smooth_pwl(double x_input, double *x, double *y, int size,
|
||||
double input_domain, double *dout_din)
|
||||
{
|
||||
|
||||
int i; /* generic loop counter index */
|
||||
|
||||
double lower_seg; /* x segment below which input resides */
|
||||
double upper_seg; /* x segment above which the input resides */
|
||||
double lower_slope; /* slope of the lower segment */
|
||||
double upper_slope; /* slope of the upper segment */
|
||||
double out; /* output */
|
||||
double threshold_lower; /* value below which the output begins smoothing */
|
||||
double threshold_upper; /* value above which the output begins smoothing */
|
||||
|
||||
|
||||
/* char *limit_error="\n***ERROR***\nViolation of 50% rule in breakpoints!\n";*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Determine segment boundaries within which x_input resides */
|
||||
|
||||
if (x_input <= (*(x+1) + *x)/2.0) {/*** x_input below lowest midpoint ***/
|
||||
*dout_din = (*(y+1) - *y)/(*(x+1) - *x);
|
||||
out = *y + (x_input - *x) * *dout_din;
|
||||
}
|
||||
else {
|
||||
if (x_input >= (*(x+size-2) + *(x+size-1))/2.0) {
|
||||
/*** x_input above highest midpoint ***/
|
||||
*dout_din = (*(y+size-1) - *(y+size-2)) /
|
||||
(*(x+size-1) - *(x+size-2));
|
||||
out = *(y+size-1) + (x_input - *(x+size-1)) * *dout_din;
|
||||
}
|
||||
else { /*** x_input within bounds of end midpoints... ***/
|
||||
/*** must determine position progressively & then ***/
|
||||
/*** calculate required output. ***/
|
||||
|
||||
for (i=1; i<size; i++) {
|
||||
|
||||
if (x_input < (*(x+i) + *(x+i+1))/2.0) {
|
||||
/* approximate position known... */
|
||||
|
||||
lower_seg = (*(x+i) - *(x+i-1));
|
||||
upper_seg = (*(x+i+1) - *(x+i));
|
||||
|
||||
|
||||
/* Calculate input_domain about this region's breakpoint.*/
|
||||
|
||||
/* Translate input_domain into an absolute.... */
|
||||
if ( lower_seg <= upper_seg ) /* Use lower */
|
||||
/* segment */
|
||||
/* for % calc.*/
|
||||
input_domain = input_domain * lower_seg;
|
||||
else /* Use upper */
|
||||
/* segment */
|
||||
/* for % calc.*/
|
||||
input_domain = input_domain * upper_seg;
|
||||
|
||||
|
||||
/* Set up threshold values about breakpoint... */
|
||||
threshold_lower = *(x+i) - input_domain;
|
||||
threshold_upper = *(x+i) + input_domain;
|
||||
|
||||
/* Determine where x_input is within region & determine */
|
||||
/* output and partial values.... */
|
||||
if (x_input < threshold_lower) { /* Lower linear region */
|
||||
*dout_din = (*(y+i) - *(y+i-1))/lower_seg;
|
||||
out = *(y+i) + (x_input - *(x+i)) * *dout_din;
|
||||
}
|
||||
else {
|
||||
if (x_input < threshold_upper) { /* Parabolic region */
|
||||
lower_slope = (*(y+i) - *(y+i-1))/lower_seg;
|
||||
upper_slope = (*(y+i+1) - *(y+i))/upper_seg;
|
||||
cm_smooth_corner(x_input,*(x+i),*(y+i),input_domain,
|
||||
lower_slope,upper_slope,&out,dout_din);
|
||||
}
|
||||
else { /* Upper linear region */
|
||||
*dout_din = (*(y+i+1) - *(y+i))/upper_seg;
|
||||
out = *(y+i) + (x_input - *(x+i)) * *dout_din;
|
||||
}
|
||||
}
|
||||
break; /* Break search loop...x_input has been found, */
|
||||
/* and out and *dout_din have been assigned. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Complex_t cm_complex_set(double real, double imag)
|
||||
{
|
||||
/* Create a complex number with the real and imaginary */
|
||||
/* parts specified in the argument list, and return it */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = real;
|
||||
c.imag = imag;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_add(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Add the two complex numbers and return the result */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = x.real + y.real;
|
||||
c.imag = x.imag + y.imag;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_subtract(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Subtract the second arg from the first and return the result */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = x.real - y.real;
|
||||
c.imag = x.imag - y.imag;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_multiply(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Multiply the two complex numbers and return the result */
|
||||
|
||||
Complex_t c;
|
||||
|
||||
c.real = (x.real * y.real) - (x.imag * y.imag);
|
||||
c.imag = (x.real * y.imag) + (x.imag * y.real);
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
Complex_t cm_complex_divide(Complex_t x, Complex_t y)
|
||||
{
|
||||
/* Divide the first number by the second and return the result */
|
||||
|
||||
Complex_t c;
|
||||
double mag_y_squared;
|
||||
|
||||
mag_y_squared = (y.real * y.real) + (y.imag * y.imag);
|
||||
|
||||
if(mag_y_squared < 1e-100) {
|
||||
printf("\nWARNING: cm_complex_divide() - divide by zero\n");
|
||||
mag_y_squared = 1e-100;
|
||||
}
|
||||
|
||||
c.real = ((x.real * y.real) + (x.imag * y.imag)) / mag_y_squared;
|
||||
c.imag = ((x.imag * y.real) - (y.imag * x.real)) / mag_y_squared;
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LIBRARIES = libenhxsp.a
|
||||
|
||||
libenhxsp_a_SOURCES = \
|
||||
enh.c \
|
||||
enhtrans.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*============================================================================
|
||||
FILE ENH.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains routines used for general enhancements made
|
||||
to the Berkeley SPICE3 core.
|
||||
|
||||
INTERFACES
|
||||
|
||||
ENHreport_conv_prob()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "enh.h"
|
||||
|
||||
/*
|
||||
ENHreport_conv_prob()
|
||||
|
||||
Report convergence problem messages from nodes, branch currents,
|
||||
or instances. This function is setup to allow providing the SI
|
||||
with information identifying the type of convergence problem.
|
||||
For now, it simply writes to stdout.
|
||||
*/
|
||||
|
||||
|
||||
void ENHreport_conv_prob(
|
||||
Enh_Conv_Source_t type, /* node, branch, or instance */
|
||||
char *name, /* the name of the node/branch/instance */
|
||||
char *msg) /* an optional message */
|
||||
{
|
||||
|
||||
char *type_str;
|
||||
char *msg_str;
|
||||
|
||||
/* Convert the type enum to a string for printing */
|
||||
switch(type) {
|
||||
|
||||
case ENH_ANALOG_NODE:
|
||||
case ENH_EVENT_NODE:
|
||||
type_str = "node";
|
||||
break;
|
||||
|
||||
case ENH_ANALOG_BRANCH:
|
||||
type_str = "branch current";
|
||||
break;
|
||||
|
||||
case ENH_ANALOG_INSTANCE:
|
||||
case ENH_EVENT_INSTANCE:
|
||||
case ENH_HYBRID_INSTANCE:
|
||||
type_str = "instance";
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("\nERROR: Internal error in ENHreport_conv_prob - impossible type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for msg == NULL and turn into null string */
|
||||
if(msg)
|
||||
msg_str = msg;
|
||||
else
|
||||
msg_str = "";
|
||||
|
||||
/* Print the convergence problem report */
|
||||
printf("\nWARNING: Convergence problems at %s (%s). %s\n",
|
||||
type_str, name, msg_str);
|
||||
|
||||
} /* ENHreport_conv_prob */
|
||||
|
||||
|
|
@ -0,0 +1,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 */
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LIBRARIES = libevtxsp.a
|
||||
|
||||
libevtxsp_a_SOURCES = \
|
||||
evtaccept.c \
|
||||
evtcall_hybrids.c \
|
||||
evtdump.c \
|
||||
evtiter.c \
|
||||
evtnext_time.c \
|
||||
evtop.c \
|
||||
evtprint.c \
|
||||
evtsetup.c \
|
||||
evtbackup.c \
|
||||
evtdeque.c \
|
||||
evtinit.c \
|
||||
evtload.c \
|
||||
evtnode_copy.c \
|
||||
evtplot.c \
|
||||
evtqueue.c \
|
||||
evttermi.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/include
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/*============================================================================
|
||||
FILE EVTaccept.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains a function called at the end of a
|
||||
successful (accepted) analog timepoint. It saves pointers
|
||||
to the states of the queues and data at this accepted time.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTaccept(CKTcircuit *ckt, double time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include "cktdefs.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTaccept()
|
||||
|
||||
This function is called at the end of a successful (accepted)
|
||||
analog timepoint. It saves pointers to the states of the
|
||||
queues and data at this accepted time.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void EVTaccept(
|
||||
CKTcircuit *ckt, /* main circuit struct */
|
||||
double time) /* time at which analog soln was accepted */
|
||||
{
|
||||
|
||||
int i;
|
||||
int index;
|
||||
int num_modified;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
|
||||
|
||||
/* Exit if no event instances */
|
||||
if(ckt->evt->counts.num_insts == 0)
|
||||
return;
|
||||
|
||||
/* Get often used pointers */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
node_data = ckt->evt->data.node;
|
||||
state_data = ckt->evt->data.state;
|
||||
msg_data = ckt->evt->data.msg;
|
||||
|
||||
|
||||
/* Process the inst queue */
|
||||
num_modified = inst_queue->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the inst modified */
|
||||
index = inst_queue->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
inst_queue->last_step[index] = inst_queue->current[index];
|
||||
/* Reset the modified flag */
|
||||
inst_queue->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Record the new last_time and reset number modified to zero */
|
||||
inst_queue->last_time = time;
|
||||
inst_queue->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the output queue */
|
||||
num_modified = output_queue->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the output modified */
|
||||
index = output_queue->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
output_queue->last_step[index] = output_queue->current[index];
|
||||
/* Reset the modified flag */
|
||||
output_queue->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Record the new last_time and reset number modified to zero */
|
||||
output_queue->last_time = time;
|
||||
output_queue->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the node data */
|
||||
num_modified = node_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
node_data->last_step[index] = node_data->tail[index];
|
||||
/* Reset the modified flag */
|
||||
node_data->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Reset number modified to zero */
|
||||
node_data->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the state data */
|
||||
num_modified = state_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the state modified */
|
||||
index = state_data->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
state_data->last_step[index] = state_data->tail[index];
|
||||
/* Reset the modified flag */
|
||||
state_data->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Reset number modified to zero */
|
||||
state_data->num_modified = 0;
|
||||
|
||||
|
||||
/* Process the msg data */
|
||||
num_modified = msg_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the msg modified */
|
||||
index = msg_data->modified_index[i];
|
||||
/* Update last_step for this index */
|
||||
msg_data->last_step[index] = msg_data->tail[index];
|
||||
/* Reset the modified flag */
|
||||
msg_data->modified[index] = MIF_FALSE;
|
||||
}
|
||||
/* Reset number modified to zero */
|
||||
msg_data->num_modified = 0;
|
||||
|
||||
} /* EVTaccept */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
/*============================================================================
|
||||
FILE EVTbackup.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains a function that resets the queues and data
|
||||
structures to their state at the new analog simulation time specified
|
||||
following the rejection of an analog timestep by the DCtran routine.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTbackup(CKTcircuit *ckt, double new_time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
#include <stdio.h>
|
||||
#include "ngspice.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
/*=== FUNCTION PROTOTYPES ===*/
|
||||
|
||||
|
||||
static void EVTbackup_node_data(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_state_data(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_msg_data(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_inst_queue(CKTcircuit *ckt, double new_time);
|
||||
static void EVTbackup_output_queue(CKTcircuit *ckt, double new_time);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup()
|
||||
|
||||
This function resets the queues and data structures to their state
|
||||
at the new analog simulation time specified. The algorithms in this file
|
||||
assume the following timestep coordination between
|
||||
analog and event-driven algorithms:
|
||||
|
||||
while(not end of analysis) {
|
||||
|
||||
while (next event time <= next analog time) {
|
||||
do event solution with call_type = event_driven
|
||||
if any instance set analog breakpoint < next analog time
|
||||
set next analog time to breakpoint
|
||||
}
|
||||
|
||||
do analog timestep solution with call_type = analog
|
||||
call all hybrid models with call_type = event_driven
|
||||
|
||||
if(analog solution doesn't converge)
|
||||
Call EVTbackup
|
||||
else
|
||||
Call EVTaccept
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void EVTbackup(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
|
||||
/* Backup the node data */
|
||||
EVTbackup_node_data(ckt, new_time);
|
||||
|
||||
/* Backup the state data */
|
||||
EVTbackup_state_data(ckt, new_time);
|
||||
|
||||
/* Backup the msg data */
|
||||
EVTbackup_msg_data(ckt, new_time);
|
||||
|
||||
/* Backup the inst queue */
|
||||
EVTbackup_inst_queue(ckt, new_time);
|
||||
|
||||
/* Backup the output queue */
|
||||
EVTbackup_output_queue(ckt, new_time);
|
||||
|
||||
/* Record statistics */
|
||||
(ckt->evt->data.statistics->tran_time_backups)++;
|
||||
|
||||
} /* EVTbackup */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_node_data()
|
||||
|
||||
Reset the node structure data.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_node_data(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int node_index;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_Node_t **node_ptr;
|
||||
Evt_Node_t *node;
|
||||
Evt_Node_t *from_node;
|
||||
Evt_Node_t *to_node;
|
||||
Evt_Node_t *head;
|
||||
Evt_Node_t *tail;
|
||||
Evt_Node_t *free_head;
|
||||
|
||||
/* Get pointers for quick access */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
num_modified = node_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the needed node and udn indexes */
|
||||
node_index = node_data->modified_index[i];
|
||||
|
||||
/* Scan data for this node from last_step to determine new setting */
|
||||
/* for tail, and splice later data into the free list */
|
||||
node_ptr = node_data->last_step[node_index];
|
||||
node = *node_ptr;
|
||||
while(1) {
|
||||
if((node->next == NULL) || (node->next->step > new_time)) {
|
||||
|
||||
/* Splice rest of list, if any, into free list */
|
||||
head = node->next;
|
||||
if(head) {
|
||||
tail = *(node_data->tail[node_index]);
|
||||
free_head = node_data->free[node_index];
|
||||
node_data->free[node_index] = head;
|
||||
tail->next = free_head;
|
||||
}
|
||||
|
||||
/* Set the tail */
|
||||
node_data->tail[node_index] = node_ptr;
|
||||
node->next = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
node_ptr = &(node->next);
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
/* Copy data from the location at tail to rhs and rhsold */
|
||||
from_node = *(node_data->tail[node_index]);
|
||||
to_node = &(node_data->rhs[node_index]);
|
||||
EVTnode_copy(ckt, node_index, from_node, &to_node);
|
||||
to_node = &(node_data->rhsold[node_index]);
|
||||
EVTnode_copy(ckt, node_index, from_node, &to_node);
|
||||
|
||||
} /* end for number modified */
|
||||
|
||||
/* Update/compact the modified list */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
node_index = node_data->modified_index[i];
|
||||
/* If nothing after last_step, remove this index from the modified list */
|
||||
if((*(node_data->last_step[node_index]))->next == NULL) {
|
||||
node_data->modified[node_index] = MIF_FALSE;
|
||||
(node_data->num_modified)--;
|
||||
}
|
||||
/* else, keep the index */
|
||||
else {
|
||||
node_data->modified_index[j] = node_data->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
} /* EVTbackup_node_data */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_state_data()
|
||||
|
||||
Reset the state structure data.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_state_data(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int inst_index;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
|
||||
Evt_State_t **state_ptr;
|
||||
Evt_State_t *state;
|
||||
Evt_State_t *head;
|
||||
Evt_State_t *tail;
|
||||
Evt_State_t *free_head;
|
||||
|
||||
/* Get pointers for quick access */
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
num_modified = state_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the inst index */
|
||||
inst_index = state_data->modified_index[i];
|
||||
|
||||
/* Scan data for this inst from last_step to determine new setting */
|
||||
/* for tail, and splice later data into the free list */
|
||||
state_ptr = state_data->last_step[inst_index];
|
||||
state = *state_ptr;
|
||||
while(1) {
|
||||
if((state->next == NULL) || (state->next->step > new_time)) {
|
||||
|
||||
/* Splice rest of list, if any, into free list */
|
||||
head = state->next;
|
||||
if(head) {
|
||||
tail = *(state_data->tail[inst_index]);
|
||||
free_head = state_data->free[inst_index];
|
||||
state_data->free[inst_index] = head;
|
||||
tail->next = free_head;
|
||||
}
|
||||
|
||||
/* Set the tail */
|
||||
state_data->tail[inst_index] = state_ptr;
|
||||
state->next = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
state_ptr = &(state->next);
|
||||
state = state->next;
|
||||
}
|
||||
} /* end for number modified */
|
||||
|
||||
/* Update/compact the modified list */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
inst_index = state_data->modified_index[i];
|
||||
/* If nothing after last_step, remove this index from the modified list */
|
||||
if((*(state_data->last_step[inst_index]))->next == NULL) {
|
||||
state_data->modified[inst_index] = MIF_FALSE;
|
||||
(state_data->num_modified)--;
|
||||
}
|
||||
/* else, keep the index */
|
||||
else {
|
||||
state_data->modified_index[j] = state_data->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
} /* EVTbackup_state_data */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_msg_data()
|
||||
|
||||
Backup the message data.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_msg_data(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int port_index;
|
||||
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
|
||||
Evt_Msg_t **msg_ptr;
|
||||
Evt_Msg_t *msg;
|
||||
Evt_Msg_t *head;
|
||||
Evt_Msg_t *tail;
|
||||
Evt_Msg_t *free_head;
|
||||
|
||||
/* Get pointers for quick access */
|
||||
msg_data = ckt->evt->data.msg;
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
num_modified = msg_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the port index */
|
||||
port_index = msg_data->modified_index[i];
|
||||
|
||||
/* Scan data for this port from last_step to determine new setting */
|
||||
/* for tail, and splice later data into the free list */
|
||||
msg_ptr = msg_data->last_step[port_index];
|
||||
msg = *msg_ptr;
|
||||
while(1) {
|
||||
if((msg->next == NULL) || (msg->next->step > new_time)) {
|
||||
|
||||
/* Splice rest of list, if any, into free list */
|
||||
head = msg->next;
|
||||
if(head) {
|
||||
tail = *(msg_data->tail[port_index]);
|
||||
free_head = msg_data->free[port_index];
|
||||
msg_data->free[port_index] = head;
|
||||
tail->next = free_head;
|
||||
}
|
||||
|
||||
/* Set the tail */
|
||||
msg_data->tail[port_index] = msg_ptr;
|
||||
msg->next = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
msg_ptr = &(msg->next);
|
||||
msg = msg->next;
|
||||
}
|
||||
|
||||
} /* end for number modified */
|
||||
|
||||
/* Update/compact the modified list */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
port_index = msg_data->modified_index[i];
|
||||
/* If nothing after last_step, remove this index from the modified list */
|
||||
if((*(msg_data->last_step[port_index]))->next == NULL) {
|
||||
msg_data->modified[port_index] = MIF_FALSE;
|
||||
(msg_data->num_modified)--;
|
||||
}
|
||||
/* else, keep the index */
|
||||
else {
|
||||
msg_data->modified_index[j] = msg_data->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_inst_queue()
|
||||
|
||||
Backup data in inst queue.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTbackup_inst_queue(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int num_pending;
|
||||
int inst_index;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
|
||||
Evt_Inst_Event_t **inst_ptr;
|
||||
Evt_Inst_Event_t *inst;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
|
||||
/* Get pointers for quick access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
/* and remove events with posted time > new_time */
|
||||
num_modified = inst_queue->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the inst index */
|
||||
inst_index = inst_queue->modified_index[i];
|
||||
|
||||
/* Scan forward from last_step and cut out data with posted time */
|
||||
/* > new_time and add it to the free list */
|
||||
|
||||
inst_ptr = inst_queue->last_step[inst_index];
|
||||
inst = *inst_ptr;
|
||||
|
||||
while(inst) {
|
||||
if(inst->posted_time > new_time) {
|
||||
*inst_ptr = inst->next;
|
||||
inst->next = inst_queue->free[inst_index];
|
||||
inst_queue->free[inst_index] = inst;
|
||||
inst = *inst_ptr;
|
||||
}
|
||||
else {
|
||||
inst_ptr = &(inst->next);
|
||||
inst = *inst_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan forward from last_step and set current to first */
|
||||
/* event with event_time > new_time */
|
||||
|
||||
inst_ptr = inst_queue->last_step[inst_index];
|
||||
inst = *inst_ptr;
|
||||
|
||||
while(inst) {
|
||||
if(inst->event_time > new_time)
|
||||
break;
|
||||
inst_ptr = &((*inst_ptr)->next);
|
||||
inst = *inst_ptr;
|
||||
}
|
||||
inst_queue->current[inst_index] = inst_ptr;
|
||||
}
|
||||
|
||||
/* Add set of items modified to set of items pending before updating the */
|
||||
/* pending list because things may have been pulled from the pending list */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
j = inst_queue->modified_index[i];
|
||||
if(! inst_queue->pending[j]) {
|
||||
inst_queue->pending[j] = MIF_TRUE;
|
||||
inst_queue->pending_index[(inst_queue->num_pending)++] = j;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the pending list and the next time by seeing if there */
|
||||
/* is anything at the location pointed to by current */
|
||||
next_time = 1e30;
|
||||
num_pending = inst_queue->num_pending;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
inst_index = inst_queue->pending_index[i];
|
||||
inst = *(inst_queue->current[inst_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! inst) {
|
||||
inst_queue->pending[inst_index] = MIF_FALSE;
|
||||
(inst_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
inst_queue->pending_index[j] = inst_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = inst->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
inst_queue->next_time = next_time;
|
||||
|
||||
/* Update the modified list by looking for any queued events */
|
||||
/* with posted time > last_time */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
|
||||
inst_index = inst_queue->modified_index[i];
|
||||
inst = *(inst_queue->last_step[inst_index]);
|
||||
|
||||
while(inst) {
|
||||
if(inst->posted_time > inst_queue->last_time)
|
||||
break;
|
||||
inst = inst->next;
|
||||
}
|
||||
|
||||
if(! inst) {
|
||||
inst_queue->modified[inst_index] = MIF_FALSE;
|
||||
(inst_queue->num_modified)--;
|
||||
}
|
||||
else {
|
||||
inst_queue->modified_index[j] = inst_queue->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTbackup_output_queue()
|
||||
|
||||
Backup data in output queue.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static void EVTbackup_output_queue(
|
||||
CKTcircuit *ckt, /* the main circuit structure */
|
||||
double new_time) /* the time to backup to */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_modified;
|
||||
int num_pending;
|
||||
|
||||
int output_index;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Output_Event_t **output_ptr;
|
||||
Evt_Output_Event_t *output;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
|
||||
/* Get pointers for quick access */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* Loop through list of indexes modified since last accepted timepoint */
|
||||
/* and remove events with posted time > new_time */
|
||||
num_modified = output_queue->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
|
||||
/* Get the output index */
|
||||
output_index = output_queue->modified_index[i];
|
||||
|
||||
/* Scan forward from last_step and cut out data with posted time */
|
||||
/* > new_time and add it to the free list */
|
||||
/* Also, unremove anything with removed time > new_time */
|
||||
|
||||
output_ptr = output_queue->last_step[output_index];
|
||||
output = *output_ptr;
|
||||
|
||||
while(output) {
|
||||
if(output->posted_time > new_time) {
|
||||
*output_ptr = output->next;
|
||||
output->next = output_queue->free[output_index];
|
||||
output_queue->free[output_index] = output;
|
||||
output = *output_ptr;
|
||||
}
|
||||
else {
|
||||
if(output->removed && (output->removed_time > new_time))
|
||||
output->removed = MIF_FALSE;
|
||||
output_ptr = &(output->next);
|
||||
output = *output_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan forward from last_step and set current to first */
|
||||
/* event with event_time > new_time */
|
||||
|
||||
output_ptr = output_queue->last_step[output_index];
|
||||
output = *output_ptr;
|
||||
|
||||
while(output) {
|
||||
if(output->event_time > new_time)
|
||||
break;
|
||||
output_ptr = &((*output_ptr)->next);
|
||||
output = *output_ptr;
|
||||
}
|
||||
output_queue->current[output_index] = output_ptr;
|
||||
}
|
||||
|
||||
/* Add set of items modified to set of items pending before updating the */
|
||||
/* pending list because things may have been pulled from the pending list */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
j = output_queue->modified_index[i];
|
||||
if(! output_queue->pending[j]) {
|
||||
output_queue->pending[j] = MIF_TRUE;
|
||||
output_queue->pending_index[(output_queue->num_pending)++] = j;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the pending list and the next time by seeing if there */
|
||||
/* is anything at the location pointed to by current */
|
||||
next_time = 1e30;
|
||||
num_pending = output_queue->num_pending;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
output_index = output_queue->pending_index[i];
|
||||
output = *(output_queue->current[output_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! output) {
|
||||
output_queue->pending[output_index] = MIF_FALSE;
|
||||
(output_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
output_queue->pending_index[j] = output_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = output->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
output_queue->next_time = next_time;
|
||||
|
||||
/* Update the modified list by looking for any queued events */
|
||||
/* with posted time > last_time */
|
||||
for(i = 0, j = 0; i < num_modified; i++) {
|
||||
|
||||
output_index = output_queue->modified_index[i];
|
||||
output = *(output_queue->last_step[output_index]);
|
||||
|
||||
while(output) {
|
||||
if(output->posted_time > output_queue->last_time)
|
||||
break;
|
||||
output = output->next;
|
||||
}
|
||||
|
||||
if(! output) {
|
||||
output_queue->modified[output_index] = MIF_FALSE;
|
||||
(output_queue->num_modified)--;
|
||||
}
|
||||
else {
|
||||
output_queue->modified_index[j] = output_queue->modified_index[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*============================================================================
|
||||
FILE EVTcall_hybrids.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTcall_hybrids which calls all models
|
||||
which have both analog and event-driven ports. It is called following
|
||||
successful evaluation of an analog iteration attempt to allow
|
||||
events to be scheduled by the hybrid models. The 'CALL_TYPE' is set
|
||||
to 'EVENT_DRIVEN' when the model is called from this function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTcall_hybrids(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
/*
|
||||
EVTcall_hybrids
|
||||
|
||||
This function calls all the hybrid instances. It is called following
|
||||
the successful evaluation of an analog iteration.
|
||||
*/
|
||||
|
||||
|
||||
void EVTcall_hybrids(
|
||||
CKTcircuit *ckt) /* the main circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_hybrids;
|
||||
|
||||
int *hybrid_index;
|
||||
|
||||
|
||||
/* Get needed data for fast access */
|
||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||
hybrid_index = ckt->evt->info.hybrid_index;
|
||||
|
||||
/* Call EVTload for all hybrids */
|
||||
for(i = 0; i < num_hybrids; i++)
|
||||
EVTload(ckt, hybrid_index[i]);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,366 @@
|
|||
/*============================================================================
|
||||
FILE EVTdequeue.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTdequeue which removes any items on the
|
||||
output and instance queues with event times matching the specified
|
||||
simulation time.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTdequeue(CKTcircuit *ckt, double time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
static void EVTdequeue_output(CKTcircuit *ckt, double time);
|
||||
static void EVTdequeue_inst(CKTcircuit *ckt, double time);
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt,
|
||||
int output_index,
|
||||
void *value);
|
||||
|
||||
|
||||
/*
|
||||
EVTdequeue
|
||||
|
||||
This function removes any items on the output and instance queues
|
||||
with event times matching the specified simulation time. EVTiter
|
||||
is then called to determine which instances need to be called.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void EVTdequeue(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
double time) /* The event time of the events to dequeue */
|
||||
{
|
||||
|
||||
/* Take all items on output queue with matching time */
|
||||
/* and set changed flags in output queue */
|
||||
EVTdequeue_output(ckt, time);
|
||||
|
||||
/* Take all items on inst queue with matching time */
|
||||
/* and set to_call flags in inst queue */
|
||||
EVTdequeue_inst(ckt, time);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTdequeue_output
|
||||
|
||||
This function de-queues output events with times matching the
|
||||
specified time.
|
||||
*/
|
||||
|
||||
static void EVTdequeue_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
double time) /* The event time of the events to dequeue */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_pending;
|
||||
int index;
|
||||
int output_index;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Output_Event_t *output;
|
||||
Evt_Output_Event_t **output_ptr;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* Exit if nothing pending on output queue or if next_time */
|
||||
/* != specified time */
|
||||
if(output_queue->num_pending == 0)
|
||||
return;
|
||||
if(output_queue->next_time != time)
|
||||
return;
|
||||
|
||||
/* Scan the list of outputs pending */
|
||||
num_pending = output_queue->num_pending;
|
||||
for(i = 0; i < num_pending; i++) {
|
||||
|
||||
/* Get the index of the output */
|
||||
index = output_queue->pending_index[i];
|
||||
|
||||
/* Get pointer to next event in queue at this index */
|
||||
output = *(output_queue->current[index]);
|
||||
|
||||
/* If event time does not match current time, skip */
|
||||
if(output->event_time != time)
|
||||
continue;
|
||||
|
||||
/* It must match, so pull the event from the queue and process it */
|
||||
EVTprocess_output(ckt, index, output->value);
|
||||
|
||||
/* Move current to point to next non-removed item in list */
|
||||
output_ptr = &(output->next);
|
||||
output = *output_ptr;
|
||||
while(output) {
|
||||
if(! output->removed)
|
||||
break;
|
||||
output_ptr = &(output->next);
|
||||
output = *output_ptr;
|
||||
}
|
||||
output_queue->current[index] = output_ptr;
|
||||
|
||||
/* Mark that this index in the queue has been modified */
|
||||
if(! output_queue->modified[index]) {
|
||||
output_queue->modified[index] = MIF_TRUE;
|
||||
output_queue->modified_index[(output_queue->num_modified)++] = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update/compact the pending list and update the next_time */
|
||||
next_time = 1e30;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
output_index = output_queue->pending_index[i];
|
||||
output = *(output_queue->current[output_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! output) {
|
||||
output_queue->pending[output_index] = MIF_FALSE;
|
||||
(output_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
output_queue->pending_index[j] = output_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = output->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
output_queue->next_time = next_time;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTdequeue_inst
|
||||
|
||||
This function de-queues instance events with times matching the
|
||||
specified time.
|
||||
*/
|
||||
|
||||
|
||||
void EVTdequeue_inst(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
double time) /* The event time of the events to dequeue */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_pending;
|
||||
int index;
|
||||
int inst_index;
|
||||
|
||||
double next_time;
|
||||
double event_time;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
|
||||
Evt_Inst_Event_t *inst;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Exit if nothing pending on inst queue or if next_time */
|
||||
/* != specified time */
|
||||
if(inst_queue->num_pending == 0)
|
||||
return;
|
||||
if(inst_queue->next_time != time)
|
||||
return;
|
||||
|
||||
/* Scan the list of insts pending */
|
||||
num_pending = inst_queue->num_pending;
|
||||
for(i = 0; i < num_pending; i++) {
|
||||
|
||||
/* Get the index of the inst */
|
||||
index = inst_queue->pending_index[i];
|
||||
|
||||
/* Get pointer to next event in queue at this index */
|
||||
inst = *(inst_queue->current[index]);
|
||||
|
||||
/* If event time does not match current time, skip */
|
||||
if(inst->event_time != time)
|
||||
continue;
|
||||
|
||||
/* It must match, so pull the event from the queue and process it */
|
||||
if(! inst_queue->to_call[index]) {
|
||||
inst_queue->to_call[index] = MIF_TRUE;
|
||||
inst_queue->to_call_index[(inst_queue->num_to_call)++] =
|
||||
index;
|
||||
}
|
||||
|
||||
/* Move current to point to next item in list */
|
||||
inst_queue->current[index] = &(inst->next);
|
||||
|
||||
/* Mark that this index in the queue has been modified */
|
||||
if(! inst_queue->modified[index]) {
|
||||
inst_queue->modified[index] = MIF_TRUE;
|
||||
inst_queue->modified_index[(inst_queue->num_modified)++] = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update/compact the pending list and update the next_time */
|
||||
next_time = 1e30;
|
||||
for(i = 0, j = 0; i < num_pending; i++) {
|
||||
inst_index = inst_queue->pending_index[i];
|
||||
inst = *(inst_queue->current[inst_index]);
|
||||
/* If nothing in queue at last_step, remove this index from the pending list */
|
||||
if(! inst) {
|
||||
inst_queue->pending[inst_index] = MIF_FALSE;
|
||||
(inst_queue->num_pending)--;
|
||||
}
|
||||
/* else, keep the index and update the next time */
|
||||
else {
|
||||
inst_queue->pending_index[j] = inst_queue->pending_index[i];
|
||||
j++;
|
||||
event_time = inst->event_time;
|
||||
if(event_time < next_time)
|
||||
next_time = event_time;
|
||||
}
|
||||
}
|
||||
inst_queue->next_time = next_time;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTprocess_output
|
||||
|
||||
This function processes a specified output after it is pulled
|
||||
from the queue.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int output_index, /* The index of the output to process */
|
||||
void *value) /* The output value */
|
||||
{
|
||||
|
||||
int num_outputs;
|
||||
int node_index;
|
||||
int udn_index;
|
||||
int output_subindex;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
output_table = ckt->evt->info.output_table;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
node_index = output_table[output_index]->node_index;
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
|
||||
rhs = ckt->evt->data.node->rhs;
|
||||
rhsold = ckt->evt->data.node->rhsold;
|
||||
|
||||
/* Determine if output is different from rhsold value */
|
||||
/* and copy it to rhs AND rhsold if so */
|
||||
/* This is somewhat inefficient, but that's the way */
|
||||
/* we have setup the structures (rhs and rhsold must match)... */
|
||||
if(num_outputs > 1) {
|
||||
output_subindex = output_table[output_index]->output_subindex;
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(value,
|
||||
rhsold[node_index].output_value[output_subindex],
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhs[node_index].output_value[output_subindex]);
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhsold[node_index].output_value[output_subindex]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(value,
|
||||
rhsold[node_index].node_value,
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhs[node_index].node_value);
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(value, rhsold[node_index].node_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* If different, put in changed list of output queue */
|
||||
if(! equal) {
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
if(! output_queue->changed[output_index]) {
|
||||
output_queue->changed[output_index] = MIF_TRUE;
|
||||
output_queue->changed_index[(output_queue->num_changed)++] =
|
||||
output_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
/*============================================================================
|
||||
FILE EVTdump.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
6/15/92 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions used
|
||||
to send event-driven node results data to the IPC channel when
|
||||
the simulator is used with CAE software.
|
||||
|
||||
INTERFACES
|
||||
|
||||
EVTdump()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtproto.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "ipc.h"
|
||||
#include "ipctiein.h"
|
||||
#include "ipcproto.h"
|
||||
|
||||
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index); /* The user-defined node index */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTdump
|
||||
|
||||
This function is called to send event-driven node data to the IPC
|
||||
channel. A ``mode'' argument determines how the data is located in
|
||||
the event data structure and what data is sent.
|
||||
|
||||
If the mode is DCOP, then this is necessarily the first call to
|
||||
the function. In this case, the set of event-driven nodes is
|
||||
scanned to determine which should be sent. Only nodes that are
|
||||
not inside subcircuits are sent. Next, the function sends
|
||||
a ``dictionary'' of node names/types vs. node indexes.
|
||||
Finally, the function sends the DC operating point solutions
|
||||
for the event-driven nodes in the dictionary.
|
||||
|
||||
If the mode is DCTRCURVE, it is assumed that the function has
|
||||
already been called with mode = DCOP. The function scans the solution
|
||||
vector and sends data for any nodes that have changed.
|
||||
|
||||
If the mode is TRAN, it is assumed that the function has already
|
||||
been called once with mode = DCOP. The function scans the
|
||||
event data for nodes that have changed since the last accepted
|
||||
analog timepoint and sends the new data.
|
||||
|
||||
Note: This function must be called BEFORE calling EVTop_save or
|
||||
EVTaccept() so that the state of the node data structure will allow
|
||||
it to determine what has changed.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct evtdump_s {
|
||||
Mif_Boolean_t send; /* True if this node should be sent */
|
||||
int ipc_index; /* Index for this node in dict sent to CAE system */
|
||||
char *node_name_str; /* Node name */
|
||||
char *udn_type_str; /* UDN type */
|
||||
} evtdump_dict_t;
|
||||
|
||||
|
||||
|
||||
void EVTdump(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Ipc_Anal_t mode, /* The analysis mode for this call */
|
||||
double step) /* The sweep step for a DCTRCURVE analysis, or */
|
||||
/* 0.0 for DCOP and TRAN */
|
||||
{
|
||||
static evtdump_dict_t *node_dict = NULL;
|
||||
static int num_send_nodes;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int num_nodes;
|
||||
int num_modified;
|
||||
int index;
|
||||
|
||||
char *name;
|
||||
int name_len;
|
||||
|
||||
Mif_Boolean_t firstcall;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhsold;
|
||||
Evt_Node_t **head;
|
||||
Evt_Node_t *here;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
char buff[10000];
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
/* Return immediately if IPC is not enabled */
|
||||
if(! g_ipc.enabled)
|
||||
return;
|
||||
|
||||
/* Get number of event-driven nodes */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
/* Exit immediately if no event-driven nodes in circuit */
|
||||
if(num_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* Get pointers for fast access to event data */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
rhsold = node_data->rhsold;
|
||||
head = node_data->head;
|
||||
|
||||
|
||||
/* Determine if this is the first call */
|
||||
if(node_dict == NULL)
|
||||
firstcall = MIF_TRUE;
|
||||
else
|
||||
firstcall = MIF_FALSE;
|
||||
|
||||
|
||||
/* If this is the first call, get the dictionary info */
|
||||
if(firstcall) {
|
||||
|
||||
/* Allocate local data structure used to process nodes */
|
||||
node_dict = (void *) MALLOC(num_nodes * sizeof(evtdump_dict_t));
|
||||
|
||||
/* Loop through all nodes to determine which nodes should be sent. */
|
||||
/* Only nodes not within subcircuits qualify. */
|
||||
|
||||
num_send_nodes = 0;
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
|
||||
/* Get the name of the node. */
|
||||
name = node_table[i]->name;
|
||||
|
||||
/* If name is in a subcircuit, mark that node should not be sent */
|
||||
/* and continue to next node. */
|
||||
name_len = strlen(name);
|
||||
for(j = 0; j < name_len; j++) {
|
||||
if(name[j] == ':')
|
||||
break;
|
||||
}
|
||||
if(j < name_len) {
|
||||
node_dict[i].send = MIF_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise, fill in info in dictionary. */
|
||||
node_dict[i].send = MIF_TRUE;
|
||||
node_dict[i].ipc_index = num_send_nodes;
|
||||
node_dict[i].node_name_str = name;
|
||||
node_dict[i].udn_type_str = g_evt_udn_info[node_table[i]->udn_index]->name;
|
||||
|
||||
/* Increment the count of nodes to be sent. */
|
||||
num_send_nodes++;
|
||||
} /* end for */
|
||||
} /* end if first call */
|
||||
|
||||
|
||||
/* Exit if there are no nodes to be sent */
|
||||
if(num_send_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* If this is the first call, send the dictionary */
|
||||
if(firstcall) {
|
||||
ipc_send_evtdict_prefix();
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
if(node_dict[i].send) {
|
||||
sprintf(buff, "%d %s %s", node_dict[i].ipc_index,
|
||||
node_dict[i].node_name_str,
|
||||
node_dict[i].udn_type_str);
|
||||
ipc_send_line(buff);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdict_suffix();
|
||||
}
|
||||
|
||||
/* If this is the first call, send the operating point solution */
|
||||
/* and return. */
|
||||
if(firstcall) {
|
||||
ipc_send_evtdata_prefix();
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
if(node_dict[i].send) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, this must be DCTRCURVE or TRAN mode and we need to */
|
||||
/* send only stuff that has changed since the last call. */
|
||||
/* The determination of what to send is modeled after code in */
|
||||
/* EVTop_save() for DCTRCURVE and EVTaccept() for TRAN. */
|
||||
|
||||
if(mode == IPC_ANAL_DCTRCURVE) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through event nodes */
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if(node_dict[i].send) {
|
||||
/* Locate end of node data */
|
||||
here = head[i];
|
||||
for(;;) {
|
||||
if(here->next)
|
||||
here = here->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Compare entry at end of list to rhsold */
|
||||
(*(g_evt_udn_info[node_table[i]->udn_index]->compare)) (
|
||||
rhsold[i].node_value,
|
||||
here->node_value,
|
||||
&equal);
|
||||
/* If value in rhsold is different, send it */
|
||||
if(!equal) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(mode == IPC_ANAL_TRAN) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through list of nodes modified since last time */
|
||||
num_modified = node_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if(node_dict[index].send) {
|
||||
/* Scan through new events and send the data for each event */
|
||||
here = *(node_data->last_step[index]);
|
||||
while((here = here->next)) {
|
||||
EVTsend_line(node_dict[index].ipc_index,
|
||||
here->step,
|
||||
here->node_value,
|
||||
node_table[index]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsend_line
|
||||
|
||||
This function formats the event node data and sends it to the IPC channel.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index) /* The user-defined node index */
|
||||
{
|
||||
double dvalue;
|
||||
char *svalue;
|
||||
void *pvalue;
|
||||
int len;
|
||||
|
||||
/* Get the data to send */
|
||||
if(g_evt_udn_info[udn_index]->plot_val)
|
||||
(*(g_evt_udn_info[udn_index]->plot_val)) (node_value, "", &dvalue);
|
||||
else
|
||||
dvalue = 0.0;
|
||||
|
||||
if(g_evt_udn_info[udn_index]->print_val)
|
||||
(*(g_evt_udn_info[udn_index]->print_val)) (node_value, "", &svalue);
|
||||
else
|
||||
svalue = "";
|
||||
|
||||
if(g_evt_udn_info[udn_index]->ipc_val)
|
||||
(*(g_evt_udn_info[udn_index]->ipc_val)) (node_value, &pvalue, &len);
|
||||
else {
|
||||
pvalue = NULL;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Send it to the IPC channel */
|
||||
ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len);
|
||||
}
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
/*============================================================================
|
||||
FILE EVTinit.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTinit which allocates and initializes
|
||||
evt structure elements after the number of instances, nodes, etc.
|
||||
have been determined in parsing during INPpas2. EVTinit also checks
|
||||
to be sure no nodes have been used for both analog and event-driven
|
||||
algorithms simultaneously.
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTinit(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
static int EVTcheck_nodes(CKTcircuit *ckt);
|
||||
static int EVTcount_hybrids(CKTcircuit *ckt);
|
||||
static int EVTinit_info(CKTcircuit *ckt);
|
||||
static int EVTinit_queue(CKTcircuit *ckt);
|
||||
static int EVTinit_limits(CKTcircuit *ckt);
|
||||
|
||||
|
||||
|
||||
/* Allocation macro with built-in check for out-of-memory */
|
||||
/* Adapted from SPICE 3C1 code in CKTsetup.c */
|
||||
#define CKALLOC(var,size,type) \
|
||||
if(size) { \
|
||||
if(!(var = (void *) MALLOC((size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTinit
|
||||
|
||||
Allocate and initialize additional evt structure elements now that
|
||||
we can determine the number of instances, nodes, etc.
|
||||
|
||||
Also check to be sure that no nodes have been used in both event-driven
|
||||
and analog domains.
|
||||
|
||||
In this version, we also report an error if there are no hybrids in the
|
||||
circuit. This restriction may be removed in the future to allow the
|
||||
simulator to be used with digital only circuits...
|
||||
*/
|
||||
|
||||
|
||||
int EVTinit(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int err; /* SPICE error return code 0 = OK */
|
||||
|
||||
/* static char *err_no_hybrids = "ERROR - no hybrids found in input deck";*/
|
||||
|
||||
|
||||
/* Exit immediately if there are no event-driven instances */
|
||||
/* but don't complain */
|
||||
if(ckt->evt->counts.num_insts == 0)
|
||||
return(OK);
|
||||
|
||||
/* Count the number of hybrids and hybrid outputs */
|
||||
err = EVTcount_hybrids(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Exit with error if there are no hybrids in the circuit. */
|
||||
/* Will probably remove this restriction later... */
|
||||
/*
|
||||
if(ckt->evt->counts.num_hybrids == 0) {
|
||||
errMsg = MALLOC(strlen(err_no_hybrids) + 1);
|
||||
strcpy(errMsg, err_no_hybrids);
|
||||
return(E_PRIVATE);
|
||||
}
|
||||
*/
|
||||
/* Check that event nodes have not been used as analog nodes also */
|
||||
err = EVTcheck_nodes(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Create info table arrays */
|
||||
err = EVTinit_info(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Setup queues */
|
||||
err = EVTinit_queue(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Initialize limits */
|
||||
err = EVTinit_limits(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Note: Options were initialized in CKTinit so that INPpas2 */
|
||||
/* could set values according to .options cards in deck. The */
|
||||
/* structure 'jobs' will be setup immediately prior to each */
|
||||
/* simulation job. The results data structure is also */
|
||||
/* allocated immediately prior to each simulation job. */
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTcount_hybrids
|
||||
|
||||
Count the number of hybrids and the number of outputs on all hybrids.
|
||||
*/
|
||||
|
||||
static int EVTcount_hybrids(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_hybrids;
|
||||
int num_hybrid_outputs;
|
||||
int num_conn;
|
||||
int num_port;
|
||||
|
||||
MIFinstance *fast;
|
||||
|
||||
Evt_Inst_Info_t *inst;
|
||||
|
||||
|
||||
/* Count number of hybrids and hybrid outputs in the inst list */
|
||||
/* created during parsing. Note: other counts */
|
||||
/* are created during parsing, but these were */
|
||||
/* too difficult to do until now... */
|
||||
num_hybrids = 0;
|
||||
num_hybrid_outputs = 0;
|
||||
inst = ckt->evt->info.inst_list;
|
||||
while(inst) {
|
||||
fast = inst->inst_ptr;
|
||||
if(fast->analog && fast->event_driven) {
|
||||
num_hybrids++;
|
||||
num_conn = fast->num_conn;
|
||||
for(i = 0; i < num_conn; i++) {
|
||||
if((! fast->conn[i]->is_null) && (fast->conn[i]->is_output)) {
|
||||
num_port = fast->conn[i]->size;
|
||||
for(j = 0; j < num_port; j++)
|
||||
if(! fast->conn[i]->port[j]->is_null)
|
||||
num_hybrid_outputs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
inst = inst->next;
|
||||
}
|
||||
ckt->evt->counts.num_hybrids = num_hybrids;
|
||||
ckt->evt->counts.num_hybrid_outputs = num_hybrid_outputs;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTcheck_nodes
|
||||
|
||||
Report error if any event node name is also used as an analog node.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTcheck_nodes(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
CKTnode *analog_node;
|
||||
Evt_Node_Info_t *event_node;
|
||||
|
||||
static char *err_prefix = "ERROR - node ";
|
||||
static char *err_collide = " cannot be both analog and digital";
|
||||
|
||||
|
||||
/* Report error if any analog node name matches any event node name */
|
||||
event_node = ckt->evt->info.node_list;
|
||||
while(event_node) {
|
||||
analog_node = ckt->CKTnodes;
|
||||
while(analog_node) {
|
||||
if(strcmp(event_node->name, analog_node->name) == 0) {
|
||||
errMsg = MALLOC(strlen(err_prefix) + strlen(event_node->name) +
|
||||
strlen(err_collide) + 1);
|
||||
sprintf(errMsg, "%s%s%s", err_prefix,
|
||||
event_node->name,
|
||||
err_collide);
|
||||
|
||||
fprintf(stdout,errMsg);
|
||||
|
||||
return(E_PRIVATE);
|
||||
}
|
||||
analog_node = analog_node->next;
|
||||
}
|
||||
event_node = event_node->next;
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTinit_info
|
||||
|
||||
This function creates the ``info'' pointer tables used in the
|
||||
event-driven circuit representation. These arrays allow faster
|
||||
access to data associated with instances, nodes, ports, and
|
||||
outputs than could be provided by having to scan the linked-list
|
||||
representations created during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTinit_info(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_insts;
|
||||
int num_nodes;
|
||||
int num_ports;
|
||||
int num_outputs;
|
||||
|
||||
Evt_Inst_Info_t *inst;
|
||||
Evt_Node_Info_t *node;
|
||||
Evt_Port_Info_t *port;
|
||||
Evt_Output_Info_t *output;
|
||||
|
||||
Evt_Inst_Info_t **inst_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
Evt_Output_Info_t **output_table;
|
||||
|
||||
int *hybrid_index;
|
||||
|
||||
int num_hybrids;
|
||||
|
||||
|
||||
/* Allocate and initialize table of inst pointers */
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
CKALLOC(inst_table, num_insts, void *)
|
||||
inst = ckt->evt->info.inst_list;
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_table[i] = inst;
|
||||
inst = inst->next;
|
||||
}
|
||||
ckt->evt->info.inst_table = inst_table;
|
||||
|
||||
/* Allocate and initialize table of node pointers */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
CKALLOC(node_table, num_nodes, void *)
|
||||
node = ckt->evt->info.node_list;
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
node_table[i] = node;
|
||||
node = node->next;
|
||||
}
|
||||
ckt->evt->info.node_table = node_table;
|
||||
|
||||
/* Allocate and initialize table of port pointers */
|
||||
num_ports = ckt->evt->counts.num_ports;
|
||||
CKALLOC(port_table, num_ports, void *)
|
||||
port = ckt->evt->info.port_list;
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
port_table[i] = port;
|
||||
port = port->next;
|
||||
}
|
||||
ckt->evt->info.port_table = port_table;
|
||||
|
||||
/* Allocate and initialize table of output pointers */
|
||||
num_outputs = ckt->evt->counts.num_outputs;
|
||||
CKALLOC(output_table, num_outputs, void *)
|
||||
output = ckt->evt->info.output_list;
|
||||
for(i = 0; i < num_outputs; i++) {
|
||||
output_table[i] = output;
|
||||
output = output->next;
|
||||
}
|
||||
ckt->evt->info.output_table = output_table;
|
||||
|
||||
|
||||
/* Allocate and create table of indexes into inst_table for hybrids */
|
||||
num_hybrids = ckt->evt->counts.num_hybrids;
|
||||
CKALLOC(hybrid_index, num_hybrids, int)
|
||||
for(i = 0, j = 0; i < num_insts; i++) {
|
||||
if(inst_table[i]->inst_ptr->analog)
|
||||
hybrid_index[j++] = i;
|
||||
}
|
||||
ckt->evt->info.hybrid_index = hybrid_index;
|
||||
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTinit_queue
|
||||
|
||||
This function prepares the event-driven queues for simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTinit_queue(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int num_insts;
|
||||
int num_nodes;
|
||||
int num_outputs;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Node_Queue_t *node_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
|
||||
/* Allocate elements in the inst queue */
|
||||
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
CKALLOC(inst_queue->head, num_insts, void *)
|
||||
CKALLOC(inst_queue->current, num_insts, void *)
|
||||
CKALLOC(inst_queue->last_step, num_insts, void *)
|
||||
CKALLOC(inst_queue->free, num_insts, void *)
|
||||
CKALLOC(inst_queue->modified_index, num_insts, int)
|
||||
CKALLOC(inst_queue->modified, num_insts, Mif_Boolean_t)
|
||||
CKALLOC(inst_queue->pending_index, num_insts, int)
|
||||
CKALLOC(inst_queue->pending, num_insts, Mif_Boolean_t)
|
||||
CKALLOC(inst_queue->to_call_index, num_insts, int)
|
||||
CKALLOC(inst_queue->to_call, num_insts, Mif_Boolean_t)
|
||||
|
||||
|
||||
/* Allocate elements in the node queue */
|
||||
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
node_queue = &(ckt->evt->queue.node);
|
||||
|
||||
CKALLOC(node_queue->to_eval_index, num_nodes, int)
|
||||
CKALLOC(node_queue->to_eval, num_nodes, Mif_Boolean_t)
|
||||
CKALLOC(node_queue->changed_index, num_nodes, int)
|
||||
CKALLOC(node_queue->changed, num_nodes, Mif_Boolean_t)
|
||||
|
||||
|
||||
/* Allocate elements in the output queue */
|
||||
|
||||
num_outputs = ckt->evt->counts.num_outputs;
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
CKALLOC(output_queue->head, num_outputs, void *)
|
||||
CKALLOC(output_queue->current, num_outputs, void *)
|
||||
CKALLOC(output_queue->last_step, num_outputs, void *)
|
||||
CKALLOC(output_queue->free, num_outputs, void *)
|
||||
CKALLOC(output_queue->modified_index, num_outputs, int)
|
||||
CKALLOC(output_queue->modified, num_outputs, Mif_Boolean_t)
|
||||
CKALLOC(output_queue->pending_index, num_outputs, int)
|
||||
CKALLOC(output_queue->pending, num_outputs, Mif_Boolean_t)
|
||||
CKALLOC(output_queue->changed_index, num_outputs, int)
|
||||
CKALLOC(output_queue->changed, num_outputs, Mif_Boolean_t)
|
||||
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTinit_limits
|
||||
|
||||
This function initializes the iteration limits applicable to the
|
||||
event-driven algorithm.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTinit_limits(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
/* Set maximum number of event load calls within a single event iteration */
|
||||
/* to the number of event outputs. This should allow for the */
|
||||
/* maximum possible number of events that can trickle through any */
|
||||
/* circuit that does not contain loops. */
|
||||
|
||||
ckt->evt->limits.max_event_passes = ckt->evt->counts.num_outputs + 1;
|
||||
|
||||
|
||||
/* Set maximum number of alternations between analog and event-driven */
|
||||
/* iterations to the number of event outputs on hybrids. */
|
||||
|
||||
ckt->evt->limits.max_op_alternations = ckt->evt->counts.num_hybrid_outputs + 1;
|
||||
|
||||
|
||||
/* Return */
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
/*============================================================================
|
||||
FILE EVTiter.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTiter which iterates through
|
||||
event-driven outputs and instances until the outputs no longer change.
|
||||
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTiter(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
/*
|
||||
EVTiter
|
||||
|
||||
This function iterates through event-driven outputs and instances
|
||||
until the outputs no longer change. The general algorithm used
|
||||
is:
|
||||
|
||||
Do:
|
||||
|
||||
Scan list of changed outputs
|
||||
Put items on the node queue 'to_eval' list for
|
||||
each changed output.
|
||||
|
||||
Scan list of changed nodes
|
||||
Resolve nodes with multiple outputs posted.
|
||||
Create inverted state for nodes with attached
|
||||
inverted inputs.
|
||||
Put items on the instance queue 'to_call' list
|
||||
for each changed node.
|
||||
If transient analysis, put state of the node
|
||||
into the node data structure.
|
||||
|
||||
Scan instance to_call list
|
||||
Call EVTload for each instance on list.
|
||||
|
||||
While there are changed outputs
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int EVTiter(
|
||||
CKTcircuit *ckt) /* the circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_changed;
|
||||
|
||||
int num_to_eval;
|
||||
int num_to_call;
|
||||
|
||||
int output_index;
|
||||
/* int output_subindex;*/
|
||||
int inst_index;
|
||||
int node_index;
|
||||
int port_index;
|
||||
|
||||
int num_outputs;
|
||||
int udn_index;
|
||||
|
||||
int passes;
|
||||
|
||||
Evt_Ckt_Data_t *evt;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Node_Queue_t *node_queue;
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
|
||||
Evt_Inst_Index_t *inst_list;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Node_t *node;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
char *err_msg;
|
||||
|
||||
|
||||
/* Get temporary pointers for fast access */
|
||||
evt = ckt->evt;
|
||||
|
||||
output_queue = &(evt->queue.output);
|
||||
node_queue = &(evt->queue.node);
|
||||
inst_queue = &(evt->queue.inst);
|
||||
|
||||
output_table = evt->info.output_table;
|
||||
node_table = evt->info.node_table;
|
||||
port_table = evt->info.port_table;
|
||||
|
||||
node_data = evt->data.node;
|
||||
rhs = node_data->rhs;
|
||||
rhsold = node_data->rhsold;
|
||||
|
||||
|
||||
/* Loop until no more output change, or too many passes through loop */
|
||||
for(passes = 0; passes < evt->limits.max_event_passes; passes++) {
|
||||
|
||||
|
||||
/* Create list of nodes to evaluate from list of changed outputs */
|
||||
num_changed = output_queue->num_changed;
|
||||
for(i = 0; i < num_changed; i++) {
|
||||
|
||||
/* Get index of node that output is connected to */
|
||||
output_index = output_queue->changed_index[i];
|
||||
node_index = output_table[output_index]->node_index;
|
||||
|
||||
/* If not already on list of nodes to evaluate, add it */
|
||||
if(! node_queue->to_eval[node_index]) {
|
||||
node_queue->to_eval[node_index] = MIF_TRUE;
|
||||
node_queue->to_eval_index[(node_queue->num_to_eval)++]
|
||||
= node_index;
|
||||
}
|
||||
|
||||
/* Reset the changed flag on the output queue */
|
||||
output_queue->changed[output_index] = MIF_FALSE;
|
||||
|
||||
}
|
||||
output_queue->num_changed = 0;
|
||||
|
||||
|
||||
|
||||
/* Evaluate nodes and for any which have changed, enter */
|
||||
/* the instances that receive inputs from them on the list */
|
||||
/* of instances to call */
|
||||
|
||||
num_to_eval = node_queue->num_to_eval;
|
||||
for(i = 0; i < num_to_eval; i++) {
|
||||
|
||||
/* Get the node index, udn index and number of outputs */
|
||||
node_index = node_queue->to_eval_index[i];
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
|
||||
/* Resolve the node value if multiple outputs on it */
|
||||
/* and test if new node value is different than old value */
|
||||
if(num_outputs > 1) {
|
||||
(*(g_evt_udn_info[udn_index]->resolve))
|
||||
(num_outputs,
|
||||
rhs[node_index].output_value,
|
||||
rhs[node_index].node_value);
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value,
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value);
|
||||
}
|
||||
}
|
||||
/* Else, load function has already determined that they were */
|
||||
/* not equal */
|
||||
else
|
||||
equal = MIF_FALSE;
|
||||
|
||||
/* If not equal, make inverted copy in rhsold if */
|
||||
/* needed, and place indexes of instances with inputs connected */
|
||||
/* to the node in the to_call list of inst queue */
|
||||
if(! equal) {
|
||||
if(node_table[node_index]->invert) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhsold[node_index].node_value,
|
||||
rhsold[node_index].inverted_value);
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(rhsold[node_index].inverted_value);
|
||||
}
|
||||
inst_list = node_table[node_index]->inst_list;
|
||||
while(inst_list) {
|
||||
inst_index = inst_list->index;
|
||||
if(! inst_queue->to_call[inst_index]) {
|
||||
inst_queue->to_call[inst_index] = MIF_TRUE;
|
||||
inst_queue->to_call_index[(inst_queue->num_to_call)++]
|
||||
= inst_index;
|
||||
}
|
||||
inst_list = inst_list->next;
|
||||
} /* end while instances with inputs on node */
|
||||
} /* end if not equal */
|
||||
|
||||
/* If transient analysis mode */
|
||||
/* Save the node data onto the node results list and mark */
|
||||
/* that it has been modified, even if the */
|
||||
/* resolved node value has not changed */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
|
||||
node = *(node_data->tail[node_index]);
|
||||
node_data->tail[node_index] = &(node->next);
|
||||
EVTnode_copy(ckt, node_index, &(rhsold[node_index]), &(node->next));
|
||||
node->next->step = g_mif_info.circuit.evt_step;
|
||||
|
||||
if(! node_data->modified[node_index]) {
|
||||
node_data->modified[node_index] = MIF_TRUE;
|
||||
node_data->modified_index[(node_data->num_modified)++] = node_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the to_eval flag on the node queue */
|
||||
node_queue->to_eval[node_index] = MIF_FALSE;
|
||||
|
||||
} /* end for number of nodes to evaluate */
|
||||
node_queue->num_to_eval = 0;
|
||||
|
||||
|
||||
|
||||
/* Call the instances with inputs on nodes that have changed */
|
||||
num_to_call = inst_queue->num_to_call;
|
||||
for(i = 0; i < num_to_call; i++) {
|
||||
inst_index = inst_queue->to_call_index[i];
|
||||
inst_queue->to_call[inst_index] = MIF_FALSE;
|
||||
EVTload(ckt, inst_index);
|
||||
}
|
||||
inst_queue->num_to_call = 0;
|
||||
|
||||
|
||||
/* Record statistics */
|
||||
if(g_mif_info.circuit.anal_type == MIF_DC)
|
||||
(ckt->evt->data.statistics->op_event_passes)++;
|
||||
|
||||
|
||||
/* If no outputs changed, iteration is over, so return with success! */
|
||||
if(output_queue->num_changed == 0)
|
||||
return(0);
|
||||
|
||||
} /* end for */
|
||||
|
||||
|
||||
/* Too many passes through loop, report problems and exit with error */
|
||||
|
||||
err_msg = MALLOC(10000);
|
||||
for(i = 0; i < output_queue->num_changed; i++) {
|
||||
output_index = output_queue->changed_index[i];
|
||||
port_index = output_table[output_index]->port_index;
|
||||
sprintf(err_msg, "\n Instance: %s\n Connection: %s\n Port: %d",
|
||||
port_table[port_index]->inst_name,
|
||||
port_table[port_index]->conn_name,
|
||||
port_table[port_index]->port_num);
|
||||
ENHreport_conv_prob(ENH_EVENT_NODE,
|
||||
port_table[port_index]->node_name,
|
||||
err_msg);
|
||||
}
|
||||
FREE(err_msg);
|
||||
|
||||
(*(SPfrontEnd->IFerror)) (ERR_WARNING,
|
||||
"Too many iteration passes in event-driven circuits",
|
||||
(IFuid *) NULL);
|
||||
return(E_ITERLIM);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,613 @@
|
|||
/*============================================================================
|
||||
FILE EVTload.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTload which is used to call a
|
||||
specified event-driven or hybrid code model during an event-driven
|
||||
iteration. The 'CALL_TYPE' is set to 'EVENT_DRIVEN' when the
|
||||
model is called from this function.
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTload(CKTcircuit *ckt, int inst_index)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "devdefs.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
extern SPICEdev **DEVices;
|
||||
|
||||
|
||||
|
||||
static void EVTcreate_state(
|
||||
CKTcircuit *ckt,
|
||||
int inst_index);
|
||||
|
||||
static void EVTadd_msg(
|
||||
CKTcircuit *ckt,
|
||||
int port_index,
|
||||
char *msg_text);
|
||||
|
||||
static void EVTcreate_output_event(
|
||||
CKTcircuit *ckt,
|
||||
int node_index,
|
||||
int output_index,
|
||||
void **value_ptr);
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt,
|
||||
Mif_Boolean_t changed,
|
||||
int output_index,
|
||||
Mif_Boolean_t invert,
|
||||
double delay);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTload
|
||||
|
||||
This function calls the code model function for the specified
|
||||
instance with CALL_TYPE set to EVENT_DRIVEN. Event outputs,
|
||||
messages, etc. are processed on return from the code model.
|
||||
Analog outputs, partials, etc. should not be computed by the
|
||||
code model when the call type is event-driven and are
|
||||
ignored.
|
||||
*/
|
||||
|
||||
int EVTload(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index) /* The instance to call code model for */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_conn;
|
||||
int num_port;
|
||||
int mod_type;
|
||||
|
||||
Mif_Conn_Data_t *conn;
|
||||
Mif_Port_Data_t *port;
|
||||
|
||||
Mif_Private_t cm_data;
|
||||
|
||||
MIFinstance *inst;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
void *value_ptr;
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Prepare the code model inputs */
|
||||
/* ***************************** */
|
||||
|
||||
/* Get pointer to instance data structure and other data */
|
||||
/* needed for fast access */
|
||||
inst = ckt->evt->info.inst_table[inst_index]->inst_ptr;
|
||||
node_data = ckt->evt->data.node;
|
||||
|
||||
/* Setup circuit data in struct to be passed to code model function */
|
||||
|
||||
if(inst->initialized)
|
||||
cm_data.circuit.init = MIF_FALSE;
|
||||
else
|
||||
cm_data.circuit.init = MIF_TRUE;
|
||||
|
||||
cm_data.circuit.anal_init = MIF_FALSE;
|
||||
cm_data.circuit.anal_type = g_mif_info.circuit.anal_type;
|
||||
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
cm_data.circuit.time = g_mif_info.circuit.evt_step;
|
||||
else
|
||||
cm_data.circuit.time = 0.0;
|
||||
|
||||
cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
cm_data.circuit.temperature = ckt->CKTtemp - 273.15;
|
||||
|
||||
|
||||
/* Setup data needed by cm_... functions */
|
||||
|
||||
g_mif_info.ckt = ckt;
|
||||
g_mif_info.instance = inst;
|
||||
g_mif_info.errmsg = "";
|
||||
g_mif_info.circuit.call_type = MIF_EVENT_DRIVEN;
|
||||
|
||||
if(inst->initialized)
|
||||
g_mif_info.circuit.init = MIF_FALSE;
|
||||
else
|
||||
g_mif_info.circuit.init = MIF_TRUE;
|
||||
|
||||
|
||||
/* If after initialization and in transient analysis mode */
|
||||
/* create a new state for the instance */
|
||||
|
||||
if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized)
|
||||
EVTcreate_state(ckt, inst_index);
|
||||
|
||||
|
||||
/* Loop through all connections on the instance and setup */
|
||||
/* load, total_load, and msg on all ports, and changed flag */
|
||||
/* and output pointer on all outputs */
|
||||
|
||||
num_conn = inst->num_conn;
|
||||
for(i = 0; i < num_conn; i++) {
|
||||
|
||||
conn = inst->conn[i];
|
||||
|
||||
/* if connection is null, continue to next */
|
||||
if(conn->is_null)
|
||||
continue;
|
||||
|
||||
/* Loop through each port on the connection */
|
||||
num_port = conn->size;
|
||||
for(j = 0; j < num_port; j++) {
|
||||
|
||||
port = conn->port[j];
|
||||
|
||||
/* Skip if port is null */
|
||||
if(port->is_null)
|
||||
continue;
|
||||
|
||||
/* If port type is Digital or User-Defined */
|
||||
if((port->type == MIF_DIGITAL) || (port->type == MIF_USER_DEFINED)) {
|
||||
|
||||
/* Initialize the msg pointer on the port to NULL, */
|
||||
/* initialize the load value to zero, and get the total load */
|
||||
port->msg = NULL;
|
||||
port->load = 0.0;
|
||||
port->total_load = node_data->total_load[port->evt_data.node_index];
|
||||
|
||||
/* If connection is an output, initialize changed to true */
|
||||
/* and create a new output event object in the free list */
|
||||
/* if transient analysis mode */
|
||||
if(conn->is_output) {
|
||||
port->changed = MIF_TRUE;
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
EVTcreate_output_event(ckt,
|
||||
port->evt_data.node_index,
|
||||
port->evt_data.output_index,
|
||||
&value_ptr);
|
||||
port->output.pvalue = value_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Get the analog input value. All we need to do is */
|
||||
/* set it to zero if mode is INITJCT. Otherwise, value */
|
||||
/* should still be around from last successful analog call */
|
||||
if(ckt->CKTmode & MODEINITJCT)
|
||||
port->input.rvalue = 0.0;
|
||||
}
|
||||
|
||||
} /* end for number of ports */
|
||||
} /* end for number of connections */
|
||||
|
||||
|
||||
/* Prepare the structure to be passed to the code model */
|
||||
cm_data.num_conn = inst->num_conn;
|
||||
cm_data.conn = inst->conn;
|
||||
cm_data.num_param = inst->num_param;
|
||||
cm_data.param = inst->param;
|
||||
cm_data.num_inst_var = inst->num_inst_var;
|
||||
cm_data.inst_var = inst->inst_var;
|
||||
|
||||
|
||||
/* ******************* */
|
||||
/* Call the code model */
|
||||
/* ******************* */
|
||||
|
||||
mod_type = inst->MIFmodPtr->MIFmodType;
|
||||
(*(DEVices[mod_type]->DEVpublic.cm_func)) (&cm_data);
|
||||
|
||||
|
||||
/* ****************************** */
|
||||
/* Process the code model outputs */
|
||||
/* ****************************** */
|
||||
|
||||
/* Loop through all connections and ports and process the msgs */
|
||||
/* and event outputs */
|
||||
|
||||
num_conn = inst->num_conn;
|
||||
for(i = 0; i < num_conn; i++) {
|
||||
|
||||
conn = inst->conn[i];
|
||||
if(conn->is_null)
|
||||
continue;
|
||||
|
||||
/* Loop through each port on the connection */
|
||||
num_port = conn->size;
|
||||
for(j = 0; j < num_port; j++) {
|
||||
|
||||
port = conn->port[j];
|
||||
|
||||
/* Skip if port is null */
|
||||
if(port->is_null)
|
||||
continue;
|
||||
|
||||
/* Process the message if any */
|
||||
if(port->msg)
|
||||
EVTadd_msg(ckt, port->evt_data.port_index, port->msg);
|
||||
|
||||
/* If this is the initialization pass, process the load factor */
|
||||
if(! inst->initialized) {
|
||||
node_data->total_load[port->evt_data.node_index] +=
|
||||
port->load;
|
||||
}
|
||||
|
||||
/* If connection is not an event output, continue to next port */
|
||||
if(! conn->is_output)
|
||||
continue;
|
||||
if((port->type != MIF_DIGITAL) && (port->type != MIF_USER_DEFINED))
|
||||
continue;
|
||||
|
||||
/* If output changed, process it */
|
||||
EVTprocess_output(ckt, port->changed,
|
||||
port->evt_data.output_index,
|
||||
port->invert, port->delay);
|
||||
|
||||
/* And prevent erroneous models from overwriting it during */
|
||||
/* analog iterations */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
port->output.pvalue = NULL;
|
||||
|
||||
} /* end for number of ports */
|
||||
} /* end for number of connections */
|
||||
|
||||
|
||||
/* Record statistics */
|
||||
if(g_mif_info.circuit.anal_type == MIF_DC)
|
||||
(ckt->evt->data.statistics->op_load_calls)++;
|
||||
else if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
(ckt->evt->data.statistics->tran_load_calls)++;
|
||||
|
||||
/* Mark that the instance has been called once */
|
||||
inst->initialized = MIF_TRUE;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTcreate_state
|
||||
|
||||
This function creates a new state storage area for a particular instance
|
||||
during an event-driven simulation. New states must be created so
|
||||
that old states are saved and can be accessed by code models in the
|
||||
future. The new state is initialized to the previous state value.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTcreate_state(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index) /* The instance to create state for */
|
||||
{
|
||||
int i;
|
||||
int total_size;
|
||||
|
||||
Evt_State_Data_t *state_data;
|
||||
|
||||
Evt_State_t *new_state;
|
||||
Evt_State_t *prev_state;
|
||||
|
||||
char *from;
|
||||
char *to;
|
||||
|
||||
|
||||
/* Get variables for fast access */
|
||||
state_data = ckt->evt->data.state;
|
||||
|
||||
/* Exit immediately if no states on this instance */
|
||||
if(state_data->desc[inst_index] == NULL)
|
||||
return;
|
||||
|
||||
/* Get size of state block to be allocated */
|
||||
total_size = state_data->total_size[inst_index];
|
||||
|
||||
/* Allocate a new state for the instance */
|
||||
if(state_data->free[inst_index])
|
||||
{
|
||||
new_state = state_data->free[inst_index];
|
||||
state_data->free[inst_index] = new_state->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
new_state = (void *) MALLOC(sizeof(Evt_State_t));
|
||||
new_state->block = (void *) MALLOC(total_size);
|
||||
|
||||
}
|
||||
|
||||
/* Splice the new state into the state data linked list */
|
||||
/* and update the tail pointer */
|
||||
prev_state = *(state_data->tail[inst_index]);
|
||||
prev_state->next = new_state;
|
||||
new_state->prev = prev_state;
|
||||
state_data->tail[inst_index] = &(prev_state->next);
|
||||
|
||||
/* Copy the old state to the new state and set the step */
|
||||
from = prev_state->block;
|
||||
to = new_state->block;
|
||||
for(i = 0; i < total_size; i++)
|
||||
to[i] = from[i];
|
||||
new_state->step = g_mif_info.circuit.evt_step;
|
||||
|
||||
/* Mark that the state data on the instance has been modified */
|
||||
if(! state_data->modified[inst_index]) {
|
||||
state_data->modified[inst_index] = MIF_TRUE;
|
||||
state_data->modified_index[(state_data->num_modified)++] = inst_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTcreate_output_event
|
||||
|
||||
This function creates a new output event.
|
||||
*/
|
||||
|
||||
static void EVTcreate_output_event(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int node_index, /* The node type port is on */
|
||||
int output_index, /* The output index for this port */
|
||||
void **value_ptr) /* The event created */
|
||||
{
|
||||
int udn_index;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Output_Event_t *event;
|
||||
|
||||
|
||||
/* Check the output queue free list and use the structure */
|
||||
/* at the head of the list if non-null. Otherwise, create a new one. */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
if(output_queue->free[output_index]) {
|
||||
*value_ptr = output_queue->free[output_index]->value;
|
||||
}
|
||||
else {
|
||||
/* Create a new event */
|
||||
event = (void *) MALLOC(sizeof(Evt_Output_Event_t));
|
||||
event->next = NULL;
|
||||
|
||||
/* Initialize the value */
|
||||
node_table = ckt->evt->info.node_table;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(event->value));
|
||||
|
||||
/* Put the event onto the free list and return the value pointer */
|
||||
output_queue->free[output_index] = event;
|
||||
*value_ptr = event->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTadd_msg
|
||||
|
||||
This function records a message output by a code model into the
|
||||
message results data structure.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTadd_msg(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int port_index, /* The port to add message to */
|
||||
char *msg_text) /* The message text */
|
||||
{
|
||||
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
|
||||
Evt_Msg_t **msg_ptr;
|
||||
Evt_Msg_t *msg;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
msg_data = ckt->evt->data.msg;
|
||||
msg_ptr = msg_data->tail[port_index];
|
||||
|
||||
/* Set pointer to location at which to add, and update tail */
|
||||
if(*msg_ptr != NULL) {
|
||||
msg_ptr = &((*msg_ptr)->next);
|
||||
msg_data->tail[port_index] = msg_ptr;
|
||||
}
|
||||
|
||||
/* Add a new entry in the list of messages for this port */
|
||||
if(msg_data->free[port_index]) {
|
||||
*msg_ptr = msg_data->free[port_index];
|
||||
msg_data->free[port_index] = msg_data->free[port_index]->next;
|
||||
}
|
||||
else {
|
||||
*msg_ptr = (void *) MALLOC(sizeof(Evt_Msg_t));
|
||||
}
|
||||
|
||||
/* Fill in the values */
|
||||
msg = *msg_ptr;
|
||||
msg->next = NULL;
|
||||
if((ckt->CKTmode & MODEDCOP) == MODEDCOP)
|
||||
msg->op = MIF_TRUE;
|
||||
else
|
||||
msg->step = g_mif_info.circuit.evt_step;
|
||||
msg->text = MIFcopy(msg_text);
|
||||
|
||||
/* Update the modified indexes */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
if(! msg_data->modified[port_index]) {
|
||||
msg_data->modified[port_index] = MIF_TRUE;
|
||||
msg_data->modified_index[(msg_data->num_modified)++] = port_index;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTprocess_output
|
||||
|
||||
This function processes an event-driven output produced by a code
|
||||
model. If transient analysis mode, the event is placed into the
|
||||
output queue according to its (non-zero) delay. If DC analysis,
|
||||
the event is processed immediately.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTprocess_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Mif_Boolean_t changed, /* Has output changed? */
|
||||
int output_index, /* The output of interest */
|
||||
Mif_Boolean_t invert, /* Does output need to be inverted? */
|
||||
double delay) /* The output delay in transient analysis */
|
||||
{
|
||||
|
||||
int num_outputs;
|
||||
int node_index;
|
||||
int udn_index;
|
||||
int output_subindex;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Output_Event_t *output_event;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
output_table = ckt->evt->info.output_table;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
node_index = output_table[output_index]->node_index;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
|
||||
|
||||
/* if transient analysis, just put the output event on the queue */
|
||||
/* to be processed at a later time */
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
/* If model signaled that output was not posted, */
|
||||
/* leave the event struct on the free list and return */
|
||||
if((! changed) || (delay <= 0.0)) {
|
||||
if(changed && (delay <= 0.0))
|
||||
printf("\nERROR - Output delay <= 0 not allowed - output ignored!\n");
|
||||
return;
|
||||
}
|
||||
/* Remove the (now used) struct from the head of the free list */
|
||||
output_event = output_queue->free[output_index];
|
||||
output_queue->free[output_index] = output_event->next;
|
||||
/* Invert the output value if necessary */
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(output_event->value);
|
||||
/* Add it to the queue */
|
||||
EVTqueue_output(ckt, output_index, udn_index, output_event,
|
||||
g_mif_info.circuit.evt_step,
|
||||
g_mif_info.circuit.evt_step + delay);
|
||||
return;
|
||||
}
|
||||
/* If not transient analysis, process immediately. */
|
||||
/* Determine if output has changed from rhsold value */
|
||||
/* and put entry in output queue changed list if so */
|
||||
else {
|
||||
|
||||
/* If model signaled that output was not posted, */
|
||||
/* just return */
|
||||
if(! changed)
|
||||
return;
|
||||
/*
|
||||
if(delay > 0.0)
|
||||
printf("\nWARNING - Non-zero output delay not allowed in DCOP - delay ignored!\n");
|
||||
*/
|
||||
rhs = ckt->evt->data.node->rhs;
|
||||
rhsold = ckt->evt->data.node->rhsold;
|
||||
|
||||
/* Determine if changed */
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
if(num_outputs > 1) {
|
||||
output_subindex = output_table[output_index]->output_subindex;
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(rhs[node_index].output_value[output_subindex]);
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(rhs[node_index].output_value[output_subindex],
|
||||
rhsold[node_index].output_value[output_subindex],
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhs[node_index].output_value[output_subindex],
|
||||
rhsold[node_index].output_value[output_subindex]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->invert))
|
||||
(rhs[node_index].node_value);
|
||||
(*(g_evt_udn_info[udn_index]->compare))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value,
|
||||
&equal);
|
||||
if(! equal) {
|
||||
(*(g_evt_udn_info[udn_index]->copy))
|
||||
(rhs[node_index].node_value,
|
||||
rhsold[node_index].node_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* If changed, put in changed list of output queue */
|
||||
if(! equal) {
|
||||
if(! output_queue->changed[output_index]) {
|
||||
output_queue->changed[output_index] = MIF_TRUE;
|
||||
output_queue->changed_index[(output_queue->num_changed)++] =
|
||||
output_index;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
} /* end else process immediately */
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*============================================================================
|
||||
FILE EVTnext_time.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTnext_time which determines and
|
||||
returns the time of the next scheduled event on the inst and output
|
||||
queues.
|
||||
|
||||
INTERFACES
|
||||
|
||||
double EVTnext_time(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTnext_time
|
||||
|
||||
Get the next event time as the minimum of the next times
|
||||
in the inst and output queues. If no next time in either,
|
||||
return machine infinity.
|
||||
*/
|
||||
|
||||
|
||||
double EVTnext_time(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
double next_time;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
|
||||
/* Initialize next time to machine infinity */
|
||||
next_time = 1e30;
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* If anything pending in inst queue, set next time */
|
||||
/* to minimum of itself and the inst queue next time */
|
||||
if(inst_queue->num_pending)
|
||||
if(inst_queue->next_time < next_time)
|
||||
next_time = inst_queue->next_time;
|
||||
|
||||
/* If anything pending in output queue, set next time */
|
||||
/* to minimum of itself and the output queue next time */
|
||||
if(output_queue->num_pending)
|
||||
if(output_queue->next_time < next_time)
|
||||
next_time = output_queue->next_time;
|
||||
|
||||
return(next_time);
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*============================================================================
|
||||
FILE EVTnode_copy.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTnode_copy which copies the state
|
||||
of a node structure.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTnode_copy(CKTcircuit *ckt, int node_index, Evt_Node_t *from,
|
||||
Evt_Node_t **to)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
#include "cm.h"
|
||||
|
||||
/*
|
||||
EVTnode_copy
|
||||
|
||||
This function copies the state of a node structure.
|
||||
|
||||
If the destination is NULL, it is allocated before the copy. This is the
|
||||
case when EVTiter copies a node during a transient analysis to
|
||||
save the state of an element of rhsold into the node data structure
|
||||
lists.
|
||||
|
||||
If the destination is non-NULL, only the internal elements of the node
|
||||
structure are copied. This is the case when EVTbackup restores that state
|
||||
of nodes that existed at a certain timestep back into rhs and rhsold.
|
||||
*/
|
||||
|
||||
|
||||
void EVTnode_copy(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int node_index, /* The node to copy */
|
||||
Evt_Node_t *from, /* Location to copy from */
|
||||
Evt_Node_t **to) /* Location to copy to */
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
int udn_index;
|
||||
int num_outputs;
|
||||
Mif_Boolean_t invert;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
Evt_Node_t *here;
|
||||
|
||||
/* Digital_t *dummy;*/
|
||||
|
||||
/* char buff[128];*/
|
||||
|
||||
/* Get data for fast access */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
num_outputs = node_table[node_index]->num_outputs;
|
||||
invert = node_table[node_index]->invert;
|
||||
|
||||
|
||||
/* If destination is not allocated, allocate it */
|
||||
/* otherwise we just copy into the node struct */
|
||||
here = *to;
|
||||
|
||||
if(here == NULL)
|
||||
{
|
||||
/* Use allocated structure on free list if available */
|
||||
/* Otherwise, allocate a new one */
|
||||
here = node_data->free[node_index];
|
||||
if(here)
|
||||
{
|
||||
*to = here;
|
||||
node_data->free[node_index] = here->next;
|
||||
here->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
here = (void *) MALLOC(sizeof(Evt_Node_t));
|
||||
*to = here;
|
||||
/* Allocate/initialize the data in the new node struct */
|
||||
if(num_outputs > 1)
|
||||
{
|
||||
here->output_value = (void *) MALLOC(num_outputs * sizeof(void *));
|
||||
|
||||
for(i = 0; i < num_outputs; i++)
|
||||
{
|
||||
(*(g_evt_udn_info[udn_index]->create))
|
||||
( &(here->output_value[i]) );
|
||||
}
|
||||
}
|
||||
|
||||
here->node_value = NULL;
|
||||
|
||||
(*(g_evt_udn_info[udn_index]->create)) ( &(here->node_value) );
|
||||
|
||||
if(invert)
|
||||
(*(g_evt_udn_info[udn_index]->create)) ( &(here->inverted_value) );
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the node data */
|
||||
here->op = from->op;
|
||||
here->step = from->step;
|
||||
if(num_outputs > 1)
|
||||
{
|
||||
for(i = 0; i < num_outputs; i++)
|
||||
{
|
||||
(*(g_evt_udn_info[udn_index]->copy)) (from->output_value[i],
|
||||
here->output_value[i]);
|
||||
}
|
||||
}
|
||||
(*(g_evt_udn_info[udn_index]->copy)) (from->node_value, here->node_value);
|
||||
if(invert)
|
||||
{
|
||||
(*(g_evt_udn_info[udn_index]->copy)) (from->inverted_value,
|
||||
here->inverted_value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/*============================================================================
|
||||
FILE EVTop.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTop which is used to perform an
|
||||
operating point analysis in place of CKTop when there are
|
||||
event-driven instances in the circuit. It alternates between doing
|
||||
event-driven iterations with EVTiter and doing analog iterations with
|
||||
NIiter/CKTop until no more event-driven outputs change.
|
||||
|
||||
INTERFACES
|
||||
|
||||
EVTop()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
#include "sperror.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtproto.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
|
||||
static void EVTnode_compare(
|
||||
CKTcircuit *ckt,
|
||||
int node_index,
|
||||
Evt_Node_t *node1,
|
||||
Evt_Node_t *node2,
|
||||
Mif_Boolean_t *equal);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTop
|
||||
|
||||
This function is used to perform an operating point analysis
|
||||
in place of CKTop when there are event-driven instances in the
|
||||
circuit. It alternates between doing event-driven iterations
|
||||
with EVTiter and doing analog iterations with NIiter/CKTop
|
||||
until no more event-driven outputs change.
|
||||
*/
|
||||
|
||||
|
||||
int EVTop(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
long firstmode, /* The SPICE 3C1 CKTop() firstmode parameter */
|
||||
long continuemode, /* The SPICE 3C1 CKTop() continuemode paramter */
|
||||
int max_iter, /* The SPICE 3C1 CKTop() max iteration parameter */
|
||||
Mif_Boolean_t first_call) /* Is this the first time through? */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_insts;
|
||||
int converged;
|
||||
int output_index;
|
||||
int port_index;
|
||||
|
||||
char *err_msg;
|
||||
|
||||
Mif_Boolean_t firstime;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Output_Info_t **output_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
|
||||
|
||||
/* get data to local storage for fast access */
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Initialize to_call entries in event inst queue */
|
||||
/* to force calling all event/hybrid instance the first */
|
||||
/* time through */
|
||||
|
||||
if(first_call) {
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_queue->to_call[i] = MIF_TRUE;
|
||||
inst_queue->to_call_index[i] = i;
|
||||
}
|
||||
inst_queue->num_to_call = num_insts;
|
||||
}
|
||||
|
||||
|
||||
/* Alternate between event-driven and analog solutions until */
|
||||
/* there are no changed event-driven outputs */
|
||||
|
||||
firstime = MIF_TRUE;
|
||||
for(;;) {
|
||||
|
||||
/* Call EVTiter to establish initial outputs from */
|
||||
/* event/hybrid instances with states (e.g. flip-flops) */
|
||||
|
||||
ckt->CKTmode = firstmode;
|
||||
converged = EVTiter(ckt);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
|
||||
/* Now do analog solution for current state of hybrid outputs */
|
||||
|
||||
/* If first analog solution, call CKTop */
|
||||
if(firstime) {
|
||||
firstime = MIF_FALSE;
|
||||
converged = CKTop(ckt,
|
||||
firstmode,
|
||||
continuemode,
|
||||
max_iter);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
}
|
||||
/* Otherwise attempt to converge with mode = continuemode */
|
||||
else {
|
||||
ckt->CKTmode = continuemode;
|
||||
converged = NIiter(ckt,max_iter);
|
||||
if(converged != 0) {
|
||||
converged = CKTop(ckt,
|
||||
firstmode,
|
||||
continuemode,
|
||||
max_iter);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call all hybrids to allow new event outputs to be posted */
|
||||
EVTcall_hybrids(ckt);
|
||||
|
||||
/* Increment count of successful alternations */
|
||||
(ckt->evt->data.statistics->op_alternations)++;
|
||||
|
||||
/* If .option card specified not to alternate solutions, exit */
|
||||
/* immediately with this first pass solution */
|
||||
if(! ckt->evt->options.op_alternate)
|
||||
return(0);
|
||||
|
||||
/* If no hybrid instances produced different event outputs, */
|
||||
/* alternation is completed, so exit */
|
||||
if(ckt->evt->queue.output.num_changed == 0)
|
||||
return(0);
|
||||
|
||||
/* If too many alternations, exit with error */
|
||||
if(ckt->evt->data.statistics->op_alternations >=
|
||||
ckt->evt->limits.max_op_alternations) {
|
||||
|
||||
(*(SPfrontEnd->IFerror)) (ERR_WARNING,
|
||||
"Too many analog/event-driven solution alternations",
|
||||
(IFuid *) NULL);
|
||||
|
||||
err_msg = MALLOC(10000);
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
output_table = ckt->evt->info.output_table;
|
||||
port_table = ckt->evt->info.port_table;
|
||||
|
||||
for(i = 0; i < output_queue->num_changed; i++) {
|
||||
output_index = output_queue->changed_index[i];
|
||||
port_index = output_table[output_index]->port_index;
|
||||
sprintf(err_msg, "\n Instance: %s\n Connection: %s\n Port: %d",
|
||||
port_table[port_index]->inst_name,
|
||||
port_table[port_index]->conn_name,
|
||||
port_table[port_index]->port_num);
|
||||
ENHreport_conv_prob(ENH_EVENT_NODE,
|
||||
port_table[port_index]->node_name,
|
||||
err_msg);
|
||||
}
|
||||
FREE(err_msg);
|
||||
|
||||
return(E_ITERLIM);
|
||||
}
|
||||
|
||||
} /* end forever */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTop_save
|
||||
|
||||
Save result from operating point iteration into the node data area.
|
||||
*/
|
||||
|
||||
void EVTop_save(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
Mif_Boolean_t op, /* True if from a DCOP analysis, false if TRANOP, etc. */
|
||||
double step)
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_nodes;
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhsold;
|
||||
Evt_Node_t **head;
|
||||
Evt_Node_t **here;
|
||||
|
||||
/* char buff[128];*/
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
node_data = ckt->evt->data.node;
|
||||
rhsold = node_data->rhsold;
|
||||
head = node_data->head;
|
||||
|
||||
/* For number of event nodes, copy rhsold to node data */
|
||||
/* and set the op member if appropriate */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
for(i = 0; i < num_nodes; i++)
|
||||
{
|
||||
/* if head is null, just copy there */
|
||||
if(head[i] == NULL)
|
||||
{
|
||||
EVTnode_copy(ckt, i, &(rhsold[i]), &(head[i]));
|
||||
|
||||
head[i]->op = op;
|
||||
head[i]->step = step;
|
||||
|
||||
}
|
||||
/* Otherwise, add to the end of the list */
|
||||
else
|
||||
{
|
||||
/* Locate end of list */
|
||||
here = &(head[i]);
|
||||
for(;;)
|
||||
{
|
||||
if((*here)->next)
|
||||
here = &((*here)->next);
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Compare entry at end of list to rhsold */
|
||||
|
||||
EVTnode_compare(ckt, i, &(rhsold[i]), *here, &equal);
|
||||
|
||||
/* If new value in rhsold is different, add it to the list */
|
||||
if(!equal)
|
||||
{
|
||||
here = &((*here)->next);
|
||||
EVTnode_copy(ckt, i, &(rhsold[i]), here);
|
||||
(*here)->op = op;
|
||||
(*here)->step = step;
|
||||
}
|
||||
} /* end else add to end of list */
|
||||
} /* end for number of nodes */
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ************************************************************ */
|
||||
|
||||
|
||||
/*
|
||||
EVTnode_compare
|
||||
|
||||
This function compares the resolved values of the old and
|
||||
new states on a node. The actual comparison is done by
|
||||
calling the appropriate user-defined node compare function.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTnode_compare(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int node_index, /* The index for the node in question */
|
||||
Evt_Node_t *node1, /* The first value */
|
||||
Evt_Node_t *node2, /* The second value */
|
||||
Mif_Boolean_t *equal) /* The computed result */
|
||||
{
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
int udn_index;
|
||||
|
||||
|
||||
/* Get data for fast access */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
udn_index = node_table[node_index]->udn_index;
|
||||
|
||||
|
||||
/* Do compare based on changes in resolved node value only */
|
||||
(*(g_evt_udn_info[udn_index]->compare)) (
|
||||
node1->node_value,
|
||||
node2->node_value,
|
||||
equal);
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/*============================================================================
|
||||
FILE EVTplot.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1992
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
5/7/92 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTplot which is used to provide basic
|
||||
plotting of event driven nodes through SPICE3's 'plot' command.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTplot()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//nclude "misc.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
#include "evtproto.h"
|
||||
#include "mif.h"
|
||||
#include "mifproto.h"
|
||||
|
||||
/*saj for output */
|
||||
#include "sim.h"
|
||||
#include "dvec.h"
|
||||
//#include "ftedata.h"
|
||||
//#include "fteconstant.h"
|
||||
//#include "util.h"
|
||||
#include "cpstd.h"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
EVTfindvec()
|
||||
|
||||
This function is called from FTE/vectors.c:findvec() when a node specified
|
||||
for plotting cannot be located in the analog plot data. It scans the
|
||||
event driven data structures looking for the node, and if found, returns
|
||||
a new 'dvec' structure holding the data to be plotted. The dvec struct
|
||||
is created with it's own v_scale member holding the event time vector
|
||||
for this node since the time vector is not aligned with the analog data
|
||||
points or with other event vectors.
|
||||
|
||||
The node name supplied as argument can either be a simple node name, or a
|
||||
name of the form <node name>(<member>), where <member> is the member of
|
||||
the event-driven structure to be plotted. These member names are defined
|
||||
by the individual "user-defined node" plot_val routines for the node
|
||||
type in question. If the simple node name form is used, the special
|
||||
keyword "all" is supplied to the plot_val routine for the member name.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
struct dvec *EVTfindvec(
|
||||
char *node) /* The node name (and optional member name) */
|
||||
{
|
||||
char *name;
|
||||
char *member = "all";
|
||||
char *ptr;
|
||||
|
||||
int i;
|
||||
int len;
|
||||
int num_nodes;
|
||||
int udn_index;
|
||||
int num_events;
|
||||
|
||||
Mif_Boolean_t found;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Node_t *head;
|
||||
Evt_Node_t *event;
|
||||
|
||||
double *anal_point_vec;
|
||||
double *value_vec;
|
||||
double value;
|
||||
|
||||
struct dvec *d;
|
||||
struct dvec *scale;
|
||||
|
||||
/* Exit immediately if event-driven stuff not allocated yet, */
|
||||
/* or if number of event nodes is zero. */
|
||||
if(! g_mif_info.ckt)
|
||||
return(NULL);
|
||||
if(! g_mif_info.ckt->evt)
|
||||
return(NULL);
|
||||
if(g_mif_info.ckt->evt->counts.num_nodes == 0)
|
||||
return(NULL);
|
||||
|
||||
/* Make a copy of the node name. */
|
||||
/* Do not free this string. It is assigned into the dvec structure below. */
|
||||
name = MIFcopy(node);
|
||||
|
||||
/* Convert to all lower case */
|
||||
len = strlen(name);
|
||||
for(i = 0; i < len; i++)
|
||||
if(isupper(name[i]))
|
||||
name[i] = tolower(name[i]);
|
||||
|
||||
/* Divide into the node name and member name */
|
||||
for(ptr = name; *ptr != '\0'; ptr++)
|
||||
if(*ptr == '(')
|
||||
break;
|
||||
|
||||
if(*ptr == '(') {
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
member = ptr;
|
||||
for( ; *ptr != '\0'; ptr++)
|
||||
if(*ptr == ')')
|
||||
break;
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
/* Look for node name in the event-driven node list */
|
||||
num_nodes = g_mif_info.ckt->evt->counts.num_nodes;
|
||||
node_table = g_mif_info.ckt->evt->info.node_table;
|
||||
|
||||
for(i = 0, found = MIF_FALSE; i < num_nodes; i++) {
|
||||
if(cieq(name, node_table[i]->name)) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(! found)
|
||||
return(NULL);
|
||||
|
||||
/* Get the UDN type index */
|
||||
udn_index = node_table[i]->udn_index;
|
||||
|
||||
/* Count the number of events */
|
||||
head = g_mif_info.ckt->evt->data.node->head[i];
|
||||
|
||||
for(event = head, num_events = 0; event; event = event->next)
|
||||
num_events++;
|
||||
|
||||
/* Allocate arrays to hold the analysis point and node value vectors */
|
||||
anal_point_vec = (double *) MALLOC(2 * (num_events + 2) * sizeof(double));
|
||||
value_vec = (double *) MALLOC(2 * (num_events + 2) * sizeof(double));
|
||||
|
||||
/* Iterate through the events and fill the arrays. */
|
||||
/* Note that we create vertical segments every time an event occurs. */
|
||||
/* Need to modify this in the future to complete the vector out to the */
|
||||
/* last analysis point... */
|
||||
for(i = 0, event = head; event; event = event->next) {
|
||||
|
||||
/* If not first point, put the second value of the horizontal line in the vectors */
|
||||
if(i > 0) {
|
||||
anal_point_vec[i] = event->step;
|
||||
value_vec[i] = value;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Get the next value by calling the appropriate UDN plot_val function */
|
||||
value = 0.0;
|
||||
(*(g_evt_udn_info[udn_index]->plot_val)) (event->node_value,
|
||||
member,
|
||||
&value);
|
||||
|
||||
/* Put the first value of the horizontal line in the vector */
|
||||
anal_point_vec[i] = event->step;
|
||||
value_vec[i] = value;
|
||||
i++;
|
||||
|
||||
}
|
||||
|
||||
/* Allocate dvec structures and assign the vectors into them. */
|
||||
/* See FTE/OUTinterface.c:plotInit() for initialization example. */
|
||||
|
||||
scale = (void *) MALLOC(sizeof(struct dvec));
|
||||
|
||||
scale->v_name = MIFcopy("step");
|
||||
scale->v_type = SV_TIME;
|
||||
scale->v_flags = VF_REAL & ~VF_PERMANENT;
|
||||
scale->v_length = i;
|
||||
scale->v_realdata = anal_point_vec;
|
||||
scale->v_scale = NULL;
|
||||
|
||||
d = (void *) MALLOC(sizeof(struct dvec));
|
||||
|
||||
d->v_name = name;
|
||||
d->v_type = SV_VOLTAGE;
|
||||
d->v_flags = VF_REAL & ~VF_PERMANENT;
|
||||
d->v_length = i;
|
||||
d->v_realdata = value_vec;
|
||||
d->v_scale = scale;
|
||||
|
||||
|
||||
/* Return the dvec */
|
||||
return(d);
|
||||
}
|
||||
|
|
@ -0,0 +1,369 @@
|
|||
/*============================================================================
|
||||
FILE EVTprint.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTprint which is used to provide a simple
|
||||
tabular output of event-driven node data. This printout is invoked
|
||||
through a new nutmeg command called 'eprint' which takes event-driven
|
||||
node names as argument.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTprint(wordlist *wl)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cpstd.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
static int get_index(char *node_name);
|
||||
|
||||
static void print_data(
|
||||
Mif_Boolean_t dcop,
|
||||
double step,
|
||||
char **node_value,
|
||||
int nargs);
|
||||
|
||||
/*
|
||||
EVTprint
|
||||
|
||||
This function implements the 'eprint' command used to print
|
||||
event-driven node values and messages from the latest simulation.
|
||||
|
||||
This is a simple prototype implementation of the
|
||||
eprint command for testing purposes. It is currently lacking
|
||||
in the following areas:
|
||||
|
||||
1) It accepts only up to 16 nodes.
|
||||
|
||||
2) It does not support the selected printing of different
|
||||
members of a user-defined data struct.
|
||||
|
||||
3) It is dumb in its output formatting - just tries to print
|
||||
everything on a line with 4 space separators.
|
||||
|
||||
4) It works only for the latest simulation - i.e. it does not
|
||||
use the evt jobs structure to find old results.
|
||||
|
||||
5) It does not allow a range of timesteps to be selected.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define EPRINT_MAXARGS 16
|
||||
|
||||
|
||||
void EVTprint(
|
||||
wordlist *wl) /* The command line entered by user */
|
||||
{
|
||||
|
||||
int i;
|
||||
int nargs;
|
||||
int num_ports;
|
||||
|
||||
wordlist *w;
|
||||
|
||||
char *node_name[EPRINT_MAXARGS];
|
||||
int node_index[EPRINT_MAXARGS];
|
||||
int udn_index[EPRINT_MAXARGS];
|
||||
Evt_Node_t *node_data[EPRINT_MAXARGS];
|
||||
char *node_value[EPRINT_MAXARGS];
|
||||
|
||||
CKTcircuit *ckt;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Port_Info_t **port_table;
|
||||
|
||||
Mif_Boolean_t more;
|
||||
Mif_Boolean_t dcop;
|
||||
|
||||
double step;
|
||||
double next_step;
|
||||
double this_step;
|
||||
|
||||
char *value;
|
||||
|
||||
Evt_Msg_t *msg_data;
|
||||
Evt_Statistic_t *statistics;
|
||||
|
||||
|
||||
/* Count the number of arguments to the command */
|
||||
nargs = 0;
|
||||
w = wl;
|
||||
while(w) {
|
||||
nargs++;
|
||||
w = w->wl_next;
|
||||
}
|
||||
|
||||
if(nargs < 1) {
|
||||
printf("Usage: eprint <node1> <node2> ...\n");
|
||||
return;
|
||||
}
|
||||
if(nargs > EPRINT_MAXARGS) {
|
||||
printf("ERROR - eprint currently limited to 16 arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get needed pointers */
|
||||
ckt = g_mif_info.ckt;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
|
||||
/* Get data for each argument */
|
||||
w = wl;
|
||||
for(i = 0; i < nargs; i++) {
|
||||
node_name[i] = w->wl_word;
|
||||
node_index[i] = get_index(node_name[i]);
|
||||
if(node_index[i] < 0) {
|
||||
printf("ERROR - Node %s is not an event node.\n", node_name[i]);
|
||||
return;
|
||||
}
|
||||
udn_index[i] = node_table[node_index[i]]->udn_index;
|
||||
node_data[i] = ckt->evt->data.node->head[node_index[i]];
|
||||
node_value[i] = "";
|
||||
w = w->wl_next;
|
||||
}
|
||||
|
||||
|
||||
/* Print results data */
|
||||
printf("\n**** Results Data ****\n\n");
|
||||
|
||||
/* Print the column identifiers */
|
||||
printf("Time or Step\n");
|
||||
for(i = 0; i < nargs; i++)
|
||||
printf("%s\n",node_name[i]);
|
||||
printf("\n\n");
|
||||
|
||||
/* Scan the node data and determine if the first vector */
|
||||
/* is for a DCOP analysis or the first step in a swept DC */
|
||||
/* or transient analysis. Also, determine if there is */
|
||||
/* more data following it and if so, what the next step */
|
||||
/* is. */
|
||||
more = MIF_FALSE;
|
||||
dcop = MIF_FALSE;
|
||||
next_step = 1e30;
|
||||
for(i = 0; i < nargs; i++) {
|
||||
if(node_data[i]->op)
|
||||
dcop = MIF_TRUE;
|
||||
else
|
||||
step = node_data[i]->step;
|
||||
(*(g_evt_udn_info[udn_index[i]]->print_val))
|
||||
(node_data[i]->node_value, "all", &value);
|
||||
node_value[i] = value;
|
||||
node_data[i] = node_data[i]->next;
|
||||
if(node_data[i]) {
|
||||
more = MIF_TRUE;
|
||||
if(node_data[i]->step < next_step)
|
||||
next_step = node_data[i]->step;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the data */
|
||||
print_data(dcop, step, node_value, nargs);
|
||||
|
||||
/* While there is more data, get the next values and print */
|
||||
while(more) {
|
||||
|
||||
more = MIF_FALSE;
|
||||
this_step = next_step;
|
||||
next_step = 1e30;
|
||||
|
||||
for(i = 0; i < nargs; i++) {
|
||||
|
||||
if(node_data[i]) {
|
||||
if(node_data[i]->step == this_step) {
|
||||
(*(g_evt_udn_info[udn_index[i]]->print_val))
|
||||
(node_data[i]->node_value, "all", &value);
|
||||
node_value[i] = value;
|
||||
node_data[i] = node_data[i]->next;
|
||||
}
|
||||
if(node_data[i]) {
|
||||
more = MIF_TRUE;
|
||||
if(node_data[i]->step < next_step)
|
||||
next_step = node_data[i]->step;
|
||||
}
|
||||
|
||||
} /* end if node_data not NULL */
|
||||
|
||||
} /* end for number of args */
|
||||
|
||||
print_data(MIF_FALSE, this_step, node_value, nargs);
|
||||
|
||||
} /* end while there is more data */
|
||||
printf("\n\n");
|
||||
|
||||
|
||||
/* Print messages for all ports */
|
||||
printf("\n**** Messages ****\n\n");
|
||||
|
||||
num_ports = ckt->evt->counts.num_ports;
|
||||
port_table = ckt->evt->info.port_table;
|
||||
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
|
||||
/* Get pointer to messages for this port */
|
||||
msg_data = ckt->evt->data.msg->head[i];
|
||||
|
||||
/* If no messages on this port, skip */
|
||||
if(! msg_data)
|
||||
continue;
|
||||
|
||||
/* Print the port description */
|
||||
printf("Node: %s Inst: %s Conn: %s Port: %d\n\n",
|
||||
port_table[i]->node_name,
|
||||
port_table[i]->inst_name,
|
||||
port_table[i]->conn_name,
|
||||
port_table[i]->port_num);
|
||||
|
||||
/* Print the messages on this port */
|
||||
while(msg_data) {
|
||||
if(msg_data->op)
|
||||
printf("DCOP ");
|
||||
else
|
||||
printf("%-16.9e", msg_data->step);
|
||||
printf("%s\n", msg_data->text);
|
||||
msg_data = msg_data->next;
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
} /* end for number of ports */
|
||||
|
||||
|
||||
/* Print statistics */
|
||||
printf("\n**** Statistics ****\n\n");
|
||||
|
||||
statistics = ckt->evt->data.statistics;
|
||||
printf("Operating point analog/event alternations: %d\n",
|
||||
statistics->op_alternations);
|
||||
printf("Operating point load calls: %d\n",
|
||||
statistics->op_load_calls);
|
||||
printf("Operating point event passes: %d\n",
|
||||
statistics->op_event_passes);
|
||||
printf("Transient analysis load calls: %d\n",
|
||||
statistics->tran_load_calls);
|
||||
printf("Transient analysis timestep backups: %d\n",
|
||||
statistics->tran_time_backups);
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
get_index
|
||||
|
||||
This function determines the index of a specified event-driven node.
|
||||
*/
|
||||
|
||||
|
||||
static int get_index(
|
||||
char *node_name /* The name of the node to search for */
|
||||
)
|
||||
{
|
||||
|
||||
/* Get the event-driven node index for the specified name */
|
||||
|
||||
int index;
|
||||
|
||||
Mif_Boolean_t found;
|
||||
Evt_Node_Info_t *node;
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Scan list of nodes in event structure to see if there */
|
||||
|
||||
found = MIF_FALSE;
|
||||
index = 0;
|
||||
|
||||
ckt = g_mif_info.ckt;
|
||||
node = ckt->evt->info.node_list;
|
||||
|
||||
while(node) {
|
||||
if(strcmp(node_name, node->name) == 0) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the index or -1 if not found */
|
||||
if(! found)
|
||||
return(-1);
|
||||
else
|
||||
return(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
print_data
|
||||
|
||||
This function prints the values of one or more nodes to
|
||||
standard output.
|
||||
*/
|
||||
|
||||
|
||||
static void print_data(
|
||||
Mif_Boolean_t dcop, /* Is this the operating point data */
|
||||
double step, /* The analysis step if dcop */
|
||||
char **node_value, /* The array of values to be printed */
|
||||
int nargs) /* The size of the value array */
|
||||
{
|
||||
|
||||
int i;
|
||||
char step_str[100];
|
||||
|
||||
if(dcop)
|
||||
strcpy(step_str, "DCOP ");
|
||||
else
|
||||
sprintf(step_str, "%-16.9e", step);
|
||||
|
||||
printf("%s", step_str);
|
||||
for(i = 0; i < nargs; i++)
|
||||
printf(" %s", node_value[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*============================================================================
|
||||
FILE EVTqueue.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains functions that place new events into the output and
|
||||
instance queues.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTqueue_output(
|
||||
CKTcircuit *ckt,
|
||||
int output_index,
|
||||
int udn_index,
|
||||
Evt_Output_Event_t *new_event,
|
||||
double posted_time,
|
||||
double event_time)
|
||||
|
||||
void EVTqueue_inst(
|
||||
CKTcircuit *ckt,
|
||||
int inst_index,
|
||||
double posted_time,
|
||||
double event_time)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTqueue_output
|
||||
|
||||
This function places the specified output event onto the output
|
||||
queue. It is called by EVTload during a transient analysis.
|
||||
|
||||
The linked list in the queue for the specified output is
|
||||
searched beginning at the current head of the pending events
|
||||
to find the location at which to insert the new event. The
|
||||
events are ordered in the list by event_time. If the event
|
||||
is placed before the end of the list, subsequent events are
|
||||
removed from the list by marking them as 'removed' and
|
||||
recording the time of removal. This allows efficient backup
|
||||
of the state of the queue if a subsequent analog timestep
|
||||
fails.
|
||||
*/
|
||||
|
||||
|
||||
void EVTqueue_output(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int output_index, /* The output in question */
|
||||
int udn_index, /* The associated user-defined node type */
|
||||
Evt_Output_Event_t *new_event, /* The event to queue */
|
||||
double posted_time, /* The current time */
|
||||
double event_time) /* The time the event should happen */
|
||||
{
|
||||
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
Evt_Output_Event_t **here;
|
||||
Evt_Output_Event_t *next;
|
||||
|
||||
Mif_Boolean_t splice;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
/* Put the times into the event struct */
|
||||
new_event->event_time = event_time;
|
||||
new_event->posted_time = posted_time;
|
||||
new_event->removed = MIF_FALSE;
|
||||
|
||||
/* Update next_time in output queue */
|
||||
if((output_queue->num_pending <= 0) ||
|
||||
(event_time < output_queue->next_time))
|
||||
output_queue->next_time = event_time;
|
||||
|
||||
/* Find location at which to insert event */
|
||||
splice = MIF_FALSE;
|
||||
here = output_queue->current[output_index];
|
||||
while(*here) {
|
||||
if(event_time <= (*here)->event_time) {
|
||||
splice = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
here = &((*here)->next);
|
||||
}
|
||||
|
||||
/* If needs to be spliced into middle of existing list */
|
||||
if(splice) {
|
||||
/* splice it in */
|
||||
next = *here;
|
||||
*here = new_event;
|
||||
new_event->next = next;
|
||||
/* mark later events as removed */
|
||||
while(next) {
|
||||
if(! next->removed) {
|
||||
next->removed = MIF_TRUE;
|
||||
next->removed_time = posted_time;
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
/* else, just put it at the end */
|
||||
else {
|
||||
*here = new_event;
|
||||
new_event->next = NULL;
|
||||
}
|
||||
|
||||
/* Add to the list of outputs modified since last accepted timestep */
|
||||
if(! output_queue->modified[output_index]) {
|
||||
output_queue->modified[output_index] = MIF_TRUE;
|
||||
output_queue->modified_index[(output_queue->num_modified)++] =
|
||||
output_index;
|
||||
}
|
||||
|
||||
/* Add to the list of outputs with events pending */
|
||||
if(! output_queue->pending[output_index]) {
|
||||
output_queue->pending[output_index] = MIF_TRUE;
|
||||
output_queue->pending_index[(output_queue->num_pending)++] =
|
||||
output_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTqueue_inst
|
||||
|
||||
This function places the specified inst event onto the inst
|
||||
queue.
|
||||
|
||||
The linked list in the queue for the specified inst is
|
||||
searched beginning at the current head of the pending events
|
||||
to find the location at which to insert the new event. The
|
||||
events are ordered in the list by event_time.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
void EVTqueue_inst(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
int inst_index, /* The instance in question */
|
||||
double posted_time, /* The current time */
|
||||
double event_time) /* The time the event should happen */
|
||||
{
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Inst_Event_t **here;
|
||||
Evt_Inst_Event_t *new_event;
|
||||
Evt_Inst_Event_t *next;
|
||||
|
||||
Mif_Boolean_t splice;
|
||||
|
||||
|
||||
/* Get pointers for fast access */
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
/* Update next_time in inst queue */
|
||||
if((inst_queue->num_pending <= 0) ||
|
||||
(event_time < inst_queue->next_time))
|
||||
inst_queue->next_time = event_time;
|
||||
|
||||
/* Create a new event or get one from the free list and copy in data */
|
||||
if(inst_queue->free[inst_index]) {
|
||||
new_event = inst_queue->free[inst_index];
|
||||
inst_queue->free[inst_index] = new_event->next;
|
||||
}
|
||||
else {
|
||||
new_event = (void *) MALLOC(sizeof(Evt_Inst_Event_t));
|
||||
}
|
||||
new_event->event_time = event_time;
|
||||
new_event->posted_time = posted_time;
|
||||
|
||||
/* Find location at which to insert event */
|
||||
splice = MIF_FALSE;
|
||||
here = inst_queue->current[inst_index];
|
||||
while(*here) {
|
||||
/* If there's an event with the same time, don't duplicate it */
|
||||
if(event_time == (*here)->event_time)
|
||||
return;
|
||||
else if(event_time < (*here)->event_time) {
|
||||
splice = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
here = &((*here)->next);
|
||||
}
|
||||
|
||||
/* If needs to be spliced into middle of existing list */
|
||||
if(splice) {
|
||||
/* splice it in */
|
||||
next = *here;
|
||||
*here = new_event;
|
||||
new_event->next = next;
|
||||
}
|
||||
/* else, just put it at the end */
|
||||
else {
|
||||
*here = new_event;
|
||||
new_event->next = NULL;
|
||||
}
|
||||
|
||||
/* Add to the list of insts modified since last accepted timestep */
|
||||
if(! inst_queue->modified[inst_index]) {
|
||||
inst_queue->modified[inst_index] = MIF_TRUE;
|
||||
inst_queue->modified_index[(inst_queue->num_modified)++] =
|
||||
inst_index;
|
||||
}
|
||||
|
||||
/* Add to the list of insts with events pending */
|
||||
if(! inst_queue->pending[inst_index]) {
|
||||
inst_queue->pending[inst_index] = MIF_TRUE;
|
||||
inst_queue->pending_index[(inst_queue->num_pending)++] =
|
||||
inst_index;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,578 @@
|
|||
/*============================================================================
|
||||
FILE EVTsetup.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTsetup which clears/allocates the
|
||||
event-driven queues and data structures immediately prior to a new
|
||||
analysis. In addition, it places entries in the job list so that
|
||||
results data from multiple analysis can be retrieved similar to
|
||||
SPICE3C1 saving multiple 'plots'.
|
||||
|
||||
INTERFACES
|
||||
|
||||
int EVTsetup(CKTcircuit *ckt)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
#include "sperror.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
static int EVTsetup_queues(CKTcircuit *ckt);
|
||||
static int EVTsetup_data(CKTcircuit *ckt);
|
||||
static int EVTsetup_jobs(CKTcircuit *ckt);
|
||||
static int EVTsetup_load_ptrs(CKTcircuit *ckt);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Allocation macros with built-in check for out-of-memory */
|
||||
/* Adapted from SPICE 3C1 code in CKTsetup.c */
|
||||
|
||||
#define CKALLOC(var,size,type) \
|
||||
if(size) { \
|
||||
if(!(var = (void *) MALLOC((size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
}
|
||||
|
||||
#define CKREALLOC(var,size,type) \
|
||||
if((size) == 1) { \
|
||||
if(!(var = (void *) MALLOC((size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
} else if((size) > 1) { \
|
||||
if(!(var = (void *) REALLOC((void *) (var), (size) * sizeof(type)))) \
|
||||
return(E_NOMEM); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup
|
||||
|
||||
This function clears/allocates the event-driven queues and data structures
|
||||
immediately prior to a new analysis. In addition, it places entries
|
||||
in the job list so that results data from multiple analysis can be
|
||||
retrieved similar to SPICE3C1 saving multiple 'plots'.
|
||||
*/
|
||||
|
||||
|
||||
int EVTsetup(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int err;
|
||||
|
||||
|
||||
/* Exit immediately if no event-driven instances in circuit */
|
||||
if(ckt->evt->counts.num_insts == 0)
|
||||
return(OK);
|
||||
|
||||
/* Clear the inst, node, and output queues, and initialize the to_call */
|
||||
/* elements in the instance queue to call all event-driven instances */
|
||||
err = EVTsetup_queues(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Allocate and initialize the node, state, message, and statistics data */
|
||||
err = EVTsetup_data(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Set the job pointers to the allocated results, states, messages, */
|
||||
/* and statistics so that data will be accessable after run */
|
||||
err = EVTsetup_jobs(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Setup the pointers in the MIFinstance structure for inputs, outputs, */
|
||||
/* and total loads */
|
||||
err = EVTsetup_load_ptrs(ckt);
|
||||
if(err)
|
||||
return(err);
|
||||
|
||||
/* Initialize additional event data */
|
||||
g_mif_info.circuit.evt_step = 0.0;
|
||||
|
||||
/* Return OK */
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_queues
|
||||
|
||||
This function clears the event-driven queues in preparation for
|
||||
a new simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_queues(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_insts;
|
||||
int num_nodes;
|
||||
int num_outputs;
|
||||
|
||||
Evt_Inst_Queue_t *inst_queue;
|
||||
Evt_Node_Queue_t *node_queue;
|
||||
Evt_Output_Queue_t *output_queue;
|
||||
|
||||
Evt_Inst_Event_t *inst_event;
|
||||
Evt_Output_Event_t *output_event;
|
||||
|
||||
void *ptr;
|
||||
|
||||
/* ************************ */
|
||||
/* Clear the instance queue */
|
||||
/* ************************ */
|
||||
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
inst_queue = &(ckt->evt->queue.inst);
|
||||
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_event = inst_queue->head[i];
|
||||
while(inst_event) {
|
||||
ptr = inst_event;
|
||||
inst_event = inst_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
inst_event = inst_queue->free[i];
|
||||
while(inst_event) {
|
||||
ptr = inst_event;
|
||||
inst_event = inst_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
inst_queue->head[i] = NULL;
|
||||
inst_queue->current[i] = &(inst_queue->head[i]);
|
||||
inst_queue->last_step[i] = &(inst_queue->head[i]);
|
||||
inst_queue->free[i] = NULL;
|
||||
}
|
||||
|
||||
inst_queue->next_time = 0.0;
|
||||
inst_queue->last_time = 0.0;
|
||||
|
||||
inst_queue->num_modified = 0;
|
||||
inst_queue->num_pending = 0;
|
||||
inst_queue->num_to_call = 0;
|
||||
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
inst_queue->modified[i] = MIF_FALSE;
|
||||
inst_queue->pending[i] = MIF_FALSE;
|
||||
inst_queue->to_call[i] = MIF_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* ******************** */
|
||||
/* Clear the node queue */
|
||||
/* ******************** */
|
||||
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
node_queue = &(ckt->evt->queue.node);
|
||||
|
||||
node_queue->num_changed = 0;
|
||||
node_queue->num_to_eval = 0;
|
||||
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
node_queue->changed[i] = MIF_FALSE;
|
||||
node_queue->to_eval[i] = MIF_FALSE;
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
/* Clear the output queue */
|
||||
/* ********************** */
|
||||
|
||||
num_outputs = ckt->evt->counts.num_outputs;
|
||||
output_queue = &(ckt->evt->queue.output);
|
||||
|
||||
for(i = 0; i < num_outputs; i++) {
|
||||
output_event = output_queue->head[i];
|
||||
while(output_event) {
|
||||
ptr = output_event;
|
||||
output_event = output_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
output_event = output_queue->free[i];
|
||||
while(output_event) {
|
||||
ptr = output_event;
|
||||
output_event = output_event->next;
|
||||
FREE(ptr);
|
||||
}
|
||||
output_queue->head[i] = NULL;
|
||||
output_queue->current[i] = &(output_queue->head[i]);
|
||||
output_queue->last_step[i] = &(output_queue->head[i]);
|
||||
output_queue->free[i] = NULL;
|
||||
}
|
||||
|
||||
output_queue->next_time = 0.0;
|
||||
output_queue->last_time = 0.0;
|
||||
|
||||
output_queue->num_modified = 0;
|
||||
output_queue->num_pending = 0;
|
||||
output_queue->num_changed = 0;
|
||||
|
||||
for(i = 0; i < num_outputs; i++) {
|
||||
output_queue->modified[i] = MIF_FALSE;
|
||||
output_queue->pending[i] = MIF_FALSE;
|
||||
output_queue->changed[i] = MIF_FALSE;
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_data
|
||||
|
||||
This function sets up the event-driven node, state, and
|
||||
message data runtime structures in preparation for
|
||||
a new simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_data(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
Evt_Data_t *data;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
int num_insts;
|
||||
int num_ports;
|
||||
int num_nodes;
|
||||
|
||||
int udn_index;
|
||||
int num_outputs;
|
||||
|
||||
Mif_Boolean_t invert;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
Evt_State_Data_t *state_data;
|
||||
Evt_Msg_Data_t *msg_data;
|
||||
/* Evt_Statistic_t *statistics_data;*/
|
||||
|
||||
Evt_Node_t *rhs;
|
||||
Evt_Node_t *rhsold;
|
||||
|
||||
Evt_Node_Info_t *node_info;
|
||||
|
||||
|
||||
/* Allocate main substructures of data */
|
||||
/* Note that we don't free any old structures */
|
||||
/* since they are pointed to by jobs and need */
|
||||
/* to be maintained so that results from multiple */
|
||||
/* jobs are kept around like SPICE does */
|
||||
|
||||
data = &(ckt->evt->data);
|
||||
CKALLOC(data->node, 1, Evt_Node_Data_t)
|
||||
CKALLOC(data->state, 1, Evt_State_Data_t)
|
||||
CKALLOC(data->msg, 1, Evt_Msg_Data_t)
|
||||
CKALLOC(data->statistics, 1, Evt_Statistic_t)
|
||||
|
||||
/* Allocate node data */
|
||||
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
node_data = data->node;
|
||||
|
||||
CKALLOC(node_data->head, num_nodes, void *)
|
||||
CKALLOC(node_data->tail, num_nodes, void *)
|
||||
CKALLOC(node_data->last_step, num_nodes, void *)
|
||||
CKALLOC(node_data->free, num_nodes, void *)
|
||||
CKALLOC(node_data->modified_index, num_nodes, int)
|
||||
CKALLOC(node_data->modified, num_nodes, Mif_Boolean_t)
|
||||
CKALLOC(node_data->rhs, num_nodes, Evt_Node_t)
|
||||
CKALLOC(node_data->rhsold, num_nodes, Evt_Node_t)
|
||||
CKALLOC(node_data->total_load, num_nodes, double)
|
||||
|
||||
/* Initialize the node data */
|
||||
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
node_data->tail[i] = &(node_data->head[i]);
|
||||
node_data->last_step[i] = &(node_data->head[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
|
||||
/* Get pointers to rhs & rhsold, the user-defined node type index, */
|
||||
/* the number of outputs on the node and the invert flag */
|
||||
rhs = &(node_data->rhs[i]);
|
||||
rhsold = &(node_data->rhsold[i]);
|
||||
node_info = ckt->evt->info.node_table[i];
|
||||
udn_index = node_info->udn_index;
|
||||
num_outputs = node_info->num_outputs;
|
||||
invert = node_info->invert;
|
||||
|
||||
/* Initialize the elements within rhs and rhsold */
|
||||
rhs->step = 0.0;
|
||||
rhsold->step = 0.0;
|
||||
if(num_outputs > 1) {
|
||||
CKALLOC(rhs->output_value, num_outputs, void *)
|
||||
CKALLOC(rhsold->output_value, num_outputs, void *)
|
||||
for(j = 0; j < num_outputs; j++) {
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhs->output_value[j]));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhs->output_value[j]);
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhsold->output_value[j]));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhsold->output_value[j]);
|
||||
}
|
||||
}
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhs->node_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhs->node_value);
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhsold->node_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhsold->node_value);
|
||||
if(invert) {
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhs->inverted_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhs->inverted_value);
|
||||
(*(g_evt_udn_info[udn_index]->create)) (&(rhsold->inverted_value));
|
||||
(*(g_evt_udn_info[udn_index]->initialize)) (rhsold->inverted_value);
|
||||
}
|
||||
|
||||
/* Initialize the total load value to zero */
|
||||
node_data->total_load[i] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate and initialize state data */
|
||||
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
state_data = data->state;
|
||||
|
||||
CKALLOC(state_data->head, num_insts, void *)
|
||||
CKALLOC(state_data->tail, num_insts, void *)
|
||||
CKALLOC(state_data->last_step, num_insts, void *)
|
||||
CKALLOC(state_data->free, num_insts, void *)
|
||||
CKALLOC(state_data->modified_index, num_insts, int)
|
||||
CKALLOC(state_data->modified, num_insts, Mif_Boolean_t)
|
||||
CKALLOC(state_data->total_size, num_insts, int)
|
||||
CKALLOC(state_data->desc, num_insts, void *)
|
||||
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
state_data->tail[i] = &(state_data->head[i]);
|
||||
state_data->last_step[i] = &(state_data->head[i]);
|
||||
}
|
||||
|
||||
|
||||
/* Allocate and initialize msg data */
|
||||
|
||||
num_ports = ckt->evt->counts.num_ports;
|
||||
msg_data = data->msg;
|
||||
|
||||
CKALLOC(msg_data->head, num_ports, void *)
|
||||
CKALLOC(msg_data->tail, num_ports, void *)
|
||||
CKALLOC(msg_data->last_step, num_ports, void *)
|
||||
CKALLOC(msg_data->free, num_ports, void *)
|
||||
CKALLOC(msg_data->modified_index, num_ports, int)
|
||||
CKALLOC(msg_data->modified, num_ports, Mif_Boolean_t)
|
||||
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
msg_data->tail[i] = &(msg_data->head[i]);
|
||||
msg_data->last_step[i] = &(msg_data->head[i]);
|
||||
}
|
||||
|
||||
/* Don't need to initialize statistics since they were */
|
||||
/* calloc'ed above */
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_jobs
|
||||
|
||||
This function prepares the jobs data for a new simulation.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_jobs(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int num_jobs;
|
||||
|
||||
Evt_Job_t *jobs;
|
||||
Evt_Data_t *data;
|
||||
|
||||
|
||||
jobs = &(ckt->evt->jobs);
|
||||
data = &(ckt->evt->data);
|
||||
|
||||
/* Increment the number of jobs */
|
||||
num_jobs = ++(jobs->num_jobs);
|
||||
|
||||
/* Allocate/reallocate necessary pointers */
|
||||
CKREALLOC(jobs->job_name, num_jobs, void *)
|
||||
CKREALLOC(jobs->node_data, num_jobs, void *)
|
||||
CKREALLOC(jobs->state_data, num_jobs, void *)
|
||||
CKREALLOC(jobs->msg_data, num_jobs, void *)
|
||||
CKREALLOC(jobs->statistics, num_jobs, void *)
|
||||
|
||||
/* Fill in the pointers, etc. for this new job */
|
||||
i = num_jobs - 1;
|
||||
jobs->job_name[i] = MIFcopy((char *) ckt->CKTcurJob->JOBname);
|
||||
jobs->node_data[i] = data->node;
|
||||
jobs->state_data[i] = data->state;
|
||||
jobs->msg_data[i] = data->msg;
|
||||
jobs->statistics[i] = data->statistics;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsetup_load_ptrs
|
||||
|
||||
This function setups up the required data in the MIFinstance
|
||||
structure of event-driven and hybrid instances.
|
||||
*/
|
||||
|
||||
|
||||
static int EVTsetup_load_ptrs(
|
||||
CKTcircuit *ckt) /* The circuit structure */
|
||||
{
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
|
||||
int num_insts;
|
||||
int num_conn;
|
||||
int num_port;
|
||||
int num_outputs;
|
||||
|
||||
int node_index;
|
||||
int output_subindex;
|
||||
|
||||
MIFinstance *fast;
|
||||
|
||||
Mif_Conn_Data_t *conn;
|
||||
|
||||
Mif_Port_Type_t type;
|
||||
Mif_Port_Data_t *port;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
|
||||
/* This function setups up the required data in the MIFinstance */
|
||||
/* structure of event-driven and hybrid instances */
|
||||
|
||||
/* Loop through all event-driven and hybrid instances */
|
||||
num_insts = ckt->evt->counts.num_insts;
|
||||
for(i = 0; i < num_insts; i++) {
|
||||
|
||||
/* Get the MIFinstance pointer */
|
||||
fast = ckt->evt->info.inst_table[i]->inst_ptr;
|
||||
|
||||
/* Loop through all connections */
|
||||
num_conn = fast->num_conn;
|
||||
for(j = 0; j < num_conn; j++) {
|
||||
|
||||
/* Skip if connection is null */
|
||||
if(fast->conn[j]->is_null)
|
||||
continue;
|
||||
|
||||
conn = fast->conn[j];
|
||||
|
||||
/* Loop through all ports */
|
||||
num_port = conn->size;
|
||||
for(k = 0; k < num_port; k++) {
|
||||
|
||||
/* Get port data pointer for quick access */
|
||||
port = conn->port[k];
|
||||
|
||||
if(port->is_null)
|
||||
continue;
|
||||
|
||||
/* Skip if port is not digital or user-defined type */
|
||||
type = port->type;
|
||||
if((type != MIF_DIGITAL) && (type != MIF_USER_DEFINED))
|
||||
continue;
|
||||
|
||||
/* Set input.pvalue to point to rhsold.node_value or to */
|
||||
/* rhsold.inverted_value as appropriate */
|
||||
node_index = port->evt_data.node_index;
|
||||
node_data = ckt->evt->data.node;
|
||||
if(conn->is_input) {
|
||||
if(port->invert) {
|
||||
port->input.pvalue = node_data->rhsold[node_index].
|
||||
inverted_value;
|
||||
}
|
||||
else {
|
||||
port->input.pvalue = node_data->rhsold[node_index].
|
||||
node_value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set output.pvalue to point to rhs.node_value or rhs.output_value[i] */
|
||||
/* where i is given by the output_subindex in output info */
|
||||
/* depending on whether more than one output is connected to the node. */
|
||||
/* Note that this is only for the DCOP analysis. During a transient */
|
||||
/* analysis, new structures will be created and the pointers will */
|
||||
/* be set by EVTload */
|
||||
if(conn->is_output) {
|
||||
num_outputs = ckt->evt->info.node_table[node_index]->num_outputs;
|
||||
if(num_outputs <= 1) {
|
||||
port->output.pvalue = node_data->rhs[node_index].
|
||||
node_value;
|
||||
}
|
||||
else {
|
||||
output_subindex = port->evt_data.output_subindex;
|
||||
port->output.pvalue = node_data->rhs[node_index].
|
||||
output_value[output_subindex];
|
||||
}
|
||||
}
|
||||
|
||||
} /* end for number of ports */
|
||||
} /* end for number of connections */
|
||||
} /* end for number of insts */
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -0,0 +1,512 @@
|
|||
/*============================================================================
|
||||
FILE EVTtermInsert.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Copyright 1991
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
All Rights Reserved
|
||||
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
This file contains function EVTtermInsert which is called by
|
||||
MIF_INP2A during the parsing of the input deck. EVTtermInsert is
|
||||
similar to SPICE3's INPtermInsert except that it is used when the node
|
||||
type is event-driven. Calls to this function build the info lists
|
||||
for instances, nodes, outputs, and ports. The completion of the info
|
||||
struct is carried out by EVTinit following the parsing of all
|
||||
instances in the deck.
|
||||
|
||||
INTERFACES
|
||||
|
||||
void EVTtermInsert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
char *node_name,
|
||||
char *type_name,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
char **err_msg)
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "ngspice.h"
|
||||
//#include "misc.h"
|
||||
|
||||
#include "cktdefs.h"
|
||||
//#include "util.h"
|
||||
|
||||
#include "mif.h"
|
||||
#include "evt.h"
|
||||
#include "evtudn.h"
|
||||
|
||||
#include "mifproto.h"
|
||||
#include "evtproto.h"
|
||||
|
||||
|
||||
static void EVTinst_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int *inst_index,
|
||||
char **err_msg);
|
||||
|
||||
static void EVTnode_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int inst_index,
|
||||
char *node_name,
|
||||
char *type_name,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
int *node_index,
|
||||
int *output_subindex,
|
||||
char **err_msg);
|
||||
|
||||
static void EVTport_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int inst_index,
|
||||
int node_index,
|
||||
char *node_name,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
int *port_index,
|
||||
char **err_msg);
|
||||
|
||||
static void EVToutput_insert(
|
||||
CKTcircuit *ckt,
|
||||
MIFinstance *fast,
|
||||
int inst_index,
|
||||
int node_index,
|
||||
int port_index,
|
||||
int output_subindex,
|
||||
int conn_num,
|
||||
int port_num,
|
||||
char **err_msg);
|
||||
|
||||
|
||||
/*
|
||||
EVTtermInsert
|
||||
|
||||
This function is called by MIF_INP2A during the parsing of the input
|
||||
deck. EVTtermInsert is similar to 3C1's INPtermInsert except that it is
|
||||
used when the node type is event-driven. Calls to this function build
|
||||
the info lists for instances, nodes, outputs, and ports. The
|
||||
completion of the info struct is carried out by EVTinit following
|
||||
the parsing of all instances in the deck.
|
||||
*/
|
||||
|
||||
|
||||
void EVTtermInsert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
char *node_name, /* The node name */
|
||||
char *type_name, /* The type of node */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 for scalar ports */
|
||||
char **err_msg) /* Returned error message if any */
|
||||
{
|
||||
|
||||
int inst_index;
|
||||
int node_index;
|
||||
int port_index;
|
||||
|
||||
int output_subindex;
|
||||
|
||||
|
||||
/* Get the instance index and create new entry in inst */
|
||||
/* info list if this is a new instance. */
|
||||
EVTinst_insert(ckt, fast, &inst_index, err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
|
||||
/* Get the node index and create new entry in node info */
|
||||
/* list if this is a new node */
|
||||
EVTnode_insert(ckt, fast, inst_index, node_name, type_name,
|
||||
conn_num, port_num, &node_index, &output_subindex,
|
||||
err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
|
||||
/* Create new entry in port info list and return port index */
|
||||
EVTport_insert(ckt, fast, inst_index, node_index, node_name, conn_num,
|
||||
port_num, &port_index, err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
|
||||
/* Create new entry in output info list if appropriate */
|
||||
if(fast->conn[conn_num]->is_output) {
|
||||
EVToutput_insert(ckt, fast, inst_index, node_index, port_index,
|
||||
output_subindex, conn_num, port_num, err_msg);
|
||||
if(*err_msg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTinst_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
instance in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTinst_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int *inst_index, /* The index found or added */
|
||||
char **err_msg) /* Error message if any */
|
||||
{
|
||||
|
||||
Mif_Boolean_t found;
|
||||
int index;
|
||||
|
||||
Evt_Inst_Info_t *inst;
|
||||
Evt_Inst_Info_t **inst_ptr;
|
||||
|
||||
|
||||
/* Scan list of instances in event structure to see if already there */
|
||||
/* and get the index */
|
||||
found = MIF_FALSE;
|
||||
index = 0;
|
||||
inst = ckt->evt->info.inst_list;
|
||||
inst_ptr = &(ckt->evt->info.inst_list);
|
||||
|
||||
while(inst) {
|
||||
if(inst->inst_ptr == fast) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
inst_ptr = &(inst->next);
|
||||
inst = inst->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If not found, create a new entry in list and increment the */
|
||||
/* instance count in the event structure */
|
||||
if(! found) {
|
||||
*inst_ptr = (void *) MALLOC(sizeof(Evt_Inst_Info_t));
|
||||
inst = *inst_ptr;
|
||||
inst->next = NULL;
|
||||
inst->inst_ptr = fast;
|
||||
index = ckt->evt->counts.num_insts;
|
||||
(ckt->evt->counts.num_insts)++;
|
||||
}
|
||||
|
||||
/* Record the inst index in the MIFinstance structure and return it */
|
||||
fast->inst_index = index;
|
||||
*inst_index = index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTnode_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
node in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTnode_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int inst_index, /* The index of inst in evt structures */
|
||||
char *node_name, /* The node name */
|
||||
char *type_name, /* The node type specified */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 if scalar port */
|
||||
int *node_index, /* The node index found or added */
|
||||
int *output_subindex, /* The output number on this node */
|
||||
char **err_msg) /* Error message text if any */
|
||||
{
|
||||
|
||||
int i;
|
||||
int udn_index=0;
|
||||
Mif_Boolean_t found;
|
||||
|
||||
int index;
|
||||
|
||||
Evt_Node_Info_t *node;
|
||||
Evt_Node_Info_t **node_ptr;
|
||||
|
||||
Evt_Inst_Index_t *inst;
|
||||
Evt_Inst_Index_t **inst_ptr;
|
||||
|
||||
|
||||
/* *************************************** */
|
||||
/* Get and check the node type information */
|
||||
/* *************************************** */
|
||||
|
||||
/* Scan the list of user-defined node types and get the index */
|
||||
found = MIF_FALSE;
|
||||
for(i = 0; i < g_evt_num_udn_types; i++) {
|
||||
if(strcmp(type_name, g_evt_udn_info[i]->name) == 0) {
|
||||
udn_index = i;
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report error if not recognized */
|
||||
if(! found) {
|
||||
*err_msg = "Unrecognized connection type";
|
||||
return;
|
||||
}
|
||||
|
||||
/* If inverted, check to be sure invert function exists for type */
|
||||
if(fast->conn[conn_num]->port[port_num]->invert) {
|
||||
if(g_evt_udn_info[udn_index]->invert == NULL) {
|
||||
*err_msg = "Connection type cannot be inverted";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************* */
|
||||
/* Find/create entry in event-driven node list */
|
||||
/* ******************************************* */
|
||||
|
||||
/* Scan list of nodes in event structure to see if already there */
|
||||
/* and get the index */
|
||||
found = MIF_FALSE;
|
||||
index = 0;
|
||||
node = ckt->evt->info.node_list;
|
||||
node_ptr = &(ckt->evt->info.node_list);
|
||||
|
||||
while(node) {
|
||||
if(strcmp(node_name, node->name) == 0) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
node_ptr = &(node->next);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If found, verify that connection type is same as type of node */
|
||||
if(found) {
|
||||
if(udn_index != node->udn_index) {
|
||||
*err_msg = "Node cannot have two different types";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found, create a new entry in list and increment the */
|
||||
/* node count in the event structure */
|
||||
if(! found) {
|
||||
*node_ptr = (void *) MALLOC(sizeof(Evt_Node_Info_t));
|
||||
node = *node_ptr;
|
||||
node->next = NULL;
|
||||
node->name = MIFcopy(node_name);
|
||||
node->udn_index = udn_index;
|
||||
index = ckt->evt->counts.num_nodes;
|
||||
(ckt->evt->counts.num_nodes)++;
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************* */
|
||||
/* Update remaining items in node list struct */
|
||||
/* ******************************************* */
|
||||
|
||||
/* Update flag on node that indicates if inversion is used by any */
|
||||
/* instance inputs */
|
||||
if(fast->conn[conn_num]->is_input)
|
||||
if(! node->invert)
|
||||
node->invert = fast->conn[conn_num]->port[port_num]->invert;
|
||||
|
||||
/* Increment counts of ports, outputs connected to node */
|
||||
(node->num_ports)++;
|
||||
if(fast->conn[conn_num]->is_output)
|
||||
(node->num_outputs)++;
|
||||
|
||||
/* If this is an input, add instance to list if not already there */
|
||||
if(fast->conn[conn_num]->is_input) {
|
||||
|
||||
found = MIF_FALSE;
|
||||
inst = node->inst_list;
|
||||
inst_ptr = &(node->inst_list);
|
||||
|
||||
while(inst) {
|
||||
if(inst_index == inst->index) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
inst_ptr = &(inst->next);
|
||||
inst = inst->next;
|
||||
}
|
||||
}
|
||||
|
||||
if(! found) {
|
||||
(node->num_insts)++;
|
||||
*inst_ptr = (void *) MALLOC(sizeof(Evt_Inst_Index_t));
|
||||
inst = *inst_ptr;
|
||||
inst->next = NULL;
|
||||
inst->index = inst_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the node index in the MIFinstance structure */
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.node_index = index;
|
||||
|
||||
/* Return the node index */
|
||||
*node_index = index;
|
||||
if(fast->conn[conn_num]->is_output)
|
||||
*output_subindex = node->num_outputs - 1;
|
||||
else
|
||||
*output_subindex = 0; /* just for safety - shouldn't need this */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTport_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
port in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTport_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int inst_index, /* The index of inst in evt structures */
|
||||
int node_index, /* The index of the node in evt structures */
|
||||
char *node_name, /* The node name */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 if scalar port */
|
||||
int *port_index, /* The port index found or added */
|
||||
char **err_msg) /* Error message text if any */
|
||||
{
|
||||
|
||||
Evt_Port_Info_t *port;
|
||||
Evt_Port_Info_t **port_ptr;
|
||||
|
||||
int index;
|
||||
|
||||
/* Find the end of the port info list */
|
||||
port = ckt->evt->info.port_list;
|
||||
port_ptr = &(ckt->evt->info.port_list);
|
||||
|
||||
index = 0;
|
||||
while(port) {
|
||||
port_ptr = &(port->next);
|
||||
port = port->next;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
||||
/* Update the port count and create a new entry in the list */
|
||||
|
||||
(ckt->evt->counts.num_ports)++;
|
||||
|
||||
*port_ptr = (void *) MALLOC(sizeof(Evt_Port_Info_t));
|
||||
port = *port_ptr;
|
||||
|
||||
/* Fill in the elements */
|
||||
port->next = NULL;
|
||||
port->inst_index = inst_index;
|
||||
port->node_index = node_index;
|
||||
port->node_name = MIFcopy(node_name);
|
||||
port->inst_name = MIFcopy((char *) fast->MIFname);
|
||||
port->conn_name = MIFcopy((char *) fast->conn[conn_num]->name);
|
||||
port->port_num = port_num;
|
||||
|
||||
/* Record the port index in the MIFinstance structure */
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.port_index = index;
|
||||
|
||||
/* Return the port index */
|
||||
*port_index = index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVToutput_insert
|
||||
|
||||
This function locates or creates a new entry for the specified
|
||||
output in the event-driven ``info'' structures during parsing.
|
||||
*/
|
||||
|
||||
|
||||
static void EVToutput_insert(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
MIFinstance *fast, /* The instance being parsed */
|
||||
int inst_index, /* The index of inst in evt structures */
|
||||
int node_index, /* The index of the node in evt structures */
|
||||
int port_index, /* The index of the port in the evt structures */
|
||||
int output_subindex, /* The output on this node */
|
||||
int conn_num, /* The port connection number */
|
||||
int port_num, /* The sub-port number - 0 if scalar port */
|
||||
char **err_msg) /* Error message text if any */
|
||||
{
|
||||
Evt_Output_Info_t *output;
|
||||
Evt_Output_Info_t **output_ptr;
|
||||
|
||||
int index;
|
||||
|
||||
/* Find the end of the port info list */
|
||||
output = ckt->evt->info.output_list;
|
||||
output_ptr = &(ckt->evt->info.output_list);
|
||||
|
||||
index = 0;
|
||||
while(output) {
|
||||
output_ptr = &(output->next);
|
||||
output = output->next;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
||||
/* Update the port count and create a new entry in the list */
|
||||
|
||||
(ckt->evt->counts.num_outputs)++;
|
||||
|
||||
*output_ptr = (void *) MALLOC(sizeof(Evt_Output_Info_t));
|
||||
output = *output_ptr;
|
||||
|
||||
/* Fill in the elements */
|
||||
output->next = NULL;
|
||||
output->inst_index = inst_index;
|
||||
output->node_index = node_index;
|
||||
output->port_index = port_index;
|
||||
output->output_subindex = output_subindex;
|
||||
|
||||
/* Record the output index and subindex in the MIFinstance structure */
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.output_index = index;
|
||||
fast->conn[conn_num]->port[port_num]->evt_data.output_subindex
|
||||
= output_subindex;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
Code Model Test - AC: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.ac dec 10 10 1000
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
v2 2 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
v3 3 0 DC 2.0
|
||||
*
|
||||
v4 4 0 0.5 AC 0.5 0.0
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 3] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 1 3 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=1.0e-10 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 4 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[-1.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
r4 4 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
Code Model Test - DC: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 1] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=0.1 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 2 1 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=1.0e-10 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 1 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[ 0.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
Code Model Test - Swept DC: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.dc v1 .1 10 .1
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 1] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=0.1 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 2 1 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=1.0e-10 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 1 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[ 0.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
Code Model Test - Transient: gain, summer, mult, divide, pwl
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.tran .1s 10s
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 DC PWL(0 0 10 10)
|
||||
*
|
||||
v2 2 0 DC 2
|
||||
*
|
||||
*** gain block ***
|
||||
a1 1 10 gain1
|
||||
.model gain1 gain (in_offset=0.0 gain=2.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** summer block ***
|
||||
a2 [1 2] 20 summer1
|
||||
.model summer1 summer (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** mult block ***
|
||||
a3 [1 1] 30 mult1
|
||||
.model mult1 mult (in_offset=[0.0 0.0] in_gain=[1.0 1.0]
|
||||
+ out_gain=0.1 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** divider block ***
|
||||
a4 2 1 40 divide1
|
||||
.model divide1 divide (num_offset=0.0 num_gain=1.0 den_offset=0.0 den_gain=1.0
|
||||
+ den_lower_limit=0.1 den_domain=1.0e-16
|
||||
+ fraction=false out_gain=1.0 out_offset=0.0)
|
||||
*
|
||||
*
|
||||
*** pwl block ***
|
||||
a5 1 50 pwl1
|
||||
.model pwl1 pwl (x_array=[-1.0 0.0 1.0 2.0 3.0 4.0 5.0]
|
||||
+ y_array=[ 0.0 0.0 1.0 4.0 4.5 5.0 5.0]
|
||||
+ input_domain=0.01 fraction=TRUE)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
r2 2 0 1k
|
||||
r3 3 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
Code Model Test - Swept DC: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.ac dec 10 10 1000
|
||||
*
|
||||
*
|
||||
*** input sources ***
|
||||
*
|
||||
v1 1 0 1.0 AC 1.0 0.0
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 1 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.414214 1.0] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=628.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
v40 45 46 0.0
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 46) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
*
|
||||
r10 10 0 1e12
|
||||
r20 20 0 1e12
|
||||
r30 30 0 1e12
|
||||
r40 40 0 1e12
|
||||
r45 45 0 1e12
|
||||
r50 50 0 1e12
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
Code Model Test - DC: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.op
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 1.0
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 1 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.425625 1.516203] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=6283.2)
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 45) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
*
|
||||
r10 10 0 1k
|
||||
r20 20 0 1k
|
||||
r30 30 0 1k
|
||||
r40 40 0 1k
|
||||
r50 50 0 1k
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
Code Model Test - Swept DC: int, d_dt, s_xfer, core, lcouple
|
||||
*
|
||||
*
|
||||
*** analysis type ***
|
||||
.dc v1 .1 10 .5
|
||||
*
|
||||
*** input sources ***
|
||||
v1 1 0 DC 2
|
||||
*
|
||||
*
|
||||
*** integrator block ***
|
||||
a1 1 10 int1
|
||||
.model int1 int (in_offset=0.0 gain=2.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6 out_ic=0.0)
|
||||
*
|
||||
*
|
||||
*** differentiator block ***
|
||||
a2 1 20 d_dt1
|
||||
.model d_dt1 d_dt (out_offset=0.0 gain=1.0 out_lower_limit=-1.0e6
|
||||
+ out_upper_limit=1.0e6 limit_range=1.0e-6)
|
||||
*
|
||||
*
|
||||
*** s_xfer block ***
|
||||
a3 1 30 filter1
|
||||
.model filter1 s_xfer (in_offset=0.0 gain=1.0 num_coeff=[1.0]
|
||||
+ den_coeff=[1.0 1.414214 1.0] int_ic=[0.0 0.0]
|
||||
+ denormalized_freq=1.0)
|
||||
*
|
||||
*
|
||||
*
|
||||
*** magnetic core & inductive coupling ***
|
||||
v40 45 46 0.0
|
||||
a4 40 45 core1
|
||||
.model core1 core (H_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ B_array=[-2.0 -1.0 1.0 2.0]
|
||||
+ area=1.0 length=1.0 input_domain=1.0e-6
|
||||
+ fraction=TRUE mode=1
|
||||
+ in_low=-1.0 in_high=1.0 hyst=0.5
|
||||
+ out_lower_limit=-1.0 out_upper_limit=1.0)
|
||||
*
|
||||
*
|
||||
r5 1 50 100.0
|
||||
a5 (50 0) (40 46) inductor1
|
||||
.model inductor1 lcouple (num_turns=10)
|
||||
*
|
||||
*
|
||||
*** resistors to ground ***
|
||||
r1 1 0 1k
|
||||
*
|
||||
r10 10 0 1e12
|
||||
r20 20 0 1e12
|
||||
r30 30 0 1e12
|
||||
r40 40 0 1e12
|
||||
r45 45 0 1e12
|
||||
r50 50 0 1e12
|
||||
*
|
||||
*
|
||||
.end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue