223 lines
6.1 KiB
C
223 lines
6.1 KiB
C
|
|
/*
|
||
|
|
* Copyright (c) 2008 True Circuits Inc.
|
||
|
|
*
|
||
|
|
* Author: Kevin Cameron
|
||
|
|
*
|
||
|
|
* This source code is free software; you can redistribute it
|
||
|
|
* and/or modify it in source code form under the terms of the GNU
|
||
|
|
* General Public License as published by the Free Software
|
||
|
|
* Foundation; either version 2 of the License, or (at your option)
|
||
|
|
* any later version.
|
||
|
|
*
|
||
|
|
* This program is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
* GNU General Public License for more details.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU General Public License
|
||
|
|
* along with this program; if not, write to the Free Software
|
||
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <dlfcn.h>
|
||
|
|
|
||
|
|
int vvp_main(int,char **);
|
||
|
|
|
||
|
|
enum eCBmode { // !!! keep in sync with Spice
|
||
|
|
CB_LOAD = 0,
|
||
|
|
CB_TRUNC,
|
||
|
|
CB_ACCEPT
|
||
|
|
};
|
||
|
|
|
||
|
|
const double EndOfTimeD = 1e99;
|
||
|
|
|
||
|
|
template<int S>
|
||
|
|
struct SpiceCallback
|
||
|
|
{
|
||
|
|
typedef double *(*SpiceCB)(SpiceCallback *,double,eCBmode,...);
|
||
|
|
|
||
|
|
double coeffs[S];
|
||
|
|
SpiceCB eval;
|
||
|
|
char *spec;
|
||
|
|
void *dll_ref;
|
||
|
|
void (*set_active)(void *,void *,double time);
|
||
|
|
|
||
|
|
inline int Slots() {return S;}
|
||
|
|
|
||
|
|
void setCoeffs(double *cof) {
|
||
|
|
int t = S;
|
||
|
|
while (t-- > 0) coeffs[t] = cof[t];
|
||
|
|
}
|
||
|
|
|
||
|
|
inline double fillEoT(int t,double val = 0.0) {
|
||
|
|
assert(t < S);
|
||
|
|
while (t < S) {
|
||
|
|
coeffs[t++] = EndOfTimeD;
|
||
|
|
coeffs[t++] = val;
|
||
|
|
}
|
||
|
|
return val;
|
||
|
|
}
|
||
|
|
|
||
|
|
SpiceCallback(double val = 0.0,double dt0 = EndOfTimeD) {
|
||
|
|
coeffs[0] = 0.0;
|
||
|
|
coeffs[1] = val;
|
||
|
|
coeffs[2] = dt0;
|
||
|
|
coeffs[3] = val;
|
||
|
|
fillEoT(4,val);
|
||
|
|
}
|
||
|
|
|
||
|
|
void dumpPWL(FILE *fp = stderr,double now = 0.0);
|
||
|
|
|
||
|
|
inline void checkPWL(double now = 0.0,double end = 0.0,
|
||
|
|
FILE *fp = stderr) {
|
||
|
|
for (int i = 2; i < S; i += 2) {
|
||
|
|
if (coeffs[i-2] > coeffs[i]) {
|
||
|
|
dumpPWL(fp);
|
||
|
|
assert(!"Bad waveform");
|
||
|
|
}
|
||
|
|
if (end > 0.0 && coeffs[i] >= end) { break; }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
enum eBLtype {
|
||
|
|
BL_UNBOUND = 0,
|
||
|
|
BL_NET,
|
||
|
|
BL_REG,
|
||
|
|
BL_LAST
|
||
|
|
};
|
||
|
|
|
||
|
|
extern "C" void *bindnet(char *spec,char T,int *coeffs,
|
||
|
|
void *,void (*set_active)(void *,void *,double));
|
||
|
|
|
||
|
|
#ifdef __vpi_priv_H
|
||
|
|
|
||
|
|
#define IVL_PWL_SLOTS 16 /* 8 pairs */
|
||
|
|
|
||
|
|
struct SpcIvlCB : SpiceCallback<IVL_PWL_SLOTS> {
|
||
|
|
SpcIvlCB *next,
|
||
|
|
*active; // non-local drive
|
||
|
|
__vpiSignal *sig; // boundary or driven signal
|
||
|
|
|
||
|
|
// Params - keep together (see below)
|
||
|
|
double vss,vdd;
|
||
|
|
double lo,hi; // drive levels
|
||
|
|
double thrshld[2]; // rising,falling
|
||
|
|
double rise,fall; // times
|
||
|
|
double init_v; // initial voltage
|
||
|
|
double prec; // local precision
|
||
|
|
|
||
|
|
double last_time,
|
||
|
|
last_value,
|
||
|
|
last_error;
|
||
|
|
SpcIvlCB *pwr[2]; // vss,vdd
|
||
|
|
char set, // value is known
|
||
|
|
others, // has other drivers
|
||
|
|
non_local, // > 0 => not boundary
|
||
|
|
mode; // 0 - discrete
|
||
|
|
// 1 - ramp over NBA
|
||
|
|
// 2 - sync event
|
||
|
|
// 3 - + tie to local vss/vdd
|
||
|
|
char go2, // error fix
|
||
|
|
reported;
|
||
|
|
|
||
|
|
static const char *parm_nm[]; // SAME ORDER as fields
|
||
|
|
|
||
|
|
inline double *parms() {return &vss;}
|
||
|
|
double *set_parms(double *);
|
||
|
|
|
||
|
|
SpcIvlCB(double dt0 = EndOfTimeD,double val = 0.0,
|
||
|
|
const char *nan_tag = "")
|
||
|
|
: SpiceCallback <IVL_PWL_SLOTS>(val,dt0) {
|
||
|
|
next = 0;
|
||
|
|
sig = 0;
|
||
|
|
active = 0;
|
||
|
|
vss = nan(nan_tag);
|
||
|
|
vdd = nan(nan_tag);
|
||
|
|
hi = nan(nan_tag);
|
||
|
|
lo = nan(nan_tag);
|
||
|
|
thrshld[0] = nan(nan_tag);
|
||
|
|
thrshld[1] = nan(nan_tag);
|
||
|
|
rise = nan(nan_tag);
|
||
|
|
fall = nan(nan_tag);
|
||
|
|
init_v = nan(nan_tag);
|
||
|
|
prec = nan(nan_tag);
|
||
|
|
set = 0;
|
||
|
|
others = 0;
|
||
|
|
non_local = 0;
|
||
|
|
mode = 0;
|
||
|
|
last_time = -1;
|
||
|
|
last_value = 0;
|
||
|
|
last_error = -1;
|
||
|
|
pwr[0] = 0;
|
||
|
|
pwr[1] = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
typedef int (*pwr_fn)(vpiHandle argh,SpcIvlCB *);
|
||
|
|
|
||
|
|
inline SpcIvlCB *Pwr(int i,const char *pfn_nm) {
|
||
|
|
if (!pwr[i]) {
|
||
|
|
pwr_fn pfn;
|
||
|
|
if (pfn_nm) {
|
||
|
|
pfn = (pwr_fn)dlsym(0,pfn_nm);
|
||
|
|
}
|
||
|
|
if (pfn) {
|
||
|
|
// (*pfn)(sig,this);
|
||
|
|
}
|
||
|
|
if (!pwr[i] && non_local) {
|
||
|
|
pwr[i] = next->pwr[i];
|
||
|
|
}
|
||
|
|
assert(pwr[i]);
|
||
|
|
}
|
||
|
|
return pwr[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
inline double Rise() { if (isnan(rise) && non_local > 0) {
|
||
|
|
rise = next->rise;
|
||
|
|
assert(!isnan(rise)); }
|
||
|
|
return rise; }
|
||
|
|
|
||
|
|
inline double Fall() { if (isnan(fall) && non_local > 0) {
|
||
|
|
fall = next->fall;
|
||
|
|
assert(!isnan(fall)); }
|
||
|
|
return fall; }
|
||
|
|
|
||
|
|
inline double LastValue() { return non_local > 0 ? next->last_value
|
||
|
|
: last_value; }
|
||
|
|
};
|
||
|
|
|
||
|
|
struct SpcDllData {
|
||
|
|
char active;
|
||
|
|
double next_time;
|
||
|
|
void (*activate)(SpcDllData *,SpcIvlCB *,double);
|
||
|
|
};
|
||
|
|
|
||
|
|
void ActivateCB(double time,SpcIvlCB *);
|
||
|
|
|
||
|
|
#ifdef DECL__IVL_PARM_NM
|
||
|
|
|
||
|
|
inline void set_if_not(double &prm,double val) {
|
||
|
|
if (isnan(prm)) prm = val;
|
||
|
|
}
|
||
|
|
|
||
|
|
const char *SpcIvlCB::parm_nm[] = // SAME ORDER as fields above
|
||
|
|
{"vss","vdd",
|
||
|
|
"lo","hi",
|
||
|
|
"thrsh0","thrsh1",
|
||
|
|
"rise","fall",
|
||
|
|
"init_v",
|
||
|
|
"prec"};
|
||
|
|
|
||
|
|
double *SpcIvlCB::set_parms(double *from)
|
||
|
|
{
|
||
|
|
int p = sizeof(parm_nm)/sizeof(*parm_nm);
|
||
|
|
|
||
|
|
while (p--) parms()[p] = from[p];
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
extern "C" SpcIvlCB **spicenets();
|
||
|
|
|
||
|
|
#endif
|