DIRECTORY Core, CoreFlat, CoreOps, FS, IO, Ports, RefTab, Rope, Rosemary, RosemaryVector, TerminalIO; RosemaryVectorImpl: CEDAR PROGRAM IMPORTS CoreFlat, CoreOps, FS, IO, Ports, RefTab, Rope, Rosemary, TerminalIO EXPORTS RosemaryVector = BEGIN OPEN RosemaryVector; OpenVectorFile: PUBLIC PROC [fileName: Rope.ROPE, port: Ports.Port, read: BOOL _ TRUE] RETURNS [vectorFile: VectorFile] = { vectorFile _ NEW [VectorFileRec]; vectorFile.port _ port; vectorFile.stream _ FS.StreamOpen[fileName, IF read THEN $read ELSE $create]; }; CloseVectorFile: PUBLIC PROC [vectorFile: VectorFile] = { IO.Close[vectorFile.stream]; }; WriteVector: PUBLIC PROC [vectorFile: VectorFile, neverSayExpect: BOOL _ FALSE] = { WriteDrive: PROC [d: Ports.Drive] = { IO.PutRope[vectorFile.stream, Ports.driveNames[IF neverSayExpect AND d=expect THEN none ELSE d]]; IO.PutRope[vectorFile.stream, " "]; }; WriteLevel: PROC [l: Ports.Level] = { IO.PutRope[vectorFile.stream, Ports.levelNames[l]]; IO.PutRope[vectorFile.stream, " "]; }; WriteBool: PROC [b: BOOL] = { IO.PutRope[vectorFile.stream, IF b THEN "T " ELSE "F "]; }; WritePort: PROC [p: Ports.Port] = { IF p.levelType=composite THEN FOR i: NAT IN [0..p.size) DO WritePort[p[i]]; ENDLOOP ELSE { IO.PutRope[vectorFile.stream, Ports.driveTypeNames[p.driveType]]; IO.PutRope[vectorFile.stream, " "]; SELECT p.driveType FROM aggregate => WriteDrive[p.d]; separate => FOR i: NAT IN [0..p.ds.size) DO WriteDrive[p.ds[i]]; ENDLOOP; ENDCASE => ERROR; SELECT p.levelType FROM l => WriteLevel[p.l]; ls => FOR i: NAT IN [0..p.ls.size) DO WriteLevel[p.ls[i]]; ENDLOOP; b => WriteBool[p.b]; bs => FOR i: NAT IN [0..p.bs.size) DO WriteBool[p.bs[i]]; ENDLOOP; c => IO.PutF[vectorFile.stream, "%g ", IO.card[p.c]]; lc => IO.PutF[vectorFile.stream, "%g ", IO.card[p.lc]]; q => FOR i: NAT IN [0..4) DO IO.PutF[vectorFile.stream, "%g ", IO.card[p.q[i]]]; ENDLOOP; ENDCASE => ERROR; }; }; WritePort[vectorFile.port]; }; ReadVector: PUBLIC PROC [vectorFile: VectorFile] = { ReadDrive: PROC RETURNS [d: Ports.Drive] = { name: Rope.ROPE _ IO.GetID[vectorFile.stream]; d _ Ports.FindDrive[name]; }; ReadLevel: PROC RETURNS [l: Ports.Level] = { name: Rope.ROPE _ IO.GetID[vectorFile.stream]; l _ Ports.FindLevel[name]; }; ReadBool: PROC RETURNS [b: BOOL] = { name: Rope.ROPE _ IO.GetID[vectorFile.stream]; b _ SELECT TRUE FROM Rope.Equal[name, "T"] => TRUE, Rope.Equal[name, "F"] => FALSE, ENDCASE => ERROR; }; ReadPort: PROC [p: Ports.Port] = { IF p.levelType=composite THEN FOR i: NAT IN [0..p.size) DO ReadPort[p[i]]; ENDLOOP ELSE { name: Rope.ROPE _ IO.GetID[vectorFile.stream]; p.driveType _ Ports.FindDriveType[name]; SELECT p.driveType FROM aggregate => p.d _ ReadDrive[]; separate => FOR i: NAT IN [0..p.ds.size) DO p.ds[i] _ ReadDrive[]; ENDLOOP; ENDCASE => ERROR; SELECT p.levelType FROM l => p.l _ ReadLevel[]; ls => FOR i: NAT IN [0..p.ls.size) DO p.ls[i] _ ReadLevel[]; ENDLOOP; b => p.b _ ReadBool[]; bs => FOR i: NAT IN [0..p.bs.size) DO p.bs[i] _ ReadBool[]; ENDLOOP; c => p.c _ IO.GetCard[vectorFile.stream]; lc => p.lc _ IO.GetCard[vectorFile.stream]; q => FOR i: NAT IN [0..4) DO p.q[i] _ IO.GetCard[vectorFile.stream]; ENDLOOP; ENDCASE => ERROR; }; }; ReadPort[vectorFile.port]; }; CheckDUTConnections: PROC [root: Core.CellType, target: Target] RETURNS [failed: BOOL] ~ { EachAtomicPublic: PROC [wire: Core.Wire] ~ { canonized: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; otherWire: Core.Wire; canonized^ _ CoreFlat.CanonizeWire[root, [flatCell: target.flatCell^, wireRoot: public, wire: wire]]; otherWire _ NARROW [RefTab.Fetch[table, canonized].val]; SELECT TRUE FROM otherWire=NIL => [] _ RefTab.Insert[table, canonized, wire]; otherWire=wire => [] _ RefTab.Insert[table, canonized, wire]; -- public is DAG ENDCASE => { -- A different public maps to the same canonized wire IF NOT failed THEN TerminalIO.PutF["*** DUT publics may not be connected during a capture simulation:\n"]; TerminalIO.PutF["*** %g connected to %g\n", IO.rope[CoreOps.GetFullWireName[target.dut.public, wire]], IO.rope[CoreOps.GetFullWireName[target.dut.public, otherWire]]]; failed _ TRUE; }; }; table: RefTab.Ref _ RefTab.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash]; failed _ FALSE; CoreOps.VisitRootAtomics[target.dut.public, EachAtomicPublic]; }; CreateTarget: PUBLIC PROC [simulation: Rosemary.Simulation, flatCell: CoreFlat.FlatCellType, test: Ports.Port] RETURNS [target: Target] = { VisitPort: Ports.EachWirePortPairProc = { IF RefTab.Fetch[visitTable, port].found THEN RETURN; IF NOT RefTab.Insert[visitTable, port, $Visited] THEN ERROR; IF port.levelType=composite THEN RETURN; subElements _ FALSE; flatWire.wire _ wire; FOR values: Rosemary.RoseValues _ Rosemary.GetValues[simulation, flatWire], values.rest UNTIL values=NIL DO revValues _ CONS[values.first, revValues]; ENDLOOP; max _ MAX[max, CoreOps.WireBits[wire]]; }; revValues: Rosemary.RoseValues _ NIL; visitTable: RefTab.Ref _ RefTab.Create[]; max: INT _ 0; flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; flatWire.flatCell _ flatCell^; flatWire.wireRoot _ public; target _ NEW [TargetRep _ [ flatCell: flatCell, dut: CoreFlat.ResolveFlatCellType[simulation.cellType, flatCell^].cellType ]]; IF Ports.VisitBinding[target.dut.public, test, VisitPort] THEN ERROR; FOR values: Rosemary.RoseValues _ revValues, values.rest UNTIL values=NIL DO target.portRoseValues _ CONS[values.first, target.portRoseValues]; ENDLOOP; target.scratchValue _ NEW[Ports.LevelSequenceRec[max]]; target.insideDrive _ NEW[Ports.DriveSequenceRec[max]]; target.outsideDrive _ NEW[Ports.DriveSequenceRec[max]]; target.compositeDrive _ NEW[Ports.DriveSequenceRec[max]]; target.mayBeTS _ NEW[Ports.BoolSequenceRec[max]]; IF CheckDUTConnections[simulation.cellType, target] THEN ERROR; }; Inside: PROC [child: CoreFlat.FlatCellTypeRec, parent: CoreFlat.FlatCellTypeRec] RETURNS [BOOL] = { IF child.path.length val.drv => val _ [lvl: writerLevel, drv: writerDrive]; writerDrive = val.drv => IF val.lvl#writerLevel AND writerDrive>none THEN val.lvl _ X; ENDCASE => NULL; ENDLOOP; wire.mark _ TRUE; -- to prevent re-exploring this wire FOR t: CARDINAL IN [0..wire.validNotOffChannels) DO tran: Rosemary.RoseTransistor _ wire.notOffChannels[t]; otherWire: Rosemary.RoseWire; mod: WireValue; -- result of analysis for otherWire IF xIsOff AND tran.type#nD AND tran.gate.wireLevel=X THEN LOOP; -- discard if off SELECT TRUE FROM tran.ch1=wire => otherWire _ tran.ch2; tran.ch2=wire => otherWire _ tran.ch1; ENDCASE => ERROR; -- wire is supposed to be on transistor channel IF otherWire.mark THEN LOOP; -- already visiting this wire... IF boundary#both THEN { -- Ignore transistor if not in correct boundary side IF Inside[tran.instance, target.flatCell^] # (boundary=inside) THEN LOOP; }; mod _ ComputeWireValue[otherWire, both, target, xIsOff]; -- deeper levels do not apply boundary mod.drv _ MIN [mod.drv, tran.conductivity]; SELECT TRUE FROM mod.drv > val.drv => val _ mod; mod.drv = val.drv => IF mod.lvl#val.lvl AND mod.drv>none THEN val.lvl _ X; ENDCASE => NULL; ENDLOOP; wire.mark _ FALSE; }; SampleTarget: PUBLIC PROC [target: Target, test: Ports.Port] = { VisitPort: PROC [port: Ports.Port] = { IF RefTab.Fetch[visitTable, port].found THEN RETURN; IF NOT RefTab.Insert[visitTable, port, $Visited] THEN ERROR; IF port.levelType=composite THEN FOR i: NAT IN [0..port.size) DO VisitPort[port[i]]; ENDLOOP ELSE { scratchValue: Ports.LevelSequence = target.scratchValue; insideDrive: Ports.DriveSequence = target.insideDrive; outsideDrive: Ports.DriveSequence = target.outsideDrive; compositeDrive: Ports.DriveSequence = target.compositeDrive; mayBeTS: Ports.BoolSequence = target.mayBeTS; portBits: NAT _ SELECT port.levelType FROM l, b => 1, ls => port.ls.size, bs => port.bs.size, c => 16-port.fieldStart, lc => 32-port.fieldStart, q => 64-port.fieldStart, ENDCASE => ERROR; firstFreeBit: NAT _ 0; FOR i: NAT IN [0..insideDrive.size) DO insideDrive[i] _ outsideDrive[i] _ none; mayBeTS[i] _ FALSE; ENDLOOP; UNTIL firstFreeBit>=portBits DO roseWire: Rosemary.RoseWire _ roseValues.first.roseWire; connections: Rosemary.Fields _ roseWire.connections; currentValue: Ports.LevelSequence _ roseWire.currentValue; IF connections#NIL THEN FOR connectionIndex: NAT IN [0..connections.size) DO portBinding: Rosemary.PortBinding _ connections[connectionIndex].portBinding; connectionInside: BOOL _ IF portBinding.instance=NIL THEN FALSE ELSE Inside[portBinding.instance.instance, target.flatCell^]; IF portBinding.clientPort.driveType=aggregate THEN { IF connectionInside THEN FOR i: NAT IN [0..roseValues.first.fieldWidth) DO insideDrive[firstFreeBit+i] _ MAX [portBinding.clientPort.d, insideDrive[firstFreeBit+i]]; ENDLOOP ELSE FOR i: NAT IN [0..roseValues.first.fieldWidth) DO outsideDrive[firstFreeBit+i] _ MAX [portBinding.clientPort.d, outsideDrive[firstFreeBit+i]]; ENDLOOP; } ELSE { FOR fieldIndex: NAT IN [0..portBinding.fields.size) DO field: Rosemary.Field _ portBinding.fields[fieldIndex]; IF field.roseWire=roseWire THEN { firstBit: NAT _ roseValues.first.fieldStart; FOR bit: NAT IN [0..roseValues.first.fieldWidth) DO IF connectionInside THEN insideDrive[firstFreeBit+bit] _ MAX [field.currentDrive[firstBit+bit], insideDrive[firstFreeBit+bit]] ELSE outsideDrive[firstFreeBit+bit] _ MAX [field.currentDrive[firstBit+bit], outsideDrive[firstFreeBit+bit]]; ENDLOOP; }; ENDLOOP; }; ENDLOOP; IF roseWire.channels#NIL THEN { -- atomic wire with transistors insideOff, insideOn, outsideOff, outsideOn: WireValue; insideOff _ ComputeWireValue[roseWire, inside, target, TRUE]; insideOn _ ComputeWireValue[roseWire, inside, target, FALSE]; outsideOff _ ComputeWireValue[roseWire, outside, target, TRUE]; outsideOn _ ComputeWireValue[roseWire, outside, target, FALSE]; SELECT TRUE FROM outsideOff#outsideOn => { -- Outside is unreasonable ... IF roseWire.wireLevel=X THEN { -- give up insideDrive[firstFreeBit] _ inspect; -- means completely unknown outsideDrive[firstFreeBit] _ outsideOn.drv; } ELSE ERROR; -- How to handle such a crazy situation ??? }; insideOff#insideOn => { -- outside is reasonable, not inside IF roseWire.wireLevel=X THEN { -- give up insideDrive[firstFreeBit] _ inspect; -- means completely unknown outsideDrive[firstFreeBit] _ outsideOn.drv; } ELSE { -- fake it so that the tester drives & checks the observed value insideDrive[firstFreeBit] _ none; outsideDrive[firstFreeBit] _ drive; }; }; ENDCASE => { -- fully-known state IF insideOff.drv=none THEN mayBeTS[firstFreeBit] _ TRUE; insideDrive[firstFreeBit] _ insideOff.drv; outsideDrive[firstFreeBit] _ outsideOff.drv; }; }; IF currentValue=NIL THEN { IF roseWire.wireDrive=infinite THEN { -- power is special, fake it... insideDrive[firstFreeBit] _ infinite; -- this is to force an expect situation... outsideDrive[firstFreeBit] _ none; }; scratchValue[firstFreeBit] _ roseWire.wireLevel; firstFreeBit _ firstFreeBit + 1; } ELSE { firstBit: NAT _ roseValues.first.fieldStart; FOR bit: NAT IN [0..roseValues.first.fieldWidth) DO scratchValue[firstFreeBit + bit] _ currentValue[firstBit+bit]; ENDLOOP; firstFreeBit _ firstFreeBit + roseValues.first.fieldWidth; }; roseValues _ roseValues.rest; ENDLOOP; IF NOT firstFreeBit=portBits THEN ERROR; FOR i: NAT IN [0..portBits) DO in: Ports.Drive = insideDrive[i]; out: Ports.Drive = outsideDrive[i]; SELECT TRUE FROM in=inspect => compositeDrive[i] _ none; in=none AND out=none => compositeDrive[i] _ inspect; in=none AND out>none => compositeDrive[i] _ drive; in>=out AND out>=none => compositeDrive[i] _ expect; out>in => compositeDrive[i] _ drive; ENDCASE => ERROR; -- unsupported case ENDLOOP; IF port.driveType=aggregate THEN { port.d _ compositeDrive[0]; FOR i: NAT IN [0..portBits) DO IF port.d#compositeDrive[i] THEN ERROR; -- different drive values for the aggregate ENDLOOP; } ELSE FOR i: NAT IN [0..port.ds.size) DO port.ds[i] _ compositeDrive[i] ENDLOOP; SELECT port.levelType FROM l => port.l _ scratchValue[0]; ls => FOR i: NAT IN [0..port.ls.size) DO port.ls[i] _ scratchValue[i]; ENDLOOP; b => port.b _ Ports.ToBool[scratchValue[0]]; bs => FOR i: NAT IN [0..port.bs.size) DO port.bs[i] _ Ports.ToBool[scratchValue[i]]; ENDLOOP; c => port.c _ Ports.LSToC[scratchValue]; lc => port.lc _ Ports.LSToLC[scratchValue]; q => port.q _ Ports.LSToQ[scratchValue]; ENDCASE => ERROR; }; }; roseValues: Rosemary.RoseValues _ target.portRoseValues; visitTable: RefTab.Ref _ RefTab.Create[]; VisitPort[test]; }; END. †RosemaryVectorImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Barth, January 12, 1988 10:42:18 am PST Jean-Marc Frailong September 30, 1988 11:40:09 am PDT Verify that the public of the DUT does not have it's DAGness altered by the way it is inserted in the simulation CellType. Compute value of wire (use only specified boundary condition). Transistor with X gates are assumed on or off according to xIsOff. First, compute contributions from ports writing into this wire Then, add-in transistor network contributions in=none AND out>none => compositeDrive[i] _ IF mayBeTS[i] THEN force ELSE drive; Jean-Marc Frailong September 13, 1988 6:24:11 pm PDT Corrected bug in computation of path to power: did not prevent reexploration of level 0 changes to: PathToPower (PT001) Jean-Marc Frailong September 14, 1988 2:35:21 pm PDT Corrected drive computation (was using aggregate case always) changes to: TraverseGraph (local of PathToPower) changed clientPort.d to drv Jean-Marc Frailong September 14, 1988 6:28:28 pm PDT Corrected drive computation (must ignore transistors with X gates) changes to: TraverseGraph (local of PathToPower), VisitPort (local of SampleTarget) Jean-Marc Frailong September 23, 1988 6:48:45 pm PDT Added check that public of DUT does not have any wire connected together changes to: CheckDUTConnections New function, CreateTarget Call CheckDUTConnections Κ³˜codešœ™Kšœ Οmœ7™BKšœ'™'K™5—K˜šΟk œžœžœ<˜eK˜—šΟnœžœž˜!Kšžœžœžœ+˜LKšžœžœžœ˜3—K˜šŸœžœžœžœžœžœžœ˜{Kšœ žœ˜!Kšœ˜Kš œžœžœžœžœ ˜MKšœ˜K˜—šŸœžœžœ˜9Kšžœ˜Kšœ˜J˜—š Ÿ œžœžœ*žœžœ˜SK˜šŸ œžœ˜%Kš žœ-žœžœ žœžœ˜aKšžœ!˜#K˜K˜—šŸ œžœ˜%Kšžœ1˜3Kšžœ!˜#K˜K˜—šŸ œžœžœ˜Kšžœžœžœžœ˜8K˜K˜—šŸ œžœ˜#š žœžœžœžœžœ ž˜:K˜Kšž˜—šžœ˜Kšžœ?˜AKšžœ!˜#šžœ ž˜Kšœ˜šœ žœžœžœž˜+Kšœ˜Kšžœ˜—Kšžœžœ˜—šžœ ž˜Kšœ˜šœžœžœžœž˜%Kšœ˜Kšžœ˜—Kšœ˜šœžœžœžœž˜%Kšœ˜Kšžœ˜—Kšœžœ žœ ˜5Kšœžœ žœ ˜7šœžœžœžœž˜Kšžœ žœ˜3Kšžœ˜—Kšžœžœ˜—K˜—K˜K˜—Kšœ˜Kšœ˜J˜—šŸ œžœžœ˜4K˜šŸ œžœžœ˜,Kšœ žœžœ˜.Kšœ˜Kšœ˜K˜—šŸ œžœžœ˜,Kšœ žœžœ˜.Kšœ˜K˜K˜—šŸœžœžœžœ˜$Kšœ žœžœ˜.šœžœžœž˜Kšœžœ˜Kšœžœ˜Kšžœžœ˜—K˜K˜—šŸœžœ˜"š žœžœžœžœžœ ž˜:Kšœ˜Kšž˜—šžœ˜Kšœ žœžœ˜.Kšœ(˜(šžœ ž˜Kšœ˜šœ žœžœžœž˜+Kšœ˜Kšžœ˜—Kšžœžœ˜—šžœ ž˜Kšœ˜šœžœžœžœž˜%Kšœ˜Kšžœ˜—Kšœ˜šœžœžœžœž˜%Kšœ˜Kšžœ˜—Kšœ žœ˜)Kšœ žœ˜+šœžœžœžœž˜Kšœ žœ˜'Kšžœ˜—Kšžœžœ˜—K˜—K˜K˜—Kšœ˜Kšœ˜J˜—šŸœžœ'žœ žœ˜ZKšœžœY™zšŸœžœ˜,Kšœžœ˜9K˜Kšœe˜eKšœ žœ&˜8šžœžœž˜Kšœ žœ/˜Οc˜Nšžœ 5˜BKšžœžœžœX˜jšœ+˜+Kšžœ8˜:Kšžœ>˜@—Kšœ žœ˜Kšœ˜——K˜—Kšœ^˜^Kšœ žœ˜Kšœ>˜>K˜K˜—šŸ œžœžœVžœ˜‹šŸ œ ˜)Kšžœ&žœžœ˜4Kšžœžœ+žœžœ˜šœ žœ˜)K˜—šŸœžœGžœžœ˜K™Kšžœžœžœ-˜SK˜K™>Kš žœžœžœžœ *˜Oš žœžœžœžœ žœžœž˜SKšœ3˜3Kšœ2˜2Kš œžœžœžœ!žœ˜wšžœžœ˜Kš œžœžœžœžœžœžœ@˜‹Kšžœ&žœžœ˜2Kšœ˜—šžœžœž˜KšœD˜DKšœžœžœžœ ˜VKšžœžœ˜—Kšžœ˜—K™-Kšœ žœ $˜6šžœžœžœž˜3Kšœ7˜7K˜Kšœ #˜3Kš žœžœžœžœžœ ˜Qšžœžœž˜Kšœ&˜&Kšœ&˜&Kšžœžœ /˜A—Kšžœžœžœ  ˜=šžœžœ 4˜LKšžœ=žœžœ˜IKšœ˜—Jšœ9 &˜_Jšœ žœ˜+šžœžœž˜Kšœ˜Kšœžœžœžœ ˜JKšžœžœ˜—Kšžœ˜—Kšœ žœ˜K˜K˜—šŸ œžœžœ'˜@šŸ œžœ˜&Kšžœ&žœžœ˜4Kšžœžœ+žœžœ˜<š žœžœžœžœžœž˜@K˜Kšž˜—šžœ˜Kšœ8˜8Kšœ6˜6Kšœ8˜8Kšœ<˜˜>Kšžœ˜—Kšœ:˜:K˜—Kšœ˜Kšžœ˜—Kšžœžœžœžœ˜(šžœžœžœž˜Kšœ!˜!Kšœ#˜#šžœžœž˜Kšœ'˜'Kšœžœ)˜4Kš œžœ!žœ žœžœ™PKšœžœ'˜2Kšœžœ)˜4Kšœ$˜$Kšžœžœ ˜%—Kšžœ˜—šžœžœ˜"Kšœ˜šžœžœžœž˜Kšžœžœžœ +˜SKšžœ˜—K˜—Kš žœžœžœžœžœ žœ˜Ošžœž˜Kšœ˜šœžœžœžœž˜(Kšœ˜Kšžœ˜—Kšœ,˜,šœžœžœžœž˜(Kšœ+˜+Kšžœ˜—Kšœ(˜(Kšœ+˜+Kšœ(˜(Kšžœžœ˜—K˜—K˜—Kšœ8˜8K˜)K˜K˜K˜—Jšžœ˜™4K™WKšœ Οr œ™—™4K™=Kšœ ‘ œ3™L—™4K™BKšœ ‘ œ‘ œ™S—™4K™HKšœ ‘œ ‘œ™S—K™—…—54Km