diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index 804c75937..62ba3b7e1 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -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 */