<> <> DIRECTORY Commander, CommandTool, Convert, BSimModel, FS, IO, IOUtils, LeastSq, Real, Rope; BSimGeomImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, BSimModel, FS, IO, IOUtils, LeastSq, Real, Rope = BEGIN WPParams: TYPE = RECORD [ weight: REAL _ 1.0, p: REF BSimModel.ProcessParams _ NIL ]; 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; <> <<>> <> <<(beta0/Cox)*(L+dL) = (dW*mu)+mu*W>> <> 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]]; }; PutFRList: PROC [ format: Rope.ROPE, v: LIST OF REF ANY ] RETURNS [ result: LIST OF Rope.ROPE ] = { ToValueList: PROC [ l: LIST OF REF ANY ] RETURNS [ vl: LIST OF IO.Value ] = { IF l = NIL THEN vl _ NIL ELSE WITH l.first SELECT FROM ri: REF INT => vl _ CONS[IO.int[ri^], ToValueList[l.rest]]; rr: REF REAL => vl _ CONS[IO.real[rr^], ToValueList[l.rest]]; rv: REF IO.Value => vl _ CONS[rv^, ToValueList[l.rest]]; r: Rope.ROPE => vl _ CONS[IO.rope[r], ToValueList[l.rest]]; t: REF TEXT => vl _ CONS[IO.text[t], ToValueList[l.rest]]; ENDCASE => vl _ CONS[IO.refAny[l.first], ToValueList[l.rest]]; }; rev: LIST OF Rope.ROPE _ NIL; FOR vl: LIST OF REF ANY _ v, vl.rest WHILE vl # NIL DO s: IO.STREAM = IO.ROS[]; pfp: IOUtils.PFProcs = IOUtils.CopyPFProcs[s]; tvl: LIST OF IO.Value _ NIL; [] _ IOUtils.SetPFCodeProc[pfProcs: pfp, char: 'j, codeProc: JunkIt]; [] _ IOUtils.SetPFProcs[stream: s, pfProcs: pfp]; WITH vl.first SELECT FROM l: LIST OF IO.Value => IO.PutFL[s, format, l]; l: LIST OF REF ANY => {tvl _ ToValueList[l]; IO.PutFL[s, format, tvl]}; ENDCASE => {tvl _ ToValueList[LIST[vl.first]]; IO.PutF[s, format, tvl.first]}; rev _ CONS[IO.RopeFromROS[s], rev]; ENDLOOP; result _ NIL; WHILE rev # NIL DO result _ CONS[rev.first, result]; rev _ rev.rest; ENDLOOP; }; JunkIt: PROC [ stream: IO.STREAM, val: IO.Value, format: IOUtils.Format, char: CHAR ] -- IOUtils.PFCodeProc -- = {NULL}; DoCommandRopeList: PROC [ parent: Commander.Handle, l: LIST OF Rope.ROPE ] RETURNS [ out: Rope.ROPE, result: REF ANY ] = { TRUSTED {[out, result] _ DoCommandList[parent, LOOPHOLE[l, LIST OF REF ANY]]}; }; DoCommandList: PROC [ parent: Commander.Handle, l: LIST OF REF ANY ] RETURNS [ out: Rope.ROPE, result: REF ANY ] = { s: IO.STREAM = IO.ROS[]; IF parent = NIL THEN parent _ NEW[Commander.CommandObject _ [out: s]]; FOR rl: LIST OF REF ANY _ l, rl.rest WHILE rl # NIL DO [out, result] _ CommandTool.DoCommandRope[commandLine: NARROW[rl.first], parent: parent]; IO.Put[s, IO.rope[out]]; IF result = $Failure THEN EXIT; ENDLOOP; out _ IO.RopeFromROS[s]; }; 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.