dcalc error handling

This commit is contained in:
James Cherry 2020-11-02 17:14:48 -08:00
parent bdd7468774
commit bfb3174784
1 changed files with 97 additions and 89 deletions

View File

@ -96,7 +96,7 @@ findRoot(void (*func)(void *state, double x, double &y, double &dy),
double x_tol, double x_tol,
int max_iter, int max_iter,
const char *&error); const char *&error);
static bool static const char *
newtonRaphson(const int max_iter, newtonRaphson(const int max_iter,
double x[], double x[],
const int n, const int n,
@ -110,19 +110,17 @@ newtonRaphson(const int max_iter,
double **fjac, double **fjac,
int *index, int *index,
double *p, double *p,
double *scale, double *scale);
const char *&error);
static void static void
luSolve(double **a, luSolve(double **a,
const int size, const int size,
const int *index, const int *index,
double b[]); double b[]);
static bool static const char *
luDecomp(double **a, luDecomp(double **a,
const int size, const int size,
int *index, int *index,
double *scale, double *scale);
const char *&error);
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -167,7 +165,7 @@ public:
protected: protected:
// Find driver parameters t0, delta_t, Ceff. // Find driver parameters t0, delta_t, Ceff.
bool findDriverParams(double &ceff); const char *findDriverParams(double ceff);
void gateCapDelaySlew(double cl, void gateCapDelaySlew(double cl,
double &delay, double &delay,
double &slew); double &slew);
@ -191,10 +189,10 @@ protected:
void showX(); void showX();
void showFvec(); void showFvec();
void showJacobian(); void showJacobian();
bool findDriverDelaySlew(double &delay, const char *findDriverDelaySlew(double &delay,
double &slew); double &slew);
bool findVoCrossing(double vth, double findVoCrossing(double vth,
double &t); const char *&error);
void showVo(); void showVo();
bool findVlCrossing(double vth, bool findVlCrossing(double vth,
double &t); double &t);
@ -335,21 +333,23 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
} }
// Find Ceff, delta_t and t0 for the driver. // Find Ceff, delta_t and t0 for the driver.
// Caller must initialize/retrieve x_[DmpParam::ceff] because // Return error msg on failure.
// order 2 eqns don't have a ceff eqn. const char *
// Return true if successful. DmpAlg::findDriverParams(double ceff)
bool
DmpAlg::findDriverParams(double &ceff)
{ {
x_[DmpParam::ceff] = ceff;
double t_vth, t_vl, slew; double t_vth, t_vl, slew;
gateDelays(ceff, t_vth, t_vl, slew); gateDelays(ceff, t_vth, t_vl, slew);
double dt = slew / (vh_ - vl_); double dt = slew / (vh_ - vl_);
double t0 = t_vth + log(1.0 - vth_) * rd_ * ceff - vth_ * dt; double t0 = t_vth + log(1.0 - vth_) * rd_ * ceff - vth_ * dt;
x_[DmpParam::dt] = dt; x_[DmpParam::dt] = dt;
x_[DmpParam::t0] = t0; x_[DmpParam::t0] = t0;
const char *nr_error; const char *error = newtonRaphson(100, x_, nr_order_, driver_param_tol,
if (newtonRaphson(100, x_, nr_order_, driver_param_tol, evalDmpEqnsState, evalDmpEqnsState,
this, fvec_, fjac_, index_, p_, scale_, nr_error)) { this, fvec_, fjac_, index_, p_, scale_);
if (error)
return error;
else {
t0_ = x_[DmpParam::t0]; t0_ = x_[DmpParam::t0];
dt_ = x_[DmpParam::dt]; dt_ = x_[DmpParam::dt];
debugPrint3(debug_, "delay_calc", 3, " t0 = %s dt = %s ceff = %s\n", debugPrint3(debug_, "delay_calc", 3, " t0 = %s dt = %s ceff = %s\n",
@ -358,11 +358,7 @@ DmpAlg::findDriverParams(double &ceff)
units_->capacitanceUnit()->asString(x_[DmpParam::ceff])); units_->capacitanceUnit()->asString(x_[DmpParam::ceff]));
if (debug_->check("delay_calc", 4)) if (debug_->check("delay_calc", 4))
showVo(); showVo();
return true; return nullptr;
}
else {
fail(nr_error);
return false;
} }
} }
@ -429,14 +425,18 @@ DmpAlg::dy(double t,
double t0, double t0,
double dt, double dt,
double cl, double cl,
// Return values.
double &dydt0, double &dydt0,
double &dyddt, double &dyddt,
double &dydcl) double &dydcl)
{ {
double t1 = t - t0; double t1 = t - t0;
#if 0
if (t1 <= 0.0) if (t1 <= 0.0)
dydt0 = dyddt = dydcl = 0.0; dydt0 = dyddt = dydcl = 0.0;
else if (t1 <= dt) { else
#endif
if (t1 <= dt) {
dydt0 = -y0dt(t1, cl) / dt; dydt0 = -y0dt(t1, cl) / dt;
dyddt = -y0(t1, cl) / (dt * dt); dyddt = -y0(t1, cl) / (dt * dt);
dydcl = y0dcl(t1, cl) / dt; dydcl = y0dcl(t1, cl) / dt;
@ -492,36 +492,34 @@ DmpAlg::showJacobian()
} }
} }
// Return true if successful. // Return error msg on failure.
bool const char *
DmpAlg::findDriverDelaySlew(double &delay, DmpAlg::findDriverDelaySlew(double &delay,
double &slew) double &slew)
{ {
double tl, th; const char *error = nullptr;
if (findVoCrossing(vth_, delay) delay = findVoCrossing(vth_, error);
&& findVoCrossing(vl_, tl) if (error)
&& findVoCrossing(vh_, th)) { return error;
slew = (th - tl) / slew_derate_; double tl = findVoCrossing(vl_, error);
return true; if (error)
} return error;
else double th = findVoCrossing(vh_, error);
return false; if (error)
return error;
slew = (th - tl) / slew_derate_;
return nullptr;
} }
// Find t such that vo(t)=v. // Find t such that vo(t)=v.
// Return true if successful. // Return true if successful.
bool double
DmpAlg::findVoCrossing(double vth, DmpAlg::findVoCrossing(double vth,
double &t) const char *&error)
{ {
v_cross_ = vth; v_cross_ = vth;
double ub = voCrossingUpperBound(); double ub = voCrossingUpperBound();
const char *error; return findRoot(evalVoEqns, this, t0_, ub, vth_time_tol, find_root_max_iter, error);
t = findRoot(evalVoEqns, this, t0_, ub, vth_time_tol, find_root_max_iter,
error);
if (error)
fail(error);
return (error == nullptr);
} }
static void static void
@ -698,12 +696,12 @@ DmpAlg::fail(const char *reason)
{ {
// Allow only failures to be reported with a unique debug flag. // Allow only failures to be reported with a unique debug flag.
if (debug_->check("delay_calc", 1) || debug_->check("delay_calc_dmp", 1)) if (debug_->check("delay_calc", 1) || debug_->check("delay_calc_dmp", 1))
debug_->print("delay_calc: DMP failed - %s c2=%s rpi=%s c1=%s\n", debug_->print("delay_calc: DMP failed - %s c2=%s rpi=%s c1=%s rd=%s\n",
reason, reason,
units_->capacitanceUnit()->asString(c2_), units_->capacitanceUnit()->asString(c2_),
units_->resistanceUnit()->asString(rpi_), units_->resistanceUnit()->asString(rpi_),
units_->capacitanceUnit()->asString(c1_)); units_->capacitanceUnit()->asString(c1_),
UNITS_->resistanceUnit()->asString(rd_));
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -846,7 +844,7 @@ public:
virtual double voCrossingUpperBound(); virtual double voCrossingUpperBound();
private: private:
bool findDriverParamsPi(); const char *findDriverParamsPi();
virtual double v0(double t); virtual double v0(double t);
virtual double dv0dt(double t); virtual double dv0dt(double t);
double ipiIceff(double t0, double ipiIceff(double t0,
@ -930,7 +928,14 @@ void
DmpPi::gateDelaySlew(double &delay, DmpPi::gateDelaySlew(double &delay,
double &slew) double &slew)
{ {
if (findDriverParamsPi()) { const char *error = findDriverParamsPi();
if (error) {
fail(error);
// Driver calculation failed - use Ceff=c1+c2.
ceff_ = c1_ + c2_;
gateCapDelaySlew(ceff_, delay, slew);
}
else {
ceff_ = x_[DmpParam::ceff]; ceff_ = x_[DmpParam::ceff];
driver_valid_ = true; driver_valid_ = true;
double table_slew; double table_slew;
@ -940,25 +945,25 @@ DmpPi::gateDelaySlew(double &delay,
// Vo slew is more accurate than table // Vo slew is more accurate than table
// (-8% max, -3% avg vs -32% max, -12% avg). // (-8% max, -3% avg vs -32% max, -12% avg).
// Need Vo delay to measure load wire delay waveform. // Need Vo delay to measure load wire delay waveform.
if (!findDriverDelaySlew(vo_delay_, slew)) const char *error = findDriverDelaySlew(vo_delay_, slew);
// Fall back to table slew if findDriverDelaySlew fails. if (error) {
fail(error);
// Fall back to table slew.
slew = table_slew; slew = table_slew;
} }
else {
// Driver calculation failed - use Ceff=c1+c2.
ceff_ = c1_ + c2_;
gateCapDelaySlew(ceff_, delay, slew);
} }
// Save for wire delay calc. // Save for wire delay calc.
gate_slew_ = slew; gate_slew_ = slew;
} }
bool const char *
DmpPi::findDriverParamsPi() DmpPi::findDriverParamsPi()
{ {
double ceff = c1_ + c2_; const char *error;
x_[DmpParam::ceff] = ceff; error = findDriverParams(c2_ + c1_);
return findDriverParams(x_[DmpParam::ceff]); if (error)
error = findDriverParams(c2_);
return error;
} }
// Given x_ as a vector of input parameters, fill fvec_ with the // Given x_ as a vector of input parameters, fill fvec_ with the
@ -1222,11 +1227,23 @@ void
DmpZeroC2::gateDelaySlew(double &delay, DmpZeroC2::gateDelaySlew(double &delay,
double &slew) double &slew)
{ {
driver_valid_ = findDriverParams(c1_); #if 0
// Not converging to a reasonable solution. set_load10
const char *error = findDriverParams(c1_);
ceff_ = c1_; ceff_ = c1_;
if (!findDriverDelaySlew(delay, slew)) driver_valid_ = (error == nullptr);
// Fall back to table slew if findDriverDelaySlew fails. if (error == nullptr)
error = findDriverDelaySlew(delay, slew);
if (error) {
fail(error);
// Fall back to table slew.
gateCapDelaySlew(ceff_, delay, slew); gateCapDelaySlew(ceff_, delay, slew);
}
vo_delay_ = delay;
gate_slew_ = slew;
#endif
ceff_ = c1_;
gateCapDelaySlew(ceff_, delay, slew);
vo_delay_ = delay; vo_delay_ = delay;
gate_slew_ = slew; gate_slew_ = slew;
} }
@ -1340,8 +1357,8 @@ findRoot(void (*func)(void *state, double x, double &y, double &dy),
// Newton-Raphson iteration to find zeros of a function. // Newton-Raphson iteration to find zeros of a function.
// x_tol is percentage that all changes in x must be less than (1.0 = 100%). // x_tol is percentage that all changes in x must be less than (1.0 = 100%).
// Eval(state) is called to fill fvec and fjac (returns false if fails). // Eval(state) is called to fill fvec and fjac (returns false if fails).
// Return true if successful. // Return error msg on failure.
static bool static const char *
newtonRaphson(const int max_iter, newtonRaphson(const int max_iter,
double x[], double x[],
const int size, const int size,
@ -1353,20 +1370,19 @@ newtonRaphson(const int max_iter,
double **fjac, double **fjac,
int *index, int *index,
double *p, double *p,
double *scale, double *scale)
const char *&error)
{ {
for (int k = 0; k < max_iter; k++) { for (int k = 0; k < max_iter; k++) {
if (!eval(state)) { if (!eval(state))
error = "Newton-Raphson eval failed"; return "Newton-Raphson eval failed";
return false;
}
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
// Right-hand side of linear equations. // Right-hand side of linear equations.
p[i] = -fvec[i]; p[i] = -fvec[i];
const char *lu_error; const char *error = luDecomp(fjac, size, index, scale);
if (luDecomp(fjac, size, index, scale, lu_error)) { if (error)
return error;
else {
luSolve(fjac, size, index, p); luSolve(fjac, size, index, p);
bool all_under_x_tol = true; bool all_under_x_tol = true;
@ -1376,15 +1392,10 @@ newtonRaphson(const int max_iter,
x[i] += p[i]; x[i] += p[i];
} }
if (all_under_x_tol) if (all_under_x_tol)
return true; return nullptr;
}
else {
error = lu_error;
return false;
} }
} }
error = "Newton-Raphson max iterations exceeded"; return "Newton-Raphson max iterations exceeded";
return false;
} }
// luDecomp, luSolve based on MatClass from C. R. Birchenhall, // luDecomp, luSolve based on MatClass from C. R. Birchenhall,
@ -1398,15 +1409,14 @@ newtonRaphson(const int max_iter,
// //
// Replaces a[0..size-1][0..size-1] by the LU decomposition. // Replaces a[0..size-1][0..size-1] by the LU decomposition.
// index[0..size-1] is an output vector of the row permutations. // index[0..size-1] is an output vector of the row permutations.
// Return true if successful. // Return error msg on failure.
bool const char *
luDecomp(double **a, luDecomp(double **a,
const int size, const int size,
int *index, int *index,
// Temporary supplied by caller. // Temporary supplied by caller.
// scale stores the implicit scaling of each row. // scale stores the implicit scaling of each row.
double *scale, double *scale)
const char *&error)
{ {
// Find implicit scaling factors. // Find implicit scaling factors.
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -1416,10 +1426,8 @@ luDecomp(double **a,
if (temp > big) if (temp > big)
big = temp; big = temp;
} }
if (big == 0.0) { if (big == 0.0)
error = "LU decomposition: no non-zero row element"; return "LU decomposition: no non-zero row element";
return false;
}
scale[i] = 1.0 / big; scale[i] = 1.0 / big;
} }
int size_1 = size - 1; int size_1 = size - 1;
@ -1469,7 +1477,7 @@ luDecomp(double **a,
a[i][j] *= pivot; a[i][j] *= pivot;
} }
} }
return true; return nullptr;
} }
// Solves the set of size linear equations a*x=b, assuming A is LU form // Solves the set of size linear equations a*x=b, assuming A is LU form