<> <> <> <> <<>> <> <<>> DIRECTORY Basics, BasicTime, Core, CoreFlat, CoreOps, CoreProperties, FS, IO, Ports, RefTab, RefText, Rosemary, RosemaryUser, RosemaryVector, Rope, SymTab, TerminalIO, TiogaFileOps, TiogaStreams, MTSVector; MTSVectorImpl: CEDAR PROGRAM IMPORTS Basics, BasicTime, CoreFlat, CoreOps, CoreProperties, FS, IO, Ports, RefTab, RefText, Rosemary, RosemaryUser, RosemaryVector, Rope, SymTab, TerminalIO, TiogaFileOps, TiogaStreams EXPORTS MTSVector SHARES MTSVector ~ BEGIN OPEN MTSVector; <> bitMask: ARRAY [0..8) OF BYTE; vectorBlockLength: NAT _ 16384; -- number of bytes in a block of test vectors (end up with 0's) testFileHeaderSize: CARD16 _ 2048; -- minimum number of bytes in file header headerSignature: Rope.ROPE _ "MTSX003"; -- signature in header <> <> <<0 1 1 0 Issue 0 & check it>> <> <<1 1 1 1 Issue 1 & check it>> <> <> <> <> <> <> MapPublicToPackage: PROC [public: Core.WireSeq, package: Package] RETURNS [wireToPins: RefTab.Ref] ~ { <> Fail: PROC [name, explanation: Rope.ROPE] ~ { failed _ TRUE; TerminalIO.PutF["*** Wire %g : %g.\n", IO.rope[name], IO.rope[explanation]]; }; CheckDefined: PROC [wire: Core.Wire] ~ { IF NOT RefTab.Fetch[wireToPins, wire].found THEN { Fail[CoreOps.GetFullWireName[public, wire], "not described in pins file"]; [] _ RefTab.Insert[wireToPins, wire, NIL]; -- to avoid double messages }; }; Define: SymTab.EachPairAction ~ { wd: WireDescription _ NARROW [val]; wire: Core.Wire = CoreOps.FindWire[public, key]; SELECT TRUE FROM wire=NIL => Fail[key, "not found in public"]; wire.size#0 => Fail[key, "not atomic"]; RefTab.Insert[wireToPins, wire, wd] => NULL; -- all OK ENDCASE => Fail[key, "wire defined twice"]; }; failed: BOOL _ FALSE; wireToPins _ RefTab.Create[]; [] _ SymTab.Pairs[package.signals, Define]; -- lookup all signals in the public CoreOps.VisitRootAtomics[public, CheckDefined]; IF failed THEN ERROR; -- DUT pins do not match package pins }; <> PutHeader: PROC [file: File] ~ { <> <
> PutByte: PROC [b: BYTE] ~ { <> IO.PutByte[file.stream, b]; file.ckSum _ Basics.BITAND[file.ckSum+b, 000FFH]; }; PutCard16: PROC [c: CARD16] ~ { <> PutByte[Basics.LowByte[c]]; PutByte[Basics.HighByte[c]]; }; PutInt32: PROC [i: INT32] ~ { <> n: Basics.LongNumber; n.li _ i; PutByte[n.ll]; PutByte[n.lh]; PutByte[n.hl]; PutByte[n.hh]; }; <> <> <> <> <> <> <> <> <<};>> PutCRope: PROC [r: Rope.ROPE] ~ { <> EachChar: Rope.ActionType ~ { PutByte[ORD[c]] }; [] _ Rope.Map[base: r, action: EachChar]; PutByte[00H]; }; PutRope: PROC [r: Rope.ROPE, length: INT] ~ { <> EachChar: Rope.ActionType ~ { PutByte[ORD[c]] }; [] _ Rope.Map[base: r, action: EachChar, start: 0, len: MIN[length, Rope.Length[r]]]; THROUGH [Rope.Length[r] .. length) DO PutByte[00H] ENDLOOP; }; PutWireDescription: SymTab.EachPairAction ~ { wd: WireDescription = NARROW [val]; PutByte[ORD[wd.flavor]]; -- will be 0FFH for termination flag PutCRope[wd.name]; FOR pins: LIST OF PinDescription _ wd.pins, pins.rest UNTIL pins=NIL DO pin: PinDescription = pins.first; PutByte[pin.group]; -- will be 0xFF for terminator PutByte[pin.byte]; PutByte[pin.mask]; PutByte[pin.bit]; PutCRope[pin.pkgName]; PutCRope[pin.conName]; ENDLOOP; PutByte[0FFH]; -- end of pin descriptions list }; ckSumOffset: INT; -- this is where the checksum will go once completed... ckSumByte: BYTE; IO.SetIndex[file.stream, 0]; -- backup to start of file PutRope[headerSignature, 8]; PutInt32[file.hdrSize]; -- garbage on 1st pass... PutCard16[file.nGroups]; PutCard16[vectorBlockLength]; PutInt32[file.nVects]; PutInt32[LOOPHOLE[file.timeStamp]]; ckSumOffset _ IO.GetIndex[file.stream]; -- note down where checksum should go finally PutByte[00H]; -- this is the checksum position, patched at end PutRope[file.id, 120]; -- comment for display on the PC PutCRope[file.package.name]; -- start of package/fixture description PutCRope[file.package.fixtureName]; [] _ SymTab.Pairs[file.package.signals, PutWireDescription]; PutByte[0FFH]; -- end of wire descriptions list THROUGH [(IO.GetIndex[file.stream] MOD 1024) .. 1024) DO PutByte[00H] ENDLOOP; -- add adequate padding file.hdrSize _ IO.GetIndex[file.stream]; IF ( file.hdrSize MOD 1024 ) # 0 THEN ERROR; -- internal bug ckSumByte _ Basics.BITAND[0100H-file.ckSum, 000FFH]; -- recompute checksum for total 0 IO.SetIndex[file.stream, ckSumOffset]; -- get back to where the checksum should be IO.PutByte[file.stream, ckSumByte]; -- and write it IO.SetIndex[file.stream, file.hdrSize]; -- get back to end of header }; WriteBByte: PROC [file: File, b: BYTE] ~ { <> block: REF TEXT _ file.block; IF block.length>=block.maxLength THEN ERROR; -- buffer overflowed block[block.length] _ VAL[b]; block.length _ block.length+1; file.ckSum _ Basics.BITAND[file.ckSum+b, 000FFH]; }; FlushBlock: PROC [file: File, nBytes: NAT] ~ { <> block: REF TEXT _ file.block; IF block.length>nBytes THEN ERROR; -- internal bug UNTIL block.length=nBytes DO WriteBByte[file, 00H] ENDLOOP; IO.PutBlock[file.stream, block, 0, nBytes]; block.length _ 0; }; <> GetHeader: PROC [file: File] ~ { <> <
> GetByte: PROC [] RETURNS [b: BYTE] ~ { <> b _ IO.GetByte[file.stream]; file.ckSum _ Basics.BITAND[file.ckSum+b, 000FFH]; }; GetInt32: PROC [] RETURNS [i: INT32] ~ { <> n: Basics.LongNumber; n.ll _ GetByte[]; n.lh _ GetByte[]; n.hl _ GetByte[]; n.hh _ GetByte[]; i _ n.li; }; GetCard16: PROC [] RETURNS [c: CARD16] ~ { <> n: Basics.ShortNumber; n.lo _ GetByte[]; n.hi _ GetByte[]; c _ n.sc; }; GetRope: PROC [length: NAT] RETURNS [r: Rope.ROPE] ~ { <> buf: REF TEXT _ RefText.ObtainScratch[length]; lastNonPad: INT _ -1; FOR i: NAT IN [0..length) DO b: BYTE = GetByte[]; buf _ RefText.AppendChar[buf, VAL[b]]; IF b#00H THEN lastNonPad _ i; ENDLOOP; r _ Rope.FromRefText[buf, 0, lastNonPad+1]; RefText.ReleaseScratch[buf]; }; GetCRope: PROC [] RETURNS [r: Rope.ROPE] ~ { <> buf: REF TEXT _ RefText.ObtainScratch[256]; -- quite reasonable length DO b: BYTE = GetByte[]; IF b=00H THEN EXIT; -- rope terminator found buf _ RefText.AppendChar[buf, VAL[b]]; ENDLOOP; r _ Rope.FromRefText[buf]; RefText.ReleaseScratch[buf]; }; signature: Rope.ROPE; blockLength: NAT; file.ckSum _ 0; signature _ GetRope[8]; IF NOT Rope.Equal[signature, headerSignature] THEN ERROR; -- invalid file format file.hdrSize _ GetInt32[]; file.nGroups _ GetCard16[]; blockLength _ GetCard16[]; IF blockLength#vectorBlockLength THEN ERROR; -- invalid file format file.nVects _ GetInt32[]; file.timeStamp _ LOOPHOLE[GetInt32[]]; [] _ GetByte[]; -- checksum file.id _ GetRope[120]; file.package _ NEW [PackageRep _ [signals: SymTab.Create[]]]; file.package.name _ GetCRope[]; file.package.fixtureName _ GetCRope[]; DO -- loop until wire description list exhausted b: BYTE _ GetByte[]; wd: WireDescription _ NEW [WireDescriptionRep]; IF b=0FFH THEN EXIT; -- end of wire description list wd.flavor _ VAL [b]; wd.name _ GetCRope[]; DO -- loop until pin description list for current wire exhausted pd: PinDescription; b _ GetByte[]; IF b=0FFH THEN EXIT; -- end of pin description list pd _ NEW [PinDescriptionRep]; pd.group _ b; pd.byte _ GetByte[]; pd.mask _ GetByte[]; pd.bit _ GetByte[]; pd.pkgName _ GetCRope[]; pd.conName _ GetCRope[]; wd.pins _ CONS [pd, wd.pins]; -- append (well, prepend) to list ENDLOOP; IF NOT SymTab.Insert[file.package.signals, wd.name, wd] THEN ERROR; -- incorrect file ENDLOOP; THROUGH [IO.GetIndex[file.stream] .. file.hdrSize) DO [] _ GetByte[] ENDLOOP; IF IO.GetIndex[file.stream]#file.hdrSize THEN ERROR; -- incorrect file UNTIL IO.EndOf[file.stream] DO [] _ GetByte[] ENDLOOP; -- to compute checksum IF Basics.BITAND[file.ckSum, 000FFH]#0 THEN ERROR; -- invalid checksum IO.SetIndex[file.stream, file.hdrSize]; -- back to the first vector }; <> Create: PUBLIC PROC [ct: Core.CellType, package: Rope.ROPE, vectors: Rope.ROPE, title: Rope.ROPE _ NIL] RETURNS [file: File] ~ { <> <> HighestBoard: SymTab.EachPairAction ~ { <> wd: WireDescription = NARROW [val]; SELECT wd.flavor FROM signal, pullup => { FOR pins: LIST OF PinDescription _ wd.pins, pins.rest UNTIL pins=NIL DO file.nGroups _ MAX [pins.first.group, file.nGroups]; ENDLOOP }; gnd, vdd, ignore => NULL; ENDCASE => ERROR; -- incorrect value ... }; file _ NEW [FileRep _ [dut: ct, nGroups: -1, ckSum: 0, nVects: 0, timeStamp: BasicTime.Now[]]]; file.package _ ReadPackage[MakeFileName[package, "mtsPins", FALSE]]; file.wireToPins _ MapPublicToPackage[ct.public, file.package]; [] _ SymTab.Pairs[file.package.signals, HighestBoard]; IF file.nGroups<0 THEN ERROR; -- incorrect pin file file.nGroups _ file.nGroups + 1; -- was index of highest board, not number of boards IF Rope.IsEmpty[title] THEN title _ IO.PutFR["%g on %g", IO.rope[CoreOps.GetCellTypeName[ct]], IO.rope[file.package.name]]; file.id _ IO.PutFR["%g -- %g", IO.rope[title], IO.time[]]; file.block _ RefText.New[vectorBlockLength]; file.vector _ NEW [VectorRep[file.nGroups]]; FOR i: NAT IN [0..file.vector.ngrps) DO file.vector[i] _ NEW [CGRep] ENDLOOP; file.stream _ FS.StreamOpen[MakeFileName[vectors, "xtv", TRUE], create]; TerminalIO.PutF["MTS vectors saved on %g\n", IO.rope[FS.GetName[FS.OpenFileFromStream[file.stream]].fullFName]]; PutHeader[file]; file.ckSum _ 0; -- ignore previous chksum, header will be rewritten ... }; WriteVector: PUBLIC PROC [file: File] ~ { <> bytesPerVector: NAT = 24*file.nGroups; file.nVects _ file.nVects+1; IF file.block.length+bytesPerVector>vectorBlockLength THEN FlushBlock[file, vectorBlockLength]; FOR g: NAT IN [0..file.vector.ngrps) DO group: CG = file.vector[g]; FOR i: NAT IN [0..8) DO WriteBByte[file, group.tristate.bytes[i]] ENDLOOP; FOR i: NAT IN [0..8) DO WriteBByte[file, group.data.bytes[i]] ENDLOOP; FOR i: NAT IN [0..8) DO WriteBByte[file, group.mask.bytes[i]] ENDLOOP; ENDLOOP; }; WriteVectorFromPorts: PUBLIC PROC [file: File, before: Ports.Port, after: Ports.Port] ~ { <> <> Record: PROC [wire: Core.Wire, levelBefore: Ports.Level, driveBefore: Ports.Drive, levelAfter: Ports.Level, driveAfter: Ports.Drive, mode: REF ANY] ~ { <> wd: WireDescription _ NARROW [RefTab.Fetch[wireToPins, wire].val]; source, data, mask: BOOL; -- the 3 bits defining a test vector "bit" useEarlyDrive: BOOL _ TRUE; -- If driven before, use that value IF wd.flavor=ignore THEN RETURN; -- pin not connected to tester, all default to FALSE SELECT mode FROM NIL => NULL; $After => useEarlyDrive _ FALSE; ENDCASE => ERROR; -- Unknown value of MTSOption property IF useEarlyDrive AND driveBefore=drive THEN { SELECT levelBefore FROM H => {source _ TRUE; data _ TRUE; mask _ TRUE}; -- 1: drive and expect a 1 L => {source _ TRUE; data _ FALSE; mask _ TRUE}; -- 0: drive and expect a 0 X => {source _ FALSE; data _ FALSE; mask _ FALSE}; -- X: don't drive, ignore result ENDCASE => ERROR; -- cannot happen } ELSE { -- driveBefore # drive SELECT driveAfter FROM expect => SELECT levelAfter FROM H => {source _ FALSE; data _ TRUE; mask _ TRUE}; -- H: don't drive, expect 1 L => {source _ FALSE; data _ FALSE; mask _ TRUE}; -- L: don't drive, expect 0 X => {source _ FALSE; data _ FALSE; mask _ FALSE}; -- X: don't drive, ignore result ENDCASE => ERROR; -- cannot happen inspect => { IF wd.flavor=pullup THEN SELECT levelAfter FROM H => {source _ FALSE; data _ TRUE; mask _ TRUE}; -- H: don't drive, expect a 1 L => {source _ TRUE; data _ FALSE; mask _ TRUE}; -- 0: drive and expect a 0 X => {source _ FALSE; data _ TRUE; mask _ TRUE}; -- H: don't drive, expect a 1 ENDCASE => ERROR -- cannot happen ELSE SELECT levelAfter FROM H => {source _ TRUE; data _ TRUE; mask _ FALSE}; -- T: drive 1 and check TS L => {source _ TRUE; data _ FALSE; mask _ FALSE}; -- F: drive 0 and check TS X => {source _ TRUE; data _ FALSE; mask _ FALSE}; -- F: drive 0 and check TS ENDCASE => ERROR; -- cannot happen }; none => {source _ FALSE; data _ FALSE; mask _ FALSE}; -- X: don't drive, ignore result drive => { IF useEarlyDrive THEN { -- didn't drive before, does after ??? source _ FALSE; data _ FALSE; mask _ FALSE; -- X: don't drive, ignore result } ELSE { -- special wire: always use the late drive value ... SELECT levelAfter FROM H => {source _ TRUE; data _ TRUE; mask _ TRUE}; -- 1: drive and expect a 1 L => {source _ TRUE; data _ FALSE; mask _ TRUE}; -- 0: drive and expect a 0 X => {source _ FALSE; data _ FALSE; mask _ FALSE}; -- X: don't drive, ignore result ENDCASE => ERROR; -- cannot happen }; }; ENDCASE => ERROR; -- Incorrect capture }; IF wd.flavor=vdd AND NOT ((NOT source) AND data AND mask) THEN ERROR; -- bug IF wd.flavor=gnd AND NOT ((NOT source) AND (NOT data) AND mask) THEN ERROR; -- bug FOR pins: LIST OF PinDescription _ wd.pins, pins.rest UNTIL pins=NIL DO pin: PinDescription = pins.first; group: CG _ vector[pin.group]; group.tristate.bits[pin.bit] _ source; group.data.bits[pin.bit] _ data; group.mask.bits[pin.bit] _ mask; ENDLOOP; }; VisitDUT: PROC [wire: Core.Wire, before: Ports.Port, after: Ports.Port] ~ { mode: REF ANY _ CoreProperties.GetWireProp[wire, $MTSOption]; IF before.levelType#after.levelType THEN ERROR; IF before.driveType#after.driveType THEN ERROR; SELECT before.levelType FROM l => Record[wire, before.l, before.d, after.l, after.d, mode]; b => Record[wire, IF before.b THEN H ELSE L, before.d, IF after.b THEN H ELSE L, after.d, mode]; ls => { IF before.driveType=separate THEN FOR i: NAT IN [0..wire.size) DO Record[wire[i], before.ls[i], before.ds[i], after.ls[i], after.ds[i], mode]; ENDLOOP ELSE FOR i: NAT IN [0..wire.size) DO Record[wire[i], before.ls[i], before.d, after.ls[i], after.d, mode]; ENDLOOP }; bs => { IF before.driveType=separate THEN FOR i: NAT IN [0..wire.size) DO Record[wire[i], IF before.bs[i] THEN H ELSE L, before.ds[i], IF after.bs[i] THEN H ELSE L, after.ds[i], mode]; ENDLOOP ELSE FOR i: NAT IN [0..wire.size) DO Record[wire[i], IF before.bs[i] THEN H ELSE L, before.d, IF after.bs[i] THEN H ELSE L, after.d, mode]; ENDLOOP }; c => ERROR; -- not yet supported lc => ERROR; -- not yet supported q => ERROR; -- not yet supported composite => { -- Explore sub-wires FOR i: NAT IN [0..wire.size) DO VisitDUT[wire[i], before[i], after[i]]; ENDLOOP; }; ENDCASE => ERROR; -- unexpected value }; vector: Vector _ file.vector; wireToPins: RefTab.Ref _ file.wireToPins; FOR i: NAT IN [0..vector.ngrps) DO -- force uninitialized bits to Ignore vector[i].tristate.bits _ ALL [FALSE]; vector[i].data.bits _ ALL [FALSE]; vector[i].mask.bits _ ALL [FALSE]; ENDLOOP; [] _ VisitDUT[file.dut.public, before, after]; -- compute vector WriteVector[file]; -- and add it to file }; Close: PUBLIC PROC [file: File] ~ { <> sum: CARD16 _ 0; IF file.block.length#0 THEN FlushBlock[file, vectorBlockLength]; TerminalIO.PutF["%g vectors captured during simulation\n", IO.int[file.nVects]]; PutHeader[file]; IO.SetIndex[file.stream, 0]; -- backtrack to start of file UNTIL IO.EndOf[file.stream] DO -- check file checksum byte: BYTE _ IO.GetByte[file.stream]; sum _ Basics.BITAND[sum+byte, 0FFH]; ENDLOOP; IF sum#0 THEN ERROR; -- implementation bug: file did not checksum properly !!! IO.Close[file.stream]; }; Read: PUBLIC PROC [ct: Core.CellType, vectors: Rope.ROPE, eachVector: PROC [File]] ~ { <> GetByte: PROC [] RETURNS [b: BYTE] ~ { b _ ORD [RefText.Fetch[block, blockOffset]]; blockOffset _ blockOffset+1; }; bytesPerVector: NAT; blockOffset: NAT _ vectorBlockLength; block: REF TEXT _ RefText.New[vectorBlockLength]; file: File _ NEW [FileRep _ [dut: ct, block: block, ckSum: 0, timeStamp: BasicTime.nullGMT]]; file.stream _ FS.StreamOpen[MakeFileName[vectors, "xtv", FALSE], read]; GetHeader[file]; IF ct#NIL THEN file.wireToPins _ MapPublicToPackage[ct.public, file.package]; -- ct=NIL for ASCII file.vector _ NEW [VectorRep[file.nGroups]]; FOR i: NAT IN [0..file.vector.ngrps) DO file.vector[i] _ NEW [CGRep] ENDLOOP; bytesPerVector _ 24*file.nGroups; TerminalIO.PutF["MTS vectors read from %g (%g vectors).\n", IO.rope[FS.GetName[FS.OpenFileFromStream[file.stream]].fullFName], IO.int[file.nVects]]; THROUGH [0..file.nVects) DO IF blockOffset+bytesPerVector>vectorBlockLength THEN { nBytesRead: NAT _ IO.GetBlock[file.stream, block, 0, vectorBlockLength]; <<-- Note that there is no need to verify the checksum since GetHeader did it...>> IF nBytesRead#vectorBlockLength THEN ERROR; -- last block truncated blockOffset _ 0; }; FOR g: NAT IN [0..file.vector.ngrps) DO group: CG = file.vector[g]; FOR i: NAT IN [0..8) DO group.tristate.bytes[i] _ GetByte[] ENDLOOP; FOR i: NAT IN [0..8) DO group.data.bytes[i] _ GetByte[] ENDLOOP; FOR i: NAT IN [0..8) DO group.mask.bytes[i] _ GetByte[] ENDLOOP; ENDLOOP; eachVector[file]; -- call back user ENDLOOP; IF NOT IO.EndOf[file.stream] THEN ERROR; -- what is trailing behind the vectors ??? IO.Close[file.stream]; }; <> CreateCapture: PUBLIC PROC [ct: Core.CellType] RETURNS [capture: Capture] ~ { <> <> <<- On top level cell: >> < -- CoreFlat path to the device under test>> < -- title of the generated MTS file>> < (c.f. RosemaryUser)>> <> <<- On the DUT: >> < -- name of the file describing the package, and hence the fixture.>> < -- name of the file where vectors will be stored.>> Failed: PROC [msg: Rope.ROPE] RETURNS [nil: Capture _ NIL] ~ { TerminalIO.PutF["*** %g, vectors will not be captured.\n", IO.rope[msg]]; }; targetRope: Rope.ROPE = NARROW [CoreProperties.GetCellTypeProp[ct, $DUT]]; vectors, package, title: Rope.ROPE; handle: RosemaryUser.RoseDisplay = RosemaryUser.RoseDisplayFor[ct]; targetFlatCT: CoreFlat.FlatCellType; targetCT: Core.CellType; capture _ NEW [CaptureRep]; IF handle=NIL THEN RETURN[Failed["Unable to recover Rosemary display"]]; IF Rope.IsEmpty[targetRope] THEN RETURN[Failed["Missing DUT description"]]; targetFlatCT _ NEW [CoreFlat.FlatCellTypeRec _ CoreFlat.ParseCellTypePath[ct, targetRope, handle.cutSet]]; IF CoreFlat.BelowCutSet[ct, targetFlatCT^, handle.cutSet] THEN RETURN[Failed["DUT is below simulation cutset"]]; targetCT _ CoreFlat.ResolveFlatCellType[ct, targetFlatCT^].cellType; vectors _ NARROW [CoreProperties.GetCellTypeProp[targetCT, $Vectors]]; package _ NARROW [CoreProperties.GetCellTypeProp[targetCT, $Package]]; title _ NARROW [CoreProperties.GetCellTypeProp[targetCT, $Title]]; IF vectors=NIL THEN vectors _ package; IF package=NIL THEN package _ vectors; IF Rope.IsEmpty[vectors] THEN RETURN[Failed["Unable to find name for vector file"]]; IF Rope.IsEmpty[package] THEN RETURN[Failed["Unable to find name for package file"]]; capture.before _ Ports.CreatePort[targetCT, TRUE]; capture.after _ Ports.CreatePort[targetCT, TRUE]; capture.target _ RosemaryVector.CreateTarget[handle.simulation, targetFlatCT, capture.before]; capture.mtsFile _ Create[targetCT, package, vectors, title]; }; EvalAndCapture: PUBLIC PROC [capture: Capture, Eval: RosemaryUser.TestEvalProc, memory: BOOL _ TRUE, useClockEval: BOOL _ TRUE, checkPorts: BOOL _ TRUE] ~ { <> IF useClockEval THEN { Eval[memory: memory, clockEval: TRUE, checkPorts: FALSE]; IF capture#NIL THEN RosemaryVector.SampleTarget[capture.target, capture.before]; Eval[memory: memory, clockEval: FALSE, checkPorts: checkPorts]; IF capture#NIL THEN { RosemaryVector.SampleTarget[capture.target, capture.after]; WriteVectorFromPorts[capture.mtsFile, capture.before, capture.after]; }; } ELSE { Eval[memory: memory, checkPorts: checkPorts]; IF capture#NIL THEN { RosemaryVector.SampleTarget[capture.target, capture.after]; WriteVectorFromPorts[capture.mtsFile, capture.after, capture.after]; }; }; }; CloseCapture: PUBLIC PROC [capture: Capture] ~ { IF capture#NIL THEN Close[capture.mtsFile]; }; ReadPort: PUBLIC PROC [ct: Core.CellType, p: Ports.Port, eachVector: PROC[]] ~ { ConvertVectorToPort: PROC [file: File] ~ { Setup: PROC [wire: Core.Wire] RETURNS [lvl: Ports.Level, drv: Ports.Drive] ~ { <> wd: WireDescription = NARROW [RefTab.Fetch[file.wireToPins, wire].val]; IF wd.flavor=ignore THEN { lvl _ L; drv _ inspect; -- ignore port contents, supplied externally } ELSE { group: CG = file.vector[wd.pins.first.group]; bit: [0..60) = wd.pins.first.bit; source, data, mask: BOOL; -- the 3 bits defining a test vector "bit" source _ group.tristate.bits[bit]; data _ group.data.bits[bit]; mask _ group.mask.bits[bit]; IF wd.flavor=pullup THEN { -- simulate the presence of an external pull-up IF source THEN IF data THEN IF mask THEN {lvl _ H; drv _ drive} -- 1 ELSE {lvl _ H; drv _ driveWeak} -- T ELSE IF mask THEN {lvl _ L; drv _ drive} -- 0 ELSE {lvl _ L; drv _ force} -- F, should not happen with pullup ELSE IF data THEN IF mask THEN {lvl _ H; drv _ driveWeak} -- H ELSE {lvl _ H; drv _ driveWeak} -- ? ELSE IF mask THEN {lvl _ L; drv _ expect} -- L ELSE {lvl _ H; drv _ driveWeak} -- X } ELSE { IF source THEN IF data THEN IF mask THEN {lvl _ H; drv _ drive} -- 1 ELSE {lvl _ H; drv _ force} -- T ELSE IF mask THEN {lvl _ L; drv _ drive} -- 0 ELSE {lvl _ L; drv _ force} -- F ELSE IF data THEN IF mask THEN {lvl _ H; drv _ expect} -- H ELSE {lvl _ X; drv _ none} -- ? ELSE IF mask THEN {lvl _ L; drv _ expect} -- L ELSE {lvl _ X; drv _ none} -- X <> } }; }; EachWirePortPair: Ports.EachWirePortPairProc ~ { <<[wire: Core.Wire, port: Port] RETURNS [subElements: BOOL _ TRUE, quit: BOOL _ FALSE]>> subElements _ FALSE; -- presume that we won't explore children SELECT port.levelType FROM l => [port.l, port.d] _ Setup[wire]; b => { [port.l, port.d] _ Setup[wire]; port.b _ SELECT port.l FROM H => TRUE, L => FALSE, ENDCASE => ERROR; }; ls => { drv: Ports.Drive; IF port.driveType=separate THEN FOR i: NAT IN [0..wire.size) DO [port.ls[i], port.ds[i]] _ Setup[wire[i]]; ENDLOOP ELSE FOR i: NAT IN [0..wire.size) DO [port.ls[i], drv] _ Setup[wire[i]]; IF i=0 THEN port.d _ drv ELSE IF port.d#drv THEN ERROR; -- should be separate drives ... ENDLOOP }; bs => { lvl: Ports.Level; drv: Ports.Drive; IF port.driveType=separate THEN FOR i: NAT IN [0..wire.size) DO [lvl, port.ds[i]] _ Setup[wire[i]]; port.bs[i] _ SELECT lvl FROM H => TRUE, L => FALSE, ENDCASE => ERROR; ENDLOOP ELSE FOR i: NAT IN [0..wire.size) DO [lvl, drv] _ Setup[wire[i]]; port.bs[i] _ SELECT lvl FROM H => TRUE, L => FALSE, ENDCASE => ERROR; IF i=0 THEN port.d _ drv ELSE IF port.d#drv THEN ERROR; -- should be separate drives ... ENDLOOP }; c => ERROR; -- not yet supported lc => ERROR; -- not yet supported q => ERROR; -- not yet supported composite => subElements _ TRUE; -- explore sub-elements ENDCASE => ERROR; -- unexpected value }; [] _ Ports.VisitBinding[ct.public, p, EachWirePortPair]; -- compute port eachVector[]; }; vectors: Rope.ROPE = NARROW [CoreProperties.GetCellTypeProp[ct, $Vectors]]; IF Rope.IsEmpty[vectors] THEN { TerminalIO.PutF["*** MTS vector file name not specified.\n"]; ERROR; }; Read[ct, vectors, ConvertVectorToPort]; }; <> <> <> <> <<[wire: Core.Wire, port: Port] RETURNS [subElements: BOOL _ TRUE, quit: BOOL _ FALSE]>> <> <> <> <