// AltIOCommand.bcpl -- terminal command processor for AltIO // Last modified March 14, 1981 3:04 PM get "altio.decl" get "streams.d" get "sysdefs.d" external [ //outgoing procedures AltIOCommand; KeySwitch; GetKeys PutsWithCursor; GetString; MaxcKeyboard; DisplayMemCode //incoming procedures MemRead; MemWrite; LoadSaveFile; BootMicroExec MemReadBlock32; MemReadBlock40; DisplayParityError PrintMaxcState; Display20Bit; Display36Bit; Display40Bit; Ding StartMaxc; StopMaxc; StartEmulator; ResetMaxc; ResetMemory ReadLM; ReadSM Ws; Wss; Gets; Puts; Resets; Endofs; Closes Allocate; Free; DefaultArgs; AddToZone Zero; MoveBlock; Dismiss; SetTimer; TimerHasExpired; Block EraseBits; CharWidth; ResetLine; DoubleIncrement; PutTemplate OpenFile; CallSwat; CounterJunta; CallSubsys //outgoing statics commandCtx; maxcKeysCtx keysCtx; cursorDsp; DisplayPuts switchStartTenex; switchBoot; switchHalt; protected loadFilename; bootDiskUnit //incoming statics keys; dsp; tDsp; CtxRunning; sysZone; versionText; maxcRunning adrMTBS; lvUserFinishProc; fatalError; diabloCopy; displayActive updateDisplayValid; numMemCabs; fpComCm; parityData; topStack; lenTopStack keepDisplayOn ] static [ commandCtx; maxcKeysCtx keysCtx; cursorDsp; cursorTimer; DisplayPuts altoNumber; maxcNumber; numberTyped; maxcAdr cursorOn = false protected = false cellOpen = false switchStartTenex = false switchBoot = false switchHalt = false loadFilename = 0 bootDiskUnit = 0 //default boot from unit 0 bootSaveArea = 1 // save area 1 ] structure String: [ length byte; char↑1,255 byte ] // --------------------------------------------------------------------------- let AltIOCommand() be // --------------------------------------------------------------------------- //context handling commands to AltIO in middle window [ // Finish initialization by freeing up the top-level stack AddToZone(sysZone, topStack, lenTopStack) SetTimer(lv cursorTimer, 0) let v = vec 2; maxcNumber = v let v = vec 1; maxcAdr = v; Zero(maxcAdr, 2) if loadFilename ne 0 then [ DefaultExtension(loadFilename, ".Sav") PutTemplate(dsp,"*n: Load from file: $S*n", loadFilename) unless LoadSaveFile(loadFilename) do switchHalt = true Free(sysZone, loadFilename) ] if switchBoot then [ Ws("*n: Boot Micro-Exec") switchHalt = not BootMicroExec(bootDiskUnit, bootSaveArea, switchStartTenex) ] test switchHalt ifso Ws("*n: Halt Maxc") ifnot [ unless switchBoot do [ Ws("*n: Resume Maxc") StartMaxc() ] DirectKeys(maxcKeysCtx, tDsp) ] [ //main command loop unless cellOpen do Ws((protected? "*n#", "*n:")) Block() repeatwhile KEndofs() & not fatalError & parityData>>ParData.flag eq 0 if fatalError then [ fatalError = false cellOpen = false Ding(dsp) DirectKeys(commandCtx, dsp) loop ] if parityData>>ParData.flag ne 0 then [ DisplayParityError() cellOpen = false Ding(dsp) loop ] let char = GetNumber() Puts(dsp, $*s) switchon char into [ case $M: case $m: [ test protected ifso Oop(char) ifnot test numberTyped ifso if Confirm("Micro-start") then [ StopMaxc(); StartMaxc(altoNumber) ] ifnot if Confirm("Midas") then ReturnToMidas() endcase ] // AltIOCommand (cont'd) case $R: case $r: [ test numberTyped % protected ifso Oop(char) ifnot [ Ws("Resume Maxc") test maxcRunning ifso Ws(" -- already running") ifnot if Confirm() then [ StartMaxc() DirectKeys(maxcKeysCtx, tDsp) ] ] endcase ] case $G: case $g: [ test protected ifso Oop(char) ifnot if Confirm("Go emulator") then [ StopMaxc() test numberTyped ifso StartEmulator(maxcNumber) ifnot StartEmulator() DirectKeys(maxcKeysCtx, tDsp) ] endcase ] case $H: case $h: [ test numberTyped % protected ifso Oop(char) ifnot if Confirm("Halt Maxc") then StopMaxc() endcase ] case $L: case $l: [ test numberTyped % protected ifso Oop(char) ifnot [ cellOpen = false let s = Allocate(sysZone, 20) if GetString("Load from file: ", s) then [ Puts(dsp, $*n) DefaultExtension(s, ".Sav") LoadSaveFile(s) updateDisplayValid = false ] Free(sysZone, s) ] endcase ] // AltIOCommand (cont'd) case $B: case $b: [ test protected ifso Oop(char) ifnot if Confirm("Boot Micro-Exec") then [ cellOpen = false if numberTyped then bootDiskUnit = altoNumber if BootMicroExec(bootDiskUnit, bootSaveArea, false) then DirectKeys(maxcKeysCtx, tDsp) updateDisplayValid = false ] endcase ] case $S: case $s: [ test protected ifso Oop(char) ifnot if Confirm("Start Tenex") then [ cellOpen = false if numberTyped then bootDiskUnit = altoNumber if BootMicroExec(bootDiskUnit, bootSaveArea, true) then DirectKeys(maxcKeysCtx, tDsp) updateDisplayValid = false ] endcase ] case $Q: case $q: [ test numberTyped % protected ifso Oop(char) ifnot if Confirm("Quit to Executive") then [ StopMaxc(); finish ] endcase ] case $P: case $p: [ test numberTyped ifso test altoNumber eq #3301 ifso [ protected = false; Ws("Protection off") ] ifnot Oop(char) ifnot [ protected = true; Ws("Protection on") ] endcase ] case $V: case $v: [ PutTemplate(dsp, "Version: $S",versionText) endcase ] case $W: case $w: [ test numberTyped ifso Oop(char) ifnot [ Ws("What's up? "); PrintMaxcState()] endcase ] // AltIOCommand (cont'd) case $Z: case $z: [ test numberTyped % protected ifso Oop(char) ifnot [ Ws("Zap memory") test maxcRunning ifso Ws(" -- please halt Maxc first") ifnot if Confirm() then ResetMemory() ] endcase ] case $E: case $e: [ test numberTyped ifso Oop(char) ifnot [ cellOpen = false Ws("Emulator state") test maxcRunning ifso Ws(" -- please halt Maxc first") ifnot DisplayEmulatorState() ] endcase ] case $D: case $d: [ test numberTyped ifso Oop() ifnot if Confirm((diabloCopy? "Diablo copy off", "Diablo copy on")) then diabloCopy = not diabloCopy endcase ] case $K: case $k: [ test numberTyped ifso Oop() ifnot if Confirm((keepDisplayOn? "Keep display off", "Keep display on")) then keepDisplayOn = not keepDisplayOn endcase ] case $/: [ if numberTyped then MoveBlock(maxcAdr, maxcNumber+1, 2) DisplayMem(maxcAdr) endcase ] case $*n: [ if numberTyped then test cellOpen & not protected ifso DisplayMemCode(MemWrite(maxcAdr, maxcNumber)) ifnot Oop() cellOpen = false endcase ] case $*l: [ ExamineNext(1) endcase ] case $↑: case $W-#100: [ ExamineNext(-1) endcase ] // AltIOCommand (cont'd) case $*011: //tab [ test numberTyped ifso Oop() ifnot [ MemRead(maxcAdr, maxcNumber) maxcAdr!0 = maxcNumber!1 & #37777 //only 18 bits maxcAdr!1 = maxcNumber!2 Puts(dsp, $*n) DisplayMem(maxcAdr) ] endcase ] case $?: [ Ws("? Boot, Diablo, Emulator, Go, Halt, Keep, Load, Midas,") Ws("*n n Micro-start, Protection, Quit, Resume,") Block() Ws("*n Start Tenex, Version, What, Zap,") Ws("*n Maxc memory commands: / ↑ cr lf tab") endcase ] case $*177: [ Ws("XXX "); endcase ] default: Oop(char) ] ] repeat ] // --------------------------------------------------------------------------- and ReturnToMidas() be // --------------------------------------------------------------------------- [ StopMaxc() let s = OpenFile("Com.cm", ksTypeWriteOnly, charItem, 0, fpComCm) if s eq 0 then CallSwat("Can't open Com.cm") Wss(s, "Midas.run/R*n") Closes(s) while @lvUserFinishProc ne 0 do (@lvUserFinishProc)() CounterJunta(AfterCounterJunta) ] // --------------------------------------------------------------------------- and AfterCounterJunta() be // --------------------------------------------------------------------------- [ let s = OpenFile("Midas.run", ksTypeReadOnly) if s eq 0 then CallSwat("Can't open Midas.Run") let userParams = vec 2 userParams>>UPE.type = globalSwitches userParams>>UPE.length = 2 userParams!1 = $R userParams!2 = 0 CallSubsys(s, 0, 0, userParams) CallSwat("CallSubsys returned!") ] // --------------------------------------------------------------------------- and ExamineNext(increment) be // --------------------------------------------------------------------------- //implements the "line feed" and "up arrow" commands [ if numberTyped then test cellOpen ifso test protected ifso Oop() ifnot DisplayMemCode(MemWrite(maxcAdr, maxcNumber)) ifnot [ Oop(); return ] Puts(dsp, $*n) DoubleIncrement(maxcAdr, increment lshift 12) DisplayMem(maxcAdr) ] // --------------------------------------------------------------------------- and DisplayMem(maxcAdr) be // --------------------------------------------------------------------------- [ if maxcAdr!0 rshift 13 ge numMemCabs then [ Ws(" Address out of bounds.") Ding(dsp) cellOpen = false return ] let maxcData = vec 3 let code = MemRead(maxcAdr, maxcData) DisplayMemCode(code) Block() //let MaxcWatcher report memory errors if fatalError % code ne 0 then [ Puts(dsp, $*n); fatalError = false ] ResetLine(dsp) Display20Bit(dsp, maxcAdr) Ws("/ ") Display40Bit(dsp, maxcData) Ws(" ") cellOpen = true ] // --------------------------------------------------------------------------- and DisplayEmulatorState() be // --------------------------------------------------------------------------- [ let maxcData = vec 2 Ws("*nAccumulators:") for ac = 0 to #17 do [ if (ac&3) eq 0 then PutTemplate(dsp, "*n $2O", ac) Ws(" ") ReadLM(ac, maxcData) Display36Bit(dsp, maxcData) Block() //don't hog the machine ] Ws("*nPC: ") ReadSM(emulatorPC, maxcData) Display36Bit(dsp, maxcData) ] // --------------------------------------------------------------------------- and DisplayMemCode(code) be // --------------------------------------------------------------------------- if code ne 0 then PutTemplate(dsp," Memory error ($S) ", selecton code into [ case 1: "Bus PE" case 2: case 3: "Timeout" default: "??" ]) //---------------------------------------------------------------------------- and GetString(prompt, addr, echo, BreakChar; numargs na) = valof //---------------------------------------------------------------------------- [ //make a bcpl string from the keyboard //if echo is true, echo the typed characters to the display. //BreakChar is a procedure that tests whether a character should //terminate the string. The default break set consists of just cr. //returns the terminating character normally. //returns 0 if del is typed (return to command level). //addr is the address of the string that should get the result. //prompt is a prompt string printed in the obvious places DefaultArgs(lv na, 2, true, IsCR) if prompt then Ws(prompt) let count = 0 [ let c = GetKeys() switchon c into [ case $*027: //word delete case $*177: //command delete [ for i = count to 1 by -1 do EraseBits(dsp, -CharWidth(dsp, addr>>String.char↑i)) if c eq $*177 resultis false count = 0 endcase ] case $*001: //↑A case $*010: //BS [ if count ne 0 then [ EraseBits(dsp, -CharWidth(dsp, addr>>String.char↑count)) count = count-1 ] endcase ] default: [ if BreakChar(c) then [ addr>>String.length = count resultis c ] if count le 39 & c ge #40 then [ count = count + 1 addr>>String.char↑count = c if echo then Puts(dsp, c) ] endcase ] ] ] repeat ] // --------------------------------------------------------------------------- and IsCR(char) = char eq $*n // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- and GetNumber() = valof // --------------------------------------------------------------------------- //inputs an octal number from the keyboard, ignoring spaces. //returns a 16-bit result in altoNumber and a 40-bit result //in maxcNumber. numberTyped will be true iff a number was typed. //returns the terminating character [ altoNumber = 0 Zero(maxcNumber, 3) numberTyped = false let string = vec 20 let res = GetString(0, string, true, NumberTerminator) if res eq 0 resultis $*177 for i = 1 to string>>String.length do [ let char = string>>String.char↑i if char ne $*s then [ numberTyped = true altoNumber = altoNumber lshift 3 + char-$0 let overflow = maxcNumber!0 rshift 13 maxcNumber!0 = maxcNumber!0 lshift 3 + maxcNumber!1 rshift 13 maxcNumber!1 = maxcNumber!1 lshift 3 + maxcNumber!2 rshift 13 maxcNumber!2 = (maxcNumber!2 & #010400) lshift 3 + (char-$0) lshift 12 + overflow lshift 8 ] ] resultis res ] // --------------------------------------------------------------------------- and NumberTerminator(c) = c ne $*s & (c ls $0 % c gr $7) // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- and DefaultExtension(string, defaultExt) be // --------------------------------------------------------------------------- [ let n = string>>String.length for i = 1 to n do if string>>String.char↑i eq $. return for i = 1 to defaultExt>>String.length do string>>String.char↑(n+i) = defaultExt>>String.char↑i string>>String.length = n+defaultExt>>String.length ] // --------------------------------------------------------------------------- and Confirm(prompt; numargs na) = valof // --------------------------------------------------------------------------- [ if na gr 0 then Ws(prompt) Ws(" [confirm] ") [ switchon GetKeys() into [ case $Y: case $y: case $*n: case $.: [ Ws("Yes."); resultis true ] case $N: case $n: case $*177: [ Ws("No."); resultis false ] ] Oop() ] repeat ] // --------------------------------------------------------------------------- and Oop(char; numargs na) be // --------------------------------------------------------------------------- [ if na gr 0 then Puts(dsp, char) Ws(" ? ") Ding(dsp) Resets(keys) ] // --------------------------------------------------------------------------- and KeySwitch() be // --------------------------------------------------------------------------- //context that directs keyboard input to the correct window [ Dismiss(4) if @#177036 eq -1 then //ignore if either ctrl or shift is down [ if @#177035 eq #177775 then DirectKeys(commandCtx, dsp) if @#177037 eq #177773 % @#177037 eq #177573 then DirectKeys(maxcKeysCtx, tDsp) ] //"ding" if shift-swat is typed if @#177036 eq #177677 & @#177037 eq #177773 % @#177037 eq #177573 then Ding(dsp) ] repeat // --------------------------------------------------------------------------- and DirectKeys(ctx, ds) be // --------------------------------------------------------------------------- [ if cursorOn then EraseCursor() keysCtx = ctx cursorDsp = ds displayActive = true ] // --------------------------------------------------------------------------- and GetKeys() = valof // --------------------------------------------------------------------------- [ Block() repeatwhile KEndofs() displayActive = true EraseCursor() resultis Gets(keys) ] // --------------------------------------------------------------------------- and KEndofs() = valof // --------------------------------------------------------------------------- [ Dismiss(4) //reduce cost of contexts polling for keyboard input if CtxRunning eq keysCtx & TimerHasExpired(lv cursorTimer) then test cursorOn ifso EraseCursor() ifnot [ Puts(cursorDsp,$|) cursorOn = true cursorDsp>>ST.puts = PutsWithCursor SetTimer(lv cursorTimer, 50) ] resultis keysCtx ne CtxRunning % Endofs(keys) ] // --------------------------------------------------------------------------- and EraseCursor() be // --------------------------------------------------------------------------- [ if cursorOn then [ EraseBits(cursorDsp, -CharWidth(cursorDsp, $|)) cursorOn = false cursorDsp>>ST.puts = DisplayPuts SetTimer(lv cursorTimer, 50) ] ] // --------------------------------------------------------------------------- and PutsWithCursor(str, char) be // --------------------------------------------------------------------------- [ displayActive = true if str eq cursorDsp & cursorOn then EraseCursor() DisplayPuts(str, char) ]