dcalc error handling
This commit is contained in:
parent
bdd7468774
commit
bfb3174784
186
dcalc/DmpCeff.cc
186
dcalc/DmpCeff.cc
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue