//D0I2.BCPL -- machine-dependent part of Init2()
// Last edited: 1 March 1982
//Implements final machine-dependent init when starting Midas, doing
//"Run-Prog", or doing "Boot". All initialization needed to restore
//the display to its initial arrangement should be carried out.
get "mcommon.d"
get "d0.d"
manifest [ get "d0regmem.d" ]
external [
// OS
SetBlock; Zero
// MINIT0
@MBlock; MStatus
// MINIT2
Initialized
// MASM
@WssCSS; WssCS1; ResetsCSS; ResetsCS1; Wait; GetStorage
// MDATA
MDATAtab; MADDRtab; @BitsChecked; @HighAddress; @AddrIncrement
MCTimeOut
// MIDAS
MidasSwat
// MMENU
@WsMarkA; AbortingCFile
// MMPRGN
UpdateMPDValues
// MCMD
WnsCS1D; WnsCSSD; SetAbortPure; CmdAbort; @CmdAbortAct
// MGO
@CantContinue
// D0I0
HWStatus; BPTable; BootTable; NBootInst
// D0TABLES
@MEMNAM; @MEMLEN
// D0ASM
recvbyte; recvword; sendbyte; sendword; @utilin; @utilout
d0recvbyte; d0recvword; d0sendbyte; d0sendword
ReadPrinter; WritePrinter
// D0REG
ReadAllRegs
// D0MEM
readrr; sovlcurr
// D0GO
Stop; d0Stop
// D0VM
SetVirtP; IMstab; RMstab
// Defined here
InitHardware; DefMemName
]
static [
DefMemName
KernelStartLoc = #7000 //********may change if kernel.mb changes
BootEStr; BootEFlg
]
//Result is 0 or an alternate command-menu forming procedure used
//to select among several target machines.
let InitHardware() = valof
[
//Check engineering number to determine whether Midas is running on an
//Alto (EngNum = 0 to 3), Dolphin (EngNum=4), or Dorado (EngNum=5).
//Different printer interface is used on the Dolphin, and Midas won't run
//on a Dorado.
let EngNum = (table[ #61014; #1401 ] )()
EngNum = EngNum rshift 12
test EngNum < 5
ifso if EngNum eq 4 do
[ Init2Boot = D0Init2Boot
Init2WaitAck = D0Init2WaitAck
SendBootByte = D0SendBootByte
recvbyte,recvword = d0recvbyte,d0recvword
sendbyte,sendword = d0sendbyte,d0sendword
Stop = d0Stop
]
ifnot MidasSwat(2019) //"Midas only runs on Altos and Dolphins"
SetVirtP(false)
DefMemName = MEMNAM!VMx
//Clear the breakpoint table
SetBlock(BPTable,#7777,BPlen*4)
//Zero the error counters and initialize test-control stuff in fake
//memories.
Zero(MDATAtab,MDATAlen*3)
Zero(MADDRtab,MADDRlen*2)
MBlock(BitsChecked,table [ -1; -1; #170000 ] , 3)
SetBlock(HighAddress,-1,2)
AddrIncrement!1 = 1
//Initialize inverted tables for FastSearch
//(Can't use GetZStorage becasue it is swapped out)
let IMstablen = MEMLEN!(IMXx+IMXx+1) rshift (BlockShift+1)
IMstab = GetStorage(IMstablen); Zero(IMstab,IMstablen)
let RMstablen = (MEMLEN!(RMx+RMx+1)+1) rshift 1
RMstab = GetStorage(RMstablen); Zero(RMstab,RMstablen)
MStatus>>MStatus.MachRunning = false
// MStatus>>MStatus.MachRunning = not CheckStopped()
sovlcurr = 0 //clear last overlay number
if HWStatus>>HWStatus.ConnectedMachine eq -1 do
[ CantContinue = didBoot
//If the boot fails, indicate that we are connected anyway
HWStatus>>HWStatus.ConnectedMachine = 0
ResetsCSS(); ResetsCS1()
for BootFailCount = 0 to 9 do
[ Init2Boot()
Wait(2000) //200 msec to let it boot
let BootBad = false
//Transfer m-i from MIM to hardware
for I = BootTable by 3 to BootTable+((NBootInst-1)*3) do
[ if SendBootWord(I!2 & #7777) then
if SendBootWord(I!0) then
if SendBootWord(I!1) then
if SendBootByte(I!2 rshift 12) then loop
BootBad = true
MCTimeOut!6 = (I-BootTable)/3 //How far into boot
break
]
test BootBad
ifso
[ BootEStr = "Communication error during KERNEL transmission"
BootEFlg = true
]
ifnot //start kernel
[ if SendBootByte(#200 % (KernelStartLoc rshift 8)) then
if SendBootByte(KernelStartLoc & #377) do
//**What is this waiting for???
[ for i = 0 to #20000 do
[ if Init2WaitAck() eq 0 then break
]
if recvbyte() eq #100 do //Successfully booted
[ ReadAllRegs()
if BootFailCount ne 0 do
[ WssCSS("Boot succeeded after ")
WnsCSSD(BootFailCount); WssCSS(" failures")
]
resultis 0
]
]
BootEStr = "KERNEL did not start up"
BootEFlg = false
]
]
SetAbortPure(lv BootAbort,nil)
resultis BootFailMenu //Boot failed return
]
UpdateMPDValues(); resultis 0
]
and BootAbort(nil,nil,nil) be
[ ReadAllRegs()
if MStatus>>MStatus.CFileStream ne 0 then
AbortingCFile = 1
CmdAbort()
]
and BootFailMenu(S,nil) be
[ WssCSS("Boot failed 10 times: ")
WssCSS(BootEStr)
if BootEFlg do
[ WssCS1(((MCTimeOut!7 & #170000) ne 0 ?
"Uack didn't drop after acknowledge",
((MCTimeOut!7 & #7400) ne 0 ?
"Didn't receive Uack",
((MCTimeOut!7 & #360) ne 0 ?
"Uack not clear initially","Direction incorrect"))))
WssCS1(" transmitting microinstruction ")
WnsCS1D(MCTimeOut!6)
]
WsMarkA(CmdAbortAct)
]
and Init2Boot() be //**Alto only
[
//Set quiescent state
@utilout = not #440; @utilout = not #40440; @utilout = not #440
//Boot it
@utilout = not #400; @utilout = not #40400; @utilout = not #400
//Set quiescent state
@utilout = not #440; @utilout = not #40440; @utilout = not #440
]
and D0Init2Boot() be //**Dolphin only
[ WritePrinter(#20400)
WritePrinter(#400)
WritePrinter(#20400)
]
and Init2WaitAck() = valof //**Alto only
[ @utilout = not #1400
resultis (@utilin & #10000)
]
and D0Init2WaitAck() = valof //**Dolphin only
[ resultis (ReadPrinter() & #4000)
]
//Send one byte to D0 via printer interface.
//We expect the d0 to have uack cleared, bus direction set
//read nibble 1, keep drive off, utilout is inverted, utilin is not
and SendBootByte(bite) = valof //**Alto only
[ @utilout = not #1400
let tst = nil
//Check for direction incorrect (count in nib3)
if (@utilin & #10000) eq 0 then
[ MCTimeOut!7 = MCTimeOut!7 + 1; resultis false
]
//Check for write ack not clear initially (count in nib2)
if (@utilin & #40000) ne 0 then
[ MCTimeOut!7 = MCTimeOut!7 + #20; resultis false
]
//Set the upper byte to quiescent state (boot bit high), drive data
@utilout = not #40; @utilout = not #40040; @utilout = not #40
//Load low byte of tester output register
@utilout = not bite; @utilout = not (bite % #100000)
@utilout = not bite
//Send iack (?write strobe?)
@utilout = not #240; @utilout = not #40240; @utilout = not #240
//The d0 should respond instantly by raising write ack (#2000). The
//bit we expect is the second bit of nibble 1, on Utilin[01]
//Set to read nibble from tester
@utilout = not #1000
//Check for write ack not coming up (count in nib1)
if (@utilin & #40000) eq 0 then
[ MCTimeOut!7 = MCTimeOut!7 + #400; resultis false
]
//Drop isend (?write strobe?), keeping boot bit high, turn drive off
@utilout = not #40; @utilout = not #40440; @utilout = not #440
//Expect the d0 to drop write ack immediately
@utilout = not #1400
//Check for write ack not dropping immediately (count in nib0)
if (@utilin & #40000) ne 0 then
[ MCTimeOut!7 = MCTimeOut!7 + #10000; resultis false
]
resultis true
]
//NOTE: The only difference between use of the printer interface during
//booting and during regular operation is that during booting wprinter is
//acknowledged by the #10000 bit in rprinter becoming 1; during normal
//operation it is acknowledged by the #100000 bit becoming 1.
and D0SendBootByte(bite) = valof //**Midas running on Dolphin only
[ WritePrinter(#20400) //#20000 = not booting
// #400 = debugger's direction to debugger
let tst = nil //Tiny delay
//Verify debuggee's direction to debuggee (count errors in nib3)
if (ReadPrinter() & #4000) eq 0 then
[ MCTimeOut!7 = MCTimeOut!7 + 1; resultis false
]
//Verify debuggee's write ack clear initially (count errors in nib2)
if (ReadPrinter() & #10000) ne 0 then
[ MCTimeOut!7 = MCTimeOut!7 + #20; resultis false
]
//Set the upper byte to quiescent state (boot bit high), drive data
WritePrinter(#20000+bite)
tst = nil
WritePrinter(#120000+bite) //Turn on write strobe
tst = nil //Tiny delay
//The D0 should respond instantly by raising boot write ack (#10000).
//Check for write ack not coming up (count errors in nib1)
if (ReadPrinter() & #10000) eq 0 then
[ MCTimeOut!7 = MCTimeOut!7 + #400; resultis false
]
//Turn off write strobe and leave direction bit in a good state
WritePrinter(#20400)
tst = nil //Tiny delay
//Check for write ack not dropping immediately (count in nib0)
if (ReadPrinter() & #10000) ne 0 then
[ MCTimeOut!7 = MCTimeOut!7 + #10000; resultis false
]
resultis true
]
and SendBootWord(wurd) = valof
[ if SendBootByte(wurd rshift 8) then
if SendBootByte(wurd & #377) then resultis true
resultis false
]