<> <> DIRECTORY Commander, CommandTool, BSimModel, FS, IO, LeastSq, Real, Rope; BSimGeomImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, BSimModel, FS, IO, LeastSq, Real, Rope = BEGIN CombineDieFiles: PROC [ from: LIST OF REF ANY -- Rope --, to: Rope.ROPE ] RETURNS [ comments: Rope.ROPE _ NIL ] = BEGIN pp: REF BSimModel.ProcessParams = NEW[BSimModel.ProcessParams]; dieList: LIST OF REF BSimModel.ProcessParams _ NIL; ps: LeastSq.PointSet _ NIL; pt: LeastSq.Row _ NEW[LeastSq.RowRec[4]]; eqn: LeastSq.Row; dieCount: INT _ 0; mu, dL, dW: REAL; sumSqErr, maxSqErr: REAL; firstDie: REF BSimModel.ProcessParams _ NIL; multipleL, multipleW: BOOL _ FALSE; comments _ IO.PutFR["*BSIM Process File %g of %g\n*generated from the following die files:\n", IO.rope[to], IO.time[]]; FOR f: LIST OF REF ANY _ from, f.rest WHILE f # NIL DO WITH f.first SELECT FROM r: Rope.ROPE => { fullFName, attachedTo: Rope.ROPE; created: BasicTime.GMT; dieCount _ dieCount+1; dieList _ CONS[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 (W/L = %g/%g)\n", IO.rope[attachedTo], IO.time[created], IO.int[Real.RoundLI[dieList.first.dutW]], IO.int[Real.RoundLI[dieList.first.dutL]], ]]; IF firstDie = NIL THEN firstDie _ dieList.first ELSE { multipleL _multipleL OR dieList.first.dutL # firstDie.dutL; multipleW _multipleW OR dieList.first.dutW # firstDie.dutW; IF dieList.first.toxMicrons # firstDie.toxMicrons OR dieList.first.tempC # firstDie.tempC OR dieList.first.vddVolts # firstDie.vddVolts THEN comments _ comments.Cat["* WARNING -- incompatible die files!!\n"]; }; }; ENDCASE => NULL; ENDLOOP; pp^ _ dieList.first^; 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; <> <<>> <> <<(beta0/Cox)*(L+dL) = (dW*mu)+mu*W>> <> FOR dl: LIST OF REF BSimModel.ProcessParams _ dieList, dl.rest WHILE dl # NIL DO CoxOverBeta0: REAL = (3.9*8.854E-10/dl.first.toxMicrons -- farads/sq cm--) /dl.first.params[BSimModel.beta0][1]; pt[1] _ CoxOverBeta0*dl.first.dutW; -- first indep var pt[2] _ CoxOverBeta0; -- second indep var pt[3] _ dl.first.dutL; -- dep variable LeastSq.AddPoint[ps, pt]; 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 BSimModel.ProcessParams _ dieList, dl.rest WHILE dl # NIL DO Cox: REAL = 3.9*8.854E-10/dl.first.toxMicrons; -- farads/sq cm Leff: REAL = dl.first.dutL+dL; Weff: REAL = dl.first.dutW+dW; pred: REAL = mu*Cox*Weff/Leff; act: REAL = dl.first.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]); sqErr: REAL = err*err; sumSqErr _ sumSqErr+sqErr; ENDLOOP; comments _ IO.PutFR["%gBeta0 has RMS error of %g%%.\n", IO.rope[comments], IO.real[Real.SqRt[sumSqErr/dieCount]]]; 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 BSimModel.ProcessParams _ dieList, dl.rest WHILE dl # NIL DO Leff: REAL = dl.first.dutL+dL; Weff: REAL = dl.first.dutW+dW; act: REAL = dl.first.params[parm][1]*(SELECT parm FROM BSimModel.x2beta0, BSimModel.beta0sat, BSimModel.x2beta0sat, BSimModel.x3beta0sat => Leff/Weff, BSimModel.u1, BSimModel.x2u1, BSimModel.x3u1 => Leff, ENDCASE => 1.0); pt[1] _ 1.0/Leff; -- first indep var pt[2] _ 1.0/Weff; -- second indep var pt[3] _ act; -- dep variable LeastSq.AddPoint[ps, pt]; 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 BSimModel.ProcessParams _ dieList, dl.rest WHILE dl # NIL DO Leff: REAL = dl.first.dutL+dL; Weff: REAL = dl.first.dutW+dW; pred: REAL = pp.params[parm][1]+(pp.params[parm][2]/Leff)+(pp.params[parm][3]/Weff); act: REAL = dl.first.params[parm][1]*(SELECT parm FROM BSimModel.x2beta0, BSimModel.beta0sat, BSimModel.x2beta0sat, BSimModel.x3beta0sat => Leff/Weff, BSimModel.u1, BSimModel.x2u1, BSimModel.x3u1 => Leff, ENDCASE => 1.0); 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.dutW; pp.params[parm][6] _ dl.first.dutL; }; sumSqErr _ sumSqErr+sqErr; ENDLOOP; comments _ IO.PutFR["%gParameter %g has RMS error of %g%%.\n", IO.rope[comments], IO.int[parm], IO.real[Real.SqRt[sumSqErr/dieCount]]]; 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 { fromFiles: LIST OF REF ANY; TRUSTED { fromFiles _ LOOPHOLE[argList.rest.rest, LIST OF REF ANY] }; comments _ CombineDieFiles[to: argList.first, from: fromFiles]; } 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"]; END.