<> <> <> <<>> DIRECTORY Atom, Basics, BitOps, CardTab, Convert, FS, GList, GPIB, IO, Process, Rope, RProperties, SymTab, TerminalIO, TestarossaRuntime, XBus; TestarossaRuntimeImpl: CEDAR PROGRAM IMPORTS Atom, Basics, BitOps, CardTab, Convert, FS, GList, GPIB, IO, Process, Rope, RProperties, SymTab, TerminalIO, XBus EXPORTS TestarossaRuntime = BEGIN OPEN TestarossaRuntime; Error: PUBLIC ERROR [msg: ROPE _ NIL] = CODE; <> ParseData: TYPE = REF ParseDataRec; ParseDataRec: TYPE = RECORD [ streams: LIST OF IO.STREAM, names: LIST OF ROPE, noticeCR: BOOL, token: ROPE, char: CHAR, kind: IO.TokenKind, charsSkipped: INT]; ParseKeywordProc: TYPE = PROC [pd: ParseData, program: Programming, nextReserved: ROPE]; Parse: PUBLIC PROC [file: ROPE] RETURNS [program: Programming] = { keywords: LIST OF ROPE _ LIST ["Parameters", "TimingGroups", "NameDutPinTimingGroup", "DutPinFixturePin", "FixturePinChipChannel", "ColumnNames", "Vectors", "End"]; keywordProcs: LIST OF ParseKeywordProc _ LIST[Parameters, TimingGroups, NameDutPinTimingGroup, DutPinFixturePin, FixturePinChipChannel, ColumnNames, Vectors]; pd: ParseData _ NEW[ParseDataRec]; pd.streams _ LIST[FS.StreamOpen[file]]; pd.names _ LIST[file]; pd.noticeCR _ FALSE; program _ NEW[ProgrammingRec]; program.timingGroups _ SymTab.Create[]; program.nameDutPinTimingGroup _ SymTab.Create[]; program.dutPinFixturePin _ CardTab.Create[]; program.fixturePinChipChannel _ CardTab.Create[]; program.columnNames _ CardTab.Create[]; program.targetAddress _ 0; ParseToken[pd]; -- prime the pump DO IF pd.kind#tokenID THEN ERROR Error["Missing keyword"]; IF NOT Rope.Equal[pd.token, keywords.first, FALSE] THEN ERROR Error["Unknown keyword"]; keywordProcs.first[pd, program, keywords.rest.first]; keywords _ keywords.rest; keywordProcs _ keywordProcs.rest; IF keywordProcs=NIL THEN EXIT; ENDLOOP; }; Parameters: ParseKeywordProc = { ParseToken[pd]; DO name: ROPE _ ParseName[pd, nextReserved]; value: REF ANY; IF name=NIL THEN EXIT; IF Rope.Fetch[pd.token] IN ['0..'9] THEN value _ NEW[INT _ Convert.IntFromRope[pd.token]] ELSE value _ pd.token; program.properties _ RProperties.PutProp[program.properties, Atom.MakeAtom[name], value]; ParseToken[pd]; ParseSeperator[pd]; ENDLOOP; }; TimingGroups: ParseKeywordProc = { ParseToken[pd]; DO name: ROPE _ NIL; group: TimingGroup _ NEW[TimingGroupRec]; IF (name _ ParseName[pd, nextReserved])=NIL THEN EXIT; <> IF pd.kind#tokenID THEN ERROR Error["Expecting timing group format"]; group.format _ SELECT TRUE FROM Rope.Equal[pd.token, "NRZ", FALSE] => NRZ, Rope.Equal[pd.token, "RZ", FALSE] => RZ, Rope.Equal[pd.token, "RO", FALSE] => RO, Rope.Equal[pd.token, "RC", FALSE] => RC, Rope.Equal[pd.token, "RT", FALSE] => RT, ENDCASE => ERROR Error["Unknown timing group format"]; ParseToken[pd]; group.delay _ ParseNs[pd]; group.width _ ParseNs[pd]; group.sample _ ParseNs[pd]; group.variableThreshold _ ParseBool[pd]; group.variableLevels _ ParseBool[pd]; ParseSeperator[pd]; IF NOT SymTab.Store[program.timingGroups, name, group] THEN ERROR Error["Multiply defined timing group"]; ENDLOOP; }; NameDutPinTimingGroup: ParseKeywordProc = { ParseToken[pd]; DO name: ROPE _ NIL; group: DutPinTimingGroup _ NEW[DutPinTimingGroupRec]; groups: DutPinTimingGroups; IF (name _ ParseName[pd, nextReserved])=NIL THEN EXIT; IF pd.kind=tokenSINGLE THEN { IF pd.char#'[ THEN ERROR Error["Bad bus index"]; ParseToken[pd]; group.index _ ParseNumber[pd]; IF pd.char#'] THEN ERROR Error["Bad bus index"]; ParseToken[pd]; } ELSE group.index _ 0; group.dutPin _ ParseNumber[pd]; group.timingGroup _ ParseName[pd]; ParseSeperator[pd]; groups _ NARROW[SymTab.Fetch[program.nameDutPinTimingGroup, name].val]; FOR s: DutPinTimingGroups _ groups, s.rest UNTIL s=NIL DO IF s.first.index=group.index THEN ERROR Error["Multiply defined signal"]; ENDLOOP; groups _ CONS[group, groups]; [] _ SymTab.Store[program.nameDutPinTimingGroup, name, groups]; ENDLOOP; }; DutPinFixturePin: ParseKeywordProc = { ParseToken[pd]; DO dutPin: CARD _ 0; fixturePin: REF CARD _ NEW[CARD]; IF pd.kind#tokenDECIMAL THEN EXIT; dutPin _ ParseNumber[pd]; fixturePin^ _ ParseNumber[pd]; ParseSeperator[pd]; IF NOT CardTab.Store[program.dutPinFixturePin, dutPin, fixturePin] THEN ERROR Error["Multiply defined Dut Pin"]; ENDLOOP; }; FixturePinChipChannel: ParseKeywordProc = { ParseToken[pd]; DO fixturePin: CARD _ 0; chipChannel: ChannelAddress _ NEW[ChannelAddressRec]; IF pd.kind#tokenDECIMAL THEN EXIT; fixturePin _ ParseNumber[pd]; chipChannel.chip _ ParseNumber[pd]; chipChannel.channel _ ParseNumber[pd]; ParseSeperator[pd]; IF NOT CardTab.Store[program.fixturePinChipChannel, fixturePin, chipChannel] THEN ERROR Error["Multiply defined Fixture Pin"]; ENDLOOP; }; ColumnNames: ParseKeywordProc = { position: CARD _ 0; pd.noticeCR _ TRUE; ParseToken[pd]; DO SELECT pd.kind FROM tokenSINGLE => { IF pd.char#IO.CR THEN ERROR Error["Expecting carriage return in ColumnNames"]; position _ 0; ParseToken[pd]; }; tokenID => { name: ROPE; IF Rope.Equal[pd.token, nextReserved, FALSE] THEN EXIT; IF Rope.Length[pd.token]#1 THEN ERROR Error["Expecting only one character in ColumnNames"]; position _ position + pd.charsSkipped + 1; name _ NARROW[CardTab.Fetch[program.columnNames, position].val]; name _ Rope.Concat[name, Rope.FromChar[pd.char]]; [] _ CardTab.Store[program.columnNames, position, name]; ParseToken[pd]; }; ENDCASE => ERROR Error["Expecting character in ColumnNames"]; ENDLOOP; pd.noticeCR _ FALSE; }; Vectors: ParseKeywordProc = { ConsVector: PROC = { IF triples#NIL THEN { triplesLength: CARD _ GList.Length[triples]; vectors _ CONS[NEW[ParsedVectorRec[triplesLength]], vectors]; FOR index: CARD DECREASING IN [0..triplesLength) DO vectors.first[index] _ triples.first; triples _ triples.rest; ENDLOOP; vectorLength _ vectorLength + 1; }; }; vectors: LIST OF ParsedVector _ NIL; triples: LIST OF ParsedVectorTriple _ NIL; position: CARD _ 0; vectorLength: CARD _ 0; pd.noticeCR _ TRUE; ParseToken[pd]; DO SELECT pd.kind FROM tokenSINGLE => { SELECT pd.char FROM IO.CR => { position _ 1; ParseToken[pd]; ConsVector[]; }; '* => { position _ position + pd.charsSkipped + 1; ParseToken[pd]; program.targetAddress _ vectorLength; }; ENDCASE => ERROR Error["Expecting carriage return in Vectors"]; }; tokenDECIMAL, tokenID => { triple: ParsedVectorTriple; skip: CARD; size: CARD; IF Rope.Equal[pd.token, nextReserved, FALSE] THEN EXIT; triple _ NEW[ParsedVectorTripleRec]; skip _ pd.charsSkipped + Rope.Length[pd.token]; size _ VectorColumnToBusSize[program, position + pd.charsSkipped]; triple.value _ ConvertBoolSequence[pd.token, size]; ParseToken[pd]; position _ position + skip; [triple.inhibit, skip] _ ParseBoolSequence[pd, size]; position _ position + skip; [triple.mask, skip] _ ParseBoolSequence[pd, size]; position _ position + skip; triples _ CONS[triple, triples]; }; ENDCASE => ERROR Error["Unknown token type in Vectors"]; ENDLOOP; pd.noticeCR _ FALSE; ConsVector[]; program.vectors _ NEW[ParsedVectorsRec[vectorLength]]; FOR index: CARD DECREASING IN [0..vectorLength) DO program.vectors[index] _ vectors.first; vectors _ vectors.rest; ENDLOOP; }; VectorColumnToBusSize: PROC [program: Programming, column: CARD] RETURNS [size: CARD] = { name: ROPE _ NARROW[CardTab.Fetch[program.columnNames, column].val]; groups: DutPinTimingGroups; max: CARD _ 0; min: CARD _ LAST[CARD]; IF name=NIL THEN ERROR Error["Some column is not properly named"]; groups _ NARROW[SymTab.Fetch[program.nameDutPinTimingGroup, name].val]; IF groups=NIL THEN ERROR Error["Some signal has vectors but is not defined in NameDutPinTimingGroup"]; UNTIL groups=NIL DO max _ MAX[groups.first.index, max]; min _ MIN[groups.first.index, min]; groups _ groups.rest; ENDLOOP; size _ max-min+1; }; ParseBool: PROC [pd: ParseData] RETURNS [bool: BOOL] = { IF pd.kind#tokenID THEN ERROR Error["Expecting boolean"]; IF Rope.Length[pd.token]#1 THEN ERROR Error["Expecting only T or F for boolean"]; bool _ SELECT pd.char FROM 'T, 't => TRUE, 'F, 'f => FALSE, ENDCASE => ERROR Error["Expecting only T or F for boolean"]; ParseToken[pd]; }; ParseBoolSequence: PROC [pd: ParseData, size: CARD] RETURNS [bools: BoolSequence, skip: CARD] = { IF NOT (pd.kind=tokenDECIMAL OR pd.kind=tokenID) THEN ERROR Error["Expecting hexadecimal number in Vectors"]; bools _ ConvertBoolSequence[pd.token, size]; ParseToken[pd]; skip _ pd.charsSkipped + Rope.Length[pd.token]; }; ConvertBoolSequence: PROC [token: ROPE, size: CARD] RETURNS [bools: BoolSequence] = { boolIndex: CARD _ size; bools _ NEW[BoolSequenceRec[size]]; FOR index: CARD DECREASING IN [0..LOOPHOLE[Rope.Length[token]]) DO char: CHAR _ Rope.Fetch[token, index]; charValue: CARD _ SELECT TRUE FROM char IN ['0..'9] => char-'0, char IN ['a..'f] => char-'a+10, char IN ['A..'F] => char-'A+10, ENDCASE => ERROR Error["Bad hexadecimal digit in Vectors"]; THROUGH [1..4] DO boolIndex _ boolIndex - 1; bools[boolIndex] _ IF charValue MOD 2=1 THEN TRUE ELSE FALSE; IF boolIndex=0 THEN EXIT; charValue _ charValue / 2; ENDLOOP; IF boolIndex=0 AND index#0 THEN ERROR Error["Too many digits"]; ENDLOOP; }; ParseName: PROC [pd: ParseData, nextReserved: ROPE _ NIL] RETURNS [name: ROPE _ NIL] = { IF pd.kind#tokenID THEN ERROR Error["Expecting name or keyword"]; IF nextReserved#NIL AND Rope.Equal[pd.token, nextReserved, FALSE] THEN RETURN; name _ pd.token; ParseToken[pd]; }; ParseNumber, ParseNs: PROC [pd: ParseData] RETURNS [ns: Ns] = { IF pd.kind#tokenDECIMAL THEN ERROR Error["Expecting number"]; ns _ Convert.CardFromRope[pd.token]; ParseToken[pd]; }; ParseSeperator: PROC [pd: ParseData] = { IF pd.kind#tokenSINGLE THEN ERROR Error["Expecting seperator"]; IF pd.char#'; THEN ERROR Error["Bad seperator"]; ParseToken[pd]; }; ParseToken: PROC [pd: ParseData] = { DO { ParseOneToken[pd ! IO.EndOfStream => GOTO PopFile]; EXIT; EXITS PopFile => { IO.Close[pd.streams.first]; pd.streams _ pd.streams.rest; pd.names _ pd.names.rest; IF pd.streams=NIL THEN ERROR; -- more pops than includes? LOOP; }; }; ENDLOOP; }; ParseOneToken: PROC [pd: ParseData] = { ParseOnlyOneToken[pd]; IF pd.kind=tokenID AND Rope.Equal[pd.token, "Include", FALSE] THEN { file: ROPE; [] _ IO.SkipWhitespace[pd.streams.first ! IO.EndOfStream => GOTO BadInclude]; file _ IO.GetLineRope[pd.streams.first ! IO.EndOfStream => GOTO BadInclude]; pd.streams _ CONS[FS.StreamOpen[file], pd.streams]; pd.names _ CONS[file, pd.names]; ParseOnlyOneToken[pd]; EXITS BadInclude => ERROR Error["No file name for include"]; }; }; ParseOnlyOneToken: PROC [pd: ParseData] = { [pd.token, pd.charsSkipped] _ IO.GetTokenRope[pd.streams.first, IF pd.noticeCR THEN BreaksCR ELSE Breaks]; pd.char _ Rope.Fetch[pd.token]; pd.kind _ SELECT TRUE FROM Rope.Length[pd.token]=1 AND (IF pd.noticeCR THEN BreaksCR ELSE Breaks)[pd.char]=break => tokenSINGLE, pd.char IN ['0..'9] => tokenDECIMAL, ENDCASE => tokenID; }; BreaksCR: IO.BreakProc = { RETURN[SELECT char FROM IO.CR => break, IN [IO.NUL .. IO.SP] => sepr, '*, '[, '], ';, '. => break, IN ['0..'9], IN ['a..'z], IN ['A..'Z] => other, ENDCASE => ERROR Error["Illegal character"]]; }; Breaks: IO.BreakProc = { RETURN[SELECT char FROM IN [IO.NUL .. IO.SP] => sepr, '[, '], ';, '. => break, IN ['0..'9], IN ['a..'z], IN ['A..'Z] => other, ENDCASE => ERROR Error["Illegal character"]]; }; <> debug: BOOL _ TRUE; minCopyLength: CARDINAL = 3; minCopyLengthNoLiteral: CARDINAL = 2; maxCopyLength: CARDINAL = 15; maxLiteralLength: CARDINAL = 64; bufferSize: CARD = 64; BufferIndex: TYPE = [0..bufferSize); DoubleByte: TYPE = RECORD [first, second: Byte10]; ColumnNameList: TYPE = LIST OF ColumnName; ColumnName: TYPE = REF ColumnNameRec; ColumnNameRec: TYPE = RECORD [ column: CARD, name: ROPE]; TripleSequence: TYPE = REF TripleSequenceRec; TripleSequenceRec: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF ChipTripleSequence]; -- chip ChipTripleSequence: TYPE = ARRAY ChannelIndex OF TripleSequenceIndex; TripleSequenceIndex: TYPE = RECORD [ assigned: BOOL, triple: CARDINAL, sequence: CARDINAL]; Transform: PUBLIC PROC [program: Programming] RETURNS [fixture: Fixture] = { FindMaxChip: CardTab.EachPairAction = { ca: ChannelAddress _ NARROW[val]; chips _ MAX[ca.chip+1, chips]; }; BuildColumnNames: CardTab.EachPairAction = { columnNames _ CONS[NEW[ColumnNameRec], columnNames]; columnNames.first.column _ key; columnNames.first.name _ NARROW[val]; }; CompareColumns: GList.CompareProc = { first: ColumnName _ NARROW[ref1]; second: ColumnName _ NARROW[ref2]; RETURN[Basics.CompareCard[first.column, second.column]]; }; FillFormatTiming: SymTab.EachPairAction = { FOR groups: DutPinTimingGroups _ NARROW[val], groups.rest UNTIL groups=NIL DO group: DutPinTimingGroup _ groups.first; fixturePin: REF CARD _ NARROW[CardTab.Fetch[program.dutPinFixturePin, group.dutPin].val]; chipChannel: ChannelAddress; timingGroup: TimingGroup; triplet: CARD _ 0; IF fixturePin=NIL THEN ERROR Error["No fixture pin assigned for dut pin"]; chipChannel _ NARROW[CardTab.Fetch[program.fixturePinChipChannel, fixturePin^].val]; IF chipChannel=NIL THEN ERROR Error["No chip and channel assigned for fixture pin"]; timingGroup _ NARROW[SymTab.Fetch[program.timingGroups, group.timingGroup].val]; IF timingGroup=NIL THEN ERROR; fixture[chipChannel.chip].formatTiming[chipChannel.channel] _ timingGroup; FOR names: ColumnNameList _ columnNames, names.rest UNTIL names=NIL DO IF Rope.Equal[names.first.name, key] THEN EXIT; triplet _ triplet + 1; REPEAT FINISHED => ERROR; ENDLOOP; map[chipChannel.chip][chipChannel.channel] _ [TRUE, triplet, group.index]; ENDLOOP; }; chips: CARD _ 0; map: TripleSequence; columnNames: ColumnNameList _ NIL; [] _ CardTab.Pairs[program.fixturePinChipChannel, FindMaxChip]; fixture _ AllocateFixture[chips]; fixture.properties _ program.properties; map _ NEW[TripleSequenceRec[chips]]; FOR chipIndex: CARD IN [0..chips) DO FOR channelIndex: CARD IN [0..channelsPerChip) DO map[chipIndex][channelIndex] _ [FALSE, 0, 0]; ENDLOOP; ENDLOOP; [] _ CardTab.Pairs[program.columnNames, BuildColumnNames]; columnNames _ NARROW[GList.Sort[columnNames, CompareColumns]]; [] _ SymTab.Pairs[program.nameDutPinTimingGroup, FillFormatTiming]; FOR chipIndex: CARD IN [0..chips) DO IF debug THEN TerminalIO.PutF["\nchip: %g", IO.int[chipIndex]]; FillMaskInhibitVector[program, fixture[chipIndex], map[chipIndex]]; ENDLOOP; }; AllocateFixture: PROC [chips: CARD] RETURNS [fixture: Fixture] = { fixture _ NEW[FixtureRec[chips]]; FOR chipIndex: CARD IN [0..chips) DO chip: Chip _ NEW[ChipRec[vectorAddressesPerChip]]; fixture[chipIndex] _ chip; FOR channel: ChannelIndex IN ChannelIndex DO chip.formatTiming[channel] _ NIL; FOR imIndex: InhibitMaskIndex IN InhibitMaskIndex DO chip.inhibitMask[imIndex][channel].inhibit _ FALSE; chip.inhibitMask[imIndex][channel].mask _ FALSE; ENDLOOP; ENDLOOP; chip.targetAddress _ 0; chip.matchAddress _ vectorAddressesPerChip; chip.firstFreeVector _ 0; FOR vectorIndex: CARD IN [0..vectorAddressesPerChip) DO FOR byteIndex: ByteIndex IN ByteIndex DO chip.vectors[vectorIndex][byteIndex] _ 0; ENDLOOP; ENDLOOP; ENDLOOP; }; FillMaskInhibitVector: PROC [program: Programming, chip: Chip, map: ChipTripleSequence] = { LiteralLength: PROC RETURNS [length: NAT] = { length _ LOOPHOLE[nextInsert-copyLength-literalPosition, CARDINAL] MOD bufferSize; }; EmitLiteral: PROC [length: NAT] = { IF length>0 THEN { IF debug THEN TerminalIO.PutF["\nLit(%g):", IO.card[length]]; EmitByte10[IF length=maxLiteralLength THEN 0 ELSE length]; FOR index: NAT IN [0..length) DO vector: BitOps.BitDWord _ buffer[literalPosition+index]; IF debug THEN TerminalIO.PutF[" %x", IO.int[LOOPHOLE[vector]]]; EmitByte10[BitOps.ECFD[vector, 0, 10, 20]]; EmitByte10[BitOps.ECFD[vector, 10, 10, 20]]; ENDLOOP; literalPosition _ (literalPosition+length) MOD bufferSize }; }; EmitCopy: PROC = { IF copyLength>0 THEN { position: NAT _ LOOPHOLE[matchPosition+1-copyLength, CARDINAL] MOD bufferSize; IF debug THEN TerminalIO.PutF["\nCopy l:%g, p: %g", IO.card[copyLength], IO.card[position]]; EmitByte10[BitOps.WordOR[BitOps.WordShift[copyLength, 6], position]]; copyLength _ 0; literalPosition _ nextInsert; }; }; EmitByte10: PROC [byte: Byte10] = { IF chip.firstFreeVector=vectorAddressesPerChip AND firstFreeByte=bytesPerAddress THEN ERROR Error["Not enough storage for this vector set"]; chip.vectors[chip.firstFreeVector][firstFreeByte] _ byte; firstFreeByte _ firstFreeByte + 1; IF firstFreeByte=bytesPerAddress THEN { firstFreeByte _ 0; chip.firstFreeVector _ chip.firstFreeVector + 1; }; }; AlignCodeWords: PROC [dontModifyBefore: CARDINAL] = { PushDown: PROC [byteCount: CARDINAL] = { IF byteCount>0 THEN { getWord: BufferIndex _ chip.firstFreeVector; getByte: ByteIndex _ firstFreeByte; putWord: BufferIndex _ chip.firstFreeVector + ((byteCount + firstFreeByte) / bytesPerAddress); putByte: ByteIndex _ (firstFreeByte + byteCount) MOD bytesPerAddress; IF putWord>vectorAddressesPerChip OR (putWord=vectorAddressesPerChip AND putByte>0) THEN ERROR; -- should never happen since padding an existing word firstFreeByte _ putByte; chip.firstFreeVector _ putWord; UNTIL getByte=getByteIndex AND getWord=getWordIndex DO IF getByte=0 THEN { getByte _ bytesPerAddress - 1; getWord _ getWord - 1; } ELSE getByte _ getByte - 1; IF putByte=0 THEN { putByte _ bytesPerAddress - 1; putWord _ putWord - 1; } ELSE putByte _ putByte - 1; chip.vectors[putWord][putByte] _ chip.vectors[getWord][getByte]; ENDLOOP; getByteIndex _ putByte; getWordIndex _ putWord; }; }; GetByte: PROC RETURNS [byte: Byte10] = { IF getWordIndex=chip.firstFreeVector AND getByteIndex=firstFreeByte THEN ERROR Error["Couldn't align code words"]; byte _ chip.vectors[getWordIndex][getByteIndex]; getByteIndex _ (getByteIndex + 1) MOD bytesPerAddress; IF getByteIndex=0 THEN getWordIndex _ getWordIndex + 1; }; PutByte: PROC [byte: Byte10] = { chip.vectors[putWordIndex][putByteIndex] _ byte; putByteIndex _ (putByteIndex + 1) MOD bytesPerAddress; IF putByteIndex=0 THEN putWordIndex _ putWordIndex + 1; }; putWordIndex: BufferIndex _ dontModifyBefore; getWordIndex: BufferIndex _ dontModifyBefore; putByteIndex: ByteIndex _ 0; getByteIndex: ByteIndex _ 0; IF copyLength < minCopyLength THEN { litLen: NAT; copyLength _ 0; litLen _ LiteralLength[]; IF litLen # 0 THEN EmitLiteral[litLen]; } ELSE EmitCopy[]; WHILE firstFreeByte>0 DO entryDelta: CARDINAL _ bytesPerAddress-firstFreeByte; <> IF dontModifyBefore=0 AND getWordIndex=chip.firstFreeVector AND getByteIndex=firstFreeByte THEN { byte: Byte10; getByteIndex _ 0; getWordIndex _ 0; byte _ GetByte[]; IF byte>=maxLiteralLength THEN ERROR; -- first not literal PushDown[entryDelta+4]; putWordIndex _ 0; putByteIndex _ 0; PutByte[1]; -- Lit 1 PutByte[GetByte[]]; -- first vector byte PutByte[GetByte[]]; -- second vector byte THROUGH [0..entryDelta+1) DO PutByte[BitOps.ICIW[0, BitOps.ICIW[1, 0, 0, 4, 10], 4, 6, 10]]; ENDLOOP; PutByte[byte]; -- restore literal IF firstFreeByte#0 THEN ERROR; } ELSE { byte: Byte10; putByteIndex _ getByteIndex; putWordIndex _ getWordIndex; byte _ GetByte[]; IF byte { IF firstFreeInhibitMask=inhibitMaskPerChip THEN ERROR Error["Not enough inhibit/mask entries for this vector set"]; chip.inhibitMask[firstFreeInhibitMask] _ inhibitMask; inhibitMaskIndex _ firstFreeInhibitMask; firstFreeInhibitMask _ firstFreeInhibitMask + 1; }; ENDLOOP; value _ BitOps.DoubleOR[value, BitOps.DoubleShift[inhibitMaskIndex, 16]]; IF debug THEN TerminalIO.PutF["\nvalue: %x", IO.int[value]]; SELECT TRUE FROM copyLength=0 => IF Match[TRUE] THEN copyLength _ 1; Match[FALSE] => copyLength _ copyLength+1; copyLength>=minCopyLength => { EmitLiteral[LiteralLength[]]; EmitCopy[]; IF Match[TRUE] THEN copyLength _ 1; }; LiteralLength[]=0 AND copyLength>=minCopyLengthNoLiteral => { EmitCopy[]; IF Match[TRUE] THEN copyLength _ 1; }; ENDCASE => { copyLength _ 0; IF LiteralLength[]>=maxLiteralLength THEN EmitLiteral[maxLiteralLength]; }; buffer[nextInsert] _ value; nextInsert _ (nextInsert + 1) MOD bufferSize; { emitCopy: BOOL _ copyLength=maxCopyLength; length: NAT _ LiteralLength[]; IF emitCopy OR length=maxLiteralLength THEN EmitLiteral[length]; IF emitCopy THEN EmitCopy[]; }; ENDLOOP; AlignCodeWords[chip.targetAddress]; chip.matchAddress _ chip.firstFreeVector - 1; }; PrintFixture: PUBLIC PROC [fixture: Fixture] = { FOR chipIndex: CARDINAL IN [0..fixture.size) DO GetByte: PROC RETURNS [byte: Byte10] = { byte _ chip.vectors[vectorIndex][byteIndex]; byteIndex _ byteIndex + 1; IF byteIndex=bytesPerAddress THEN { byteIndex _ 0; vectorIndex _ vectorIndex + 1; } }; chip: Chip _ fixture[chipIndex]; vectorIndex: CARDINAL _ 0; byteIndex: CARDINAL _ 0; TerminalIO.PutF["\nchip: %g", IO.card[chipIndex]]; TerminalIO.PutF["\nfirstFreeVector: %g", IO.card[chip.firstFreeVector]]; TerminalIO.PutF["\nInhibitMask"]; FOR inhibitMaskIndex: InhibitMaskIndex IN InhibitMaskIndex DO TerminalIO.PutF["\n%g:", IO.card[inhibitMaskIndex]]; FOR channelIndex: ChannelIndex IN ChannelIndex DO TerminalIO.PutF[" (%g, %g)", IO.card[IF chip.inhibitMask[inhibitMaskIndex][channelIndex].inhibit THEN 1 ELSE 0], IO.card[IF chip.inhibitMask[inhibitMaskIndex][channelIndex].mask THEN 1 ELSE 0]]; ENDLOOP; ENDLOOP; UNTIL vectorIndex>=chip.firstFreeVector DO byte: Byte10 _ GetByte[]; IF byte=chip.firstFreeVector DO byte: Byte10 _ GetByte[]; IF byte> Pickle: PUBLIC PROC [fixture: Fixture, file: ROPE] = { }; Unpickle: PUBLIC PROC [file: ROPE] RETURNS [fixture: Fixture] = { }; <> <> Timing: TYPE = {Sample, Width, Delay}; PEReg: TYPE = [0..16); PEData: TYPE = [0..1024); Ram: TYPE = {VRam, HRam, ERam, CRam}; VRamAdd: TYPE = [0..1024); HalfClocks: TYPE = [0..20); InvStages: TYPE = [0..20); EdgeC: TYPE = [0..4); EdgeF: TYPE = [0..6); Delay: TYPE = [0..475); --nS Width: TYPE = [5..475); --nS Sample: TYPE = [0..480); --nS Period: TYPE = [30..480); --nS ClockDivisor: TYPE = {one, two, four, eight}; Phase: TYPE = {Even, Odd}; Edge: TYPE = {Leading, Trailing}; Transition: TYPE = {Up, Down}; DataPattern: TYPE = {p00, p11, p01, p10}; <> clock8112: GPIB.DeviceAddr = 12; fineMap: ARRAY EdgeF OF [0..16) = [4, 2, 12, 10, 1, 9]; baseAdd: LONG POINTER = LOOPHOLE[LONG[4000h]]; <> gClkPeriod: Period _ 50; -- nS, only global for debugging, could be local to SetClock gClkDivisor: ClockDivisor _ one; -- only global for debugging gClockCtl: CARDINAL _ 0; -- shared amongst various procedures gDebug: BOOL _ FALSE; gRamDebug: BOOL _ FALSE; hardwareEnabled: BOOL _ TRUE; gCycOffset: Ns _ 0; -- shared by SetRefDelay, FindTZero pause: NAT _ 100; -- hack for HoneEdge <> <> pinElecBase: CARDINAL ~ 000h; -- up to 17Fh <> <> dsr0: CARDINAL ~ 000h; dsr1: CARDINAL ~ 001h; invCh0: CARDINAL ~ 002h; invCh1: CARDINAL ~ 003h; invCh2: CARDINAL ~ 004h; risingEdge: CARDINAL ~ 005h; fallingEdge: CARDINAL ~ 006h; ioCtl: CARDINAL ~ 007h; format: CARDINAL ~ 00fh; <> decompBase: CARDINAL ~ 180h; -- up to 1FFh writeLoopAdd: CARDINAL ~ 180h; writeEndAdd: CARDINAL ~ 181h; writeExtRamAdd: CARDINAL ~ 182h; writeExtRamCtl: CARDINAL ~ 183h; ramWD0: CARDINAL ~ 184h; ramWD1: CARDINAL ~ 185h; ramWD2: CARDINAL ~ 186h; ramWD3: CARDINAL ~ 187h; dramCtl: CARDINAL ~ 188h; readDebug: CARDINAL ~ 180h; readVRamAdd: CARDINAL ~ 181h; readHRamAdd: CARDINAL ~ 182h; readCmd: CARDINAL ~ 183h; ramRD0 : CARDINAL ~ 184h; ramRD1 : CARDINAL ~ 185h; ramRD2 : CARDINAL ~ 186h; ramRD3 : CARDINAL ~ 187h; <> extCtlBase: CARDINAL ~ 200h; -- up to 3FFh clkCtl: CARDINAL ~ 200h; refDelay: CARDINAL ~ 201h; <> phaseComp: CARDINAL ~ 001h; sampleLate: CARDINAL ~ 002h; analogSample: CARDINAL ~ 004h; ttlMode: CARDINAL ~ 008h; selLateData: CARDINAL ~ 010h; <> nrz: CARDINAL ~ 001h; rz: CARDINAL ~ 002h; ro: CARDINAL ~ 004h; rc: CARDINAL ~ 008h; rt: CARDINAL ~ 010h; <> writeCRam: CARDINAL ~ 101h; writeERam: CARDINAL ~ 102h; writeHRam: CARDINAL ~ 104h; writeVRam: CARDINAL ~ 108h; readCRam: CARDINAL ~ 110h; readERam: CARDINAL ~ 120h; readHRam: CARDINAL ~ 140h; readVRam: CARDINAL ~ 180h; extRamAccess: CARDINAL ~ 100h; vramBypass: CARDINAL ~ 200h; <> resetMinus1: CARDINAL ~ 001h; wrHRamLow: CARDINAL ~ 002h; wrHRamHigh: CARDINAL ~ 004h; fetchCmd: CARDINAL ~ 008h; prefetch: CARDINAL ~ 010h; error: CARDINAL ~ 020h; <> Run: PUBLIC PROC [fixture: Fixture] = { <> InitSystem[]; Reset[]; SetClock[NARROW[RProperties.GetProp[fixture.properties, $Clock], REF INT]^]; IF hardwareEnabled THEN FindTZero[]; FOR chipIndex: CARDINAL IN [0..fixture.size) DO chip: Chip _ fixture[chipIndex]; FOR ch: ChannelIndex IN ChannelIndex DO tg: TimingGroup _ chip.formatTiming[ch]; IF tg#NIL THEN { IF hardwareEnabled THEN SELECT tg.format FROM NRZ => NRZMode[ch, tg.delay]; RZ => RZMode[ch, tg.delay, tg.width]; RO => ROMode[ch, tg.delay, tg.width]; RT => RTMode[ch, tg.delay, tg.width]; RC => RCMode[ch, tg.delay, tg.width]; ENDCASE => ERROR; SetAnalogSample[ch, tg.variableThreshold]; SetTTLLevels[ch, tg.variableLevels]; }; ENDLOOP; FOR vi: CARD IN [0..chip.firstFreeVector) DO RamWrite[VRam, vi, chip.vectors[vi].elements[0], chip.vectors[vi].elements[1], chip.vectors[vi].elements[2], chip.vectors[vi].elements[3]]; ENDLOOP; FOR imi: InhibitMaskIndex IN InhibitMaskIndex DO data0, data1, data2, data3: Byte10 _ 0; FOR ch: ChannelIndex IN ChannelIndex DO SELECT ch FROM IN [0..6) => { data0 _ BitOps.IBIW[chip.inhibitMask[imi][ch].mask, data0, ch, 6]; data2 _ BitOps.IBIW[chip.inhibitMask[imi][ch].inhibit, data2, ch, 6]; }; IN [6..16) => { data1 _ BitOps.IBIW[chip.inhibitMask[imi][ch].mask, data1, ch-6, 10]; data3 _ BitOps.IBIW[chip.inhibitMask[imi][ch].inhibit, data3, ch-6, 10]; }; ENDCASE => ERROR; ENDLOOP; RamWrite[CRam, imi, data0, data1, data2, data3]; ENDLOOP; CBusWrite[writeEndAdd, chip.matchAddress]; CBusWrite[writeLoopAdd, chip.targetAddress]; ENDLOOP; StartCtl[TRUE, TRUE, FALSE]; }; InitSystem: PROC ~ { IF gDebug THEN TerminalIO.PutRope["\nInit\n"]; InitGPIBDevices[]; SetRefDelayAbs[0]; CBusWrite[clkCtl, 0]; gClockCtl _ 0; SetClock[100]; }; Reset: PROC ~ { IF gDebug THEN TerminalIO.PutRope["Reset\n"]; StartCtl[FALSE, FALSE, FALSE]; CBusWrite[writeLoopAdd, 0]; CBusWrite[writeEndAdd, 0]; CBusWrite[writeExtRamCtl, 0]; StartCtl[FALSE, FALSE, TRUE]; StartCtl[FALSE, FALSE, FALSE]; }; FindTZero: PROC ~ { <> <<>> biggest: ChannelIndex _ 0; new: Ns _ 0; gCycOffset _ 0; ClearAllPE[]; SetDataPattern[p10]; FOR ch: ChannelIndex IN ChannelIndex DO SetFormat[ch, RZ]; ForcePulseHigh[ch]; new _ MAX[FindOutputEdge[ch, Even, Up], FindOutputEdge[ch, Odd, Down]]; IF new>gCycOffset THEN {gCycOffset _ new; biggest _ ch}; ENDLOOP; TerminalIO.PutF["Cycle Start Offset = %g, chan: %g\n", IO.int[gCycOffset], IO.int[biggest]]; }; NRZMode: PROC [ch: ChannelIndex, delay: Delay] ~ { dhc, whc: HalfClocks _ 0; dis, wis: InvStages _ 0; delayFix: NAT _ 0; TerminalIO.PutF["Chan: %g, NRZ, Delay: %g\n", IO.int[ch], IO.int[delay]]; [dhc, dis] _ CalibrateDL[ch, Delay, delay]; [whc, wis] _ CalibrateDL[ch, Width, delay+20]; --doesn't matter how wide MakePulse[ch, NRZ, dhc, dis, whc, wis]; DO WHILE HoneEdge[ch, Leading, Even, Up, delay, p10] DO IF (delayFix _ delayFix+1) > 7 THEN ERROR; [dhc, dis] _ CalibrateDL[ch, Delay, delay-delayFix]; MakePulse[ch, NRZ, dhc, dis, whc, wis]; ENDLOOP; IF HoneEdge[ch, Leading, Odd, Up, delay, p01] THEN { IF (delayFix _ delayFix+1) > 7 THEN ERROR; [dhc, dis] _ CalibrateDL[ch, Delay, delay-delayFix]; MakePulse[ch, NRZ, dhc, dis, whc, wis]; LOOP; }; EXIT; ENDLOOP; SetDataPattern[p10]; --Display the result SetRefDelay[0]; }; RZMode: PROC [ch: ChannelIndex, delay: Delay, width: Width] ~ { dhc, whc: HalfClocks _ 0; dis, wis: InvStages _ 0; delayFix, widthFix: NAT _ 0; TerminalIO.PutF["Chan: %g, RZ, Delay: %g, Width: %g\n", IO.int[ch], IO.int[delay], IO.int[width]]; [dhc, dis] _ CalibrateDL[ch, Delay, delay]; [whc, wis] _ CalibrateDL[ch, Width, delay+width]; MakePulse[ch, RZ, dhc, dis, whc, wis]; DO WHILE HoneEdge[ch, Leading, Even, Up, delay, p10] DO IF (delayFix _ delayFix+1) > 7 THEN ERROR; [dhc, dis] _ CalibrateDL[ch, Delay, delay-delayFix]; MakePulse[ch, RZ, dhc, dis, whc, wis]; ENDLOOP; WHILE HoneEdge[ch, Trailing, Even, Down, delay+width, p10] DO IF (widthFix _ widthFix+1) > 7 THEN ERROR; [whc, wis] _ CalibrateDL[ch, Width, delay+width-widthFix]; MakePulse[ch, RZ, dhc, dis, whc, wis]; ENDLOOP; IF HoneEdge[ch, Leading, Odd, Up, delay, p01] THEN { IF (delayFix _ delayFix+1) > 7 THEN ERROR; [dhc, dis] _ CalibrateDL[ch, Delay, delay-delayFix]; MakePulse[ch, RZ, dhc, dis, whc, wis]; LOOP; }; IF HoneEdge[ch, Trailing, Odd, Down, delay+width, p01] THEN { IF (widthFix _ widthFix+1) > 7 THEN ERROR; [whc, wis] _ CalibrateDL[ch, Width, delay+width-widthFix]; MakePulse[ch, RZ, dhc, dis, whc, wis]; LOOP; }; EXIT; ENDLOOP; SetDataPattern[p11]; --Display the result SetRefDelay[0]; }; ROMode: PROC [ch: ChannelIndex, delay: Delay, width: Width] ~ { dhc, whc: HalfClocks _ 0; dis, wis: InvStages _ 0; delayFix, widthFix: NAT _ 0; TerminalIO.PutF["Chan: %g, RO, Delay: %g, Width: %g\n", IO.int[ch], IO.int[delay], IO.int[width]]; [dhc, dis] _ CalibrateDL[ch, Delay, delay]; [whc, wis] _ CalibrateDL[ch, Width, delay+width]; MakePulse[ch, RO, dhc, dis, whc, wis]; DO WHILE HoneEdge[ch, Leading, Even, Down, delay, p01] DO IF (delayFix _ delayFix+1) > 7 THEN ERROR; [dhc, dis] _ CalibrateDL[ch, Delay, delay-delayFix]; MakePulse[ch, RO, dhc, dis, whc, wis]; ENDLOOP; WHILE HoneEdge[ch, Trailing, Even, Up, delay+width, p01] DO IF (widthFix _ widthFix+1) > 7 THEN ERROR; [whc, wis] _ CalibrateDL[ch, Width, delay+width-widthFix]; MakePulse[ch, RO, dhc, dis, whc, wis]; ENDLOOP; IF HoneEdge[ch, Leading, Odd, Down, delay, p10] THEN { IF (delayFix _ delayFix+1) > 7 THEN ERROR; [dhc, dis] _ CalibrateDL[ch, Delay, delay-delayFix]; MakePulse[ch, RO, dhc, dis, whc, wis]; LOOP; }; IF HoneEdge[ch, Trailing, Odd, Up, delay+width, p10] THEN { IF (widthFix _ widthFix+1) > 7 THEN ERROR; [whc, wis] _ CalibrateDL[ch, Width, delay+width-widthFix]; MakePulse[ch, RO, dhc, dis, whc, wis]; LOOP; }; EXIT; ENDLOOP; SetDataPattern[p00]; --Display the result SetRefDelay[0]; }; RTMode: PROC [ch: ChannelIndex, delay: Delay, width: Width] ~ { RZMode[ch, delay, width]; SetFormat[ch, RT]; }; RCMode: PROC [ch: ChannelIndex, delay: Delay, width: Width] ~ { RZMode[ch, delay, width]; SetFormat[ch, RC]; }; MakePulse: PROC [ch: ChannelIndex, f: Format, dhc: HalfClocks, dis: InvStages, whc: HalfClocks, wis: InvStages] ~ { SetFormat[ch, f]; SetTimingChan[ch, Delay, dhc, dis]; SetTimingChan[ch, Width, whc, wis]; }; FindHC: PROC [ch: ChannelIndex, tg: Timing, t: Transition, start: HalfClocks _ 0] RETURNS [hc: HalfClocks _ 0] ~ { SetTimingChan[ch, tg, 0, 0]; hc _ start; WHILE NOT EdgeIsEarly[ch, t] DO SetTimingChan[ch, tg, (hc_hc+1), 0]; ENDLOOP; WHILE EdgeIsEarly[ch, t] DO SetTimingChan[ch, tg, (hc_hc+1), 0]; ENDLOOP; }; FindIS: PROC [ch: ChannelIndex, tg: Timing, hc: HalfClocks, t: Transition] RETURNS [is: InvStages _ 0]~ { SetTimingChan[ch, tg, hc, 0]; WHILE EdgeIsEarly[ch, t] DO SetTimingChan[ch, tg, hc, (is_is+1)]; ENDLOOP; }; CalibrateDL: PROC [ch: ChannelIndex, tg: Timing, ns: Ns] RETURNS [hc: HalfClocks, is: InvStages] ~ { Cal: PROC [t: Transition] RETURNS [hc: HalfClocks _ 0, is: InvStages _ 0] ~ { IF (hc _ FindHC[ch, tg, t]) = 0 THEN hc _ FindHC[ch, tg, t, 1]; hc _ hc-1; IF (is _ FindIS[ch, tg, hc, t]) = 0 THEN IF hc#0 THEN { hc _ hc-1; is _ FindIS[ch, tg, hc, t]; } ELSE { hc _ FindHC[ch, tg, t, 2]-1; is _ FindIS[ch, tg, hc, t]; IF is=0 THEN ERROR; }; is_is-1; SetTimingChan[ch, tg, hc, is]; }; hce, hco: HalfClocks; ise, iso: InvStages; SetRefPhase[Even]; SetDataPattern[p11]; SetFormat[ch, RZ]; IF tg=Delay THEN SetDelayPassThru[ch] ELSE SetWidthPassThru[ch]; SetRefDelay[ns]; [hce, ise] _ Cal[Up]; SetRefPhase[Odd]; [hco, iso] _ Cal[Down]; [hc, is] _ MinDelay[hce, ise, hco, iso]; IF gDebug THEN TerminalIO.PutF["Half Clocks: %g, Inv Stages: %g\n", IO.int[hc], IO.int[is]]; }; HoneEdge: PROC [ch: ChannelIndex, e: Edge, p: Phase, t: Transition, ns: Ns, pat: DataPattern] RETURNS [tooLate: BOOL _ FALSE] ~ { ec: EdgeC _ 0; SetRefPhase[p]; SetRefDelay[ns]; SetDataPattern[pat]; FOR i: NAT IN EdgeC DO TweakEdge[ch, e, p, (ec _ i), 0]; Process.PauseMsec[pause]; IF NOT EdgeIsEarly[ch, t] THEN EXIT; ENDLOOP; IF ec#0 THEN TweakEdge[ch, e, p, (ec _ ec-1), 0] ELSE { TerminalIO.PutF["Too early\n"]; RETURN[TRUE]; }; FOR i: NAT IN EdgeF DO TweakEdge[ch, e, p, ec, i]; Process.PauseMsec[pause]; IF NOT EdgeIsEarly[ch, t] THEN GOTO foundIt; REPEAT foundIt => {TerminalIO.PutF[" %g %g EdgeC: %g, EdgeF: %g\n", IO.rope[IF e=Leading THEN "Leading" ELSE "Trailing"], IO.rope[IF p=Even THEN "Even" ELSE "Odd"], IO.int[ec], IO.int[i]]}; FINISHED => TerminalIO.PutF["Exceeded range\n"]; ENDLOOP; }; TweakEdge: PROCEDURE [ch: ChannelIndex, e: Edge, p: Phase, ec: EdgeC, ef: EdgeF] = { PEWrite[ch, IF p=Odd THEN risingEdge ELSE fallingEdge, MapEdge[ec, ef], IF e=Leading THEN Delay ELSE Width]; }; ClearAllPE: PROC ~ { FOR c: ChannelIndex IN ChannelIndex DO ClearPEChan[c]; ENDLOOP; }; ClearPEChan: PROC [c: ChannelIndex] ~ { FOR t: Timing IN Timing DO SetTimingChan[c, t, 0, 0]; ENDLOOP; PEWrite[c, ioCtl, 0]; PEWrite[c, format, nrz]; }; MinDelay: PROC [hc0: HalfClocks, is0: InvStages, hc1: HalfClocks, is1: InvStages] RETURNS [hs: HalfClocks, is: InvStages] ~ { SELECT TRUE FROM hc0>hc1 => RETURN[hc1, is1]; hc0 RETURN[hc0, is0]; hc0=hc1 AND is0>is1 => RETURN[hc1, is1]; hc0=hc1 AND is0 RETURN[hc0, is0]; ENDCASE => RETURN[hc0, is0]; }; SetTimingChan: PROC [chan: ChannelIndex, timing: Timing, halfClocks: HalfClocks, invStages: InvStages, upEdgeC: EdgeC _ 0, upEdgeF: EdgeF _ 0, dnEdgeC: EdgeC _ 0, dnEdgeF: EdgeF _ 0] ~ { PEWrite[chan, dsr0, DSR[halfClocks].high, timing]; PEWrite[chan, dsr1, DSR[halfClocks].low, timing]; PEWrite[chan, invCh0, IC[invStages, FALSE, FALSE].high, timing]; PEWrite[chan, invCh1, IC[invStages, FALSE, FALSE].mid, timing]; PEWrite[chan, invCh2, IC[invStages, FALSE, FALSE].low, timing]; PEWrite[chan, risingEdge, MapEdge[upEdgeC, upEdgeF], timing]; PEWrite[chan, fallingEdge, MapEdge[dnEdgeC, dnEdgeF], timing]; }; DSR: PROC [halfClocks: HalfClocks] RETURNS [high, low: CARDINAL] ~ { c: BitOps.BitDWord _ 0; c _ BitOps.IBID[TRUE, c, halfClocks/2, 12]; c _ BitOps.IBID[TRUE, c, IF (halfClocks MOD 2)=0 THEN 10 ELSE 11, 12]; high _ BitOps.ECFD[c, 0, 8, 12]; low _ Basics.BITSHIFT[BitOps.ECFD[c, 8, 4, 12], 4]; --left justify result }; IC: PROC [invStages: InvStages, forceH, forceL: BOOL] RETURNS [high, mid, low: CARDINAL] ~ { c: BitOps.BitDWord _ 0; c _ BitOps.IBID[TRUE, c, invStages, 22]; IF forceL THEN c _ BitOps.IBID[TRUE, c, 20, 22]; IF forceH THEN c _ BitOps.IBID[TRUE, c, 21, 22]; high _ BitOps.ECFD[c, 0, 8, 22]; mid _ BitOps.ECFD[c, 8, 8, 22]; low _ Basics.BITSHIFT[BitOps.ECFD[c, 16, 6, 22], 2]; --left justify result }; MapEdge: PROC [edgeC: EdgeC, edgeF: EdgeF] RETURNS [CARDINAL] ~ { RETURN[Basics.BITOR[Basics.BITSHIFT[80h, -edgeC], fineMap[edgeF]]]; }; RamWrite: PROC [which: Ram, add: Address, d0, d1, d2, d3: Byte10] ~ { IF gRamDebug THEN TerminalIO.PutRope[IO.PutFLR["Write %g Add: %x, Data: %x, %x, %x, %x\n", LIST[IO.rope[ SELECT which FROM VRam => "VRam", HRam => "HRam", ERam => "ERam", CRam => "CRam", ENDCASE => ERROR], IO.card[add], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]]; CBusWrite[writeExtRamAdd, add]; LoadRamWD[d0, d1, d2, d3]; CBusWrite[writeExtRamCtl, extRamAccess]; CBusWrite[writeExtRamCtl, SELECT which FROM VRam => writeVRam, HRam => writeHRam, ERam => writeERam, CRam => writeCRam, ENDCASE => ERROR]; CBusWrite[writeExtRamCtl, extRamAccess]; CBusWrite[writeExtRamCtl, 0]; }; RamRead: PROC [which: Ram, add: Address] RETURNS [d0, d1, d2, d3: Byte10] ~ { CBusWrite[writeExtRamAdd, add]; CBusWrite[writeExtRamCtl, extRamAccess]; CBusWrite[writeExtRamCtl, SELECT which FROM VRam => readVRam, HRam => readHRam, ERam => readERam, CRam => readCRam, ENDCASE => ERROR]; [d0, d1, d2, d3] _ FetchRamRD[]; CBusWrite[writeExtRamCtl, 0]; IF gRamDebug THEN TerminalIO.PutRope[IO.PutFLR["Read %g Add: %x, Data: %x, %x, %x, %x\n", LIST[IO.rope[ SELECT which FROM VRam => "VRam", HRam => "HRam", ERam => "ERam", CRam => "CRam", ENDCASE => ERROR], IO.card[add], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]]; }; LoadRamWD: PROC [d0, d1, d2, d3: Byte10] ~ { CBusWrite[ramWD0, d0]; CBusWrite[ramWD1, d1]; CBusWrite[ramWD2, d2]; CBusWrite[ramWD3, d3]; }; FetchRamRD: PROC RETURNS [d0, d1, d2, d3: Byte10] ~ { d0 _ CBusRead[ramRD0]; d1 _ CBusRead[ramRD1]; d2 _ CBusRead[ramRD2]; d3 _ CBusRead[ramRD3]; }; InitGPIBDevices: PROC ~ TRUSTED { IF hardwareEnabled THEN { IF ~GPIB.InitializeController[] THEN ERROR; GPIB.InterfaceClear[]; GPIB.SelectedDeviceClear[clock8112]; GPIB.SelectedRemoteEnable[clock8112]; <<-- fixed edge rate, square wave output, 5V, 0V, output on>> WriteGPIB[clock8112, "W1 DTY 50% HIL -0.5V LOL -2.0V D0"]; }; }; ForcePulseHigh: PROC [ch: ChannelIndex] = { SetTimingChan[ch, Delay, 0, 0]; SetTimingChan[ch, Width, 0, 0]; PEWrite[ch, invCh0, 0, Delay]; PEWrite[ch, invCh2, IC[0, TRUE, FALSE].low, Delay]; PEWrite[ch, invCh0, 0, Width]; PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Width]; }; ForcePulseLow: PROC [ch: ChannelIndex] = { SetTimingChan[ch, Delay, 0, 0]; SetTimingChan[ch, Width, 0, 0]; PEWrite[ch, invCh0, 0, Delay]; PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Delay]; PEWrite[ch, invCh0, 0, Width]; PEWrite[ch, invCh2, IC[0, TRUE, FALSE].low, Width]; }; SetDelayPassThru: PROC [ch: ChannelIndex] ~ { IF gDebug THEN TerminalIO.PutF["Set Delay pass thru\n"]; SetTimingChan[ch, Delay, 0, 0]; SetTimingChan[ch, Width, 0, 0]; PEWrite[ch, invCh2, IC[0, FALSE, FALSE].low, Delay]; PEWrite[ch, invCh0, 0, Width]; PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Width]; }; SetWidthPassThru: PROC [ch: ChannelIndex] ~ { IF gDebug THEN TerminalIO.PutF["Set Width pass thru\n"]; SetTimingChan[ch, Delay, 0, 0]; SetTimingChan[ch, Width, 0, 0]; PEWrite[ch, invCh0, 0, Delay]; PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Delay]; PEWrite[ch, invCh2, IC[0, FALSE, FALSE].low, Width]; }; SetDataPattern: PROC [dp: DataPattern] ~ { Reset[]; IF gDebug THEN TerminalIO.PutF["Set pattern: %g\n", IO.rope[SELECT dp FROM p00 => "00", p01 => "01", p10 => "10", p11 => "11", ENDCASE => ERROR]]; RamWrite[CRam, 0, 03Fh, 3FFh, 0h, 0h]; --mask: FFFF, inhibit: 0000 SELECT dp FROM p00 => { RamWrite[VRam, 0, 2h, 0h, 0h, 0h]; --Lit 2, 00, 00, 00 RamWrite[VRam, 1, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0 RamWrite[VRam, 2, 2h, 0h, 0h, 0h]; --Lit 2, 00, 00, 00 RamWrite[VRam, 3, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0 }; p01 => { RamWrite[VRam, 0, 2h, 0h, 0h, 3Fh]; --Lit 2, 00, 00, 3f RamWrite[VRam, 1, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0 RamWrite[VRam, 2, 2h, 0h, 0h, 3Fh]; --Lit 2, 00, 00, 3f RamWrite[VRam, 3, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0 }; p10 => { RamWrite[VRam, 0, 2h, 3Fh, 3FFh, 0h]; --Lit 2, 3f, 3FF, 00 RamWrite[VRam, 1, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0 RamWrite[VRam, 2, 2h, 3Fh, 3FFh, 0h]; --Lit 2, 3f, 3FF, 00 RamWrite[VRam, 3, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0 }; p11 => { RamWrite[VRam, 0, 2h, 3Fh, 3FFh, 3Fh]; --Lit 2, 3f, 3FF, 3f RamWrite[VRam, 1, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0 RamWrite[VRam, 2, 2h, 3Fh, 3FFh, 3Fh]; --Lit 2, 3f, 3FF, 3f RamWrite[VRam, 3, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0 }; ENDCASE => ERROR; CBusWrite[writeLoopAdd, 0]; CBusWrite[writeEndAdd, 3]; StartCtl[TRUE, TRUE, FALSE]; }; FindOutputEdge: PROC [ch: ChannelIndex, p: Phase, t: Transition] RETURNS [time: Ns _ 0] ~ { SetRefPhase[p]; SetRefDelayAbs[time]; WHILE NOT EdgeIsEarly[ch, t] DO SetRefDelayAbs[(time _ time+1)]; ENDLOOP; }; EdgeIsEarly: PROCEDURE [ch: ChannelIndex, t: Transition] RETURNS [BOOL] = { trueCount, falseCount: NAT _ 0; FOR i: NAT IN [0..7) DO IF (t=Down) = (Basics.BITAND[PERead[ch, ioCtl], phaseComp]#0) THEN trueCount _ trueCount+1 ELSE falseCount _ falseCount + 1; ENDLOOP; IF gDebug THEN TerminalIO.PutF[" %g/%g ", IO.card[trueCount], IO.card[falseCount]]; RETURN[trueCount>falseCount]; }; SetFormat: PROC [ch: ChannelIndex, f: Format] = { PEWrite[ch, format, SELECT f FROM NRZ => nrz, RZ => rz, RO => ro, RC=> rc, RT => rt, ENDCASE => ERROR]; IF gDebug THEN TerminalIO.PutF["Set format: %g\n", IO.rope[SELECT f FROM NRZ => "NRZ", RZ => "RZ", RO => "RO", RC=> "RC", RT => "RT", ENDCASE => ERROR]] }; SetAnalogSample: PROC [ch: ChannelIndex, b: BOOL] = { PEWrite[ch, ioCtl, BitOps.IBIW[b, PERead[ch, ioCtl], 2, 5]]; }; SetTTLLevels: PROC [ch: ChannelIndex, b: BOOL] = { PEWrite[ch, ioCtl, BitOps.IBIW[b, PERead[ch, ioCtl], 1, 5]]; }; SetRefDelayAbs: PROC [d: Delay] ~ { CBusWrite[refDelay, d]; IF gDebug THEN TerminalIO.PutF["Ref clock delay: %g\n", IO.card[d]]; }; SetRefDelay: PROC [d: Delay] ~ { SetRefDelayAbs[d+gCycOffset]; }; SetClock: PROC [period: Period] ~ { divisor: ClockDivisor; SELECT TRUE FROM period IN [30..70) => {divisor _ one; gClkPeriod _ period}; period IN [70..140) => {divisor _ two; gClkPeriod _ (period+1)/2}; period IN [140..280) => {divisor _ four; gClkPeriod _ (period+2)/4}; period IN [280..560) => {divisor _ eight; gClkPeriod _ (period+4)/8}; ENDCASE => ERROR; SetClockDivisor[divisor]; WriteGPIB[clock8112, IO.PutFR["PER %gNS", IO.card[gClkPeriod]]]; IF gDebug THEN TerminalIO.PutF["Set clock to %g ns\n", IO.card[period]] }; StartCtl: PROC [start, loop, reset: BOOL _ FALSE] ~ { gClockCtl _ BitOps.IBIW[start, gClockCtl, 5, 8]; gClockCtl _ BitOps.IBIW[loop, gClockCtl, 4, 8]; gClockCtl _ BitOps.IBIW[reset, gClockCtl, 0, 8]; CBusWrite[clkCtl, gClockCtl]; }; SetRefPhase: PROC [p: Phase] ~ { gClockCtl _ BitOps.IBIW[p=Even, gClockCtl, 2, 8]; CBusWrite[clkCtl, gClockCtl]; IF gDebug THEN TerminalIO.PutF["Set reference phase %g\n", IO.rope[IF p=Even THEN "Even" ELSE "Odd"]] }; SetClockDivisor: PROC [cd: ClockDivisor] ~ { gClockCtl _ BitOps.ICIW[ORD[cd], gClockCtl, 6, 2, 8]; CBusWrite[clkCtl, gClockCtl]; gClkDivisor _ cd; }; PEWrite: PROC [chan: ChannelIndex, reg: PEReg, data: PEData, timing: Timing _ Sample] ~ { <> CBusWrite[(chan*24)+(timing.ORD*8)+reg, data]; }; PERead: PROC [chan: ChannelIndex, reg: PEReg, timing: Timing _ Sample] RETURNS [data: PEData] ~ { <> data _ Basics.BITAND[CBusRead[(chan*24)+(timing.ORD*8)+reg], 0FFh]; --PE only uses 8 bits }; CBusRead: PROC [add: Address] RETURNS [data: Byte10 _ 0] ~ { IF hardwareEnabled THEN data _ XBus.IORead[baseAdd + add*2]; }; CBusWrite: PROC [add: Address, data: Byte10] ~ { IF hardwareEnabled THEN XBus.IOWrite[baseAdd + add*2, data]; }; WriteGPIB: PROCEDURE [device: GPIB.DeviceAddr, msg: Rope.ROPE] = TRUSTED { IF hardwareEnabled THEN GPIB.WriteDevice[device, Rope.Concat[msg, "\n\l"]]; }; END.