// AltIOMaxc2.bcpl -- code implementing communication with Maxc // and error monitoring // Last modified April 17, 1978 2:57 PM get "altio.decl" get "altiomaxc2.decl" external [ //outgoing procedures MaxcWatcher; ClockInterrupt; SignalMaxc; AltIOReset StartMaxc; StopMaxc; StopMaxcForcefully; ResetMaxc TakeDLSOutput; GiveDLSInput; ConfigureMemory; ResetMemory MaxcState; PrintMaxcState; StartEmulator ReadLM; ReadSM //incoming procedures Block; Allocate; Free; MoveBlock; SetBlock; CallSwat; Timer DoubleIncrement; DoubleDifference; Puts; Ws SetTimer; TimerHasExpired; PupReset; ImpReset InputSMI; OutputSMI; OutputSMIPulse; InputSMIErrors; OutputSMITest ExecuteMicroInstruction; LoadBus; ReadBus; DisplaceMaxcAdr FindZeroMaxcBit; SetOneMaxcBit; IncrementMaxcWord StartIntervalTimer; DisableInterrupts; EnableInterrupts MemReadAbsolute; MemWriteAbsolute; MemRMWAbsolute MemReadRelative; MemWriteRelative; MemRMWRelative RMWBitAbsolute; RMWBitRelative; MemWriteBlock40A //outgoing statics adrMTBS; adrDLSBS; maxcRunning; resetExecuted; dlsOutputChar maxcClock; lastTime; interruptInterval; clockMask fatalError; stdMemConf //incoming statics dsp; updateDisplayValid; sysZone pupInputRequest; pupOutputRequest; impInputRequest; impOutputRequest ] static [ adrMTBS; adrDLSBS dlsOutputChar maxcRunning = false resetExecuted = false smiErr = 0 fatalSE = false fatalPBF = false fatalError = false clockUpdateEnabled = false interruptInterval = 17 maxcClock; lastTime; interruptTimer; clockMask ] // --------------------------------------------------------------------------- let MaxcWatcher() be // --------------------------------------------------------------------------- //process that watches for Maxc i/o requests and errors [ Block() unless maxcRunning do [ //watch only for memory errors if Maxc not running if InputSMI(smiJKERRS) ne 0 % InputSMI(smiLMERRS) ne 0 then [ let qErr = vec 2 ReadMemErrors(qErr) if FatalMemError(qErr) then [ ReportMemErrorsToDisplay(qErr) fatalError = true ] ] loop ] //all places that read the SMI error register must update smiErr. //this is because reading the register causes it to be cleared, //and signals such as COMA may be lost if we aren't careful smiErr = (smiErr % InputSMIErrors()) & smiErrorMask if smiErr ne 0 then [ if smiErr<<SMIErr.fer then //fatal error? [ maxcRunning = false if MaxcState() eq stateRunning then [ StopMaxcForcefully() Ws("*nMaxc didn't stop on fatal error, PMAINT switch ok?") ] //read and reset all memory error latches let qErr = vec 2 ReadMemErrors(qErr) //discover whether a fatal memory error occurred, and if so, //whether Maxc is enabled to handle it test CheckMemErrors(qErr) ifso [ //fatal memory error that Maxc was enabled for ReportMemErrorsToMaxc(qErr) StartMaxc() ] ifnot [ //not an enabled memory error. //It is possibly an I/O reset request that we //are slow in responding to. If so, fall through //to the COMA code, else leave Maxc halted. let resetRequested = false if smiErr<<SMIErr.coma & MaxcState() eq stateBreakpoint then [ let maxcData = vec 3 MemReadAbsolute(aMAXNV, maxcData) resetRequested = (maxcData!(mnIORST/16) & #100000 rshift (mnIORST rem 16)) eq 0 ] unless resetRequested do [ Puts(dsp,$*n) PrintMaxcState() //tell what happened fatalError = true loop //ignore requests until Maxc restarted ] ] ] // MaxcWatcher (cont'd) if smiErr<<SMIErr.coma then //communication strobe? [ smiErr = 0 let maxNV = vec 3 MemReadAbsolute(aMAXNV, maxNV) //read MAXNV [ //stay in this loop until all requests have been processed let bitNumber = FindZeroMaxcBit(maxNV) switchon bitNumber into [ //process a single request. //if the processing code resets the request bit itself, //it must do so using the maxNV data vector, and //it should finish with "loop" rather than "endcase" case mnIORST: //io reset request [ Block() repeatuntil MaxcState() ne stateRunning ConfigureMemory(0, 0) //normal memory configuration AltIOReset() resetExecuted = true updateDisplayValid = false StartMaxc() //resume processor break //we have completely reset MAXNV ] case mnPUPIBG: //Pup begin input request [ pupInputRequest = true; endcase ] case mnPUPOBG: //Pup begin output request [ pupOutputRequest = true; endcase ] case mnIMPIBG: //Imp begin input request [ impInputRequest = true; endcase ] case mnIMPOBG: //Imp begin output request [ impOutputRequest = true; endcase ] case mnDLSOBG: //DLS begin output request [ SetOneMaxcBit(maxNV, bitNumber) //reset request first MemRMWAbsolute(aMAXNV, maxNV) DLSOutputRequest() loop ] case mnCDVS: //CDVS (miscellaneous requests) [ let maxcData = vec 3 MemReadRelative(xCCHS, maxcData) //read the arg switchon maxcData!0 into [ case cdvsSetClock: [ SetClockInterval(maxcData!1); endcase ] case cdvsSetConfiguration: [ StopMaxc() ConfigureMemory(maxcData!1, maxcData!2) StartMaxc() endcase ] default: CallSwat("Undefined Maxc CDVS request") ] endcase ] case -1: break default: CallSwat("Undefined Maxc request (MAXNV)") ] SetOneMaxcBit(maxNV, bitNumber) //reset request bit MemRMWAbsolute(aMAXNV, maxNV) ] repeat ] ] ] repeat // --------------------------------------------------------------------------- and ReadMemErrors(qErr) be // --------------------------------------------------------------------------- //read memory error status into 2-word vector qErr, then reset //error latches in memory system. [ qErr!0 = InputSMI(smiJKERRS) qErr!1 = InputSMI(smiLMERRS) OutputSMI(smiRESR, allResetErrors) ] // --------------------------------------------------------------------------- and FatalMemError(qErr) = valof // --------------------------------------------------------------------------- //return true if a fatal memory error has occurred [ let mask = qeTimeout+qeDIP+qeAPE+qeDE //always-fatal errors if fatalSE then mask = mask+qeSE if fatalPBF then mask = mask+qePBF mask = mask + mask lshift 8 resultis (qErr!0 & mask) ne 0 % (qErr!1 & mask) ne 0 ] // --------------------------------------------------------------------------- and CheckMemErrors(qErr) = valof // --------------------------------------------------------------------------- //analyze memory errors indicated by qErr!0 and qErr!1. //return true if a fatal memory error occurred and Maxc is //enabled for it, false otherwise. If Maxc is not enabled, //display whatever errors we find. [ unless FatalMemError(qErr) resultis false //no fatal errors let state = MaxcState() let maxcData = vec 3 MemReadRelative(xPSCAN, maxcData) //see if Maxc enabled for error test maxcData!0 eq 0 & (state eq stateHalted % state eq stateMainBusPE) ifnot [ //not enabled, report all errors to display ReportMemErrorsToDisplay(qErr) resultis false ] ifso resultis true //pass errors to Maxc ] // --------------------------------------------------------------------------- and ReportMemErrorsToDisplay(qErr) be // --------------------------------------------------------------------------- [ Ws("*nMain memory error:") for i = 0 to 5 do [ let mask = #401 lshift i if (qErr!0 & mask) ne 0 % (qErr!1 & mask) ne 0 then [ Ws(selecton i into [ case 0: " SE: " case 1: " DE: " case 2: " PBF: " case 3: " APE: " case 4: " DIP: " case 5: " Timeout: " ]) for q = 0 to 3 do if (qErr>>QErr↑q & mask) ne 0 then Puts(dsp, $J+q) ] ] ] // --------------------------------------------------------------------------- and ReportMemErrorsToMaxc(qErr) be // --------------------------------------------------------------------------- [ //figure out which kind of error to hand Maxc manifest timeMask = qeTimeout + qeTimeout lshift 8 let errBit = (qErr!0 & timeMask) ne 0 % (qErr!1 & timeMask) ne 0? nmNXM, nmPARERR RMWBitAbsolute(aNVMAX, errBit) //set NXM or PARERR //hand over assorted other interesting information MemWriteRelative(xMEMER, qErr) let uInst = table [ #040102; #077546; #120001; #000000; #003400 // B←MAR #040102; #077546; #100001; #000000; #003400 // B←MDR #040102; #077546; #110001; #000000; #003400 // B←MDRL #040102; #077546; #160001; #000000; #003400 // B←KMAR #040102; #077546; #140001; #000000; #003400 // B←KMDR #040102; #077546; #150001; #000000; #003400 // B←KMDRL ] let errorData = vec 3*6 for i = 0 to 15 by 3 do [ ExecuteMicroInstruction(uInst) uInst = uInst+5 ReadBus(errorData+i) ] let errorAdr = vec 1 DisplaceMaxcAdr(xMAR, errorAdr) MemWriteBlock40A(errorAdr, errorData, 6) MemWriteRelative(xPSCAN, table [ -1; -1; -1 ]) ] // --------------------------------------------------------------------------- and DLSOutputRequest() be // --------------------------------------------------------------------------- [ let maxcData = vec 3 MemReadRelative(xDLSO, maxcData, adrDLSBS) //read request bits [ let line = FindZeroMaxcBit(maxcData) if line ls 0 return //no lines requesting output if line ls numDLSLines then [ //found line requesting output, copy the character MemReadRelative(xDLSB+2*line+1, maxcData, adrDLSBS) dlsOutputChar!line = maxcData!0 ] SetOneMaxcBit(maxcData, line) MemRMWRelative(xDLSO, maxcData, adrDLSBS) //reset line request ] repeat ] // --------------------------------------------------------------------------- and TakeDLSOutput(line) = valof // --------------------------------------------------------------------------- //procedure called externally to wait for a DLS output request //on line and return the character. [ Block() repeatwhile dlsOutputChar!line eq -1 let char = dlsOutputChar!line dlsOutputChar!line = -1 //no character pending now RMWBitRelative(xDLSOD, line, adrDLSBS) //set done bit for line RMWBitAbsolute(aNVMAX, nmDLSDN) //signal DLS done SignalMaxc() resultis char ] // --------------------------------------------------------------------------- and GiveDLSInput(line, char) be // --------------------------------------------------------------------------- //procedure called externally to send a DLS input character to Maxc [ MemWriteRelative(xDLSB+2*line, lv char, adrDLSBS) //give char to Maxc RMWBitRelative(xDLSIN, line, adrDLSBS) //set done bit for line RMWBitAbsolute(aNVMAX, nmDLSDN) //signal DLS done SignalMaxc() ] // --------------------------------------------------------------------------- and AltIOReset() be // --------------------------------------------------------------------------- //perform i/o reset operation [ OutputSMITest(#16) //put SMI in normal mode OutputSMI(smiRESR, allResetErrors) //reset memory error latches let maxcData = vec 3 let zeroWord = table [ 0; 0; 0 ] let oneWord = table [ #177777; #177777; #177400 ] //read the addresses of the communication regions MemReadAbsolute(aMTBS, maxcData) MoveBlock(adrMTBS, maxcData+1, 2) MemReadAbsolute(aDLSBS, maxcData) MoveBlock(adrDLSBS, maxcData+1, 2) //reset DLS state SetBlock(dlsOutputChar, -1, numDLSLines) //no output chars pending MemWriteRelative(xDLSOD, zeroWord, adrDLSBS) //reset output done MemWriteRelative(xDLSO, oneWord, adrDLSBS) //reset output requests MemWriteRelative(xDLSIN, zeroWord, adrDLSBS) //reset input done //reset Maxc clock SetClockInterval(0) //reset the Pup and Imp processes PupReset() ImpReset() //finally, reset NVMAX and MAXNV to their idle states MemWriteAbsolute(aNVMAX, zeroWord) MemWriteAbsolute(aMAXNV, oneWord) ] // --------------------------------------------------------------------------- and SignalMaxc() be // --------------------------------------------------------------------------- if maxcRunning then OutputSMI(smiCR, not (crNormal+crStrobe)) // --------------------------------------------------------------------------- and StartMaxc(microAdr; numargs na) be // --------------------------------------------------------------------------- //start Maxc running at the specified micro-address, or just //resume it if microAdr is not specified [ if na gr 0 then [ let maxcData = vec 3 maxcData!0 = 0 maxcData!1 = microAdr rshift 4 maxcData!2 = microAdr lshift 12 LoadBus(maxcData) ExecuteMicroInstruction( // NPC←BR, ENPC table [ #040102; #077546; #000000; #020000; #113600 ]) DoubleIncrement(maxcData+1, #10000) LoadBus(maxcData) ExecuteMicroInstruction( // NPC←BR, ENPC, EIMA table [ #040102; #077546; #000000; #020000; #133600 ]) ExecuteMicroInstruction( // IRET, INHINT table [ #040102; #077546; #000152; #000000; #103400 ]) ResetArm() //reset bipolar memory errors ] ExecuteMicroInstruction( // WRESTART, KWRESTART table [ #040102; #077546; #000110; #160000; #103400 ]) ExecuteMicroInstruction( // FRZBALUBC, EIC, EB, ENPC, EIMA, NOTSS, Strobe table [ #040102; #077546; #000155; #000000; #177140 ]) //now that Maxc is running again, read and reset the SMI error //register, ignoring FER (which will be on) but being careful //not to lose other signals (COMA). smiErr = (smiErr % InputSMIErrors()) & (smiErrorMask - #100000 rshift offset SMIErr.fer) maxcRunning = true ] // --------------------------------------------------------------------------- and StopMaxc() be // --------------------------------------------------------------------------- [ if maxcRunning then [ RMWBitAbsolute(aNVMAX, nmHALT) //request console halt SignalMaxc() maxcRunning = false //shut off MaxcWatcher process let timer, state = nil, nil SetTimer(lv timer, 5) //wait 50 ms for request to take [ Block() state = MaxcState() ] repeatuntil state ne stateRunning % TimerHasExpired(lv timer) unless state eq stateBreakpoint do [ Ws("*nUnclean micro stop: ") test state eq stateRunning ifso //Maxc didn't stop, halt it by force. [ StopMaxcForcefully() Ws("Maxc didn't respond to halt request") ] ifnot PrintMaxcState(state) ] ] ] // --------------------------------------------------------------------------- and StopMaxcForcefully() be // --------------------------------------------------------------------------- OutputSMI(smiCR, not (crEIC+crEB+crEIMA+crENPC+crIntOn)) // --------------------------------------------------------------------------- and ResetMaxc() be // --------------------------------------------------------------------------- //do emulator reset in preparation for starting a program [ StopMaxc() StartMaxc(emulatorReset) StopMaxc() //wait for reset to complete MemWriteAbsolute(aNVMAX, table [ 0; 0; 0 ]) //reset Alto requests ] // --------------------------------------------------------------------------- and MaxcState() = valof // --------------------------------------------------------------------------- [ let runReg = InputSMI(smiRUN) if runReg<<RUN.running resultis stateRunning unless runReg<<RUN.notBreakpoint resultis stateBreakpoint if runReg<<RUN.localPE resultis stateLocalMemPE if runReg<<RUN.mainPE resultis stateMainBusPE resultis stateHalted ] // --------------------------------------------------------------------------- and PrintMaxcState(state; numargs na) be // --------------------------------------------------------------------------- [ if na eq 0 then state = MaxcState() Ws(selecton state into [ case stateRunning: "Maxc running" case stateBreakpoint: "Maxc halted at breakpoint" case stateLocalMemPE: "Maxc halted with bipolar memory error" case stateMainBusPE: "Maxc halted with memory bus parity error" case stateHalted: "Maxc halted" ]) ] // --------------------------------------------------------------------------- and StartEmulator(maxcWord; numargs na) be // --------------------------------------------------------------------------- //start emulation of PDP-10 instructions at the specified address //(given as a 36-bit maxcWord, not a maxcAdr). [ StopMaxc() if na gr 0 then MemWriteAbsolute(aSTADR,maxcWord) //set starting address StartMaxc(emulatorStart) ] // --------------------------------------------------------------------------- and ResetMemory() be // --------------------------------------------------------------------------- [ OutputSMI(smiRESR, 0) //full reset ConfigureMemory(0, 0) ] // --------------------------------------------------------------------------- and ConfigureMemory(map, fatality) be // --------------------------------------------------------------------------- //setup the memory system with the logical-physical mapping //defined by "map", which is in the following form (see Maxc 11.6): // B0: disable error correction for module 0 // B1-3: logical module assignment for module 0 // B4: disable error correction for module 1 // etc. //"fatality" determines whether SE and PBF are fatal: // B0: SE fatal // B1: PBF fatal [ //set standard quadrant configuration (0) and fatality as specified fatalSE = (fatality & #100000) ne 0 fatalPBF = (fatality & #40000) ne 0 OutputSMI(smiCONFR, enableFER+(allSEF&fatalSE)+(allPBFF&fatalPBF)) //set logical-physical map for each module in each quadrant if map eq 0 then map = stdMemConf //standard configuration for m = 0 to 3 do for q = 0 to 3 do [ let plmr = map rshift (7-4*m) //position ec and log mod number plmr<<PLMR.physicalModule = m plmr<<PLMR.quadrant = q OutputSMIPulse(smiPLMR, plmr) ] OutputSMI(smiRESR, allResetErrors) ] // --------------------------------------------------------------------------- and SetClockInterval(interval) be // --------------------------------------------------------------------------- //set the Maxc clock interrupt interval to "interval", and, if //nonzero, enable the automatic updating of TODCLK [ DisableInterrupts() //lock out the clock interrupt clockUpdateEnabled = interval ne 0 test clockUpdateEnabled ifso [ //get starting value of TODCLK that we are to update MemReadRelative(xTODCLK, maxcClock) interruptInterval = interval ] ifnot interruptInterval = 17 EnableInterrupts() ] // --------------------------------------------------------------------------- and ClockInterrupt() be // --------------------------------------------------------------------------- //this procedure services the interval timer interrupt, updates the //clock in Maxc if required, and initiates Maxc clock interrupts. //Note that although we are simulating a millisecond clock, //it is too expensive to actually update the clock every //millisecond. The clock update interval is given by the //parameter clockUpdateInterval, which is independent of the //interrupt interval requested by Maxc. Hence the Maxc interrupt //interval is quantized to the nearest clockUpdateInterval unit. [ let now = vec 1 Timer(now) let dif = DoubleDifference(now, lastTime) MoveBlock(lastTime, now, 2) if clockUpdateEnabled then [ //update TODCLK cell in Maxc IncrementMaxcWord(maxcClock, dif) MemWriteRelative(xTODCLK, maxcClock) ] interruptTimer = interruptTimer+dif if interruptTimer ge interruptInterval then [ //generate Maxc clock interrupt RMWBitAbsolute(aNVMAX, nmCLOCK) SignalMaxc() interruptTimer = interruptTimer rem interruptInterval ] StartIntervalTimer(clockUpdateInterval, clockMask) ] // --------------------------------------------------------------------------- and ReadLM(adr, maxcData) be // --------------------------------------------------------------------------- [ let state = SaveMaxcState() LoadX(adr) ExecuteMicroInstruction( // Q←LX table [ #040062; #077046; #000001; #000000; #103400 ]) ReadQ(maxcData) RestoreMaxcState(state) ] // --------------------------------------------------------------------------- and ReadSM(adr, maxcData) be // --------------------------------------------------------------------------- [ let state = SaveMaxcState() LoadY(adr) ExecuteMicroInstruction( // B←SY table [ #040102; #077546; #060001; #000000; #103400 ]) ReadBus(maxcData) RestoreMaxcState(state) ] // --------------------------------------------------------------------------- and SaveMaxcState() = valof // --------------------------------------------------------------------------- [ let state = Allocate(sysZone, 8) ExecuteMicroInstruction( // B←EREG table [ #040102; #077547; #020001; #000000; #003400 ]) ReadBus(state) ReadQ(state+3) state!6 = ReadX() state!7 = ReadY() resultis state ] // --------------------------------------------------------------------------- and RestoreMaxcState(state) be // --------------------------------------------------------------------------- [ LoadY(state!7) LoadX(state!6) LoadBus(state+3) ExecuteMicroInstruction( // Q←BR, EIC table [ #040102; #077746; #000001; #000000; #103600 ]) LoadBus(state) ExecuteMicroInstruction( // EREG←BR, EIC table [ #040102; #077546; #000001; #000000; #103600 ]) Free(sysZone, state) ] // --------------------------------------------------------------------------- and ReadQ(maxcData) be // --------------------------------------------------------------------------- [ ExecuteMicroInstruction( // B←Q table [ #040102; #077547; #040001; #000000; #003400 ]) ReadBus(maxcData) ] // --------------------------------------------------------------------------- and ReadX() = Read16BitReg( // B←X // --------------------------------------------------------------------------- table [ #040102; #077546; #010001; #000000; #003400 ]) // --------------------------------------------------------------------------- and ReadY() = Read16BitReg( // B←Y // --------------------------------------------------------------------------- table [ #040102; #077546; #020001; #000000; #003400 ]) // --------------------------------------------------------------------------- and Read16BitReg(microInst) = valof // --------------------------------------------------------------------------- [ let data = vec 2 ExecuteMicroInstruction(microInst) ReadBus(data) resultis data!1 lshift 4 + data!2 rshift 12 ] // --------------------------------------------------------------------------- and LoadX(value) be Load16BitReg(value, // X←BR, EIC // --------------------------------------------------------------------------- table [ #040102; #077546; #000201; #000000; #103600 ]) // --------------------------------------------------------------------------- and LoadY(value) be Load16BitReg(value, // Y←BR, EIC // --------------------------------------------------------------------------- table [ #040102; #077546; #000401; #000000; #103600 ]) // --------------------------------------------------------------------------- and Load16BitReg(value, microInst) be // --------------------------------------------------------------------------- [ let data = vec 2 data!1 = value rshift 4; data!2 = value lshift 12 LoadBus(data) ExecuteMicroInstruction(microInst) ] // --------------------------------------------------------------------------- and ResetArm() be //reset bipolar parity errors // --------------------------------------------------------------------------- [ let data = vec 2 ExecuteMicroInstruction( // B←ARM table [ #040102; #077546; #000055; #000000; #003400 ]) ReadBus(data) data!0 = (data!0 & #16) lshift 3 LoadBus(data) ExecuteMicroInstruction( // ARM←BR, EIC table [ #100102; #077546; #007745; #000000; #103600 ]) ]