diff --git a/src/xspice/icm/analog/delay/cfunc.mod b/src/xspice/icm/analog/delay/cfunc.mod new file mode 100644 index 000000000..4a51cd234 --- /dev/null +++ b/src/xspice/icm/analog/delay/cfunc.mod @@ -0,0 +1,344 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE delay/cfunc.mod + +3-clause BSD + +Copyright 2021 +The ngspice team + +AUTHORS + + 21 May 2021 Holger Vogt + + +MODIFICATIONS + + + +SUMMARY + + This file contains the functional description of the analog + delay code model. + + +INTERFACES + + FILE ROUTINE CALLED + + CMutil.c void cm_smooth_corner(); + + CM.c void *cm_analog_alloc() + void *cm_analog_get_ptr() + int cm_analog_integrate() + cm_delay_callback() + + + +REFERENCED FILES + + Inputs from and outputs to ARGS structure. + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ + +/*=== INCLUDE FILES ====================*/ + +#include + + +/*=== CONSTANTS ========================*/ + + + + +/*=== MACROS ===========================*/ + + + + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +typedef struct { + + double *buffer; /* the storage array for input values */ + int buffer_size; /* size of buffer */ + int buff_write; /* buffer write index */ + int buff_del; /* buffer index, delayed */ + int step_count; /* steps processed */ + double tdelmin; /* min delay, if controlled */ + double tdelmax; /* max delay, if controlled */ + double tdelay; /* time delay */ + double tstep; /* tran step size */ + double tstop; /* tran stop value */ + double tprev; /* previous time value */ + double prev_val; /* previous data value */ + double start_val; /* signal time 0 value */ +} mLocal_Data_t; + + +struct CKTcircuitmin { + +/* This is a minimum re-definition of the circuit structure defined in + cktdefs.h. We are interested in TSTEP and TSTOP */ + + GENmodel **CKThead; + STATistics *CKTstat; /* The STATistics structure */ + double *CKTstates[8]; /* Used as memory of past steps ??? */ + double CKTtime; /* Current transient simulation time */ + double CKTdelta; /* next time step in transient simulation */ + double CKTdeltaOld[7]; /* Memory for the 7 most recent CKTdelta */ + double CKTtemp; /* Actual temperature of CKT, initialzed to 300.15 K in cktinit.c*/ + double CKTnomTemp; /* Reference temperature 300.15 K set in cktinit.c */ + double CKTvt; /* Thernmal voltage at CKTtemp */ + double CKTag[7]; /* the gear variable coefficient matrix */ +#ifdef PREDICTOR + double CKTagp[7]; /* the gear predictor variable coefficient matrix */ +#endif /*PREDICTOR*/ + int CKTorder; /* the integration method order */ + int CKTmaxOrder; /* maximum integration method order */ + int CKTintegrateMethod; /* the integration method to be used */ + double CKTxmu; /* for trapezoidal method */ + int CKTindverbosity; /* control check of inductive couplings */ + SMPmatrix *CKTmatrix; /* pointer to sparse matrix */ + int CKTniState; /* internal state */ + double *CKTrhs; /* current rhs value - being loaded */ + double *CKTrhsOld; /* previous rhs value for convergence testing */ + double *CKTrhsSpare; /* spare rhs value for reordering */ + double *CKTirhs; /* current rhs value - being loaded imag) */ + double *CKTirhsOld; /* previous rhs value (imaginary)*/ + double *CKTirhsSpare; /* spare rhs value (imaginary)*/ +#ifdef PREDICTOR + double *CKTpred; /* predicted solution vector */ + double *CKTsols[8]; /* previous 8 solutions */ +#endif /* PREDICTOR */ + double *CKTrhsOp; /* opearating point values */ + double *CKTsenRhs; /* current sensitivity rhs values */ + double *CKTseniRhs; /* current sensitivity rhs values (imag)*/ + int CKTmaxEqNum; /* And this ? */ + int CKTcurrentAnalysis; /* the analysis in progress (if any) */ + CKTnode *CKTnodes; /* ??? */ + CKTnode *CKTlastNode; /* ??? */ + CKTnode *prev_CKTlastNode; /* just before model setup */ + int CKTnumStates; /* Number of sates effectively valid ??? */ + long CKTmode; /* Mode of operation of the circuit ??? */ + int CKTbypass; /* bypass option, how does it work ? */ + int CKTdcMaxIter; /* iteration limit for dc op. (itl1) */ + int CKTdcTrcvMaxIter; /* iteration limit for dc tran. curv (itl2) */ + int CKTtranMaxIter; /* iteration limit for each timepoint for tran*/ + int CKTbreakSize; /* ??? */ + int CKTbreak; /* ??? */ + double CKTsaveDelta; /* ??? */ + double CKTminBreak; /* ??? */ + double *CKTbreaks; /* List of breakpoints ??? */ + double CKTabstol; /* --- */ + double CKTpivotAbsTol; /* --- */ + double CKTpivotRelTol; /* --- */ + double CKTreltol; /* --- */ + double CKTchgtol; /* --- */ + double CKTvoltTol; /* --- */ + /* What is this define for ? */ +#ifdef NEWTRUNC + double CKTlteReltol; + double CKTlteAbstol; +#endif /* NEWTRUNC */ + double CKTgmin; /* .options GMIN */ + double CKTgshunt; /* .options RSHUNT */ + double CKTcshunt; /* .options CSHUNT */ + double CKTdelmin; /* minimum time step for tran analysis */ + double CKTtrtol; /* .options TRTOL */ + double CKTfinalTime; /* TSTOP */ + double CKTstep; /* TSTEP */ + double CKTmaxStep; /* TMAX */ + double CKTinitTime; /* TSTART */ + /* struct is truncated here */ +}; + +typedef struct CKTcircuitmin CKTcircuitmin; + +/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ + +static void cm_delay_callback(ARGS, Mif_Callback_Reason_t reason); + +/*=== CM_DELAY ROUTINE ===*/ + +void cm_delay(ARGS) +{ + int buffer_size, delay_step; + double delay; + double delmin, delmax; + double *ins, *ins_old; + + mLocal_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector */ + CKTcircuitmin *ckt; + + + if (ANALYSIS != MIF_AC) { /**** only Transient Analysis and dc ****/ + + /** INIT: allocate storage **/ + + if (INIT==1) { + + CALLBACK = cm_delay_callback; + + ckt = (CKTcircuitmin*)cm_get_circuit(); + + if (PARAM_NULL(buffer_size)) { + /* size depends on TSTOP/TSTEP, if no parameter given */ + buffer_size = (int) (ckt->CKTfinalTime / ckt->CKTstep) + 1; + } + else { + buffer_size = PARAM(buffer_size); + if (buffer_size < 0) { + cm_message_send("Negative buffer size is not allowed " + "in a delay code model"); + return; + } + } + + delay = PARAM(delay); + if (delay < 0.0) { + delay = 0.0; + } + + /*** allocate static storage for *loc ***/ + if ((loc = (mLocal_Data_t *) (STATIC_VAR(locdata) = calloc(1, + sizeof(mLocal_Data_t)))) == (mLocal_Data_t *) NULL) { + cm_message_send("Unable to allocate Local_Data_t " + "in cm_delay()"); + return; + } + /*** allocate static storage for the delay buffer ***/ + loc->buffer = (double *) calloc((size_t)buffer_size, sizeof(double)); + if (loc->buffer == (double *) NULL) { + cm_message_send("Unable to allocate delay buffer " + "in cm_delay()"); + return; + } + loc->buffer_size = buffer_size; + + cm_analog_alloc(TRUE,sizeof(double)); + ins = (double *) cm_analog_get_ptr(TRUE,0); /* Set out pointer to current + time storage */ + ins_old = (double *) cm_analog_get_ptr(TRUE,1); /* Set old-output-state pointer + to previous time storage */ + + *ins = *ins_old = loc->start_val = INPUT(in); + + /* The delay is controlled by input delay_cnt */ + if (PARAM(has_delay_cnt) == MIF_TRUE) { + if (PARAM_NULL(delmin)) + loc->tdelmin = 0.0; + else + loc->tdelmin = PARAM(delmin); + + if (PARAM_NULL(delmax)) + loc->tdelmax = ckt->CKTfinalTime; + else + loc->tdelmax = PARAM(delmax); + } + + loc->buff_write = 0; + loc->buff_del = 0; + loc->step_count = 0; + loc->tdelay = delay; + loc->tstop = ckt->CKTfinalTime; + loc->tstep = ckt->CKTstep; + loc->tprev = 0.0; + loc->prev_val = 0.0; + } + /* retrieve previous values */ + + loc = STATIC_VAR (locdata); + + ins = (double *) cm_analog_get_ptr(TRUE,0); /* Set out pointer to current + time storage */ + ins_old = (double *) cm_analog_get_ptr(TRUE,1); /* Set old-output-state pointer + to previous time storage */ + + delay = loc->tdelay; + if (delay == 0.0) { + OUTPUT(out) = INPUT(in); + return; + } + + if (TIME == 0.0) + loc->start_val = INPUT(in); + + /* input, simply interpolated to TSTEP */ + double tacct = loc->step_count * loc->tstep; + if (TIME >= tacct) { + double curr_in; +/* double tdiff = TIME - tacct; + // interpolate + if (tdiff > 0) { + curr_in = loc->prev_val + (INPUT(in) - loc->prev_val) / (TIME - loc->tprev) * tacct; + } + else*/ + curr_in = INPUT(in); + + loc->buffer[loc->buff_write] = *ins = curr_in; + /* next buffer location, circular, for writing */ + loc->buff_write = (loc->buff_write + 1) % loc->buffer_size; + loc->step_count++; + loc->tprev = tacct; + loc->prev_val = curr_in; + } + + delmin = loc->tdelmin; + delmax = loc->tdelmax; + + if (PARAM(has_delay_cnt) == MIF_TRUE) { + delay = (delmax - delmin) * INPUT(cntrl) + delmin; + } + + /* time not yet advanced for delay output */ + if (TIME < delay) { + OUTPUT(out) = loc->start_val; + } + else + OUTPUT(out) = loc->buffer[loc->buff_del]; + + /* delay in steps */ + delay_step = (int)(delay / loc->tstep); + /* FIXME: For whatever reason the model is assessed two times per time step */ + + /* next readout location, delayed after writing */ + if ((loc->buff_write - delay_step) >= 0) + loc->buff_del = loc->buff_write - delay_step; + else + loc->buff_del = loc->buff_write - delay_step + loc->buffer_size; + } + + else { /**** all others ****/ + OUTPUT(out) = INPUT(in); + } +} + +/* free the memory created locally */ +static void cm_delay_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: { + mLocal_Data_t *loc = (mLocal_Data_t *) STATIC_VAR(locdata); + if (loc == (mLocal_Data_t *) NULL) { + break; + } + + if (loc->buffer != (double *) NULL) { + free(loc->buffer); + } + + free(loc); + + STATIC_VAR(locdata) = NULL; + break; + } + } +} /* end of function cm_delay_callback */ diff --git a/src/xspice/icm/analog/delay/ifspec.ifs b/src/xspice/icm/analog/delay/ifspec.ifs new file mode 100644 index 000000000..e27d9ac9b --- /dev/null +++ b/src/xspice/icm/analog/delay/ifspec.ifs @@ -0,0 +1,81 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +------------------------------------------------------------------------- + Copyright 2011 Thomas Sailer + 3 - Clause BSD license + (see COPYING or https://opensource.org/licenses/BSD-3-Clause) +------------------------------------------------------------------------- + +AUTHORS + + 19 May 2011 Thomas Sailer + + +SUMMARY + + This file contains the interface specification file for the + delay code model. + +===============================================================================*/ + +NAME_TABLE: + +C_Function_Name: cm_delay +Spice_Model_Name: delay +Description: "analog delay line" + + +PORT_TABLE: + +Port_Name: in out cntrl +Description: "input" "output" "control" +Direction: in out in +Default_Type: v v v +Allowed_Types: [v,vd,vnam] [v,vd] [v,vd,i,id] +Vector: no no no +Vector_Bounds: - - - +Null_Allowed: no no yes + + +PARAMETER_TABLE: + +Parameter_Name: delay buffer_size +Description: "time delay" "size of delay buffer" +Data_Type: real int +Default_Value: 0.0 1024 +Limits: - [1 -] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: has_delay_cnt +Description: "controlled delay" +Data_Type: boolean +Default_Value: FALSE +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +PARAMETER_TABLE: + +Parameter_Name: delmin delmax +Description: "min delay" "max delay" +Data_Type: real real +Default_Value: 0 0 +Limits: [0 -] [0 -] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: locdata +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/analog/modpath.lst b/src/xspice/icm/analog/modpath.lst index d5555b2a4..834054af6 100644 --- a/src/xspice/icm/analog/modpath.lst +++ b/src/xspice/icm/analog/modpath.lst @@ -17,3 +17,4 @@ summer s_xfer triangle file_source +delay diff --git a/visualc/xspice/analog.vcxproj b/visualc/xspice/analog.vcxproj index 4bbc0fd19..0e0fa1fac 100644 --- a/visualc/xspice/analog.vcxproj +++ b/visualc/xspice/analog.vcxproj @@ -250,6 +250,8 @@ + + @@ -291,6 +293,8 @@ + +