// AltIOUtilb.bcpl -- utility routines for AltIO

//	Last modified April 17, 1978  2:38 PM

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

external
[
//outgoing procedures
LoadSaveFile; ZeroMaxcMem; BootMicroExec
MemReadBlock32; MemWriteBlock32; MemReadBlock40; MemWriteBlock40
MemZero; RMWBitAbsolute; RMWBitRelative

//incoming procedures
OpenFile; Ws; PutTemplate; Gets; Closes; Endofs; SysErr
MyFrame; GotoFrame; Zero; Usc
MemRead; MemWrite; MemRMW; DoubleIncrement; DoubleAdd; Block
MemReadBlock32A; MemWriteBlock32A; MemReadBlock40A
MemWriteBlock40A; MemZeroA; SetOneMaxcBit
MemReadAbsolute; MemWriteAbsolute; MemRMWAbsolute
MemReadRelative; MemWriteRelative; MemRMWRelative
AltIOReset; StartMaxc; StopMaxc; ResetMaxc; ConfigureMemory
DisplayMemCode

//incoming statics
dsp; sysZone; adrMTBS; numMemCabs
MaxcBootLoader; lenMaxcBootLoader
]

// ---------------------------------------------------------------------------
let LoadSaveFile(s) = valof
// ---------------------------------------------------------------------------
//load into Maxc memory a save-format file whose name is the
//string s.
[
let str = OpenFile(s, ksTypeReadOnly, charItem)
if str eq 0 then
   [ PutTemplate(dsp, "File $S not found", s); resultis false ]
StopMaxc()
unless ZeroMaxcMem() resultis false
str>>ST.error = LoadErrors  //catch running off end of file
str>>ST.par1 = MyFrame()
let maxcAdr, maxcData = vec 2, vec 3
let errorCode = 0
   [
   unless GetMaxcWord(str, maxcData) do
      [
      Ws("Premature end of file, probable bad format")
      errorCode = -1
      break
      ]
   if maxcData!0 ge 0 then
      [
      unless Endofs(str) do
         [
         Ws("End block before eof, probable bad format")
         errorCode = -1
         break
         ]
      //end block, put starting address in location 7
      maxcData!0 = 0; maxcData!1 = maxcData!1 & #37777
      MemWriteAbsolute(aSTADR, maxcData)
      //put something reasonable in MTBS and DLSBS
      maxcData!1 = #200 rshift 4; maxcData!2 = 0
      MemWriteAbsolute(aMTBS, maxcData)
      maxcData!1 = #600 rshift 4
      MemWriteAbsolute(aDLSBS, maxcData)
      AltIOReset()  //reset Alto state
      ResetMaxc()  //reset Maxc so "Resume" will start program
      break
      ]
   //this is an iowd, set up to transfer data block
   if (maxcData!0 & #140000) ne #140000 then
      [
      Ws("Block size larger than 2↑16, probable bad format")
      errorCode = -1
      break
      ]
   let count = maxcData!0 lshift 2 + maxcData!1 rshift 14
   maxcAdr!0 = maxcData!1 & #37777
   maxcAdr!1 = maxcData!2
      [
      DoubleIncrement(maxcAdr, #10000)
      unless GetMaxcWord(str, maxcData) break
      errorCode = MemWrite(maxcAdr, maxcData)
      count = count+1
      ] repeatuntil count eq 0 % errorCode ne 0
   ] repeatwhile errorCode eq 0
if errorCode gr 0 then DisplayMemCode(errorCode)
Closes(str)
resultis errorCode eq 0
]

// ---------------------------------------------------------------------------
and GetMaxcWord(str, maxcData) = valof
// ---------------------------------------------------------------------------
[
let b1 = Gets(str)
let b2 = Gets(str)
let b3 = Gets(str)
let b4 = Gets(str)
let b5 = Gets(str)
maxcData!0 = b1 lshift 12 + b2 lshift 4 + b3 rshift 4
maxcData!1 = b3 lshift 12 + b4 lshift 4 + b5 rshift 4
maxcData!2 = b5 lshift 12
resultis true
]

// ---------------------------------------------------------------------------
and LoadErrors(str, ec) be
// ---------------------------------------------------------------------------
[
test ec eq 1302
   ifso GotoFrame(str>>ST.par1, false)  //end of file
   ifnot SysErr(str, ec)  //other error
]

// ---------------------------------------------------------------------------
and ZeroMaxcMem() = valof
// ---------------------------------------------------------------------------
//zeroes all of Maxc memory in preparation for loading a program.
[
let maxcAdr = vec 2
Zero(maxcAdr, 2)
for i = 0 to 4*numMemCabs-1 do
   [
   let code = MemZero(maxcAdr, #100000)  //do 2↑15 words
   if code ne 0 then [ DisplayMemCode(code); resultis false ]
   ]
resultis true
]

// ---------------------------------------------------------------------------
and BootMicroExec(diskUnit, saveArea, autoStart) = valof
// ---------------------------------------------------------------------------
//loads into Maxc memory and starts the disk boot loader which
//in turn starts Micro-Exec.  diskUnit and saveArea specify
//the disk address to load Micro-Exec from, and autoStart
//supplies the top 16 bits of the "switches" (Micro-Exec
//does an automatic start of Tenex if bit 0 is set).
[
manifest loaderPage = #347  //page in which loader runs

//normalize processor state
ResetMaxc()
ConfigureMemory(0, 0)

//setup the first word of the loader to contain the unit number
//in bits 11-13 and #6221 - #40*saveArea in bits 18-35.
MaxcBootLoader!0 = diskUnit lshift 2
let diskAdr = #6221 - #40*saveArea
MaxcBootLoader!1 = diskAdr rshift 4
MaxcBootLoader!2 = diskAdr lshift 12

//copy the loader to Maxc memory
let v = vec 2
v!0 = loaderPage lshift 5
v!1 = 0
let code = MemWriteBlock40(v, MaxcBootLoader, lenMaxcBootLoader)
if code ne 0 then [ DisplayMemCode(code); resultis false ]

//set starting address and auto-start parameter, then go.
MemWriteAbsolute(aSTADR, table [ 0; loaderPage lshift 5; #10000 ])
v!0 = autoStart
v!1, v!2 = 0, 0
MemWriteAbsolute(aSWICH, v)
StartMaxc()
resultis true
]

// ---------------------------------------------------------------------------
and MemReadBlock32(maxcAdr, maxcData, count) =
// ---------------------------------------------------------------------------
   MemBlockTransfer(MemReadBlock32A, maxcAdr, maxcData, count, 2)

// ---------------------------------------------------------------------------
and MemWriteBlock32(maxcAdr, maxcData, count) =
// ---------------------------------------------------------------------------
   MemBlockTransfer(MemWriteBlock32A, maxcAdr, maxcData, count, 2)

// ---------------------------------------------------------------------------
and MemReadBlock40(maxcAdr, maxcData, count) =
// ---------------------------------------------------------------------------
   MemBlockTransfer(MemReadBlock40A, maxcAdr, maxcData, count, 3)

// ---------------------------------------------------------------------------
and MemWriteBlock40(maxcAdr, maxcData, count) =
// ---------------------------------------------------------------------------
   MemBlockTransfer(MemWriteBlock40A, maxcAdr, maxcData, count, 3)

// ---------------------------------------------------------------------------
and MemZero(maxcAdr, count) =
// ---------------------------------------------------------------------------
   MemBlockTransfer(MemZeroA, maxcAdr, nil, count, 3)

// ---------------------------------------------------------------------------
and MemBlockTransfer(Operation, maxcAdr, maxcData, count, inc) = valof
// ---------------------------------------------------------------------------
//Perform some flavor of Maxc memory block transfer.
//The transfer is done a piece at a time with calls to Block()
//interspersed to prevent excessive latency to other contexts.
//inc is the Alto address increment for each Maxc word
[
let code = nil
while count ne 0 do
   [
   let c = Usc(count, maxBlt) ls 0? count, maxBlt
   code = Operation(maxcAdr, maxcData, c)
   if code ne 0 break
   maxcData = maxcData + c*inc
   count = count-c
   Block()
   ]
resultis code
]

// ---------------------------------------------------------------------------
and RMWBitAbsolute(adr, bitNumber) = valof
// ---------------------------------------------------------------------------
//set bit "bitNumber" in Maxc location "adr"
[
let maxcData = vec 3
SetOneMaxcBit(maxcData, bitNumber)
resultis MemRMWAbsolute(adr, maxcData)
]

// ----------------------------------------------------------------
and RMWBitRelative(displacement, bitNumber, base; numargs na) = valof
// ----------------------------------------------------------------
//set bit "bitNumber" in Maxc location "adr" relative to "base"
[
let maxcData = vec 3
SetOneMaxcBit(maxcData, bitNumber)
resultis MemRMWRelative(displacement, maxcData, (na ls 3? adrMTBS, base))
]