<> <> <> <> <> <> <<>> DIRECTORY Boole, BooleCore, CD, CDBasics, CDDirectory, CDInstances, CDProperties, CDRects, CMosB, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, RefTab, GList, IO, PW, PWCore, Rope, Sinix, Sisyph, TilingClass, TerminalIO; BooleCoreImpl: CEDAR PROGRAM IMPORTS Boole, CD, CDBasics, CDDirectory, CDInstances, CDProperties, CDRects, CMosB, CoreClasses, CoreCreate, CoreOps, CoreProperties, RefTab, GList, 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; cellLibrary: PRIVATE CD.Design _ NIL; GetCellLibrary: PUBLIC PROC RETURNS [CD.Design] = { IF cellLibrary#NIL THEN RETURN [cellLibrary]; cellLibrary _ PW.OpenDesign["BooleLibrary"]; RETURN [cellLibrary]; }; GetCellLibraryCell: PUBLIC PROC [name: ROPE] RETURNS [CellType _ NIL] = { name _ Rope.Cat[name, ".sch"]; IF CDDirectory.Fetch[GetCellLibrary[], name].object=NIL THEN RETURN [NIL]; RETURN [Sisyph.ES[name, Sisyph.Create[GetCellLibrary[]]]]; }; <> 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: RefTab.Ref, source: Expression] RETURNS [Expression] = { whenTrue, whenFalse: Expression; var: Variable = Boole.FindVar[source]; newVar: Variable _ NARROW [RefTab.Fetch[wireToRefInt, var].val]; 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.PutF["*** 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.PutF["*** 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[GetCellLibrary[], IO.PutR[IO.atom[case], IO.rope[".mask"]]].object; }; CoreCell: PROC [case: ATOM] RETURNS [cellType: CellType] = { schCell: CD.Object _ CDDirectory.Fetch[GetCellLibrary[], IO.PutR[IO.atom[case], IO.rope[".sch"]]].object; IF schCell=NIL THEN { obj: CD.Object _ CDDirectory.Fetch[GetCellLibrary[], IO.PutR[IO.atom[case], IO.rope[".mask"]]].object; cellType _ PWCore.FromLayoutWithoutPublic[obj]; RETURN; }; cellType _ NARROW [Sinix.Extract[schCell, Sisyph.mode, NIL, Sisyph.Create[GetCellLibrary[]]].result]; }; AddCaseCellsInLibrary: PW.GeneratorProc = { size: CD.Position = [8* AtomicTile: TYPE = {nope, gnd, trans}; masks: ARRAY AtomicTile OF CD.Object _ [PW.Get[GetCellLibrary[], "AtomicNope.mask"], PW.Get[GetCellLibrary[], "AtomicGnd.mask"], PW.Get[GetCellLibrary[], "AtomicTrans.mask"]]; Square: PROC [name: ATOM, upLeft, upRight, lowLeft, lowRight: AtomicTile] RETURNS [cell: CD.Object] = { IncludeMask: PROC [mask: CD.Object, pos: CD.Position, orient: CD.Orientation] = { instances _ CONS [CDInstances.NewInst[mask, [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[mask], [[0, 0], orient]]]], orient]], instances]; }; IncludePin: PROC [name: ROPE, layer: CD.Layer, pos: CD.Position, size: CD.Position] = { inst: CD.Instance = CDInstances.NewInst[CDRects.CreateRect[size, layer], [pos]]; instances _ CONS [inst, instances]; CDProperties.PutInstanceProp[inst, $SignalName, name]; }; instances: CD.InstanceList _ NIL; IncludeMask[masks[upLeft], [0, size.y], original]; IncludeMask[masks[upRight], size, mirrorX]; IncludeMask[masks[lowLeft], [0, 0], rotate180X]; IncludeMask[masks[lowRight], [size.x, 0], rotate180]; IncludePin["Input", CMosB.pol, [3* IncludePin["Input", CMosB.met2, [2* IncludePin["NotInput", CMosB.pol, [11* IncludePin["NotInput", CMosB.met2, [10* IncludePin["Gnd", CMosB.met, [0, 10* IncludePin["Plus", CMosB.met, [14* IncludePin["Minus", CMosB.met, [14* IF upLeft=trans OR upRight=trans THEN IncludePin["PlusLeft", CMosB.met, [0, 19* IF lowLeft=trans OR lowRight=trans THEN IncludePin["MinusLeft", CMosB.met, [0, 2* cell _ PW.CreateCell[instances, [0, 0, 2*size.x, 2*size.y]]; cell _ PW.Flatten[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: RefTab.Ref _ RefTab.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; [] _ RefTab.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; TerminalIO.PutF["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[NARROW[GList.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: case=$CaseXX OR case=$CaseNull, 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]]]; ENDLOOP; FillArray[expr, nbInput, 0, size]; TerminalIO.PutF["%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.RegisterGenerator[AddCaseCellsInLibrary, "AddCaseCellsInLibrary"]; END.