// Resist.bcpl -- board open/short tester -- main program and utilities // Last modified September 22, 1980 2:15 PM get "Resist.decl" get "Streams.d" get "AltoDefs.d" get "SysDefs.d" external [ // outgoing procedures ReportError; PermAllocate; ExpandTemplate; ResistFinish; Confirm // incoming procedures InitResist; ICState; ReEstablishStream ReadResistFile; ReadWireListFile; UnparseIC; SummarizeBadNets CreateSymbolTable; EnumerateSymbolTable DefineSymbol; LookupSymbol; LookupOrDefineSymbol; MustLookupSymbol SymbolsObject; SymbolsString; ObjectsString; SymbolsType; PinsNetSymbol DisplayIC; DisplaySingleOhms; DisplayOhms ShowFullDisplay; FlashWindow MeasureOhms; SignalOn; PulseChannel; Wait DeleteFile; RenameFile; CleanupDiskStream CreateStringStream; ConcatenateStrings; ExtractSubstring PutTemplate; ResetLine; EraseBits; CharWidth Ws; Wss; Gets; Puts; Resets; Closes; Endofs Allocate; Free; AddToZone Usc; Max; SysErr; Junta // outgoing statics endInitCode; permZone; version; startLocation; serialNumber; errorTolerance maxNPins; resistSavedUFP; displayInterruptMask resStream; exStream; wlStream; outStream resName; outName; mustRename; stuffed; restart stateCFA; outCFA; symbolTable // incoming statics sysZone; dsp; keys; statusDsp; lvUserFinishProc; stateStream ] static [ endInitCode resStream = 0 exStream = 0 wlStream = 0 outStream = 0 serialNumber = 0 startLocation = 0 maxNPins = defaultMaxNPins resistSavedUFP; displayInterruptMask resName; outName; mustRename stuffed = 1 errorTolerance = 0 lastChar; version permZone; symbolTable symDIP3; symMB7071H; symSpareSocket; symAUGATCG16; symUnknownNet restart = false stateCFA; outCFA ] manifest [ normal = 0; quit = 1; ignore = 2; repeatIC = 3 ] // command action manifest maxPass = 5 // --------------------------------------------------------------------------- let Resist() be // --------------------------------------------------------------------------- [ version = "Resist of September 22, 1980" Junta(levDisplay, ResistAfterJunta) ] // --------------------------------------------------------------------------- and ResistAfterJunta() be // --------------------------------------------------------------------------- [ InitResist() AddToZone(sysZone, InitResist, endInitCode-InitResist) Ws("*nReading Resist file...") symbolTable = CreateSymbolTable(251, permZone) symDIP3 = LookupOrDefineSymbol(symbolTable, "DIP3", stICPackage) symMB7071H = LookupOrDefineSymbol(symbolTable, "MB7071H", stICType) symSpareSocket = LookupOrDefineSymbol(symbolTable, "SpareSocket", stICType) symAUGATCG16 = LookupOrDefineSymbol(symbolTable, "AUGATCG16", stICType) let firstIC = ReadResistFile(resStream, symbolTable) Closes(resStream) if exStream ne 0 then [ Ws("*nReading Exceptions file...") ReadResistFile(exStream, symbolTable, true) Closes(exStream) ] Ws("*nReading Wire List file...") ReadWireListFile(wlStream, symbolTable) Closes(wlStream) symUnknownNet = MustLookupSymbol(symbolTable, "?") stateStream = ReEstablishStream(stateCFA, ksTypeReadWrite, wordItem) if restart then [ Ws("*nRestoring results from interrupted test...") until Endofs(stateStream) do startLocation = ObjectsString(ICState(true, nil)) ] let freeWords = nil Allocate(sysZone, 77777B, lv freeWords) PutTemplate(dsp, "*n$D+$D free words remaining.*nReady to begin testing.", freeWords, permZone>>PermZone.wordsLeft) let ic = firstIC let firstPass = 1 if startLocation ne 0 then [ let symbol = LookupSymbol(symbolTable, startLocation) test symbol eq 0 ifso ReportError("Board location $S undefined", startLocation) ifnot [ ic = SymbolsObject(symbol) firstPass = WhichPassForIC(ic) if firstPass eq 0 then firstPass = 1 ] ] ShowFullDisplay(true) let action = nil for pass = firstPass to maxPass do [ action = DoPass(lv pass, ic) if action eq quit then break ic = firstIC ] unless action eq quit do [ ShowFullDisplay(false) Ws("*nWriting defects file...") Closes(stateStream) outStream = ReEstablishStream(outCFA, ksTypeWriteOnly, charItem) let badUnknownNets = ReportDefects(firstIC, outStream) SummarizeBadNets(outStream, symbolTable, InTolerance) if badUnknownNets ne 0 then PutTemplate(outStream, "*n; There are $D errors involving pins whose net names are not known.*n", badUnknownNets) Closes(outStream) if mustRename then [ let backupName = ConcatenateStrings(outName, "$") DeleteFile(backupName) RenameFile(outName, backupName) RenameFile("Resist.temp$", outName) PutTemplate(dsp, "*nInput file renamed to $S.", backupName) Free(sysZone, backupName) ] Free(sysZone, outName) DeleteFile("Resist.state$") ] @displayListHead = 0 finish ] // --------------------------------------------------------------------------- and DoPass(lvPass, ic) = valof // --------------------------------------------------------------------------- [ // repeat let action = normal if ic eq 0 resultis action if WhichPassForIC(ic) eq @lvPass then [ PutTemplate(statusDsp, " Location $S ($S) $D-pin*n", ObjectsString(ic), SymbolsString(ic>>IC.type), ic>>IC.nPins) let Measure = HowToMeasure(ic) [ // repeat switchon Measure(ic) into [ case $*s: break case $D: Measure = MeasureMultiple; endcase case $S: Measure = MeasureSingle; endcase case $Q: if Confirm() then [ action = quit; SetAllUnknown(ic); break ] endcase case $I: if Confirm() then [ action = ignore; SetAllUnknown(ic); break ] endcase case $L: [ let location = GetString() if location ne 0 then [ let icSymbol = LookupSymbol(symbolTable, location) Free(sysZone, location) test icSymbol eq 0 % SymbolsType(icSymbol) ne stIC ifso Ws("*nBoard location not defined.") ifnot [ SetAllUnknown(ic) ic = SymbolsObject(icSymbol) @lvPass = WhichPassForIC(ic) action = repeatIC break ] ] endcase ] ] ] repeat Resets(statusDsp) if action eq normal then [ ICState(false, ic); CleanupDiskStream(stateStream) ] ] if action eq quit resultis action unless action eq repeatIC do ic = ic>>IC.next ] repeat // --------------------------------------------------------------------------- and WhichPassForIC(ic) = valof // --------------------------------------------------------------------------- // Returns the pass during which it is appropriate to test this IC, // or 0 if the IC should never be tested. // 1: 16- and 14-pin DIPs, except Spare and Platforms if board is stuffed // 2: Spare if board is stuffed // 3: 24-pin DIPs // 4: QIT packages // 5: Everything else (including Platforms if board is stuffed) [ for pinNumber = 1 to ic>>IC.nPins do if ic>>IC.pins↑pinNumber.expectedOhms ne unknown then [ resultis ic>>IC.package eq symDIP3? selecton ic>>IC.nPins into [ case 16: // 16-pin DIP3 stuffed? (ic>>IC.type eq symSpareSocket? 2, ic>>IC.type eq symAUGATCG16? 5, 1), 1 case 14: 1 // 14-pin DIP3 case 2: 0 // 2-pin "DIP3"s are bypass capacitors -- don't test default: 5 // Oddball DIP3 (not sure this can ever happen) ], selecton ic>>IC.nPins into [ case 26: 4 // QIT package case 24: 3 // 24-pin DIP case 8: 0 // SIP -- don't test default: 5 // Oddball, test with single probe ] ] // All the pins of this IC have unknown resistance resultis 0 ] // --------------------------------------------------------------------------- and HowToMeasure(ic) = // --------------------------------------------------------------------------- WhichPassForIC(ic) eq 5 % (ic>>IC.nPins eq 26 & stuffed)? MeasureSingle, MeasureMultiple // --------------------------------------------------------------------------- and MeasureMultiple(ic) = valof // --------------------------------------------------------------------------- [ ResetLine(statusDsp) PutTemplate(statusDsp, "Install $S probe; press switch when ready", (ic>>IC.type eq symMB7071H? "QIT", "DIP")) Resets(keys) let probeState = 0 [ // repeat let ok = true let allOpen = true for pinNumber = 1 to ic>>IC.nPins do [ let pin = lv ic>>IC.pins↑pinNumber pin>>Pin.measuredOhms = Max(MeasureOhms(PinChannel(ic, pinNumber)), 0) ok = ok & InTolerance(pin) allOpen = allOpen & pin>>Pin.measuredOhms eq open ] DisplayIC(ic, InTolerance) DisplaySingleOhms(MeasureOhms(chanSingle)) probeState = selecton probeState into [ case 0: allOpen? 1, 0 case 1: allOpen? 1, 2 case 2: 2 ] SignalOn(probeState eq 2 & not ok) ] repeatuntil CheckKeys() SignalOn(false) resultis lastChar // returned by CheckKeys ] // --------------------------------------------------------------------------- and PinChannel(ic, pinNumber) = // --------------------------------------------------------------------------- (chanPin1-1) + selecton ic>>IC.nPins into [ case 14: pinNumber ls 8? pinNumber, pinNumber+2 case 26: pinNumber le 24? pinNumber, 24 default: pinNumber ] // --------------------------------------------------------------------------- and MeasureSingle(ic) = valof // --------------------------------------------------------------------------- [ let nPins = ic>>IC.nPins for pinNumber = 1 to nPins do [ ResetLine(statusDsp) PutTemplate(statusDsp, "Install single probe on pin $D and press switch", pinNumber) Resets(keys) [ // repeat let pin = lv ic>>IC.pins↑pinNumber pin>>Pin.measuredOhms = Max(MeasureOhms(chanSingle), 0) ic>>IC.nPins = pinNumber DisplayIC(ic, InTolerance) ic>>IC.nPins = nPins DisplaySingleOhms(MeasureOhms(chanSingle)) SignalOn(not InTolerance(pin)) // for current tracer, pulse the channel for 100 ms and then // leave it off for 100 ms. PulseChannel(chanSingle, 100/17) Wait(100/17) ] repeatuntil CheckKeys() switchon lastChar into [ case $*s: endcase case $B: // Back up if pinNumber gr 1 then pinNumber = pinNumber-2 // +1 in for loop endcase default: break ] ] SignalOn(false) if lastChar eq $*s then [ ResetLine(statusDsp) Wss(statusDsp, "Press switch when ready for next IC.") Resets(keys) until CheckKeys() do loop ] resultis lastChar ] // --------------------------------------------------------------------------- and InTolerance(pin) = valof // --------------------------------------------------------------------------- [ if pin>>Pin.expectedOhms eq unknown resultis true let diff = pin>>Pin.measuredOhms - pin>>Pin.expectedOhms diff = Max(diff, -diff) // Abs(diff) resultis diff le (errorTolerance* (pin>>Pin.expectedOhms ls 33? 33, pin>>Pin.expectedOhms) + 50)/100 ] // --------------------------------------------------------------------------- and ReportDefects(firstIC, stream) = valof // --------------------------------------------------------------------------- // Returns the number of pins that are out-of-tolerance and connected // to net "?". [ let badUnknownNets = 0 while firstIC ne 0 do [ CheckForDefect(firstIC, stream, lv badUnknownNets) firstIC = firstIC>>IC.next ] resultis badUnknownNets ] // --------------------------------------------------------------------------- and CheckForDefect(ic, stream, lvBadUnknownNets) be // --------------------------------------------------------------------------- [ let firstError = true for pinNumber = 1 to ic>>IC.nPins do [ let pin = lv ic>>IC.pins↑pinNumber unless pin>>Pin.measuredOhms eq unknown % InTolerance(pin) do [ if firstError then [ Puts(stream, $*n); UnparseIC(stream, ic) ] firstError = false PutTemplate(stream, "; Pin $2D expected resistance: ", pinNumber) DisplayOhms(stream, pin>>Pin.expectedOhms) Wss(stream, ", measured: ") DisplayOhms(stream, pin>>Pin.measuredOhms) let symPin = PinsNetSymbol(pin) PutTemplate(stream, ". Net $S*n", SymbolsString(symPin)) if symPin eq symUnknownNet then @lvBadUnknownNets = @lvBadUnknownNets+1 ] ] ] // --------------------------------------------------------------------------- and SetAllUnknown(ic) be // --------------------------------------------------------------------------- for pinNumber = 1 to ic>>IC.nPins do ic>>IC.pins↑pinNumber.measuredOhms = unknown // --------------------------------------------------------------------------- and CheckKeys() = valof // --------------------------------------------------------------------------- // Returns true if a key has been struck or the switch depressed. // Stores the character into lastChar (depressed switch => $*s) [ // repeat if Endofs(keys) resultis false lastChar = Gets(keys) if lastChar ge $a & lastChar le $z then lastChar = lastChar - ($a-$A) switchon lastChar into [ case $D: Ws("*nDIP probe"); endcase case $S: Ws("*nSingle probe"); endcase case $B: Ws("*nBack up"); endcase case $I: Ws("*nIgnore this IC"); endcase case $L: Ws("*nLocation: "); endcase case $Q: Ws("*nQuit"); endcase case $*s: endcase default: FlashWindow(dsp) case $?: Ws("*n? Depress switch or strike space bar to advance .") Ws("*nCommands are:") Ws("*nDIP probe, Single probe, Back up, Ignore IC, Location, Quit.") loop ] resultis true ] repeat // --------------------------------------------------------------------------- and GetString() = valof // --------------------------------------------------------------------------- [ let string = vec 127 let length = 0 [ // repeat let char = Gets(keys) switchon char into [ case $*001: case $*010: if length gr 0 then [ EraseBits(dsp, -CharWidth(dsp, string>>String.char↑length)) length = length-1 ] endcase case $*n: case $*033: break case $*177: Ws(" XXX") resultis 0 default: unless length eq 255 do [ length = length+1 string>>String.char↑length = char Puts(dsp, char) ] endcase ] ] repeat string>>String.length = length resultis ExtractSubstring(string) ] // --------------------------------------------------------------------------- and Confirm() = valof // --------------------------------------------------------------------------- [ Ws(" [Confirm] ") switchon Gets(keys) into [ case $Y: case $y: case $*n: Ws("yes"); resultis true case $N: case $n: case $*177: Ws("no"); resultis false default: FlashWindow(dsp); Resets(keys); endcase ] repeat ] // --------------------------------------------------------------------------- and ReportError(template, arg1, arg2, arg3, arg4, arg5) be // --------------------------------------------------------------------------- [ Ws("*n") PutTemplate(dsp, template, arg1, arg2, arg3, arg4, arg5) Ws(" (more?...)") Resets(keys) Gets(keys) Resets(dsp) ] //---------------------------------------------------------------------------- and PermAllocate(zone, words) = valof //---------------------------------------------------------------------------- [ // repeat if words gr zone>>PermZone.threshold then resultis Allocate(zone>>PermZone.underlyingZone, words) if words gr zone>>PermZone.wordsLeft then [ zone>>PermZone.currentBlock = Allocate(zone>>PermZone.underlyingZone, permIncrement, true) if zone>>PermZone.currentBlock eq 0 then // If failed to allocate, do all future allocations directly from zone [ zone>>PermZone.threshold = 0; loop ] zone>>PermZone.wordsLeft = permIncrement ] let result = zone>>PermZone.currentBlock zone>>PermZone.currentBlock = zone>>PermZone.currentBlock + words zone>>PermZone.wordsLeft = zone>>PermZone.wordsLeft - words resultis result ] repeat //---------------------------------------------------------------------------- and ExpandTemplate(template, arg1, arg2, arg3, arg4, arg5) = valof //---------------------------------------------------------------------------- [ let string = vec 127 let ss = CreateStringStream(string, 255) PutTemplate(ss, template, arg1, arg2, arg3, arg4, arg5) Closes(ss) resultis ExtractSubstring(string) ] //---------------------------------------------------------------------------- and ResistFinish() be //---------------------------------------------------------------------------- [ @displayInterrupt = @displayInterrupt & not displayInterruptMask @lvUserFinishProc = resistSavedUFP ] //---------------------------------------------------------------------------- and Wss(stream, string) be //---------------------------------------------------------------------------- for i = 1 to string>>String.length do Puts(stream, string>>String.char↑i) //---------------------------------------------------------------------------- and Ws(string) be Wss(dsp, string) //----------------------------------------------------------------------------