<> <> <> <> <> <<>> < InstrDecode.ttt >> DIRECTORY Basics, CD, CDFrame, CDPinObjects, IO, PLAOps, PW, IFUPW, IFUPWControl, REFBit, Rope, SymTab, ViewerClasses; IFUPWContPLA: CEDAR PROGRAM IMPORTS Basics, CD, CDFrame, CDPinObjects, IFUPW, IFUPWControl, IO, PLAOps, PW, REFBit, Rope EXPORTS IFUPWControl = BEGIN OPEN IFUPWControl; <<>> MakePLA: PUBLIC PROC [ name: ROPE, plaType: PLAType, drIn, drInClk, plaIn, drOutClk, drOut: Ph_unk, design: CD.Design, orCols: INT_0, termCols: INT_1, fullWidthTerms: BOOL_FALSE, termsPerHeader: INT _ 1000] RETURNS[new: Frame] = { fileName: ROPE _ Rope.Cat["IFUPLA", name, ".ttt"]; desc: IFUPWControl.PLADescription; plaFm, outFm, inFm: Frame; pla: PLAOps.PLA _ PLAOps.ReadPLAFile[fileName, log]; IF plaType = precharged AND termsPerHeader=1000 THEN termsPerHeader_20; outFm _ DrPLA[name, pla, plaType, plaIn, drOutClk, drOut]; desc _ NARROW[outFm.data]; plaFm _ DrivenPLA[ outFm, design, orCols, termCols, fullWidthTerms, termsPerHeader]; inFm _ RefToDriverFrame[name: name.Cat["InDrs"], xory: y, data: NIL, unordered: FALSE, refRec: pla.data, initial: [drDir: in, dualOut: TRUE, in:[pos, drIn], ref:[pos, drInClk], out:[pos, plaIn] ] ]; IF plaType # precharged THEN DeleteUnusedStaticInDrs[desc, inFm]; new _ IFUPW.NFS[name, x, LIST[ CDFrame.Glue[l: ext, r: conn], IFUPW.NFS[name.Cat["Main"], y, LIST[ plaFm, IFUPW.NFS[name.Cat["InputsSBDr"], x, LIST[ CDFrame.Glue[t: conn, r: conn], inFm ] ] ] ] ] ] }; DrPLA: PUBLIC PROC [name: ROPE, pla: PLAOps.PLA, plaType: PLAType, plaIn, plaOut, drOut: Ph_unk] RETURNS[new: Frame] = { desc: REF PLADescriptionRec _ NEW[PLADescriptionRec]; inForm: REFBit.Format _ REFBit.Desc[pla.data].bitForm; outForm: REFBit.Format _ REFBit.Desc[pla.out].bitForm; new _ IFUPWControl.RefToDriverFrame[ name: name, xory: y, data: desc, unordered: TRUE, refRec: pla.out, initial: [drDir: out, in: [neg, plaOut], ref: [pos, plaOut], out: [pos, drOut] ] ]; new _ new[1]; -- throw away xheader and xfooter frames desc.ttt _ pla; desc.name _ name; desc.plaType _ plaType; desc.drFrame _ new; -- can change FOR i: CARDINAL DECREASING IN [0..inForm.size) DO namePos: ROPE _ BitNameToSigName[inForm[i].name]; nameInv: ROPE _ BitNameToSigName[inForm[i].nameInv]; desc.plaInNames _ CONS[ SignalName[TRUE, namePos, nameInv, plaIn], desc.plaInNames]; desc.plaInNames _ CONS[ SignalName[FALSE, namePos, nameInv, plaIn], desc.plaInNames]; ENDLOOP; FOR i: CARDINAL DECREASING IN [0..outForm.size) DO namePos: ROPE _ BitNameToSigName[outForm[i].name]; nameInv: ROPE _ BitNameToSigName[outForm[i].nameInv]; desc.plaOutNames _ CONS[ SignalName[FALSE, namePos, nameInv, plaOut], desc.plaOutNames]; ENDLOOP}; DrivenPLA: PUBLIC PROC [ drFrame: Frame, design: CD.Design, orCols: INT_0, termCols: INT_1, fullWidthTerms: BOOL_FALSE, termsPerHeader: INT _ 1000] RETURNS [new: Frame] = { desc: REF PLADescriptionRec _ NARROW[drFrame.data]; log.PutRope["\n"]; desc.design _ design; desc.drFrame _ drFrame; desc.nofOrCols _ MAX[orCols, desc.nofOrCols]; desc.nofTermCols _ MAX[termCols, desc.nofTermCols]; desc.termsPerHeader _ MIN[termsPerHeader, desc.termsPerHeader]; desc.fullWidthTerms _ fullWidthTerms OR desc.fullWidthTerms; BuildSignalOrderListFromDrFrame[desc]; BuildConnTranslationArray[desc]; SELECT desc.plaType FROM precharged => MakePreChargedPLA[desc]; ENDCASE => MakeStaticPLASection[desc]; new _ CDFrame.NewFrame[2, x, desc.name.Cat["-PlaDr"] ]; new[0] _ CDFrame.NewObjectFrame[desc.cell]; new[1] _ desc.drFrame; log.PutRope["\n"]}; <> <> <> <> <> <> <> <> <> <> <<[(IF xory=y THEN size1.x ELSE 0), (IF xory=x THEN size1.y ELSE 0)]];>> <> <> BuildSignalOrderListFromDrFrame: PUBLIC PROC[desc: REF PLADescriptionRec] = { proc: CDFrame.EnumProc = { rec: REF DriveRec _ NARROW[frame.data]; name: ROPE _ BitNameToSigName[rec.name]; nameInv: ROPE _ BitNameToSigName[rec.nameInv]; desc.drSignalOrder _ CONS[ SignalName[FALSE, name, nameInv, rec.in.ph], desc.drSignalOrder]}; CDFrame.EnumFrameBotOnly[desc.drFrame, proc]; desc.drSignalOrder _ ReverseList[desc.drSignalOrder]}; <> <> <> <> <> <<[pla, drives] _ SELECT desc.plaType FROM>> < MakeStaticPLASection[desc],>> < MakePreChargedPLA[desc],>> < ERROR;>> <> <> <> <> <> <> <> <<[drives, pla] _ CreatePLAFromDesc[desc];>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> BuildConnTranslationArray: PROC [desc: PLADescription ] = { index: INT _ -1; smlOutNames: LIST OF ROPE; log.PutRope["\n Building pla translation array"]; <> desc.connSeq _ NEW[ConnSeq[ListLength[desc.drSignalOrder]]]; FOR list: LIST OF ROPE _ desc.drSignalOrder, list.rest WHILE list#NIL DO pos: INT _ ListItemIndex[desc.plaInNames, list.first]; index _ index+1; IF pos#-1 THEN { desc.connSeq[index] _ [index: pos/2, isOutput: FALSE, isLeftSide: (pos MOD 2 = 0)]; LOOP}; pos _ ListItemIndex[desc.plaOutNames, list.first]; IF pos=-1 THEN ERROR; -- Signal name not found; smlOutNames _ CONS[list.first, smlOutNames]; desc.connSeq[index] _ [index: pos, isOutput: TRUE, isLeftSide: FALSE]; ENDLOOP; smlOutNames _ ReverseList[smlOutNames]; desc.smlToBigOut _ NEW[XsFormSeqRec[ListLength[smlOutNames]]]; FOR i: CARDINAL IN [0..desc.smlToBigOut.size) DO desc.smlToBigOut[i] _ ListItemIndex[desc.plaOutNames, ListIndexItem[smlOutNames, i]] ENDLOOP; desc.plaOutNames _ smlOutNames; IF desc.drFrame#NIL THEN { index: INT _ 0; proc: CDFrame.EnumProc = { desc.connSeq[index].dr _ NARROW[frame.data]; index _ index+1}; CDFrame.EnumFrameBotOnly[desc.drFrame, proc]} }; ZeroUnusedTTTOutputs: PROC [desc: PLADescription ] = { maskTerm: PLAOps.Term _ PLAOps.CopyTerm[desc.ttt.termList.begin]; log.PutRope["\n Zero unused TTT outputs"]; FOR i: CARDINAL IN [0..maskTerm.out.wdSize) DO maskTerm.out[i] _ PLAOps.initOutQrtWz ENDLOOP; FOR index: INT IN [0..desc.smlToBigOut.size) DO pos: INT _ desc.smlToBigOut[index]; PLAOps.SetOutQrt[one, maskTerm, REFBit.Desc[desc.ttt.out].bitForm[pos].firstBit] ENDLOOP; FOR term: PLAOps.Term _ desc.ttt.termList.begin, term.next WHILE term#NIL DO FOR i: CARDINAL IN [0..maskTerm.out.wdSize) DO term.out[i].d _ Basics.BITAND[term.out[i].d, maskTerm.out[i].d] ENDLOOP ENDLOOP }; CheckPLACompress: PROC [desc: PLADescription ] = { IF desc.doCompleteSum THEN { [ ] _ PLAOps.ConvertTermListToCompleteSum[ list: desc.ttt.termList, addMerges: desc.csAddMerges, addConsensus: desc.csAddConsensus, log: log ]}; IF desc.doMinimization THEN { [ ] _ PLAOps.FindAMinimalCover[ list: desc.ttt.termList, time: desc.timeOutMinutes, log: log ]} }; ToRopeList: PROC [ refList: LIST OF REF ] RETURNS [ ropeList: LIST OF ROPE ] = { FOR l: LIST OF REF _ refList, l.rest UNTIL l = NIL DO IF l.first # NIL AND NOT ISTYPE[l.first, ROPE] THEN ERROR; ENDLOOP; TRUSTED {ropeList _ LOOPHOLE[refList]} }; MakePreChargedPLA: PROC[desc: PLADescription] = { ZeroUnusedTTTOutputs [desc]; CheckPLACompress [desc]; DefinePLARows [desc]; MakeOutDrs [desc]; MakePla [desc]}; PreChargedParams: TYPE = RECORD[ minConnSpace: INT _ 2, -- SPACING rows between driver rows; insPerExtra: INT _ 10, -- SPACING cols between extra columns; outsPerExtra: INT _ 10, nextTerm: PLAOps.Term _ NIL, -- specific parameter nextConn: INT _ 0, -- specific parameter rows: REF RowsRec _ NIL ]; -- specific parameter RowsRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF REF RowRec]; RowRec: TYPE = RECORD[ dr: REF DriveRec, type: RowType, and: ColSeqRef, or: ColSeqRef ]; ColSeqRef: TYPE = REF ColSeqRec; ColSeqRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF NormalCellType]; DefinePLARows: PROC [desc: PLADescription] = { pp: REF PreChargedParams _ NEW[PreChargedParams _ [nextTerm: desc.ttt.termList.begin]]; firstRow: BOOL _ TRUE; index: INT _ 0; termUp: BOOL _ TRUE; nofOuts: INT _ MAX[ListLength[desc.plaOutNames], desc.nofOrCols]; nofIns: INT _ ListLength[desc.plaInNames]; cRowsLeft: INT _ ListLength[desc.drSignalOrder]; dRowsLeft: INT _ desc.ttt.termList.length; hRowsLeft: INT; dRowsLeft _ MAX[dRowsLeft, cRowsLeft*(pp.minConnSpace)]; hRowsLeft _ MAX[1, (dRowsLeft+ desc.termsPerHeader/2)/desc.termsPerHeader]; log.PutRope["\n Assign precharged pla row types"]; desc.data _ pp; desc.nofAndCols _ nofIns/2 + (nofIns/2 -1) / pp.insPerExtra; desc.nofOrCols _ nofOuts + (nofOuts -1) / pp.outsPerExtra; pp.rows _ NEW[RowsRec[cRowsLeft+dRowsLeft+2*hRowsLeft]]; WHILE hRowsLeft#0 DO -- actually one more header is appended afterwards RperH: INT _ (cRowsLeft+dRowsLeft+hRowsLeft + hRowsLeft/2)/hRowsLeft; IF firstRow THEN firstRow_FALSE ELSE {pp.rows[index] _ NextRow[desc, xheader]; index_index+1}; pp.rows[index] _ NextRow[desc, header]; index_index+1; RperH_RperH-1; hRowsLeft_hRowsLeft-1; WHILE RperH > 0 DO CperD, DperC: INT; CperD _ MAX[1, (cRowsLeft + dRowsLeft/2)/dRowsLeft]; DperC _ MAX[1, (dRowsLeft + cRowsLeft/2)/cRowsLeft]; IF DperC < pp.minConnSpace OR (CperD>1) AND (pp.minConnSpace>0) THEN ERROR; RperH _ RperH - CperD - DperC; WHILE CperD > 0 DO pp.rows[index] _ NextRow[desc, conn]; index_index+1; cRowsLeft_cRowsLeft-1; CperD_CperD-1; ENDLOOP; termUp _ TRUE; WHILE DperC > 0 DO pp.rows[index] _ NextRow[desc, IF termUp THEN dataUp ELSE dataDn]; index_index+1; dRowsLeft_dRowsLeft-1; DperC_DperC-1; termUp _ NOT termUp; ENDLOOP; ENDLOOP; ENDLOOP; IF index+1#pp.rows.size THEN ERROR; pp.rows[index] _ NextRow[desc, footer]}; NextRow: PROC [desc: PLADescription, type: RowType] RETURNS[row: REF RowRec] = { pp: REF PreChargedParams _ NARROW[desc.data]; andIndex, orIndex, index: INT _ 0; data: PLAOps.Term; conn: Connection; row _ NEW[RowRec _ [type: type]]; row.and _ NEW[ColSeqRec[desc.nofAndCols]]; IF desc.nofOrCols#0 THEN row.or _ NEW[ColSeqRec[desc.nofOrCols]]; SELECT type FROM header => { }; conn => {conn _ NextConnection[desc]; row.dr _ conn.dr}; dataUp, dataDn => { data _ NextDataTerm[desc]; row.dr _ NIL; IF data=NIL THEN type _ row.type _ blank}; ENDCASE; FOR index IN[0..desc.nofAndCols) DO IF (index+1) MOD (pp.insPerExtra+1) = 0 THEN row.and[index] _ extra ELSE { SELECT type FROM dataUp, dataDn => SELECT PLAOps.GetInQrt [data, REFBit.Desc[desc.ttt.data].bitForm[andIndex].firstBit] FROM zero => row.and[index] _ left; one => row.and[index] _ right; ENDCASE => row.and[index] _ nc; conn => IF conn.isOutput OR conn.index#andIndex THEN row.and[index] _ nc ELSE IF conn.isLeftSide THEN row.and[index] _ left ELSE row.and[index] _ right; ENDCASE => row.and[index] _ nc; andIndex_andIndex+1 } ENDLOOP; IF desc.nofOrCols#0 THEN FOR index IN[0..desc.nofOrCols) DO IF (index+1) MOD (pp.outsPerExtra+1) = 0 THEN row.or[index] _ extra ELSE { row.or[index] _ nc; IF orIndex < desc.smlToBigOut.size THEN { IF (type=dataUp OR type=dataDn) AND PLAOps.GetOutQrt [data, REFBit.Desc[desc.ttt.out].bitForm[desc.smlToBigOut[orIndex]].firstBit]=one THEN row.or[index] _ left; IF type=conn AND conn.isOutput AND conn.index=desc.smlToBigOut[orIndex] THEN row.or[index] _ left }; orIndex_orIndex+1 } ENDLOOP}; NextDataTerm: PROC [desc: PLADescription] RETURNS[term: PLAOps.Term] = { pp: REF PreChargedParams _ NARROW[desc.data]; term _ pp.nextTerm; IF term#NIL THEN pp.nextTerm _ pp.nextTerm.next}; NextConnection: PROC [desc: PLADescription] RETURNS[conn: Connection] = { pp: REF PreChargedParams _ NARROW[desc.data]; conn _ desc.connSeq[pp.nextConn]; pp.nextConn _ pp.nextConn+1}; MakeOutDrs: PROC[desc: PLADescription] = { pp: REF PreChargedParams _ NARROW[desc.data]; new: Frame; last: INT _ -1-pp.minConnSpace; cnt: INT _ 0; list: LIST OF Frame; FOR driverIndex: INT IN [0..pp.rows.size) DO SELECT pp.rows[driverIndex].type FROM header, xheader, footer => { IF (driverIndex-last) <= pp.minConnSpace THEN ERROR; last _ driverIndex-pp.minConnSpace}; blank, dataUp, dataDn => { IF (driverIndex-last) <= pp.minConnSpace THEN LOOP}; conn => { IF (driverIndex-last) <= pp.minConnSpace THEN ERROR; last _ driverIndex} ENDCASE => ERROR; list _ CONS[CDFrame.NewObjectFrame[ DriverCell [precharged, pp.rows[driverIndex].type, pp.rows[driverIndex].dr, desc.design]], list]; cnt _ cnt+1; ENDLOOP; new _ CDFrame.NewFrame[cnt, y, desc.name.Cat["-OutDr"]]; FOR ii: INT IN [0..cnt) DO new[ii] _ list.first; list _ list.rest ENDLOOP; desc.drFrame _ new}; MakePla: PROC[desc: PLADescription] = { tiles: REF TileVarieties _ GetPLATiles[ ]; pp: REF PreChargedParams _ NARROW[desc.data]; refPhase: Ph _ unk; rowList: PW.ListOb _ NIL; log.PutRope["\n Assemble precharged pla row cells"]; FOR rowIndex: INT IN [0..pp.rows.size) DO objects: PW.ListOb _ NIL; row: REF RowRec _ pp.rows[rowIndex]; IF pp.rows[rowIndex].dr#NIL THEN refPhase _ pp.rows[rowIndex].dr.ref.ph; objects _ CONS[tiles.glue[row.type][leftSide], objects]; FOR index: INT IN [0..row.and.size) DO objects _ CONS[tiles.and[row.type][row.and[index]], objects] ENDLOOP; IF desc.nofOrCols#0 THEN { objects _ CONS[tiles.glue[row.type][between], objects]; FOR index: INT IN [0..row.or.size) DO objects _ CONS[tiles.or[row.type][row.or[index]], objects] ENDLOOP; objects _ CONS[tiles.glue[row.type][rightSide], objects] }; rowList _ CONS[PW.AbutListX[desc.design, PW.Reverse[objects]], rowList] ENDLOOP; desc.cell _ PW.AbutListY[desc.design, rowList]; ReNamePLAInputPins[desc]}; ReNamePLAInputPins: PROC[desc: PLADescription] = { pp: REF PreChargedParams _ NARROW[desc.data]; tiles: REF TileVarieties _ GetPLATiles[ ]; format: REFBit.Format _ REFBit.Desc[desc.ttt.data].bitForm; leftSize: INT _ CD.InterestSize[tiles.glue[blank][leftSide]].x; andWidth: INT _ CD.InterestSize[tiles.and[blank][nc]].x; extraWidth: INT _ CD.InterestSize[tiles.and[blank][extra]].x; renameProc: IFUPW.PinNameProc ~ { list: LIST OF ROPE _ desc.plaInNames; index: INT; oldRope: Rope.ROPE _ CDPinObjects.GetName[pin]; in0: BOOL _ Rope.Equal[oldRope, "in0"]; in1: BOOL _ Rope.Equal[oldRope, "in1"]; IF NOT(in0 OR in1) THEN RETURN[oldRope]; index _ (pin.location.x - leftSize)/(pp.insPerExtra*andWidth+extraWidth); index _ (pin.location.x - leftSize - extraWidth*index)/andWidth; WHILE index#0 DO list _ list.rest.rest; index _ index-1 ENDLOOP; name _ IF in1 THEN list.rest.first ELSE list.first}; desc.cell _ IFUPW.RenameObjAndPins[desc.design, desc.cell, desc.name, renameProc] }; plaTilesDesign: CD.Design; tileBuffer: REF TileVarieties; TileVarieties: TYPE = RECORD[glue: REF GlueTiles, and, or: REF NormalTiles]; GlueTiles: TYPE = ARRAY RowType OF ARRAY GlueCellType OF CD.Object; GlueCellType: TYPE = {leftSide, between, rightSide}; NormalTiles: TYPE = ARRAY RowType OF ARRAY NormalCellType OF CD.Object; NormalCellType: TYPE = {left, right, nc, extra}; GetPLATiles: PROC RETURNS[tiles: REF TileVarieties] = { tDesign: CD.Design; IF tileBuffer#NIL THEN RETURN[tileBuffer]; log.PutRope["\n Initialize precharged PLA tiles"]; tDesign _ plaTilesDesign_ PW.OpenDesign["IFUPWControl.dale"]; IF tDesign=NIL THEN ERROR PW.Error[MissingDesign, "TileSet design not found or empty"]; tiles _ tileBuffer _ NEW[TileVarieties]; tiles.glue _ NEW[GlueTiles]; tiles.and _ NEW[NormalTiles]; tiles.or _ NEW[NormalTiles]; tiles.glue [xheader][leftSide] _ PW.Get[design: tDesign, name: "XLeftSide" ]; tiles.glue [xheader][between] _ PW.Get[design: tDesign, name: "XBetween" ]; tiles.glue [xheader][rightSide] _ PW.Get[design: tDesign, name: "XOrEx" ]; tiles.and [xheader][nc] _ PW.Get[design: tDesign, name: "XAnd" ]; tiles.and [xheader][extra] _ PW.Get[design: tDesign, name: "XAndEx" ]; tiles.or [xheader][nc] _ PW.Get[design: tDesign, name: "XOr" ]; tiles.or [xheader][extra] _ PW.Get[design: tDesign, name: "XOrEx" ]; tiles.glue [header][leftSide] _ PW.Get[design: tDesign, name: "HLeftSide" ]; tiles.glue [header][between] _ PW.Get[design: tDesign, name: "HBetween" ]; tiles.glue [header][rightSide] _ PW.Get[design: tDesign, name: "HOrEx" ]; tiles.and [header][nc] _ PW.Get[design: tDesign, name: "HAnd" ]; tiles.and [header][extra] _ PW.Get[design: tDesign, name: "HAndEx" ]; tiles.or [header][nc] _ PW.Get[design: tDesign, name: "HOr" ]; tiles.or [header][extra] _ PW.Get[design: tDesign, name: "HOrEx" ]; tiles.glue [footer][leftSide] _ PW.FlipY[tDesign, tiles.glue [header][leftSide] ]; tiles.glue [footer][between] _ PW.FlipY[tDesign, tiles.glue [header][between] ]; tiles.glue [footer][rightSide] _ PW.FlipY[tDesign, tiles.glue [header][rightSide] ]; tiles.and [footer][nc] _ PW.FlipY[tDesign, tiles.and [header][nc] ]; tiles.and [footer][extra] _ PW.FlipY[tDesign, tiles.and [header][extra] ]; tiles.or [footer][nc] _ PW.FlipY[tDesign, tiles.or [header][nc] ]; tiles.or [footer][extra] _ PW.FlipY[tDesign, tiles.or [header][extra] ]; tiles.glue [blank][leftSide] _ PW.Get[design: tDesign, name: "BLeftSide" ]; tiles.glue [blank][between] _ PW.Get[design: tDesign, name: "BBetween" ]; tiles.glue [blank][rightSide] _ PW.Get[design: tDesign, name: "BOrEx" ]; tiles.and [blank][nc] _ PW.Get[design: tDesign, name: "BAnd" ]; tiles.and [blank][extra] _ PW.Get[design: tDesign, name: "BAndEx" ]; tiles.or [blank][nc] _ PW.Get[design: tDesign, name: "BOr" ]; tiles.or [blank][extra] _ PW.Get[design: tDesign, name: "BOrEx" ]; tiles.glue [conn][leftSide] _ PW.Get[design: tDesign, name: "BLeftSide" ]; tiles.glue [conn][between] _ PW.Get[design: tDesign, name: "BBetween" ]; tiles.glue [conn][rightSide] _ PW.Get[design: tDesign, name: "CRightSide" ]; tiles.and [conn][left] _ PW.Get[design: tDesign, name: "CAndLt" ]; tiles.and [conn][right] _ PW.Get[design: tDesign, name: "CAndRt" ]; tiles.and [conn][nc] _ PW.Get[design: tDesign, name: "BAnd" ]; tiles.and [conn][extra] _ PW.Get[design: tDesign, name: "BAndEx" ]; tiles.or [conn][left] _ PW.Get[design: tDesign, name: "COr" ]; tiles.or [conn][nc] _ PW.Get[design: tDesign, name: "COrNC" ]; tiles.or [conn][extra] _ PW.Get[design: tDesign, name: "COrEx" ]; tiles.glue [dataUp][leftSide] _ PW.Get[design: tDesign, name: "DLeftSide" ]; tiles.glue [dataUp][between] _ PW.Get[design: tDesign, name: "DBetween" ]; tiles.glue [dataUp][rightSide] _ PW.Get[design: tDesign, name: "DRightSide" ]; tiles.and [dataUp][left] _ PW.Get[design: tDesign, name: "DAndLt" ]; tiles.and [dataUp][right] _ PW.Get[design: tDesign, name: "DAndRt" ]; tiles.and [dataUp][nc] _ PW.Get[design: tDesign, name: "DAnd" ]; tiles.and [dataUp][extra] _ PW.Get[design: tDesign, name: "DAndEx" ]; tiles.or [dataUp][left] _ PW.Get[design: tDesign, name: "DOr" ]; tiles.or [dataUp][nc] _ PW.Get[design: tDesign, name: "DOrNC" ]; tiles.or [dataUp][extra] _ PW.Get[design: tDesign, name: "DOrEx" ]; tiles.glue [dataDn][leftSide] _ tiles.glue [dataUp][leftSide]; tiles.glue [dataDn][between] _ tiles.glue [dataUp][between]; tiles.glue [dataDn][rightSide] _ PW.FlipY[tDesign, tiles.glue [dataUp][rightSide] ]; tiles.and [dataDn][left] _ tiles.and [dataUp][left]; tiles.and [dataDn][right] _ tiles.and [dataUp][right]; tiles.and [dataDn][nc] _ tiles.and [dataUp][nc]; tiles.and [dataDn][extra] _ tiles.and [dataUp][extra]; tiles.or [dataDn][left] _ PW.FlipY[tDesign, tiles.or [dataUp][left] ]; tiles.or [dataDn][nc] _ PW.FlipY[tDesign, tiles.or [dataUp][nc] ]; tiles.or [dataDn][extra] _ PW.FlipY[tDesign, tiles.or [dataUp][extra] ]; RETURN[tiles]}; ReverseList: PUBLIC PROC [list: LIST OF ROPE] RETURNS [new: LIST OF ROPE] = {FOR list _ list, list.rest WHILE list#NIL DO new _ CONS[list.first, new] ENDLOOP}; ListLength: PUBLIC PROC [list: LIST OF ROPE] RETURNS[size: INT] = {FOR size _ 0, size+1 WHILE list#NIL DO list_list.rest ENDLOOP}; ListIndexItem: PUBLIC PROC [list: LIST OF ROPE, index: INT] RETURNS[item: ROPE] = { FOR index _ index, index-1 WHILE index#0 AND list#NIL DO list_list.rest ENDLOOP; RETURN[IF list=NIL THEN NIL ELSE list.first]}; ListItemIndex: PUBLIC PROC [list: LIST OF ROPE, item: ROPE] RETURNS[index: INT] = { IF item=NIL THEN RETURN[-1]; FOR index _ 0, index+1 WHILE list#NIL DO IF Rope.Equal[list.first, item, FALSE] THEN RETURN[index]; list_list.rest ENDLOOP; RETURN[-1]}; ListConcat: PUBLIC PROC [list1, list2: LIST OF ROPE] RETURNS[new: LIST OF ROPE] = { FOR i: INT DECREASING IN [0..ListLength[list2]) DO new _ CONS[ ListIndexItem[list2, i], new] ENDLOOP; FOR i: INT DECREASING IN [0..ListLength[list1]) DO new _ CONS[ ListIndexItem[list1, i], new] ENDLOOP}; log: IO.STREAM _ CDFrame.GetLog[]; <> END.