XSPICE: fix double delta subtraction in dll mode
The problem is in XSPICE breakpoints handling and dll mode. When ngspice is built as dll, it delegates CKTtime - CKTdelta operation to the dll client using sharedsync call. Delta that needs to be subtracted is passed as an olddelta argument, and the client must subtract it if there are convergence issues. If the client does not add a callback for this operation, default implementation begins to work and substracts olddelta from CKTtime. The problem is in breakpoints. When an analog breakpoint is between the last accepted timepoint and CKTTime, then ngspice substracts CKTdelta from CKTtime and passes 0 as olddelta to sharedsync. It is ok. The problem is in XSPICE breakpoints. If XSPICE breakpoint is set between the last accepted timepoint and CKTtime, then ngspice substracts CKTdelta but pass non-zero olddelta to sharedsync. As a result, olddelta is subtracted twice, and CKTtime becomes less than the last accepted timepoint, which is incorrect. The solution is to inform sharedsync call that olddelta has already been subtracted from CKTtime during XSPICE breakpoint processing. olddelta can't be set to 0 during XSPICE breakpoint handling because it also takes part in the "timestep too small" check. That is why a new flag has been introduced. It should be reset during each iteration and set to 1 only when there are no convergence issues and there are breakpoints between the last accepted timepoint and CKTtime. If it is set, then DCtran knows that olddelta need to be set to zero. This issue has been fixed for SHARED_MODULE option only. Looks like CLUSTER feature also uses incorrect olddelta, and it has to take into account the XSPICE breakpoints flag. This problem has not been fixed because we can't properly test this case. WARNING: sharedsync is still broken if the library client decides to use a callback for step delta managing and discard a valid delta after the successful integration step. EVTBackup may drop valid points in this case. The rule of thumb: do not set GetSyncData callback in ngSpice_Init_Sync.
This commit is contained in:
parent
39b4f2733f
commit
c4470db441
|
|
@ -104,6 +104,23 @@ DCtran(CKTcircuit *ckt,
|
|||
double ipc_last_time = 0.0;
|
||||
double ipc_last_delta = 0.0;
|
||||
/* gtri - end - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
// It is introduced for sharedsync olddelta fix. When DCTran processes
|
||||
// either analog or XSPICE breakpoint, then it substracts delta from
|
||||
// ckt->CKTtime by itself. It sends 0 as olddelta after analog breakpoint
|
||||
// processing. Still, for XSPICE breakpoints it substracts delta (see code
|
||||
// at 'else if(g_mif_info.breakpoint.current < ckt->CKTtime)' branch) and
|
||||
// then sends non zero olddelta to sharedsync at the end of the function
|
||||
// (see chkStep: label). This doesn't seem right because olddelta is
|
||||
// substracted twice and makes ckt->CKTtime < last_accepted_time.
|
||||
// 0 - XSPICE models didn't have breakpoints in [last_accepted_time,
|
||||
// CKTtime]
|
||||
// 1 - convergence criaterias are satisfied but XSPICE breakpoint(s) is in
|
||||
// [last_accepted_time, CKTtime].
|
||||
int xspice_breakpoints_processed = 0;
|
||||
#ifdef SHARED_MODULE
|
||||
double olddelta_for_shared_sync = 0.0;
|
||||
#endif // SHARED_MODULE
|
||||
#endif
|
||||
#if defined CLUSTER || defined SHARED_MODULE
|
||||
int redostep;
|
||||
|
|
@ -706,6 +723,7 @@ resume:
|
|||
ckt->CKTcurrentAnalysis = DOING_TRAN;
|
||||
|
||||
/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */
|
||||
xspice_breakpoints_processed = 0;
|
||||
#endif
|
||||
olddelta=ckt->CKTdelta;
|
||||
/* time abort? */
|
||||
|
|
@ -799,6 +817,7 @@ resume:
|
|||
ckt->CKTtime -= ckt->CKTdelta;
|
||||
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
||||
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
||||
xspice_breakpoints_processed = 1;
|
||||
|
||||
if(firsttime) {
|
||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN;
|
||||
|
|
@ -929,8 +948,24 @@ resume:
|
|||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Do event backup */
|
||||
|
||||
if(ckt->evt->counts.num_insts > 0)
|
||||
if(ckt->evt->counts.num_insts > 0) {
|
||||
#ifdef SHARED_MODULE
|
||||
double discard_start_time = ckt->CKTtime + ckt->CKTdelta;
|
||||
// ngspice in executable mode substracts olddelta from the time
|
||||
// before new delta calculation, but it keeps delta in CKTtime and
|
||||
// postpones subtraction in library mode. Delayed subtraction leads
|
||||
// to incorrect points dropping because ckt->CKTdelta almost always
|
||||
// less than olddelta if there are convergence issues, and EVTbackup
|
||||
// may drop valid events that need to be processed within
|
||||
// [last_accepted_time, last_accepted_time + ckt->CKTdelta] range
|
||||
// after delta adjustment.
|
||||
if (redostep && xspice_breakpoints_processed == 0)
|
||||
discard_start_time -= olddelta;
|
||||
EVTbackup(ckt, discard_start_time);
|
||||
#else
|
||||
EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* gtri - end - wbk - Do event backup */
|
||||
#endif
|
||||
|
|
@ -957,10 +992,26 @@ resume:
|
|||
function.
|
||||
*/
|
||||
chkStep:
|
||||
#ifdef XSPICE
|
||||
// There is no need to subtract olddelta from ckt->CKTtime one more time
|
||||
// if it has been subtracted during XSPICE breakpoint processing. Double
|
||||
// subtracting puts ckt->CKTtime before last accepted timepoint i.e.
|
||||
// time[i] < time[i-1] which is wrong. olddelta will be reinitialized on
|
||||
// the new iteration, so it reassigning here should be safe. It can't be
|
||||
// zeroed during breakpoint processing because it takes part in the
|
||||
// "timestep too small" check.
|
||||
olddelta_for_shared_sync = olddelta;
|
||||
if (xspice_breakpoints_processed)
|
||||
olddelta_for_shared_sync = 0.0;
|
||||
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta_for_shared_sync, ckt->CKTfinalTime,
|
||||
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
||||
goto nextTime;
|
||||
#else
|
||||
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta, ckt->CKTfinalTime,
|
||||
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
||||
goto nextTime;
|
||||
#endif
|
||||
#endif // XSPICE
|
||||
#endif // SHARED_MODULE
|
||||
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
|
|
|||
Loading…
Reference in New Issue