CombineDieFiles:
PROC [ from:
LIST
OF Rope.
ROPE, to: Rope.
ROPE ]
RETURNS [ comments: Rope.
ROPE ←
NIL ] =
BEGIN
pp: REF BSimModel.ProcessParams = NEW[BSimModel.ProcessParams];
dieList: LIST OF REF WPParams ← NIL;
ps: LeastSq.PointSet ← NIL;
pt: LeastSq.Row ← NEW[LeastSq.RowRec[4]];
eqn: LeastSq.Row;
dieCount: INT ← 0;
wtSum: REAL ← 0.0;
mu, dL, dW: REAL;
sumSqErr, maxSqErr: REAL;
firstDie: REF WPParams ← NIL;
multipleL, multipleW: BOOL ← FALSE;
f: LIST OF Rope.ROPE ← from;
comments ← IO.PutFR["*BSIM Process File %g of %g\n*generated from the following die files:\n", IO.rope[to], IO.time[]];
WHILE f #
NIL
DO
r: Rope.ROPE ← f.first;
fullFName, attachedTo: Rope.ROPE;
created: BasicTime.GMT;
wt: REAL ← 1.0;
dieCount ← dieCount+1;
IF r.Equal["-w"]
THEN {
wt ← Convert.RealFromLiteral[f.rest.first];
f ← f.rest.rest;
r ← f.first;
};
dieList ← CONS[NEW[WPParams ← [weight: wt, p: BSimModel.ReadProcessFile[r]]], dieList];
[fullFName: fullFName, attachedTo: attachedTo, created: created] ←
FS.FileInfo[name: r];
IF attachedTo.Length = 0 THEN attachedTo ← fullFName;
comments ← comments.Cat[
IO.PutFR["* %g of %g (wt = %g, W/L = %g/%g)\n",
IO.rope[attachedTo],
IO.time[created],
IO.real[dieList.first.weight],
IO.int[Real.RoundLI[dieList.first.p.dutW]],
IO.int[Real.RoundLI[dieList.first.p.dutL]]
]];
IF firstDie =
NIL
THEN firstDie ← dieList.first
ELSE {
multipleL ←multipleL OR dieList.first.p.dutL # firstDie.p.dutL;
multipleW ←multipleW OR dieList.first.p.dutW # firstDie.p.dutW;
IF dieList.first.p.toxMicrons # firstDie.p.toxMicrons
OR dieList.first.p.tempC # firstDie.p.tempC
OR dieList.first.p.vddVolts # firstDie.p.vddVolts
THEN
comments ← comments.Cat["* WARNING -- incompatible die files!!\n"];
};
wtSum ← wtSum+wt;
f ← f.rest;
ENDLOOP;
pp^ ← dieList.first.p^;
comments ← Rope.Cat[comments, (IF multipleL THEN NIL ELSE "* WARNING -- dice have only one channel length\n"), (IF multipleW THEN NIL ELSE "* WARNING -- dice have only one channel width\n")];
pp.info ← Rope.Cat[comments, "*\n*The following information is from the last die file:\n", pp.info];
ps ← LeastSq.NewPointSet[4];
pt[0] ← 1.0;
The parameter in the file is beta0.
beta0 = mu*Cox*(W+dW)/(L+dL), where we know Cox, beta0, W, and L
(beta0/Cox)*(L+dL) = (dW*mu)+mu*W
L = (dW*mu)*(Cox/beta0)+mu*(W*(Cox/beta0))-dL
FOR dl:
LIST
OF
REF WPParams ← dieList, dl.rest
WHILE dl #
NIL
DO
CoxOverBeta0: REAL = (3.9*8.854E-10/dl.first.p.toxMicrons -- farads/sq cm--)
/dl.first.p.params[BSimModel.beta0][1];
pt[1] ← CoxOverBeta0*dl.first.p.dutW; -- first indep var
pt[2] ← CoxOverBeta0; -- second indep var
pt[3] ← dl.first.p.dutL; -- dep variable
LeastSq.AddPoint[ps, pt, dl.first.weight];
ENDLOOP;
eqn ← LeastSq.LeastSqFit[ps];
dL ← eqn[0];
mu ← -eqn[1];
dW ← -eqn[2]/mu;
pp.params[BSimModel.beta0][1] ← mu;
pp.params[BSimModel.beta0][2] ← dL;
pp.params[BSimModel.beta0][3] ← dW;
sumSqErr ← 0.0;
FOR dl:
LIST
OF
REF WPParams ← dieList, dl.rest
WHILE dl #
NIL
DO
Cox: REAL = 3.9*8.854E-10/dl.first.p.toxMicrons; -- farads/sq cm
Leff: REAL = dl.first.p.dutL+dL;
Weff: REAL = dl.first.p.dutW+dW;
pred: REAL = mu*Cox*Weff/Leff;
act: REAL = dl.first.p.params[BSimModel.beta0][1];
err: REAL = 100*(IF act=0 THEN (IF pred=0 THEN 0.0 ELSE 1.0) ELSE ABS[(pred-act)/act]);
sumSqErr ← sumSqErr+dl.first.weight*err*err;
ENDLOOP;
comments ←
IO.PutFR["%gBeta0 has RMS error of %g%%.\n",
IO.rope[comments],
IO.real[Real.SqRt[sumSqErr/wtSum]]];
FOR parm:
NAT
IN [0..BSimModel.nBasicBSimParams)
DO
sumSqErr ← maxSqErr ← 0.0;
IF parm = BSimModel.beta0 THEN LOOP;
ps ← LeastSq.NewPointSet[4];
FOR dl:
LIST
OF
REF WPParams ← dieList, dl.rest
WHILE dl #
NIL
DO
Leff: REAL = dl.first.p.dutL+dL;
Weff: REAL = dl.first.p.dutW+dW;
pt[1] ← 1.0/Leff; -- first indep var
pt[2] ← 1.0/Weff; -- second indep var
pt[3] ← dl.first.p.params[parm][1]; -- dep variable
LeastSq.AddPoint[ps, pt, dl.first.weight];
ENDLOOP;
eqn ← LeastSq.LeastSqFit[ps];
pp.params[parm][1] ← -eqn[0];
pp.params[parm][2] ← -eqn[1];
pp.params[parm][3] ← -eqn[2];
FOR dl:
LIST
OF
REF WPParams ← dieList, dl.rest
WHILE dl #
NIL
DO
Leff: REAL = dl.first.p.dutL+dL;
Weff: REAL = dl.first.p.dutW+dW;
Cox: REAL = 3.9*8.854E-10/dl.first.p.toxMicrons; -- farads/sq cm
pred: REAL = pp.params[parm][1]+(pp.params[parm][2]/Leff)+(pp.params[parm][3]/Weff);
act: REAL = dl.first.p.params[parm][1];
err: REAL = 100*(IF act=0 THEN (IF pred=0 THEN 0.0 ELSE 1.0) ELSE ABS[(pred-act)/act]);
sqErr: REAL = err*err;
IF sqErr>maxSqErr
THEN {
maxSqErr ← sqErr;
pp.params[parm][4] ← err;
pp.params[parm][5] ← dl.first.p.dutW;
pp.params[parm][6] ← dl.first.p.dutL;
};
sumSqErr ← sumSqErr+dl.first.weight*sqErr;
ENDLOOP;
comments ←
IO.PutFR["%gParameter %g has RMS error of %g%%.\n",
IO.rope[comments], IO.int[parm], IO.real[Real.SqRt[sumSqErr/wtSum]]];
ENDLOOP;
BSimModel.WriteProcessFile[to, pp];
END;
MakeBSimProcessFile:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF ←
NIL, msg: Rope.
ROPE ←
NIL]
-- Commander.CommandProc -- = {
argList: LIST OF Rope.ROPE;
nArgs: NAT;
comments: Rope.ROPE;
[list: argList, length: nArgs] ← CommandTool.ParseToList[cmd];
IF nArgs>4
AND Rope.Equal[argList.rest.first, "←"]
THEN {
comments ← CombineDieFiles[to: argList.first, from: argList.rest.rest];
}
ELSE comments ← Rope.Cat["Improper argument format", cmd.procData.doc];
cmd.out.PutF["\n%g", IO.rope[comments]];
};
Commander.Register["MakeBSimProcessFile", MakeBSimProcessFile, "\n\nMakeBSimProcessFile takes a collection of BSim die files for dice of different lengths and widths and produces a process file from which BSim parameters can be calculated for any geometry. Format is:\n MakeBSIMProcessFile processFile ← dieFile dieFile ...\n"];