<> <> <> <> 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> IF wire.wireDrive=infinite THEN RETURN [val: [lvl: wire.wireLevel, drv: infinite]]; val _ [X, none]; <> IF wire.currentValue#NIL THEN ERROR; -- Not yet supported (c.f. RecomputeValue) IF wire.connections#NIL THEN FOR writers: CARDINAL IN [0..wire.connections.size) DO writer: Rosemary.Field _ wire.connections[writers]; writerLevel: Ports.Level _ writer.currentValue[0]; writerDrive: Ports.Drive _ IF writer.currentDrive=NIL THEN writer.portBinding.currentDrive ELSE writer.currentDrive[0]; IF boundary#both THEN { connectionInside: BOOL _ IF writer.portBinding.instance=NIL THEN FALSE ELSE Inside[writer.portBinding.instance.instance, target.flatCell^]; IF connectionInside # (boundary=inside) THEN LOOP; }; SELECT TRUE FROM writerDrive > 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; <none => compositeDrive[i] _ IF mayBeTS[i] THEN force ELSE drive;>> 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. <> <> <> <> <> <> <> <> <> <> <> <> <<>>