<> <> DIRECTORY PLAGen, CD, CDIO, CDRects, CDRoutingObjects, CDSimpleRules, CDViewer, CMosB, Core, CoreClasses, CoreCreate, CoreDirectory, CoreGeometry, CoreOps, IO, PLAOps, PWCore, TilingClass, Real, REFBit, Rope, RopeList, Sinix, Sisyph, TerminalIO, ViewerOps, WireIconExtras; PLAGenImpl: CEDAR PROGRAM IMPORTS CD, CDIO, CDRects, CDRoutingObjects, CDSimpleRules, CDViewer, CMosB, CoreClasses, CoreCreate, CoreDirectory, CoreGeometry, CoreOps, IO, PLAOps, PWCore, TilingClass, Real, REFBit, Rope, RopeList, Sinix, Sisyph, TerminalIO, ViewerOps, WireIconExtras EXPORTS PLAGen = BEGIN <> ROPE: TYPE = Rope.ROPE; ROPES: TYPE = LIST OF Rope.ROPE; CellType: TYPE = Core.CellType; Wire: TYPE = Core.Wire; Wires: TYPE = Core.Wires; DriverTileType: TYPE = {left, in, between, extra, out2, out1, rightHalf}; BodyTileKey: TYPE = RECORD[rt: RowType, tv: TileVariety, tt: TileType, sz: Size _ norm]; RowType: TYPE = {header, footer, conn, dataUp, dataDn, blank, inCntc}; TileVariety: TYPE = {glue, and, or}; TileType: TYPE = {leftSide, between, rightSide, left, right, nc, extra}; Size: TYPE = {norm, big}; minOutsRp: ROPE _ "PLAGenOuts"; rowsPerExtraRp: ROPE _ "PLAGenRowsPerExtra"; vddNm: ROPE _ "Vdd"; gndNm: ROPE _ "Gnd"; inNm: ROPE _ "in"; in0Nm: ROPE _ "in0"; in1Nm: ROPE _ "in1"; outNm: ROPE _ "out"; out0Nm: ROPE _ "out0"; out1Nm: ROPE _ "out1"; logicInNm: ROPE _ "logicIn"; logicOutNm: ROPE _ "logicOut"; rowsPerDr: INT _ 3; -- not easily changed outsPerExtra: INT _ 10; -- can be changed layRules: ATOM _ $cmosB; Signal: SIGNAL = CODE; <> ExpToPlaCell: PUBLIC PROC[expr: REF, type: ATOM _ NIL] RETURNS[cell: CellType] = { pla: PLAOps.PLA _ PLAOps.ExpressionToPLA[expr]; IF type=NIL THEN type _ $buffered; SELECT type FROM $basic => cell _ PLABodyBasic[pla]; $bufferedBot => cell _ PLABuffered[pla]; <<$latchedBot => cell _ XXX[pla];>> $basicRt => cell _ PLABodyBasic[pla, TRUE]; <<$clockedRt => cell _ XXX[pla];>> <<$latchedRt => cell _ XXX[pla];>> ENDCASE => ERROR}; PLABuffered: PROC[pla: PLAOps.PLA] RETURNS[cell: CellType] = { logic: CellType _ PLABodyBasic[pla]; bufs: CellType _ BufferedPLADrivers[pla]; vdd: Wire _ CoreOps.CreateWires[0, vddNm]; gnd: Wire _ CoreOps.CreateWires[0, gndNm]; logicIn: Wire _ WireIconExtras.RefWire[pla.data, logicInNm, TRUE]; logicOut: Wire _ WireIconExtras.RefWire[pla.out, logicOutNm, FALSE]; in: Wire _ WireIconExtras.RefWire[pla.data, inNm, FALSE]; out: Wire _ WireIconExtras.RefWire[pla.out, outNm, FALSE]; logicI: CoreCreate.CellInstance _ CoreCreate.Instance[logic, [inNm, logicIn], [outNm, logicOut], [vddNm, vdd], [gndNm, gnd] ]; bufsI: CoreCreate.CellInstance _ CoreCreate.Instance[bufs, [inNm, in], [outNm, out], [logicInNm, logicIn], [logicOutNm, logicOut], [vddNm, vdd], [gndNm, gnd] ]; StripSubWireNames[logicIn]; StripSubWireNames[logicOut]; AddSubWireNamePrefix[to: out, prefix: "Nxt"]; <> cell _ CoreCreate.Cell[ public: CoreCreate.WireList[LIST[in, out, vdd, gnd]], onlyInternal: CoreCreate.WireList[LIST[logicIn, logicOut]], instances: LIST[bufsI, logicI], name: pla.name ]; PWCore.SetAbutY[cell]; RETURN[cell]}; PLAInSB: PUBLIC PROC[cx: PLAGen.Context, tttFile: ROPE] RETURNS[cell: CellType] = { pla: PLAOps.PLA _ PLAOps.ReadPLAFile [tttFile.Cat[".ttt"], TerminalIO.TOS[], TRUE]; rec: CoreClasses.RecordCellType _ NEW[CoreClasses.RecordCellTypeRec[0]]; in: Wire _ WireIconExtras.RefWire[pla.data, "in", TRUE]; out: Wire _ WireIconExtras.RefWire[pla.out, "out", FALSE]; public: Wire _ CoreOps.CreateWire[LIST[in]]; internal: Wire _ CoreOps.CreateWire[LIST[in]]; flatIn: Wire _ CoreOps.CreateWire[Flatten[in]]; flatInOrd: Wire _ CoreOps.CreateWire[Flatten[ReorderWire[in, GetSideNames[cx, right]]]]; insAtTop: BOOL _ GetSideNames[cx, top] #NIL; insAtBot: BOOL _ GetSideNames[cx, bottom] #NIL AND ~insAtTop; ins: NAT _ flatIn.size/2; nofOrCols: NAT _ NofOrCols[MAX[CoreOps.WireBits[out], GetCxParam[cx, minOutsRp]]]; leftSize: INT _ 44 * CMosB.lambda; betweenSize: INT _ 16 * CMosB.lambda; rightSize: INT _ 16 * CMosB.lambda; blankSize: INT _ 8 * CMosB.lambda; biasX: INT _ 48 * CMosB.lambda; biasY: INT _ 12 * CMosB.lambda; colAnd: INT _ 16 * CMosB.lambda; colOr: INT _ 8 * CMosB.lambda; halfColSize: INT _ 8 * CMosB.lambda; rowSize: INT _ 24 * CMosB.lambda; halfRowSize: INT _ 16 * CMosB.lambda; obj: CD.Object; contObj: CD.Object _ CDSimpleRules.Contact[layRules, CMosB.met, CMosB.met2]; contW: INT _ CD.InterestSize[contObj].x; metW: INT _ CDSimpleRules.MinWidth[layRules, CMosB.met]; met2W: INT _ CDSimpleRules.MinWidth[layRules, CMosB.met2]; iSizeX: NAT _ leftSize +ins*colAnd +betweenSize +nofOrCols*colOr +rightSize; iSizeY: NAT _ blankSize + ins*rowSize + blankSize; nodes: LIST OF CDRoutingObjects.Node; cell _ CoreClasses.CreateRecordCell[public, internal, NIL, tttFile.Cat["InSB"]]; FOR indexX: INT IN [0..ins) DO FOR polarity: INT IN [0..2) DO node: CDRoutingObjects.Node; pub: Wire _ flatIn[2*indexX + polarity]; name: ROPE _ CoreOps.GetFullWireName[public, pub]; indexY: INT _ WireIndex[flatInOrd, pub]/2; refX: INT _ biasX + indexX * colAnd + polarity * halfColSize; refY: INT _ biasY + indexY * rowSize + polarity * halfRowSize; verYSize: INT _ SELECT TRUE FROM insAtTop AND insAtBot => iSizeY, insAtTop => iSizeY-refY, insAtBot => refY, ENDCASE => ERROR; horSize: CD.Position _ [iSizeX-refX, metW]; verSize: CD.Position _ [met2W, verYSize]; horPos: CD.Position _ [refX, refY-metW/2]; verPos: CD.Position _ [refX-met2W/2, (IF insAtBot THEN 0 ELSE refY)]; contPos: CD.Position _ [refX-contW/2, refY-contW/2]; horObj: CD.Object _ CDRects.CreateRect[horSize, CMosB.met]; verObj: CD.Object _ CDRects.CreateRect[verSize, CMosB.met2]; pos: LIST OF CDRoutingObjects.PlacedObject _ NIL; <> IF name=NIL THEN ERROR; pos _ CONS[[ horObj, horPos], pos]; --pins _ CONS[[horObj, [horPos]], pins]; pos _ CONS[[ verObj, verPos], pos]; --pins _ CONS[[verObj, [verPos]], pins]; pos _ CONS[[ contObj, contPos], pos]; <> node _ CDRoutingObjects.CreateNode [pos, LIST[[$SignalName, name], [$InstanceName, name]]]; nodes _ CONS[node, nodes]; ENDLOOP; ENDLOOP; obj _ CDRoutingObjects.CreateRoutingObject[nodes, [x1: 0, y1: 0, x2: iSizeX, y2: iSizeY]]; PWCore.SetLayout[cell, $Value, $PWCoreValue, obj]}; <> PLAOutDrHeader: PUBLIC PROC[tttFile: ROPE] RETURNS[cell: CellType] = { pla: PLAOps.PLA _ PLAOps.ReadPLAFile[tttFile.Cat[".ttt"], TerminalIO.TOS[], TRUE]; out: Wire _ WireIconExtras.RefWire[pla.out, "out", FALSE]; outSize: INT _ CoreOps.WireBits[out]; minSize: NAT _ (rowsPerDr-1)*outSize; outFill: INT _ MAX[pla.termList.length, minSize] - minSize; header: CellType _ Get[orig, "PLAGen.DrHeader.sch"]; blank: CellType _ Get[orig, "PLAGen.DrBlank.sch"]; name: ROPE _ "DrHeader"; insts: CoreCreate.CellInstances _ LIST[CoreCreate.Instance[header]]; <<[]_PWCore.Layout[header];>> <<[]_PWCore.Layout[blank];>> IF outFill=0 THEN RETURN[header]; name _ IO.PutFR["%gWith%gBlanks", IO.rope[name], IO.int[outFill]]; FOR i: INT IN [1..outFill] DO insts _ CONS[CoreCreate.Instance[blank], insts]; ENDLOOP; cell _ CoreCreate.Cell[ public: CoreOps.CopyWire[header.public], instances: insts, name: name]; PWCore.SetAbutY[cell]}; PLABody: PUBLIC PROC[cx: PLAGen.Context, tttFile: ROPE] RETURNS[cell: CellType] = { pla: PLAOps.PLA _ PLAOps.ReadPLAFile[tttFile, TerminalIO.TOS[], TRUE]; minOuts: INT _ GetCxParam[cx, minOutsRp]; rowsPerExtra: INT _ GetCxParam[cx, rowsPerExtraRp, 1000]; rightNames: ROPES _ GetSideNames[cx, right]; cell _ PLABodyBasic[pla, rightNames#NIL, rightNames, minOuts, rowsPerExtra]}; <> PLABodyBasic: PROC[ pla: PLAOps.PLA, horOuts: BOOL _ FALSE, rtNms: ROPES _ NIL, minOuts: INT _ 0, rowsPerExtra: INT _ 10] RETURNS[cell: CellType] = { <> < output connections positioned every 3 rows>> <<`out' or output names on bottom => output connections at bottom>> <<`in' or input names may be on top or bottom or both.>> vdd: Wire _ CoreOps.CreateWires[0, vddNm]; gnd: Wire _ CoreOps.CreateWires[0, gndNm]; in: Wire _ WireIconExtras.RefWire[pla.data, "in", TRUE]; out: Wire _ WireIconExtras.RefWire[pla.out, "out", FALSE]; flatIn: Wire _ CoreOps.CreateWire[Flatten[in]]; flatOut: Wire _ CoreOps.CreateWire[Flatten[out]]; flatOutOrd: Wire _ CoreOps.CreateWire[Flatten[ReorderWire[out, rtNms]]]; public: Wire _ NIL; baseRows: NAT _ (IF horOuts THEN flatOut.size+MAX[flatOut.size*(rowsPerDr-1), pla.termList.length] ELSE pla.termList.length); nofRows: NAT _ 2 + baseRows + (baseRows-1)/rowsPerExtra; nofOrCols: NAT _ NofOrCols[MAX[flatOut.size, minOuts] ]; nofAndCols: NAT _ flatIn.size/2; row: INT _ 0; up: BOOL _ FALSE; cRow: INT _ 0; fillLt: INT _ 0; ta: TilingClass.TileArray _ NEW[TilingClass.TileArrayRec[nofRows]]; terms: LIST OF PLAOps.Term _ NIL; data: PLAOps.Term _ NIL; GetRow: PROC[type: RowType] RETURNS[rowRef: TilingClass.TileRow ] = { AndBit: PROC[index: INT] RETURNS[TileType] = { RETURN[SELECT type FROM dataUp, dataDn => SELECT PLAOps.GetInQrt [data, REFBit.Desc[pla.data].bitForm[index].firstBit] FROM zero => left, one => right, ENDCASE => nc, ENDCASE => nc]}; OrBit: PROC[index: INT] RETURNS[TileType] = { IF (index+1) MOD (outsPerExtra+1) = 0 THEN RETURN[extra]; index _ index - index/(outsPerExtra+1); IF index >= flatOut.size THEN RETURN[nc]; SELECT type FROM conn => IF flatOutOrd[cRow]=flatOut[index] THEN RETURN[left]; dataUp, dataDn => IF PLAOps.GetOutQrt [data, REFBit.Desc[pla.out].bitForm[index].firstBit]=one THEN RETURN[left]; ENDCASE; RETURN[nc]}; TileIt: PROC[ cell: CellType, pubType: {in, out, none} _ none, index: INT _ 0, header: BOOL_FALSE ] = { pas: LIST OF CoreCreate.PA _ NIL; SELECT pubType FROM in => pas _ LIST[[in0Nm, flatIn[2*index+0]], [in1Nm, flatIn[2*index+1]] ]; out => pas _ LIST[[outNm, flatOut[index]]]; ENDCASE; IF header THEN pas _ CONS[[vddNm, vdd], CONS[[gndNm, gnd], pas]]; rowRef[col] _ NEW[TilingClass.TileRec _ [cell, pas]]; col _ col+1}; col: INT _ 0; <> rowRef _ NEW[TilingClass.TileRowRec[1 + nofAndCols + 1 + nofOrCols + 1]]; SELECT type FROM conn => { up _ FALSE}; dataUp, dataDn => { IF terms = NIL THEN data _ NIL ELSE {data _ terms.first; terms _ terms.rest}; type _ IF data=NIL THEN blank ELSE IF (up_~up) THEN dataUp ELSE dataDn}; ENDCASE; IF (type=dataUp OR type=dataDn) AND data#NIL AND TermLoad[pla, data] > hotTermThreshold THEN TileIt[ BodyTile[[type, glue, leftSide, big ]], none, 0] ELSE TileIt[ BodyTile[[type, glue, leftSide ]], none, 0]; FOR i: INT IN [0..nofAndCols) DO IF row=0 AND AndBit[i]#extra THEN {TileIt[BodyTile[[type, and, AndBit[i]]], in, i]} ELSE {TileIt[BodyTile[[type, and, AndBit[i]]]]}; ENDLOOP; TileIt[ BodyTile[[type, glue, between]]]; FOR i: INT IN [0..nofOrCols) DO outI: INT _ i-i/(outsPerExtra+1); IF row=0 AND OrBit[i]#extra AND outI < flatOut.size THEN {TileIt[ BodyTile[[type, or, OrBit[i]]], out, outI]} ELSE {TileIt[ BodyTile[[type, or, OrBit[i]]]]} ENDLOOP; IF type#conn THEN {TileIt[BodyTile[[type,glue,rightSide]], none, 0, (type=header OR type=footer)]} ELSE {TileIt[BodyTile[[type,glue,rightSide]] ]} }; <> hotTermThreshold: INT _ HotTermThreshold[pla]; TerminalIO.PutRope[Estimates[pla, 2, TRUE]]; IF horOuts THEN terms _ GetHorOutsTermList[pla, flatOut, flatOutOrd] ELSE FOR term: PLAOps.Term _ pla.termList.end, term.last WHILE term#NIL DO terms _ CONS[PLAOps.CopyTerm[term], terms] ENDLOOP; FOR row IN [0..ta.size) DO extraRow: PROC RETURNS[BOOL] = {RETURN[(row-1+1) MOD (rowsPerExtra+1) = 0]}; SELECT TRUE FROM row=0 => {ta[row]_ GetRow[footer]; fillLt _ rowsPerDr-1}; row+1=nofRows => {ta[row]_ GetRow[header]}; fillLt#0 => {ta[row]_ GetRow[dataUp]; fillLt _ fillLt -1}; extraRow[] => {ta[row]_ GetRow[inCntc]}; cRow=flatOut.size => {ta[row]_ GetRow[dataUp]}; ~horOuts => {ta[row]_ GetRow[dataUp]}; --fillLt not used unless horOuts ENDCASE => {ta[row]_ GetRow[conn]; fillLt_rowsPerDr-1; cRow_cRow+1}; ENDLOOP; IF terms # NIL THEN ERROR; AddSubWireNamePrefix[to: out, prefix: "Nxt"]; <> cell _ TilingClass.CreateTiling[ public: CoreOps.CreateWire[LIST[in, out, vdd, gnd]], tileArray: ta, neighborX: TilingClass.LayoutNeighborX, neighborY: TilingClass.LayoutNeighborY, name: pla.name, props: NIL ]}; BufferedPLADrivers: PROC[pla: PLAOps.PLA] RETURNS[cell: CellType]={ vdd: Wire _ CoreOps.CreateWires[0, vddNm]; gnd: Wire _ CoreOps.CreateWires[0, gndNm]; lIn: Wire _ WireIconExtras.RefWire[pla.data, logicInNm, TRUE]; lOut: Wire _ WireIconExtras.RefWire[pla.out, logicOutNm, FALSE]; dIn: Wire _ WireIconExtras.RefWire[pla.data, inNm, FALSE]; dOut: Wire _ WireIconExtras.RefWire[pla.out, outNm, FALSE]; flatLIn: Wire _ CoreOps.CreateWire[Flatten[lIn]]; flatLOut: Wire _ CoreOps.CreateWire[Flatten[lOut]]; flatDIn: Wire _ CoreOps.CreateWire[Flatten[dIn]]; flatDOut: Wire _ CoreOps.CreateWire[Flatten[dOut]]; nofOrCols: NAT _ NofOrCols[flatDOut.size]; nofOrColExs: NAT _ nofOrCols/(outsPerExtra+1); nofOrColOut: NAT _ nofOrCols - nofOrColExs; nofAndCols: NAT _ flatDIn.size; ta: TilingClass.TileArray _ NEW[TilingClass.TileArrayRec[1]]; orIndex: INT _ 0; extras: INT _ 0; col: INT _ 0; TileIt: PROC[ cell: CellType, pubType: {in, out2, out1, filler} _ filler, index: INT _ 0] = { pas: LIST OF CoreCreate.PA _ LIST[[vddNm, vdd], [gndNm, gnd]]; SELECT pubType FROM in => pas _ CONS[[inNm, flatDIn[index]], CONS[[out0Nm, flatLIn[2*index+0]], CONS[[out1Nm, flatLIn[2*index+1]], pas]]]; out1 => pas _ CONS[[in0Nm, flatLOut[index]], CONS[[out0Nm, flatDOut[index]], pas]]; out2 => pas _ CONS[[in0Nm, flatLOut[index]], CONS[[out0Nm, flatDOut[index]], CONS[[in1Nm, flatLOut[index+1]], CONS[[out1Nm, flatDOut[index+1]], pas]]]]; ENDCASE; ta[0][col] _ NEW[TilingClass.TileRec _ [cell, pas]]; col _ col+1}; ta[0] _ NEW[TilingClass.TileRowRec [1 + nofAndCols + 1 + nofOrColExs + nofOrColOut/2 + 3]]; TileIt[ DriverTile[left], filler]; FOR i: INT IN [0..nofAndCols) DO TileIt[DriverTile[in], in, i] ENDLOOP; TileIt[ DriverTile[between], filler]; WHILE orIndex < nofOrCols DO IF ((orIndex+1) MOD (outsPerExtra+1)) = 0 THEN {TileIt[ DriverTile[extra], filler]; orIndex _ orIndex+1; extras _ extras+1; LOOP} ELSE {IF orIndex+1=nofOrCols THEN {TileIt[ DriverTile[out1], out1, orIndex-extras]; orIndex _ orIndex+1} ELSE {TileIt[ DriverTile[out2], out2, orIndex-extras]; orIndex _ orIndex+2}}; ENDLOOP; TileIt[ DriverTile[rightHalf], filler]; TileIt[ DriverTile[rightHalf], filler]; IF ((nofOrCols-extras) MOD 2)=0 THEN TileIt[ DriverTile[rightHalf], filler]; StripSubWireNames[lIn]; -- to prevent confusion with driver in subWire names StripSubWireNames[lOut]; -- to prevent confusion with driver out subWire names <> cell _ TilingClass.CreateTiling[ public: CoreOps.CreateWire[LIST[dIn, dOut, lIn, lOut, vdd, gnd]], tileArray: ta, neighborX: TilingClass.LayoutNeighborX, neighborY: TilingClass.LayoutNeighborY, name: pla.name, props: NIL ]}; GetCxParam: PROC[cx: Sisyph.Context, param: ROPE, default: INT_0] RETURNS[nofOrCols: INT] = { RETURN[IF (cx=NIL OR NOT Sisyph.FetchInt[cx, param].found) THEN default ELSE Sisyph.FetchInt[cx, param].value]}; NofOrCols: PROC[nofOuts: INT] RETURNS[nofOrCols: INT] = {RETURN[nofOuts+(nofOuts-1)/outsPerExtra]}; StripSubWireNames: PROC[w: Wire] = { IF w.size=0 THEN RETURN; FOR i: INT IN [0..w.size) DO []_CoreOps.SetShortWireName[w[i], NIL]; StripSubWireNames[w[i]]; ENDLOOP}; AddSubWireNamePrefix: PROC[to: Wire, prefix: ROPE] = { FOR i: INT IN [0..to.size) DO name1: ROPE _ CoreOps.GetShortWireName[to[i]]; []_CoreOps.SetShortWireName[to[i], Rope.Cat[prefix, name1]] ENDLOOP;}; AddSubWireNamePrefixIfDuplicate: PROC[ref, to: Wire, prefix: ROPE] = { FOR i: INT IN [0..to.size) DO name1: ROPE _ CoreOps.GetShortWireName[to[i]]; FOR j: INT IN [0..ref.size) DO IF CoreOps.GetShortWireName[ref[j]].Equal[name1] THEN EXIT; REPEAT FINISHED => LOOP ENDLOOP; []_CoreOps.SetShortWireName[to[i], Rope.Cat[prefix, name1]] ENDLOOP;}; <> <> <> <<{clash _ clash OR CoreOps.GetShortWireName[w].Equal[name]};>> <> <> < 0 THEN [] _ CoreOps.VisitRootAtomics[ck, CkClash];>> <> <0 THEN AddSubWireNamePrefixIfClash[to[i], ck, prefix]; ENDLOOP};>> <<>> GetHorOutsTermList: PROC[pla: PLAOps.PLA, flatOut, flatOutOrd: Wire] RETURNS[terms: LIST OF PLAOps.Term _ NIL] = { <> SeqTermLists: TYPE = REF SeqTermListsRec; SeqTermListsRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF LIST OF PLAOps.Term]; TwoTermRecs: TYPE = RECORD[t1, t2: PLAOps.TermRec]; MoveFromTermsToOuts: PROC[idx: INT] = { terms _ CONS[NIL, terms]; IF terms=NIL THEN RETURN; FOR list: LIST OF PLAOps.Term _ terms, list.rest WHILE list.rest#NIL DO term: PLAOps.Term _ list.rest.first; IF PLAOps.GetOutQrt[term, idx]#one THEN {list.rest _ list.rest.rest; terms _ terms.rest; outs[idx] _ CONS[term, outs[idx]]; RETURN}; ENDLOOP; FOR list: LIST OF PLAOps.Term _ terms, list.rest WHILE list.rest#NIL DO term: PLAOps.Term _ list.rest.first; FOR i: INT IN [0..outs.size) DO IF PLAOps.GetOutQrt[term, i]#one THEN FOR sub: LIST OF PLAOps.Term _ outs[i], sub.rest WHILE sub#NIL DO IF PLAOps.GetOutQrt[sub.first, idx]#one THEN { [term^, sub.first^] _ TwoTermRecs[sub.first^, term^]; list.rest _ list.rest.rest; terms _ terms.rest; outs[idx] _ CONS[term, outs[idx]]; RETURN} ENDLOOP; ENDLOOP; REPEAT FINISHED => ERROR ENDLOOP}; outForm: PLAOps.Format _ REFBit.Desc[pla.out].bitForm; end: PLAOps.Term; outs: SeqTermLists _ NEW[SeqTermListsRec[pla.termList.outBits]]; FOR output: INT IN [pla.termList.length..flatOutOrd.size*2) DO terms _ CONS[PLAOps.NewTerm[pla.termList.inBits, pla.termList.outBits], terms] ENDLOOP; FOR term: PLAOps.Term _ pla.termList.end, term.last WHILE term#NIL DO terms _ CONS[PLAOps.CopyTerm[term], terms] ENDLOOP; FOR output: INT IN [0..flatOutOrd.size) DO outs[output] _ NIL ENDLOOP; FOR output: INT IN [0..flatOutOrd.size) DO FOR index: INT IN [0..flatOut.size) DO IF flatOutOrd[output] # flatOut[index] THEN LOOP; MoveFromTermsToOuts[ outForm[index].firstBit ]; MoveFromTermsToOuts[ outForm[index].firstBit ]; EXIT REPEAT FINISHED => ERROR ENDLOOP; ENDLOOP; <> FOR output: INT DECREASING IN [0..flatOutOrd.size) DO FOR index: INT IN [0..flatOut.size) DO IF flatOutOrd[output] # flatOut[index] THEN LOOP; FOR sub: LIST OF PLAOps.Term _ outs[outForm[index].firstBit], sub.rest WHILE sub#NIL DO terms _ CONS[sub.first, terms] ENDLOOP; outs[outForm[index].firstBit] _ NIL; ENDLOOP ENDLOOP; terms _ ReverseTerms[terms]; -- make last first UNTIL end#NIL DO end _ terms.first; terms _ terms.rest ENDLOOP; -- remove end term terms _ ReverseTerms[terms]; -- make first first terms _ CONS[end, terms]; -- add end term to beginning FOR list: LIST OF PLAOps.Term _ terms, list.rest WHILE list#NIL DO FOR i: CARDINAL IN [0..list.first.out.wdSize) DO IF list.first.out[i].d#0 THEN EXIT; REPEAT FINISHED => list.first _ NIL ENDLOOP ENDLOOP}; ReverseTerms: PROC[terms: LIST OF PLAOps.Term] RETURNS[new: LIST OF PLAOps.Term] = {FOR terms _ terms, terms.rest WHILE terms#NIL DO new_CONS[terms.first, new] ENDLOOP}; WireIndex: PROC[big, little: Wire] RETURNS[index: INT _ -1] = { FOR index: INT IN [0..big.size) DO IF big[index]=little THEN RETURN[index] ENDLOOP; RETURN[-1]}; ReorderWire: PROC[wire: Wire, names: ROPES, extras: BOOL _ FALSE] RETURNS[Wire] = { wires: Wires _ NIL; nms: ROPES _ CONS[NIL, names]; IF names=NIL THEN RETURN[wire]; IF extras THEN FOR nms _ nms, nms.rest WHILE nms.rest#NIL DO index: INT _ CoreOps.GetWireIndex[wire, nms.rest.first]; IF index=-1 THEN nms.rest _ nms.rest.rest REPEAT FINISHED => names _ nms.rest ENDLOOP; FOR names _ names, names.rest WHILE names#NIL DO index: INT _ CoreOps.GetWireIndex[wire, names.first]; IF index=-1 THEN { TerminalIO.PutF ["The icon wire name \"%g\" is not an element of the PLA interface.\n", IO.rope[names.first]]; ERROR}; wires _ CONS[wire[index], wires] ENDLOOP; RETURN[ CoreOps.CreateWire[ CoreOps.Reverse[wires]]]}; Flatten: PROC[wire: Wire] RETURNS[wires: Wires _ NIL] = { temp: Wires; IF wire.size=0 THEN RETURN[LIST[wire]]; FOR ii: INT IN [0..wire.size) DO FOR temp _ Flatten[wire[ii]], temp.rest WHILE temp#NIL DO wires _ CONS[temp.first, wires] ENDLOOP ENDLOOP; temp _ wires; wires _ NIL; FOR temp _ temp, temp.rest WHILE temp#NIL DO wires _ CONS[temp.first, wires] ENDLOOP}; GetSideNames: PROC[cx: PLAGen.Context, side: CoreGeometry.Side] RETURNS[names: ROPES] = { obj: CD.Object _ Sisyph.GetCDObj[cx]; cell: CellType _ NARROW[Sinix.ExtractCell[obj, Sisyph.mode, NIL, cx].result]; eachSortedPin: CoreGeometry.EachSortedPinProc = {names _ CONS[CoreOps.GetShortWireName[wire], names]}; []_CoreGeometry.EnumerateSortedSides [Sisyph.mode.decoration, cell, side, eachSortedPin]; names _ RopeList.Reverse[names]}; <> Get: PROC [orientation: {orig, flipY}, name: ROPE] RETURNS [cellType: CellType] ~ { libraryNm: IO.ROPE = "PLAGen"; library: CoreDirectory.Library _ CoreDirectory.FetchLibrary[libraryNm]; IF library=NIL THEN library _ CoreDirectory.RegisterLibrary[CoreDirectory.CreateLibrary[], libraryNm]; cellType _ CoreDirectory.Fetch[library, name]; IF cellType=NIL THEN { designName: IO.ROPE _ name.Substr[0, name.Find["."]]; cellName: IO.ROPE _ name.Substr[name.Index[0, "."]+1]; design: CD.Design _ CDViewer.FindDesign[designName]; cx: PLAGen.Context; IF design=NIL THEN { design _ CDIO.ReadDesign[designName]; IF design=NIL THEN ERROR; ViewerOps.CloseViewer[CDViewer.CreateViewer[design, FALSE]]}; -- caches the design cx _ Sisyph.Create[design]; cellType _ Sisyph.ExtractSchematicByName[name: cellName, cx: cx]; []_CoreDirectory.Insert[library, name, cellType]}; IF orientation=flipY THEN { flipName: IO.ROPE _ Rope.Cat["FlipY.", name]; flipCT: CellType _ CoreDirectory.Fetch[library, flipName]; IF flipCT = NIL THEN { flipCT _ PWCore.RotateCellType[cellType, $FlipY]; []_CoreDirectory.Insert[library, flipName, flipCT]}; cellType _ flipCT} }; DriverTile: PROC[key: DriverTileType] RETURNS[cell: CellType] = {SELECT key FROM left => cell _ Get[orig, "PLAGen.BPlaDrLeftSide.sch" ]; in => cell _ Get[orig, "PLAGen.BPlaDrDualIn.sch" ]; between => cell _ Get[orig, "PLAGen.BPlaDrBetween.sch" ]; extra => cell _ Get[orig, "PLAGen.BPlaDrOrEx.sch" ]; out2 => cell _ Get[orig, "PLAGen.BPlaDrDualOutInv.sch" ]; out1 => cell _ Get[orig, "PLAGen.BPlaDrSingOutInv.sch" ]; rightHalf => cell _ Get[orig, "PLAGen.BPlaDrRightSideHalf.sch" ]; ENDCASE}; BodyTile: PROC[key: BodyTileKey] RETURNS[cell: CellType] = {SELECT key FROM [header, glue, leftSide ] => cell _ Get[orig, "PLAGen.HPlaHLeftSide.sch" ]; [header, glue, between ] => cell _ Get[orig, "PLAGen.HPlaHBetween.sch" ]; [header, glue, rightSide ] => cell _ Get[orig, "PLAGen.HPlaHRightSide.sch" ]; [header, and, nc ] => cell _ Get[orig, "PLAGen.HPlaHAnd.sch" ]; [header, or, nc ] => cell _ Get[orig, "PLAGen.HPlaHOr.sch" ]; [header, or, extra ] => cell _ Get[orig, "PLAGen.HPlaHOrEx.sch" ]; [footer, glue, leftSide ] => cell _ Get[flipY, "PLAGen.HPlaHLeftSide.sch" ]; [footer, glue, between ] => cell _ Get[flipY, "PLAGen.HPlaHBetween.sch" ]; [footer, glue, rightSide ] => cell _ Get[flipY, "PLAGen.HPlaHRightSide.sch" ]; [footer, and, nc ] => cell _ Get[flipY, "PLAGen.HPlaHAnd.sch" ]; [footer, or, nc ] => cell _ Get[flipY, "PLAGen.BPlaHOr.sch" ]; [footer, or, extra ] => cell _ Get[flipY, "PLAGen.HPlaHOrEx.sch" ]; [blank, glue, leftSide ] => cell _ Get[orig, "PLAGen.HPlaBLeftSide.sch" ]; [blank, glue, between ] => cell _ Get[orig, "PLAGen.HPlaBBetween.sch" ]; [blank, glue, rightSide ] => cell _ Get[orig, "PLAGen.HPlaBRightSide.sch" ]; [blank, and, nc ] => cell _ Get[orig, "PLAGen.HPlaBAnd.sch" ]; [blank, or, nc ] => cell _ Get[orig, "PLAGen.BOr.sch" ]; [blank, or, extra ] => cell _ Get[orig, "PLAGen.HPlaBOrEx.sch" ]; [conn, glue, leftSide ] => cell _ Get[orig, "PLAGen.HPlaBLeftSide.sch" ]; [conn, glue, between ] => cell _ Get[orig, "PLAGen.HPlaBBetween.sch" ]; [conn, glue, rightSide ] => cell _ Get[orig, "PLAGen.HPlaCRightSide.sch" ]; [conn, and, nc ] => cell _ Get[orig, "PLAGen.HPlaBAnd.sch" ]; [conn, or, left ] => cell _ Get[orig, "PLAGen.COr.sch" ]; [conn, or, nc ] => cell _ Get[orig, "PLAGen.COrNC.sch" ]; [conn, or, extra ] => cell _ Get[orig, "PLAGen.HPlaCOrEx.sch" ]; [dataUp, glue, leftSide, big ] => cell _ Get[orig, "PLAGen.HPlaDLeftSideHot.sch" ]; [dataUp, glue, leftSide ] => cell _ Get[orig, "PLAGen.HPlaDLeftSide.sch" ]; [dataUp, glue, between ] => cell _ Get[orig, "PLAGen.HPlaDBetween.sch" ]; [dataUp, glue, rightSide ] => cell _ Get[orig, "PLAGen.HPlaDRightSide.sch" ]; [dataUp, and, left ] => cell _ Get[orig, "PLAGen.DAndLt.sch" ]; [dataUp, and, right ] => cell _ Get[orig, "PLAGen.DAndRt.sch" ]; [dataUp, and, nc ] => cell _ Get[orig, "PLAGen.DAnd.sch" ]; [dataUp, or, left ] => cell _ Get[orig, "PLAGen.DOr.sch" ]; [dataUp, or, nc ] => cell _ Get[orig, "PLAGen.DOrNC.sch" ]; [dataUp, or, extra ] => cell _ Get[orig, "PLAGen.HPlaDOrEx.sch" ]; [dataDn, glue, leftSide, big ] => cell _ Get[orig, "PLAGen.HPlaDLeftSideHot.sch" ]; [dataDn, glue, leftSide ] => cell _ Get[orig, "PLAGen.HPlaDLeftSide.sch" ]; [dataDn, glue, between ] => cell _ Get[flipY, "PLAGen.HPlaDBetween.sch" ]; [dataDn, glue, rightSide ] => cell _ Get[flipY, "PLAGen.HPlaDRightSide.sch" ]; [dataDn, and, left ] => cell _ Get[orig, "PLAGen.DAndLt.sch" ]; [dataDn, and, right ] => cell _ Get[orig, "PLAGen.DAndRt.sch" ]; [dataDn, and, nc ] => cell _ Get[orig, "PLAGen.DAnd.sch" ]; [dataDn, or, left ] => cell _ Get[flipY, "PLAGen.DOr.sch" ]; [dataDn, or, nc ] => cell _ Get[flipY, "PLAGen.DOrNC.sch" ]; [dataDn, or, extra ] => cell _ Get[flipY, "PLAGen.HPlaDOrEx.sch" ]; [inCntc, glue, leftSide ] => cell _ Get[orig, "PLAGen.HPlaInCntcLeftSide.sch" ]; [inCntc, glue, between ] => cell _ Get[orig, "PLAGen.HPlaInCntcBetween.sch" ]; [inCntc, glue, rightSide ] => cell _ Get[orig, "PLAGen.HPlaInCntcRightSide.sch" ]; [inCntc, and, nc ] => cell _ Get[orig, "PLAGen.HPlaInCntcAnd.sch" ]; [inCntc, or, nc ] => cell _ Get[orig, "PLAGen.HPlaInCntcOr.sch" ]; [inCntc, or, extra ] => cell _ Get[orig, "PLAGen.HPlaInCntcOrEx.sch" ]; ENDCASE}; <> nSqRes: REAL = 18.0; pSqRes: REAL = nSqRes*2.5; InDrRes: PROC[drSize: INT] RETURNS[REAL] = {RETURN[nSqRes * .5 / drSize]}; TermPURes: PROC[hot: BOOL] RETURNS[REAL] = {RETURN[IF hot THEN pSqRes*.75 ELSE pSqRes]}; OutPURes: PROC RETURNS[REAL] = {RETURN[pSqRes*.75]}; InCap: PROC[ldsPerIn, nofTerms: INT] RETURNS[REAL] = {RETURN[.03 + .0100 * ldsPerIn + .0015 * nofTerms]}; TermCap: PROC[ldsPerTerm, nofIns, nofOuts: INT] RETURNS[REAL] = {RETURN[.0020 * nofIns + .0100 * ldsPerTerm + .0012 * nofOuts]}; OutCap: PROC[ldsPerOut, nofTerms, drSize: INT] RETURNS[REAL] = {RETURN[.0010 * nofTerms + .0100 * ldsPerOut + .0100 * drSize*3.5]}; Estimates: PUBLIC PROC[ pla: PLAOps.PLA, drSize: INT _ 0, useHotTermPU: BOOL _ TRUE] RETURNS[rope: IO.ROPE] = { < pE=10 and nE=4, assume in driver size = out driver size>> nofIns: INT _ REFBit.Desc[pla.data].bitForm.size; nofOuts: INT _ REFBit.Desc[pla.out].bitForm.size; nofTerms: INT _ pla.termList.length; ldsPerIn: INT _ MaxLdsPerIn[pla]; ldsPerTerm: INT _ MaxLdsPerTerm[pla]; ldsPerOut: INT _ MaxLdsPerOut[pla]; hotTermT: INT _ IF useHotTermPU THEN HotTermThreshold[pla] ELSE ldsPerTerm; hotTerms: INT _ NofHotTerms[pla, hotTermT]; inCap: REAL _ InCap [ldsPerIn, nofTerms]; termCap: REAL _ TermCap [ldsPerTerm, nofIns, nofOuts]; outCap: REAL _ OutCap [ldsPerOut, nofTerms, drSize]; inRest: REAL _ InDrRes[drSize]; tUpRes: REAL _ TermPURes[useHotTermPU]; oUpRes: REAL _ OutPURes[]; tDnRes: REAL _ (tUpRes * nSqRes/2) / (tUpRes - nSqRes/2); oDnRes: REAL _ (oUpRes * nSqRes/2) / (oUpRes - nSqRes/2); inTime: REAL _ .7 * inCap * inRest; termUpTime: REAL _ .7 * termCap * tUpRes; termDnTime: REAL _ .7 * termCap * tDnRes; outUpTime: REAL _ .7 * outCap * oUpRes; outDnTime: REAL _ .7 * outCap * oDnRes; onTime: REAL _ inTime+termUpTime+outDnTime; offTime: REAL _ inTime+termDnTime+outUpTime; ros: IO.STREAM _ IO.ROS[]; ros.PutF["\nTiming and power estimates for PLA: %g\n", IO.rope[pla.name]]; ros.PutF[" BufUnits: %3g\n", IO.int[drSize]]; ros.PutF[" HotThld: %3g\n", IO.int[hotTermT]]; ros.PutF[" HotTerms: %3g\n", IO.int[hotTerms]]; ros.PutF[" Ins Terms Outs\n"]; ros.PutF[" Count: %3g %3g %3g\n", IO.int[nofIns], IO.int[nofTerms], IO.int[nofOuts] ]; ros.PutF[" Max Ld: %3g %3g %3g\n", IO.int[ldsPerIn], IO.int[ldsPerTerm], IO.int[ldsPerOut] ]; ros.PutF[" Max Cap: %6.2f %6.2f %6.2f pF\n", IO.real[inCap], IO.real[termCap], IO.real[outCap]]; ros.PutF[" Time Up: %6.2f %6.2f %6.2f nS\n", IO.real[inTime], IO.real[termUpTime], IO.real[outUpTime]]; ros.PutF[" Time Dn: %6.2f %6.2f %6.2f nS\n", IO.real[inTime], IO.real[termDnTime], IO.real[outDnTime]]; ros.PutF[" Times: Av:%6.2f On:%6.2f Off:%6.2f nS\n", IO.real[(onTime+offTime)/2], IO.real[onTime], IO.real[offTime] ]; ros.PutF[" Power: %6.2f mW\n\n", IO.real[25.0*(hotTerms/TermPURes[TRUE]+(nofTerms-hotTerms)/TermPURes[FALSE])]]; rope _ IO.RopeFromROS[ros]}; HotTermThreshold: PUBLIC PROC[pla: PLAOps.PLA] RETURNS[threshold: INT _ LAST[INT]] = { nofIns: INT _ REFBit.Desc[pla.data].bitForm.size; nofOuts: INT _ REFBit.Desc[pla.out].bitForm.size; max: INT _ MaxLdsPerTerm[pla]; termCap: REAL _ TermCap [max, nofIns, nofOuts]; biasCap: REAL _ TermCap [0, nofIns, nofOuts]; factCap: REAL _ (termCap-biasCap)/max; -- sb .01 rRatio: REAL _ TermPURes[TRUE]/TermPURes[FALSE]; -- sb .75 nReal: REAL _ rRatio*max - (1 - rRatio)*biasCap/factCap; threshold _ Real.Round[nReal]}; TermLoad: PUBLIC PROC[pla: PLAOps.PLA, term: PLAOps.Term] RETURNS[load: INT _ 0] = { inForm: PLAOps.Format _ REFBit.Desc[pla.data].bitForm; outForm: PLAOps.Format _ REFBit.Desc[pla.out].bitForm; FOR in: INT IN [0..inForm.size) DO IF PLAOps.GetInQrt[term, inForm[in].firstBit]#dontcare THEN load _ load+1 ENDLOOP; FOR out: INT IN [0..outForm.size) DO IF PLAOps.GetOutQrt[term, outForm[out].firstBit]=one THEN load _ load+1 ENDLOOP}; MaxLdsPerIn: PROC[pla: PLAOps.PLA] RETURNS[max: INT _ 0] = { IntSeq: TYPE = RECORD[SEQUENCE size: NAT OF INT]; inForm: PLAOps.Format _ REFBit.Desc[pla.data].bitForm; ones: REF IntSeq _ NEW[IntSeq[inForm.size]]; zeros: REF IntSeq _ NEW[IntSeq[inForm.size]]; FOR in: INT IN [0..inForm.size) DO ones[in] _ zeros[in] _ 0 ENDLOOP; FOR term: PLAOps.Term _ pla.termList.begin, term.next WHILE term#NIL DO FOR in: INT IN [0..inForm.size) DO SELECT PLAOps.GetInQrt[term, inForm[in].firstBit] FROM one => ones[in] _ ones[in] +1; zero => zeros[in] _ zeros[in] +1; ENDCASE ENDLOOP ENDLOOP; FOR in: INT IN [0..inForm.size) DO max _ MAX[ones[in], zeros[in], max] ENDLOOP}; MaxLdsPerTerm: PROC[pla: PLAOps.PLA] RETURNS[max: INT _ 0] = { FOR term: PLAOps.Term _ pla.termList.begin, term.next WHILE term#NIL DO max _ MAX[max, TermLoad[pla, term]] ENDLOOP}; NofHotTerms: PROC[pla: PLAOps.PLA, threshold: INT] RETURNS[cnt: INT _ 0] = { FOR term: PLAOps.Term _ pla.termList.begin, term.next WHILE term#NIL DO IF TermLoad[pla, term] > threshold THEN cnt _ cnt+1 ENDLOOP}; MaxLdsPerOut: PROC[pla: PLAOps.PLA] RETURNS[max: INT _ 0] = { bitFormat: PLAOps.Format _ REFBit.Desc[pla.out].bitForm; FOR out: INT IN [0..bitFormat.size) DO thisOutMax: INT _ 0; FOR term: PLAOps.Term _ pla.termList.begin, term.next WHILE term#NIL DO IF PLAOps.GetOutQrt[term, bitFormat[out].firstBit]=one THEN thisOutMax _ thisOutMax+1 ENDLOOP; max _ MAX[max, thisOutMax] ENDLOOP}; END.