<> <> <> <> <> <> <<>> DIRECTORY Boole, BooleCore, CD, CDDirectory, CDSymbolicObjects, CMosB, Core, CoreClasses, CoreCreate, CoreIO, CoreOps, CoreProperties, IO, PW, PWCore, Rope, RopeList, Rosemary, Ports, Sinix, Sisyph, TerminalIO; BooleCoreImpl: CEDAR PROGRAM IMPORTS Boole, CD, CDDirectory, CDSymbolicObjects, CMosB, CoreClasses, CoreCreate, CoreIO, CoreOps, CoreProperties, IO, PW, PWCore, Rope, RopeList, Rosemary, Ports, Sinix, Sisyph, TerminalIO EXPORTS BooleCore SHARES Boole = BEGIN OPEN BooleCore; <> false: Expression = Boole.false; Signal: SIGNAL = CODE; true: Expression = Boole.true; debug: BOOL _ TRUE; <> ExprVars: TYPE = REF ExprVarsRec; ExprVarsRec: TYPE = RECORD [ expr: Expression, vars: LIST OF ROPE, -- the order in which variables should be size: NAT _ 0 -- filled by the recast proc: nb of lines for this ordering ]; alpsClass: PUBLIC Core.CellClass _ CoreIO.RegisterClass[ Rosemary.BindCellClass[NEW [Core.CellClassRec _ [name: "Alps", recast: RecastAlps, properties: CoreProperties.Props[[PWCore.layoutAtomProp, $Recast]]]], Rosemary.Register["AlpsRoseClass", InitAlps, EvalAlps]], WriteAlps, ReadAlps]; <> <> <> <> <> WriteAlps: CoreIO.ClassWriteProc = { data: ExprVars _ NARROW[cellType.data]; CoreIO.WriteRope[h, Boole.ToRope[data.expr, LAST[INT]]]; CoreIO.WriteListOfRope[h, data.vars]; CoreIO.WriteInt[h, data.size]; }; <<>> ReadAlps: CoreIO.ClassReadProc = { data: ExprVars _ NEW[ExprVarsRec]; data.expr _ Boole.FromRope[CoreIO.ReadRope[h]]; data.vars _ CoreIO.ReadListOfRope[h]; data.size _ CoreIO.ReadInt[h]; cellType.data _ data; }; <<>> CreateAlps: PROC [inputVars: LIST OF ROPE, expr: Expression, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [alps: CellType] = { input: Wire _ CreatePlusMinusN[name: "Input", names: inputVars]; data: ExprVars _ NEW [ExprVarsRec _ [expr: expr, vars: inputVars]]; CheckVarsOfExprInVars[expr, inputVars]; alps _ CoreOps.CreateCellType[ class: alpsClass, public: CoreOps.CreateWire[LIST [ InitPort[input], InitPort[CreatePlusMinus[name: "Output"]], InitPort[CoreOps.CreateWire[name: "Gnd"]], InitPort[CoreOps.CreateWire[name: "Vdd"]] ]], data: data, name: name, props: props ]; [] _ Rosemary.AddCutSets[alps, "AlpsCell"]; }; Input: NAT = 0; Output: NAT = 1; Gnd: NAT = 2; Vdd: NAT = 3; Plus: NAT = 0; Minus: NAT = 1; InitAlps: Rosemary.InitProc = { stateAny _ cellType; }; inputXmeansX: PUBLIC BOOL _ TRUE; PlusMinusLevel: PROC [p: Ports.Port] RETURNS [l: Ports.Level] = { l _ SELECT TRUE FROM p[Plus].l=L AND p[Minus].l=H => L, p[Plus].l=H AND p[Minus].l=L => H, ENDCASE => X; }; EvalAlps: Rosemary.EvalProc = { cellType: CellType _ NARROW [stateAny]; exprVars: ExprVars _ NARROW [cellType.data]; expr: Expression _ exprVars.expr; vars: LIST OF ROPE _ exprVars.vars; input: Wire _ cellType.public[Input]; <> p[Output][Plus].l _ X; p[Output][Plus].d _ drive; p[Output][Minus].l _ X; p[Output][Minus].d _ drive; <> IF p[Gnd].l#L THEN RETURN; IF p[Vdd].l#H THEN RETURN; <> WHILE Boole.FindVar[expr]#NIL DO var: ROPE _ Boole.FindVar[expr]; index: NAT _ 0; UNTIL Rope.Equal[CoreOps.GetShortWireName[input[index]], var] DO index _ index + 1 ENDLOOP; SELECT PlusMinusLevel[p[Input][index]] FROM L => expr _ Boole.Eval[var, expr].whenFalse; H => expr _ Boole.Eval[var, expr].whenTrue; ENDCASE => { IF ~inputXmeansX THEN <> FOR i: NAT IN [0..p[Input].size) DO rope: ROPE _ CoreOps.GetShortWireName[input[i]]; SELECT PlusMinusLevel[p[Input][i]] FROM L => expr _ Boole.Eval[rope, expr].whenFalse; H => expr _ Boole.Eval[rope, expr].whenTrue; ENDCASE; ENDLOOP; EXIT; }; ENDLOOP; <> SELECT expr FROM false => {p[Output][Plus].d _ none; p[Output][Minus].l _ L; p[Output][Minus].d _ drive}; true => {p[Output][Plus].l _ L; p[Output][Plus].d _ drive; p[Output][Minus].d _ none}; ENDCASE; }; RecastAlps: Core.RecastProc = { AlpsArrayLine: TYPE = REF AlpsArrayLineRec; AlpsArrayLineRec: TYPE = RECORD [c: SEQUENCE size: NAT OF ATOM]; AlpsArray: TYPE = REF AlpsArrayRec; AlpsArrayRec: TYPE = RECORD [c: SEQUENCE size: NAT OF AlpsArrayLine]; exprVars: ExprVars _ NARROW [me.data]; expr: Expression _ exprVars.expr; vars: LIST OF ROPE _ exprVars.vars; nbInput: NAT = me.public[Input].size; revVars: LIST OF ROPE _ RopeList.Reverse[vars]; size: NAT _ Size[revVars, expr]; alpsArray: AlpsArray _ NEW [AlpsArrayRec[size]]; FillArray: PROC [expr: Expression, input: NAT, minLine, nbLines: NAT] = { FillSubColumn: PROC [case: ATOM, min: NAT, nb: NAT] = { FOR i: NAT IN [min .. min+nb) DO alpsArray[i][input-1] _ case ENDLOOP; }; FillColumn: PROC [case: ATOM] = {FillSubColumn[case, minLine, nbLines]}; Empty: PROC = { FOR i: NAT IN [minLine .. minLine+nbLines) DO FOR j: NAT IN [0 .. input-1) DO alpsArray[i][j] _ $CaseNull ENDLOOP; ENDLOOP; }; var: ROPE _ CoreOps.GetShortWireName[me.public[Input][input-1]]; whenTrue, whenFalse: Expression; case: ATOM; [whenTrue, whenFalse] _ Boole.Eval[var, expr]; case _ Boole.Case[whenTrue, whenFalse]; SELECT case FROM $Case11, $Case00, $Case10, $Case01 => {FillColumn[case]; Empty[]}; $Case1X, $Case0X, $CaseXX => { FillColumn[case]; FillArray[whenFalse, input-1, minLine, nbLines]; }; $CaseX1, $CaseX0 => { FillColumn[case]; FillArray[whenTrue, input-1, minLine, nbLines]; }; $CaseXY => { sizeTrue: NAT _ Size[revVars, whenTrue]; sizeFalse: NAT _ Size[revVars, whenFalse]; IF sizeTrue+sizeFalse#nbLines THEN Signal[]; FillSubColumn[$CaseTX, minLine, sizeTrue]; FillArray[whenTrue, input-1, minLine, sizeTrue]; FillSubColumn[$CaseXT, minLine+sizeTrue, sizeFalse]; FillArray[whenFalse, input-1, minLine+sizeTrue, sizeFalse]; }; ENDCASE => ERROR; }; instances: LIST OF CoreCreate.CellInstance _ NIL; exprVars.size _ size; FOR i: NAT IN [0 .. size) DO alpsArray[i] _ NEW [AlpsArrayLineRec[nbInput]]; FOR j: NAT IN [0 .. nbInput) DO alpsArray[i][j] _ $Undefined ENDLOOP; ENDLOOP; FillArray[expr, nbInput, 0, size]; FOR i: NAT DECREASING IN [0 .. size) DO linePublic: Wire _ CoreOps.CopyWire[me.public]; line: CellType; abutInstances: LIST OF PWCore.AbutInstance _ LIST [[ CDCell[SELECT TRUE FROM size=1 => $AlpsRouteNone, i=size-1 => $AlpsRouteTop, i=0 => $AlpsRouteBottom, ENDCASE => $AlpsRoute], LIST [ ["Plus", linePublic[Output][Plus]], ["Minus", linePublic[Output][Minus]], ["Gnd", linePublic[Gnd]], ["Vdd", linePublic[Vdd]] ] ]]; FOR j: NAT DECREASING IN [0 .. nbInput) DO abutInstances _ CONS [ [CDCell[alpsArray[i][j]], LIST [ ["Input", linePublic[Input][j][Plus]], ["NotInput", linePublic[Input][j][Minus]] ]], abutInstances]; ENDLOOP; line _ PWCore.AbutCell[linePublic, abutInstances, TRUE, FALSE]; instances _ CONS [CoreCreate.Instance[line], instances]; ENDLOOP; TerminalIO.WriteF["%gExpression %g laid out: %g lines.\n", IO.rope[IF size=1 THEN NIL ELSE "*** "], IO.rope[Boole.ToRope[expr]], IO.int[size]]; IF size=1 THEN RETURN [instances.first.type]; new _ CoreCreate.Cell[public: CoreOps.CopyWire[me.public], instances: instances]; PWCore.SetAbutY[new]; }; <> CheckAtomic: PROC [public: Wire, name: ROPE] = { wire: Wire _ CoreCreate.FindWire[public, name]; IF wire=NIL OR wire.size#0 THEN { TerminalIO.WriteF["*** Atomic wire %g does not appear correctly in public\n", IO.rope[name]]; Signal[]; }; }; CheckPlusMinus: PROC [public: Wire, name: ROPE] = { wire: Wire _ CoreCreate.FindWire[public, name]; IF wire=NIL OR wire.size#2 OR ~Rope.Equal[CoreOps.GetShortWireName[wire[0]], "Plus"] OR wire[0].size#0 OR ~Rope.Equal[CoreOps.GetShortWireName[wire[1]], "Minus"] OR wire[1].size#0 THEN { TerminalIO.WriteF["*** Structured (Plus, Minus) wire %g does not appear correctly in public\n", IO.rope[name]]; Signal[]; }; }; CheckVarsOfExprInVars: PROC [expr: Expression, vars: LIST OF ROPE] = { var: ROPE _ Boole.FindVar[expr]; whenTrue, whenFalse: Expression; IF var=NIL THEN RETURN; IF ~RopeList.Memb[vars, var] THEN { TerminalIO.WriteF["*** Expression contains %g which is not an input\n", IO.rope[var]]; Signal[]; }; [whenTrue, whenFalse] _ Boole.Eval[var, expr]; CheckVarsOfExprInVars[whenTrue, vars]; CheckVarsOfExprInVars[whenFalse, vars]; }; CreatePlusMinusN: PUBLIC PROC [name: ROPE, names: LIST OF ROPE] RETURNS [wire: Wire] = { wire _ CoreOps.CreateWires[size: RopeList.Length[names], name: name]; FOR i: NAT IN [0 .. NAT [RopeList.Length[names]]) DO wire[i] _ CreatePlusMinus[name: names.first]; names _ names.rest; ENDLOOP; }; CreatePlusMinus: PUBLIC PROC [name: ROPE] RETURNS [wire: Wire] = { wire _ CoreOps.CreateWire[ elements: LIST [CoreOps.CreateWire[name: "Plus"], CoreOps.CreateWire[name: "Minus"]], name: name]; }; <> InitPort: PROC [wire: Core.Wire] RETURNS [sameWire: Core.Wire] = { sameWire _ IF wire.size=0 THEN Ports.InitPort[wire, l] ELSE wire; FOR i: NAT IN [0 .. wire.size) DO [] _ InitPort[wire[i]] ENDLOOP; }; cellLibrary: PUBLIC CD.Design _ PW.OpenDesign["BooleLibrary"]; cx: PUBLIC Sisyph.Context _ Sisyph.Create[cellLibrary]; CDCell: PROC [case: ATOM, makeCellType: BOOL _ TRUE] RETURNS [obj: CD.Object] = { cellType: CellType; schCell: CD.Object _ CDDirectory.Fetch[cellLibrary, IO.PutR[IO.atom[case], IO.rope[".sch"]]].object; IF schCell=NIL THEN { maskCell: CD.Object _ CDDirectory.Fetch[cellLibrary, IO.PutR[IO.atom[case], IO.rope[".mask"]]].object; IF maskCell=NIL THEN Signal[]; IF makeCellType THEN cellType _ PWCore.FromLayoutWithoutPublic[maskCell]; RETURN [maskCell]; }; cellType _ NARROW [Sinix.Extract[schCell, Sisyph.sisyphMode, NIL, cx].result]; PWCore.SetGet[cellType, cellLibrary]; obj _ PWCore.Layout[cellType]; }; AddCaseCellsInLibrary: PW.UserProc = { size: CD.Position = [8* AtomicTile: TYPE = {nope, gnd, trans}; masks: ARRAY AtomicTile OF CD.Object _ [PW.Get[cellLibrary, "AtomicNope.mask"], PW.Get[cellLibrary, "AtomicGnd.mask"], PW.Get[cellLibrary, "AtomicTrans.mask"]]; IncludePin: PROC [cell: CD.Object, name: ROPE, layer: CD.Layer, pos: CD.Position, size: CD.Position] = { pin: CD.Instance _ PW.IncludeInCell[cell, CDSymbolicObjects.CreatePin[size], pos]; CDSymbolicObjects.SetName[pin, name]; CDSymbolicObjects.SetLayer[pin, layer]; }; Square: PROC [name: ATOM, upLeft, upRight, lowLeft, lowRight: AtomicTile] RETURNS [cell: CD.Object] = { cell _ PW.CreateEmptyCell[]; [] _ PW.IncludeInCell[cell, masks[upLeft], [0, size.y]]; [] _ PW.IncludeInCell[cell, masks[upRight], size, 1]; [] _ PW.IncludeInCell[cell, masks[lowLeft], [0, 0], 5]; [] _ PW.IncludeInCell[cell, masks[lowRight], [size.x, 0], 4]; CDCells.SetInterestRect[cell, [0, 0, 2*size.x, 2*size.y]]; IncludePin[cell, "Input", CMosB.pol, [3* IncludePin[cell, "Input", CMosB.met2, [2* IncludePin[cell, "NotInput", CMosB.pol, [11* IncludePin[cell, "NotInput", CMosB.met2, [10* IncludePin[cell, "Gnd", CMosB.met, [0, 10* IncludePin[cell, "Plus", CMosB.met, [14* IncludePin[cell, "Minus", CMosB.met, [14* IF upLeft=trans OR upRight=trans THEN IncludePin[cell, "PlusLeft", CMosB.met, [0, 18* IF lowLeft=trans OR lowRight=trans THEN IncludePin[cell, "MinusLeft", CMosB.met, [0, 2* PW.RepositionCell[cell]; [] _ CDDirectory.Include[design, cell, IO.PutFR["%g.mask", IO.atom[name]]]; CoreOps.Print[Sinix.Extract[cell, PWCore.extractMode].result, TerminalIO.TOS[]]; }; RETURN [PW.AbutListX[LIST [ Square[$Case11, gnd, gnd, nope, nope], Square[$Case00, nope, nope, gnd, gnd], Square[$Case10, gnd, nope, nope, gnd], Square[$Case01, nope, gnd, gnd, nope], Square[$Case1X, gnd, nope, nope, trans], Square[$Case0X, nope, trans, gnd, nope], Square[$CaseX1, nope, gnd, trans, nope], Square[$CaseX0, trans, nope, nope, gnd], Square[$CaseXX, nope, nope, nope, nope], Square[$CaseTX, trans, nope, trans, nope], Square[$CaseXT, nope, trans, nope, trans] ]]]; }; FindWires: PROC [name: ROPE, internals: Wires] RETURNS [wire: Wire _ NIL] = { WHILE internals#NIL DO IF Rope.Equal[CoreOps.GetShortWireName[internals.first], name] THEN RETURN [internals.first]; internals _ internals.rest; ENDLOOP; }; <> CreateAlpsRow: PROC [inputVars: LIST OF ROPE, output: OutputRec, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [recordCell: CellType, futureBindings: LIST OF PA _ NIL] = { instances: LIST OF CoreClasses.CellInstance _ NIL; internal: Wire _ CreatePlusMinus[name: "OutputPlusMinus"]; bindings: LIST OF PA _ LIST [["Input", internal]]; input: Wire _ CreatePlusMinusN[name: "Input", names: inputVars]; publics: Wires _ LIST [input, CoreOps.CreateWire[name: "Output"], CoreOps.CreateWire[name: "Gnd"], CoreOps.CreateWire[name: "Vdd"]]; CheckPlusMinus[output.driver.public, "Input"]; CheckAtomic[output.driver.public, "Output"]; FOR i: NAT IN [0 .. output.driver.public.size) DO name: ROPE _ CoreOps.GetShortWireName[output.driver.public[i]]; new: Wire _ CoreOps.CopyWire[output.driver.public[i]]; IF CoreOps.GetWireIndex[CoreOps.CreateWire[publics], name]#-1 THEN LOOP; publics _ CONS [new, publics]; FOR pas: LIST OF PA _ output.pas, pas.rest WHILE pas#NIL DO pub: Wire _ CoreCreate.FindWire[output.driver.public, pas.first.public]; IF pub=NIL THEN ERROR; IF pub=output.driver.public[i] THEN { futureBindings _ CONS [[new, pas.first.actual], futureBindings]; bindings _ CONS [[pub, new], bindings]; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; ENDLOOP; recordCell _ CoreCreate.Cell[ public: CoreOps.CreateWire[publics], onlyInternal: CoreOps.CreateWire[LIST [internal]], instances: LIST [ CoreCreate.Instance[CreateAlps[inputVars, Boole.Not[output.expr]], ["Output", internal]], -- Not because of current output drivers CoreCreate.InstanceList[output.driver, bindings] ] ]; PWCore.SetLayout[recordCell, $AlpsRow]; }; AlpsRowLayout: PWCore.LayoutProc = { data: CoreClasses.RecordCellType _ NARROW [cellType.data]; alpsOb: CD.Object _ PWCore.Layout[data[0].type]; alpsData: ExprVars _ NARROW [data[0].type.data]; outputDecoderObjects: LIST OF CD.Object _ LIST [PWCore.Layout[data[1].type]]; IF ((CD.InterestSize[alpsOb].y) MOD (24* IF alpsData.size=1 THEN RETURN [PW.AbutX[alpsOb, outputDecoderObjects.first]]; FOR j: NAT IN [0 .. alpsData.size-1) DO outputDecoderObjects _ CONS [CDCell[$FillerOutputDriver, FALSE], outputDecoderObjects]; ENDLOOP; obj _ PW.AbutX[alpsOb, PW.AbutListY[outputDecoderObjects]]; }; <> <> <> AlpsCell: PUBLIC PROC [public: Wire, inputs: Inputs, outputs: Outputs, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [recordCell: CellType] = { nbIn, nbOut: NAT _ 0; instances: LIST OF CoreClasses.CellInstance _ NIL; inputVars: LIST OF ROPE _ NIL; structuredInputs: Wire; inputWires: Wires _ NIL; CheckAtomic[public, "Gnd"]; CheckAtomic[public, "Vdd"]; WHILE inputs#NIL DO driver: CellType _ inputs.first.driver; pas: LIST OF PA _ inputs.first.pas; input: Wire _ CoreCreate.FindWire[public, inputs.first.input]; inputName: ROPE _ CoreOps.GetFullWireName[public, input]; drivedInput: Wire _ CreatePlusMinus[inputName]; IF input=NIL THEN ERROR; CheckAtomic[driver.public, "Input"]; CheckPlusMinus[driver.public, "Output"]; inputVars _ CONS [inputName, inputVars]; inputWires _ CONS [drivedInput, inputWires]; pas _ CONS [["Output", drivedInput], pas]; pas _ CONS [["Input", input], pas]; instances _ CONS [CoreCreate.InstanceList[driver, pas], instances]; inputs _ inputs.rest; nbIn _ nbIn + 1; ENDLOOP; inputVars _ RopeList.Reverse[inputVars]; structuredInputs _ CoreOps.CreateWire[elements: CoreOps.Reverse[inputWires], name: "PlusMinusInputs"]; WHILE outputs#NIL DO row: CellType; futureBindings: LIST OF PA; output: Wire _ CoreCreate.FindWire[public, outputs.first.output]; outputName: ROPE _ CoreOps.GetFullWireName[public, output]; IF output=NIL THEN ERROR; [row, futureBindings] _ CreateAlpsRow[inputVars, outputs.first, outputName]; futureBindings _ CONS [["Input", structuredInputs], futureBindings]; futureBindings _ CONS [["Output", output], futureBindings]; instances _ CONS [CoreCreate.InstanceList[row, futureBindings], instances]; outputs _ outputs.rest; nbOut _ nbOut + 1; ENDLOOP; PW.WriteF["Core for AlpsCell done: %g inputs and %g outputs\n", IO.int[nbIn], IO.int[nbOut]]; recordCell _ CoreCreate.Cell[ public: public, onlyInternal: CoreOps.CreateWire[LIST [structuredInputs]], instances: CoreClasses.ReverseCellInstances[instances], name: name, props: props ]; CoreProperties.PutCellTypeProp[recordCell, $NbIn, NEW [INT _ nbIn]]; PWCore.SetLayout[recordCell, $FullAlpsCell]; }; FullAlpsCellLayout: PWCore.LayoutProc = { refNbIn: REF INT _ NARROW [CoreProperties.GetCellTypeProp[cellType, $NbIn]]; nbIn: INT _ refNbIn^; data: CoreClasses.RecordCellType _ NARROW [cellType.data]; refContactPolyMetal2: REF INT _ NARROW [CoreProperties.GetCellTypeProp[cellType, $ContactPolyMetal2]]; contactPolyMetal2: INT _ IF refContactPolyMetal2=NIL THEN LAST [INT] ELSE refContactPolyMetal2^; distanceSinceLastContact: INT _ 0; i: NAT _ 0; lineObjects: LIST OF CD.Object; -- lines from top to bottom (during construction) contactLine: CD.Object; <> contacts: LIST OF CD.Object _ LIST [CDCell[$ContactPolyMetal2Route, FALSE], CDCell[$ContactPolyMetal2OutputFiller, FALSE]]; THROUGH [0 .. nbIn) DO contacts _ CONS [CDCell[$ContactPolyMetal2, FALSE], contacts] ENDLOOP; contactLine _ PW.AbutListX[contacts]; <> BEGIN inputDriversObjects: LIST OF CD.Object _ NIL; WHILE i> WHILE i=contactPolyMetal2 THEN { lineObjects _ CONS [contactLine, lineObjects]; distanceSinceLastContact _ 0; }; i _ i + 1; ENDLOOP; obj _ PW.AbutListY[PW.Reverse[lineObjects]]; }; DecorateFullAlpsCell: PWCore.DecorateProc = { Sort: PROC [pos1, pos2: CD.Position] RETURNS [BOOL] = { RETURN [pos1.y=max THEN int _ int - max ELSE var _ Boole.Not[var]; expr _ Boole.And[var, expr]; }; wire: Wire _ NARROW [wr]; count: NAT _ CoreOps.WireBits[wire]; max: INT _ 1; WHILE count>0 DO max _ max * 2; count _ count -1 ENDLOOP; IF int>=max THEN Signal[]; expr _ true; CoreOps.VisitAtomicWires[wire, Andify]; IF int#0 THEN Signal[]; }; <> Size: PUBLIC PROC [vars: LIST OF ROPE, expr: Expression] RETURNS [size: INT _ 1] = { whenTrue, whenFalse: Expression; IF vars=NIL THEN {IF expr#true AND expr#false THEN ERROR; RETURN}; [whenTrue, whenFalse] _ Boole.Eval[vars.first, expr]; SELECT Boole.Case[whenTrue, whenFalse] FROM $Case11, $Case00, $Case10, $Case01 => RETURN; $Case1X, $Case0X, $CaseXX => RETURN [Size[vars.rest, whenFalse]]; $CaseX1, $CaseX0 => RETURN [Size[vars.rest, whenTrue]]; $CaseXY => RETURN [Size[vars.rest, whenTrue] + Size[vars.rest, whenFalse]]; ENDCASE => ERROR; }; <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <<[whenTrue, whenFalse] _ Boole.Eval[var, expr];>> <> <> <> <<};>> coreBoolePermuteProp: PUBLIC ATOM _ CoreProperties.RegisterProperty[$BoolePermuteProp]; Permute: PUBLIC PROC [expr: Expression, public: Wire] RETURNS [bestPermutedExpr: Expression, bestPermutedWire: Wire] = { <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> <