<> <> <> <> <> <> <<>> DIRECTORY Boole, BooleCore, CD, CDDirectory, CDSymbolicObjects, CMosB, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, HashTable, IO, PW, PWCore, Rope, Sinix, Sisyph, TilingClass, TerminalIO; BooleCoreImpl: CEDAR PROGRAM IMPORTS Boole, CD, CDDirectory, CDSymbolicObjects, CMosB, CoreClasses, CoreCreate, CoreOps, CoreProperties, HashTable, IO, PW, PWCore, Rope, Sinix, Sisyph, TilingClass, TerminalIO EXPORTS BooleCore SHARES Boole = BEGIN OPEN BooleCore; <> false: Expression = Boole.false; true: Expression = Boole.true; Signal: SIGNAL = CODE; debug: BOOL _ TRUE; <> EqualInt: PUBLIC PROC [wire: Wire, int: INT] RETURNS [expr: Expression] = { Andify: PROC [wire: Wire] = { var: Variable _ wire; max _ max / 2; IF int>=max THEN int _ int - max ELSE var _ Boole.Not[var]; expr _ Boole.And[var, expr]; }; 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.VisitRootAtomics[wire, Andify]; IF int#0 THEN Signal[]; }; <> TranslateVar: PROC [wireToRefInt: HashTable.Table, source: Expression] RETURNS [Expression] = { whenTrue, whenFalse: Expression; var: Variable = Boole.FindVar[source]; newVar: Variable _ NARROW [HashTable.Fetch[wireToRefInt, var].value]; IF source=true OR source=false THEN RETURN [source]; [whenTrue, whenFalse] _ Boole.Eval[var, source]; IF newVar=NIL THEN ERROR; -- variable is not an input wire! RETURN [Boole.If[newVar, TranslateVar[wireToRefInt, whenTrue], TranslateVar[wireToRefInt, whenFalse]]]; }; 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[]; }; }; CreatePlusMinus: PUBLIC PROC [name: ROPE] RETURNS [wire: Wire] = { wire _ CoreOps.CreateWire[ elements: LIST [CoreOps.CreateWire[name: "Plus"], CoreOps.CreateWire[name: "Minus"]], name: name]; }; CDCell: PROC [case: ATOM] RETURNS [obj: CD.Object] = { obj _ CDDirectory.Fetch[cellLibrary, IO.PutR[IO.atom[case], IO.rope[".mask"]]].object; }; CoreCell: PROC [case: ATOM] RETURNS [cellType: CellType] = { schCell: CD.Object _ CDDirectory.Fetch[cellLibrary, IO.PutR[IO.atom[case], IO.rope[".sch"]]].object; IF schCell=NIL THEN { obj: CD.Object _ CDDirectory.Fetch[cellLibrary, IO.PutR[IO.atom[case], IO.rope[".mask"]]].object; cellType _ PWCore.FromLayoutWithoutPublic[obj]; RETURN; }; cellType _ NARROW [Sinix.Extract[schCell, Sisyph.mode, NIL, cx].result]; PWCore.SetGet[cellType, cellLibrary]; }; cellLibrary: PUBLIC CD.Design _ PW.OpenDesign["BooleLibrary"]; cx: Sisyph.Context _ Sisyph.Create[cellLibrary]; 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] ]]]; }; <> <> <> <> AlpsCell: PUBLIC PROC [public: Wire, inputs: Inputs, outputs: Outputs, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [recordCell: CellType] = { wireToRefInt: HashTable.Table _ HashTable.Create[]; nbIn, nbOut: NAT _ 0; instances: LIST OF CoreClasses.CellInstance _ NIL; structuredInputs: Wire; -- each of the nbIn wires is a Plus-Minus inputWires: Wires _ NIL; -- aux. var. 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]; drivedInput: Wire _ CreatePlusMinus[CoreOps.GetFullWireName[public, input]]; IF input=NIL THEN ERROR; [] _ HashTable.Store[wireToRefInt, input, NEW [INT _ nbIn]]; CheckAtomic[driver.public, "Input"]; CheckPlusMinus[driver.public, "Output"]; 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; structuredInputs _ CoreOps.CreateWire[elements: CoreOps.Reverse[inputWires], name: "PlusMinusInputs"]; WHILE outputs#NIL DO driver: CellType = outputs.first.driver; row: CellType; subPas: LIST OF PA _ NIL; rowPas: LIST OF PA _ NIL; output: Wire _ CoreCreate.FindWire[public, outputs.first.output]; outputName: ROPE _ CoreOps.GetFullWireName[public, output]; subInput: Wire = CoreOps.SetShortWireName[CoreOps.CopyWire[structuredInputs], "Input"]; subPublic: Wire _ CoreOps.CreateWire[LIST [ subInput, CoreOps.CreateWire[name: "Output"], CoreOps.CreateWire[name: "Gnd"], CoreOps.CreateWire[name: "Vdd"] ]]; IF output=NIL THEN ERROR; <<-- let us add the top level wires of output.driver.public>> FOR i: NAT IN [0 .. driver.public.size) DO name: ROPE _ CoreOps.GetShortWireName[driver.public[i]]; new: Wire _ CoreOps.CopyWire[driver.public[i]]; IF CoreOps.GetWireIndex[subPublic, name]#-1 THEN LOOP; -- easy one! subPublic _ CoreOps.UnionWire[subPublic, CoreOps.CreateWire[LIST [new]]]; FOR pas: LIST OF PA _ outputs.first.pas, pas.rest WHILE pas#NIL DO pub: Wire _ CoreCreate.FindWire[driver.public, pas.first.public]; IF pub=NIL THEN ERROR; IF pub=driver.public[i] THEN { subPas _ CONS [[new, pas.first.actual], subPas]; rowPas _ CONS [[pub, new], rowPas]; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; ENDLOOP; row _ CreateAlps[subPublic, TranslateVar[wireToRefInt, Boole.Not[outputs.first.expr]], driver, rowPas, outputName]; -- Not because of current output drivers subPas _ CONS [["Input", structuredInputs], subPas]; subPas _ CONS [["Output", output], subPas]; instances _ CONS [CoreCreate.InstanceList[row, subPas], 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], CDCell[$ContactPolyMetal2OutputFiller]]; THROUGH [0 .. nbIn) DO contacts _ CONS [CDCell[$ContactPolyMetal2], 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> Plus: NAT = 0; Minus: NAT = 1; <<>> <> <> CreateAlps: PROC [public: Wire, expr: Expression, driver: CellType, pas: LIST OF PA, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [alps: CellType] = { Tile: PROC [i, j: NAT, case: ATOM, renaming: LIST OF TilingClass.PA] = { alpsArray[i][j] _ NEW [TilingClass.TileRec _ [ type: CoreCell[case], flatten: TRUE, renaming: renaming ]]; }; Size: PROC [input: NAT, expr: Expression] RETURNS [size: INT _ 1] = { whenTrue, whenFalse: Expression; IF input=0 THEN {IF expr#true AND expr#false THEN ERROR; RETURN}; [whenTrue, whenFalse] _ Boole.Eval[NEW [INT _ input-1], expr]; SELECT Boole.Case[whenTrue, whenFalse] FROM $Case11, $Case00, $Case10, $Case01 => RETURN; $Case1X, $Case0X, $CaseXX => RETURN [Size[input-1, whenFalse]]; $CaseX1, $CaseX0 => RETURN [Size[input-1, whenTrue]]; $CaseXY => RETURN [Size[input-1, whenTrue] + Size[input-1, whenFalse]]; ENDCASE => ERROR; }; 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 Tile [i, input-1, case, LIST [ ["Input", Input[input-1][Plus]], ["NotInput", Input[input-1][Minus]], ["Gnd", "Gnd"] ]]; 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 Tile[i, j, $CaseNull, LIST [ ["Input", Input[j][Plus]], ["NotInput", Input[j][Minus]], ["Gnd", "Gnd"] ]]; ENDLOOP; ENDLOOP; }; var: Variable _ NEW [INT _ 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[input-1, whenTrue]; sizeFalse: NAT _ Size[input-1, 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; }; inputIndex: INT _ CoreOps.GetWireIndex[public, "Input"]; Input: Wire = public[NAT[inputIndex]]; -- this avoid CoreOps.FindWire[public, "Input"] which cost much, much more (creates a name cache) nbInput: NAT = Input.size; size: NAT = Size[nbInput, expr]; alpsArray: TilingClass.TileArray = NEW [TilingClass.TileArrayRec[size]]; CheckPlusMinus[driver.public, "Input"]; CheckAtomic[driver.public, "Output"]; pas _ CONS [["Gnd", "Gnd"], pas]; pas _ CONS [["Vdd", "Vdd"], pas]; pas _ CONS [["Output", "Output"], pas]; FOR i: NAT IN [0 .. size) DO alpsArray[i] _ NEW [TilingClass.TileRowRec[nbInput+2]]; -- last Tiles is for pseudo-routing and driver Tile[ i, nbInput, SELECT TRUE FROM size=1 => $AlpsRouteNone, i=size-1 => $AlpsRouteTop, i=0 => $AlpsRouteBottom, ENDCASE => $AlpsRoute, LIST [["Gnd", "Gnd"], ["Vdd", "Vdd"]] ]; alpsArray[i][nbInput+1] _ IF i=0 THEN NEW [TilingClass.TileRec _ [type: driver, renaming: pas]] ELSE NEW [TilingClass.TileRec _ [type: CoreCell[$FillerOutputDriver], flatten: TRUE]]; ENDLOOP; FillArray[expr, nbInput, 0, size]; TerminalIO.WriteF["%gTiling done for Expression '%g' : %g lines.\n", IO.rope[IF size=1 THEN NIL ELSE "*** "], IO.rope[Boole.ToRope[expr]], IO.int[size]]; alps _ TilingClass.CreateTiling[public: public, tileArray: alpsArray, neighborX: TilingClass.LayoutNeighborX, neighborY: TilingClass.LayoutNeighborY, name: name, props: props]; }; <> [] _ PWCore.RegisterLayoutAtom[$FullAlpsCell, FullAlpsCellLayout, DecorateFullAlpsCell]; IF debug THEN PW.Register[AddCaseCellsInLibrary, "AddCaseCellsInLibrary"]; END.