// AltIODisplay.bcpl -- handles parts of Alto display other
//			than command window.  Also contains
//			various display subroutines

//	Last modified December 13, 1982  9:43 AM

get "altio.decl"
get "streams.d"
get "AltoDefs.d"


external
[
//outgoing procedures
MaxcTerminal; MaxcKeyboard; MaxcTerminal1
DiabloError; UpdateRegisterDisplay; DisplayParityError
Display20Bit; Display36Bit; Display40Bit; PrintOctalField
Ding

//incoming procedures
Ws; Wss; Gets; Puts; Resets; Stateofs; Block
Allocate; Free; Dismiss; PutTemplate; SetTimer; TimerHasExpired
MyFrame; GotoFrame; ResetLine
GetKeys
MemRead; MemReadBlock32; MemReadBlock40; DisplaceMaxcAdr
TakeDLSOutput; GiveDLSInput

//outgoing statics
tDsp; hDsp; hShow; hNoShow; updateDisplayValid; displayActive
diabloStr; diabloCopy; keepDisplayOn

//incoming statics
sysZone; dsp; resetExecuted; adrMTBS; parityData
]

static
[
tDsp; hDsp; hShow; hNoShow; updateDisplayValid; displayActive
diabloStr
diabloCopy = false
diabloBusy = false
diabloHung = false
keepDisplayOn = false
]

manifest ecDiabloPrinterCheck = 2501

// ---------------------------------------------------------------------------
let MaxcTerminal() be
// ---------------------------------------------------------------------------
//context simulating Maxc DLS terminal 0 in bottom window
[
let char = TakeDLSOutput(0) & #177
switchon char into
   [
   case $*007:  //bell
      [ Ding(tDsp); endcase ]
   case $*n:  //ignore carriage return
      endcase
   case $*l:  //turn line feed into carriage return
      char = $*n  //fall into default case
   default:
      Puts(tDsp, char)
      if diabloCopy then DiabloPrint(char)
   ]
] repeat

// ---------------------------------------------------------------------------
and MaxcKeyboard() be GiveDLSInput(0, GetKeys()) repeat
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
and MaxcTerminal1() be
// ---------------------------------------------------------------------------
//context simulating Maxc DLS terminal 1 using Diablo printer
[
let char = TakeDLSOutput(1) & #177
switchon char into
   [
   case $*n:  //ignore carriage return
      endcase
   case $*l:  //turn line feed into carriage return
      char = $*n  //fall into default case
   default:
      DiabloPrint(char)
   ]
] repeat

// ---------------------------------------------------------------------------
and DiabloPrint(char) be
// ---------------------------------------------------------------------------
[
while diabloBusy do Block()
if diabloHung then
   test Stateofs(diabloStr)  //now ready?
      ifso [ diabloHung = false; Resets(diabloStr) ]  //yes, time to try again
      ifnot return  //no, throw char away
diabloBusy = true
diabloStr>>ST.par1 = MyFrame()
Puts(diabloStr, char)
if diabloHung then
   [
   Ws("*nDiablo printer not ready*n")
   Ding(dsp)
   ]
diabloBusy = false
]

// ---------------------------------------------------------------------------
and DiabloError(str, ec) be
// ---------------------------------------------------------------------------
//Errors procedure called from within Diablo Printer package
[
if ec eq ecDiabloPrinterCheck then Resets(str)
diabloHung = true
GotoFrame(str>>ST.par1)
]

// ---------------------------------------------------------------------------
and UpdateRegisterDisplay() be
// ---------------------------------------------------------------------------
//context that updates the Maxc register display in top window
[
structure Bytes↑1,80 byte
Resets(hShow); Resets(hDsp)  //clear the register display window
Block() repeatuntil resetExecuted
let regAdr = vec 3*5
let textBuf = Allocate(sysZone, 41)
let maxcAdr = vec 1
DisplaceMaxcAdr(xNVMSG, maxcAdr)
MemReadBlock32(maxcAdr, textBuf, 20)  //read 80 bytes of text
MemReadBlock40(maxcAdr, regAdr, 5)  //read 5 words of pointers
updateDisplayValid = true
for i = 0 to 29 do  //test for reasonable looking stuff in header
   if textBuf!i eq 0 % (textBuf!i & #100200) ne 0 then
      updateDisplayValid = false
unless updateDisplayValid do
   [  //nothing to display, clear the window
   Free(sysZone, textBuf)
   Dismiss(1000)  //wait 10 seconds and try again
   loop
   ]
for i = 1 to 80 do Puts(hDsp, textBuf>>Bytes↑i)  //display text line
Free(sysZone, textBuf)
Puts(hDsp, $*n)
for i = 0 to 4 do
   [
   Block()  //don't hog the machine
   Wss(hDsp, "   ")
   Display20Bit(hDsp, regAdr+3*i+1)
   Wss(hDsp,"      ")
   ]

displayActive = true
let timer = nil
while updateDisplayValid do
   [  //refresh the data portion of the display once per second
   ResetLine(hNoShow)  //the stream not being shown now
   for i = 0 to 4 do
      [  //read and display current values of Maxc registers
      Block()
      let maxcData = vec 3
      MemRead(regAdr+3*i+1, maxcData)
      Display36Bit(hNoShow, maxcData)
      Wss(hNoShow, "   ")
      ]
   //swap the updating display streams
   hDsp>>DS.ldcb>>DCB.next = hNoShow>>DS.fdcb
   let t = hShow; hShow = hNoShow; hNoShow = t
   Dismiss(100)

   // If nothing interesting is happening, turn off the display
   if displayActive % keepDisplayOn then
      [ SetTimer(lv timer, 12000); displayActive = false ]
   if TimerHasExpired(lv timer) then
      [
      let save420 = @#420
      @#420 = 0
      while not (displayActive % keepDisplayOn) &
       updateDisplayValid do Dismiss(100)
      @#420 = save420
      ]
   ]
] repeat

// ---------------------------------------------------------------------------
and DisplayParityError() be
// ---------------------------------------------------------------------------
//displays and prints data for an Alto parity error
[
let str = lv SplitStream - offset ST.puts/16  //make split stream
Wss(str, "*nAn Alto memory parity error has occurred.")
PutTemplate(str, "*nDCBR=$UO, KNMAR=$UO, DWA=$UO, CBA=$UO, PC=$UO, SAD=$UO",
 parityData>>ParData.dcbr, parityData>>ParData.knmar,
 parityData>>ParData.dwa, parityData>>ParData.cba,
 parityData>>ParData.pc, parityData>>ParData.sad)
PutTemplate(str, selecton parityData>>ParData.numErrors into
   [
   case 0: "*nNo errors found during sweep."
   case 1: "*n$UD error found:  address=$UO, contents=$UO."
   default: "*n$UD errors found;  first address=$UO, contents=$UO."
   ], parityData>>ParData.numErrors,
 parityData>>ParData.errorAdr, parityData>>ParData.errorData)
DiabloPrint($*n)
parityData>>ParData.flag = 0
]

// ---------------------------------------------------------------------------
and SplitStream(nil, char) be
// ---------------------------------------------------------------------------
   [ Puts(dsp, char); DiabloPrint(char) ]

// ---------------------------------------------------------------------------
and Display20Bit(str, adr) be PrintOctalField(str, adr, 0, 19)
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
and Display36Bit(str, adr) be
// ---------------------------------------------------------------------------
[
PrintOctalField(str, adr, 0, 17)
Puts(str, $*s)
PrintOctalField(str, adr, 18, 35)
]

// ---------------------------------------------------------------------------
and Display40Bit(str, adr) be
// ---------------------------------------------------------------------------
[
test (adr!2 & #7400) ne 0
   ifso PrintOctalField(str, adr, 36, 39)
   ifnot Wss(str, "  ")
Puts(str, $*s)
Display36Bit(str, adr)
]


// ---------------------------------------------------------------------------
and PrintOctalField(str, adr, firstBit, lastBit) be
// ---------------------------------------------------------------------------
[
let r = (lastBit-firstBit) rem 3
firstBit = firstBit+r
let mask = (2 lshift r)-1
   [
   let q, r = firstBit rshift 4, firstBit&#17
   Puts(str, $0 + ((adr!(q-1) lshift (1+r) + adr!q rshift (15-r)) & mask))
   firstBit = firstBit+3
   mask = 7
   ] repeatuntil firstBit gr lastBit
]


// ---------------------------------------------------------------------------
and Ding(stream) be
// ---------------------------------------------------------------------------
[
InvertWindow(stream, 1)
Dismiss(50)
InvertWindow(stream, 0)
]


// ---------------------------------------------------------------------------
and InvertWindow(stream, background) be
// ---------------------------------------------------------------------------
[
let dcb = stream>>DS.fdcb
   [
   dcb>>DCB.background = background
   if dcb eq stream>>DS.ldcb return
   dcb = dcb>>DCB.next
   ] repeat
]