// AltIOInit.bcpl -- Initialization for AltIO
// Last modified March 14, 1981 3:25 PM
get "altio.decl"
get "altiomaxc2.decl"
get "pup0.decl"
get "streams.d"
get "AltoDefs.d"
external
[
//outgoing procedures
AltIOInit
//incoming procedures
GetFixed; MyFrame; CallersFrame
InitializeZone; Allocate; Free; Zero; MoveBlock
LogOpen; AltIOReset; AltIOFinish; OpenFile; CallSwat; FileLength
SysErr; Resets; ReadBlock; Closes; SetupReadParam; ReadParam
CreateDisplayStream; ShowDisplayStream; Enqueue
InitializeInterrupt; FindInterruptMask; Timer
InitializeContext; AltIOCommand; UpdateRegisterDisplay; KeySwitch
MaxcKeyboard; MaxcTerminal; MaxcWatcher; PutsWithCursor
MaxcTerminal1; DiabloError; CreateDiabloStream
LoadRam; Ws; Wss; Ding; Dismiss; PutTemplate; InitBcplRuntime
OutputSMI; OutputSMITest; StopMaxcForcefully; ClockInterrupt
ResetMemory; InputSMI; InitAltoEther; InitAltoImp; AltIOParityHandler
AltIOSwatProc; ZeroMaxcMem; ConfigureMemory
//outgoing statics
numPBI; debug; savedParityHandler; altIOSavedSCP
ctxQ; altIOSavedUFP; tDspLines; numMemCabs; stdMemConf; topStack; lenTopStack
//incoming statics
dsp; sysZone; lvSysZone; sysFont; fpSysFont; lvUserFinishProc
fpComCm; switchStartTenex; switchBoot; switchHalt; protected
loadFilename; silentBoot; sysDisk; versionText; lvAbortFlag
tDsp; hDsp; hShow; hNoShow; commandCtx; maxcKeysCtx
keysCtx; cursorDsp; DisplayPuts; diabloStr; bootDiskUnit
adrMTBS; adrDLSBS; RamImage; dlsOutputChar; lvSwatContextProc
maxcClock; lastTime; clockMask; ClockSecond
lenPup; lenPBI; pbiIQ; pbiFreeQ; ndbQ; pupCtx; lenPupCtx
etherNDB; impNDB
]
static
[
ctxQ; tDspLines; numMemCabs; stdMemConf
altIOSavedUFP; altIOSavedSCP
savedParityHandler = 0
lastShownStream = 0
numPBI = 0 //number of pbis to allocate initially
spyBuffer = 0
debug = false
switchZero = false
topStack; lenTopStack
]
manifest
[
endCode = #335
lenCDsp = 5000 //space for command display bitmap
lenTDsp = 17000 //space for maxc tty display bitmap
]
structure String: [ length byte; char↑1,255 byte ]
// ---------------------------------------------------------------------------
let AltIOInit() be
// ---------------------------------------------------------------------------
[
// Load the special Ram microcode
let res = LoadRam(RamImage, true) //load and boot
if res ne 0 then CallSwat("LoadRam failed")
silentBoot = true
InitBcplRuntime()
@endCode = LoadRam // Throw away LoadRam and RamImage
// First allocate some big blocks using GetFixed. This ensures
// that we will have less than 32k left to pass to InitializeZone.
dsp = GetFixed(lenCDsp) //command display window
tDsp = GetFixed(lenTDsp) //maxc tty display window
// Turn remaining storage into a zone
topStack = MyFrame()-1000 //top-level stack during initialization
lenTopStack = CallersFrame()-topStack
sysZone = InitializeZone(@endCode, topStack-@endCode, SysErr,
(debug? SysErr, 0))
@lvSysZone = sysZone
@endCode = topStack
// Reinitialize some things we Junta'ed away
LogOpen(sysZone) //Junta closed the log but we want it open
altIOSavedUFP = @lvUserFinishProc
@lvUserFinishProc = AltIOFinish
altIOSavedSCP = @lvSwatContextProc
@lvSwatContextProc = AltIOSwatProc
// Read in the system font
let fontStr = OpenFile("SysFont.al", ksTypeReadOnly, 0, 0, fpSysFont)
if fontStr eq 0 then CallSwat("Can't open SysFont.al")
let fontSize = (FileLength(fontStr)+1) rshift 1
Resets(fontStr)
sysFont = Allocate(sysZone, fontSize)
ReadBlock(fontStr,sysFont, fontSize)
Closes(fontStr)
let fontHeight = (sysFont!0+1) & #177776
let lineWords = lDCB + 38*fontHeight
sysFont = sysFont+2
// Initialize the display
ShowNext(MakeBar(5, 0)) //10 scan lines of white at top
//2 lines for register display header
hDsp = CreateDisplayStream(2, Allocate(sysZone, 2*lineWords+20),
2*lineWords+10, sysFont, 0, DSstopright)
ShowNext(hDsp)
//2 one-liners for updated display (show only the first)
hShow = CreateDisplayStream(1,
Allocate(sysZone, lineWords+20), lineWords+10, sysFont, 0, DSstopright)
hNoShow = CreateDisplayStream(1,
Allocate(sysZone, lineWords+20), lineWords+10, sysFont, 0, DSstopright)
ShowNext(hShow)
ShowNext(MakeBar(2, 0)) //4 scan lines of white
ShowNext(MakeBar(2, 1)) //4 scan lines of black
hNoShow>>DS.ldcb>>DCB.next = hShow>>DS.ldcb>>DCB.next
// AltIOInit (cont'd)
// Command display stream doesn't need a full bitmap
let cmdScanLines = 808-(10+2+3*fontHeight+8+4+lenTDsp/38+4)
dsp = CreateDisplayStream(cmdScanLines/fontHeight, dsp, lenCDsp-10, sysFont)
DisplayPuts = dsp>>ST.puts
dsp>>ST.puts = PutsWithCursor
ShowNext(dsp)
ShowNext(MakeBar(2,1)) //4 scan lines of black
// Maxc tty display stream does need a full bitmap
tDspLines = (lenTDsp-20)/lineWords
tDsp = CreateDisplayStream(tDspLines, tDsp, lenTDsp-10, sysFont, 0, DSnone)
ShowNext(tDsp)
ShowNext(MakeBar(2, 1)) //4 scan lines of black
PutTemplate(dsp, "$S - command window", versionText)
Wss(tDsp, "Maxc console terminal window*n")
// Initialize contexts
ctxQ = Allocate(sysZone, 2)
ctxQ!0 = 0
commandCtx = MakeContext(AltIOCommand, 1000)
maxcKeysCtx = MakeContext(MaxcKeyboard, 100)
keysCtx = commandCtx //initially type to command window
cursorDsp = dsp
MakeContext(MaxcTerminal, 200)
MakeContext(MaxcTerminal1, 200)
MakeContext(UpdateRegisterDisplay, 200)
MakeContext(KeySwitch, 100)
MakeContext(MaxcWatcher, 500)
//initialize Diablo printer
diabloStr = CreateDiabloStream(0, 0, 0, 0, 25*6)
diabloStr>>ST.error = DiabloError
//initialize Pup package
InitAltIOPup()
//check for Maxc being powered on, and find out how much
//memory there is.
OutputSMITest(#16) //put SMI in normal mode
StopMaxcForcefully() //make sure the processor isn't running
if InputSMI(smiPPSTAT) ne 3 then
Punt("*nProcessor or port not turned on, can't do anything")
let lastModuleOff = false
stdMemConf, numMemCabs = 0, 0
for physMod = 0 to 3 do
[
let logMod = nil
test InputSMI(smiCABST+2*physMod) eq #17
ifso
[
logMod = table [ 4; 0; 6; 2 ]!numMemCabs
numMemCabs = numMemCabs+1
if lastModuleOff then
[
Ws("*nUnusual memory configuration: ")
PutTemplate(dsp, "Cabinet $O off but $O on", physMod-1, physMod)
Ding(dsp)
lastModuleOff = false
]
]
ifnot
[
lastModuleOff = true
logMod = 3
]
stdMemConf = stdMemConf + logMod lshift (12-4*physMod)
]
if numMemCabs eq 0 then
Punt("*nNo memories turned on, can't do anything")
// AltIOInit (cont'd)
//prepare to scan command line
let comStr = OpenFile("Com.cm", ksTypeReadOnly, charItem, 0, fpComCm)
if comStr eq 0 then Punt("*Can't open Com.cm")
let stringVec = Allocate(sysZone, 128)
let switchVec = Allocate(sysZone, 128)
//read program name and global switches
SetupReadParam(0, 0, comStr, switchVec)
for i = 1 to switchVec!0 do
switchon switchVec!i into
[
case $S: case $s:
switchStartTenex = true //fall into case $B
case $B: case $b:
switchBoot = true //fall into case $Z
case $Z: case $z:
[ switchZero = true; endcase ]
case $H: case $h:
[ switchHalt = true; endcase ]
case $P: case $p:
[ protected = true; endcase ]
case $R: case $r:
[ ResetMemory(); endcase ] //full memory reset
case $D: case $d:
[ debug = true; endcase ]
default:
PutTemplate(dsp,"*nBad global switch /$C, ignored", switchVec!i)
]
//read parameters and local switches
[
if ReadParam($P, -1, stringVec, switchVec) eq -1 then break
if switchVec!0 ne 1 then [ CantParse(stringVec, switchVec); loop]
switchon switchVec!1 into
[
case $L: case $l: //save file from which to load memory
[
let length = stringVec>>String.length rshift 1 +1
loadFilename = Allocate(sysZone, length+2) //room for .Sav
MoveBlock(loadFilename, stringVec, length)
endcase
]
case $U: case $u: //unit number for booting Micro-Exec
[
let char = stringVec>>String.char↑1
test stringVec>>String.length eq 1 &
char ge $0 & char le $7
ifso bootDiskUnit = char-$0
ifnot CantParse(stringVec, switchVec)
endcase
]
default:
CantParse(stringVec, switchVec)
]
] repeat
Free(sysZone, stringVec)
Free(sysZone, switchVec)
Closes(comStr)
// AltIOInit (cont'd)
//put hardware and software in standard initial state
adrMTBS,adrDLSBS = Allocate(sysZone, 2),Allocate(sysZone, 2)
dlsOutputChar = Allocate(sysZone, numDLSLines)
if switchZero then [ ConfigureMemory(0, 0); ZeroMaxcMem() ]
AltIOReset() //simulate i/o reset
//initialize clock interrupt
maxcClock = Allocate(sysZone, 3)
lastTime = Allocate(sysZone, 2)
Timer(lastTime)
clockMask = FindInterruptMask(1)
InitializeInterrupt(Allocate(sysZone, 75), 75, clockMask, ClockInterrupt)
ClockInterrupt() //get clock going
//the Maxc2 Alto's clock is a bit slow.
//set clock constants in OS to compensate.
if ClockSecond ne 0 then
MoveBlock(ClockSecond, table [ #31; #120162 ], 2) //1679474
//install own parity handler
savedParityHandler = @#501
@#501 = AltIOParityHandler
//diable shift-swat abort
@lvAbortFlag = 1
// Install own cursor pattern
MoveBlock(#431, table [
#110000; #170000; #110000; #113000; #114400; #007400; #004620; #004540
#000157; #000150; #074230; #004010; #034017; #040000; #074000; #000000
], 16)
// *** for performance debugging ***
if debug then spyBuffer = Allocate(sysZone, 1000)
]
// ---------------------------------------------------------------------------
and MakeBar(height, color) = valof
// ---------------------------------------------------------------------------
//make a bar 2*height scan lines high of specified color (black=1)
[
structure Bar: [ firstDCB word; lastDCB word; dcb: @DCB ]
manifest lenBar = size Bar/16
let bar = Allocate(sysZone, lenBar, false, true) //even word
Zero(bar, lenBar)
bar>>Bar.firstDCB = lv bar>>Bar.dcb
bar>>Bar.lastDCB = lv bar>>Bar.dcb
bar>>Bar.dcb.background = color
bar>>Bar.dcb.height = height
resultis bar
]
// ---------------------------------------------------------------------------
and ShowNext(str) be
// ---------------------------------------------------------------------------
//show display stream immediately below lastShownStream
[
ShowDisplayStream(str, (lastShownStream eq 0? DSalone, DSbelow),
lastShownStream)
lastShownStream = str
]
// ---------------------------------------------------------------------------
and MakeContext(proc, len) = valof
// ---------------------------------------------------------------------------
[
let ctx = InitializeContext(Allocate(sysZone, len), len, proc)
Enqueue(ctxQ, ctx)
resultis ctx
]
// ---------------------------------------------------------------------------
and InitAltIOPup() be
// ---------------------------------------------------------------------------
[
// Since we are not using Pup level 1, we have to do a lot of
// initialization ourselves
// The Pup portion of a PBI must be a multiple of 4 bytes.
lenPup = (pupOvBytes+defaultPupDataBytes)/2+1 & #177776
lenPBI = lenPBIOverhead+lenPup
let level1Qs = Allocate(sysZone, 6)
Zero(level1Qs, 6)
pbiIQ = level1Qs
pbiFreeQ = level1Qs+2
ndbQ = level1Qs+4
for i = 1 to numPBI do Enqueue(pbiFreeQ, Allocate(sysZone, lenPBI))
InitAltoEther(sysZone, ctxQ, 0)
etherNDB = ndbQ!0 // the one and only Ethernet NDB
InitAltoImp(sysZone, ctxQ)
// Wire-in the local net numbers (yuk)
etherNDB>>NDB.localNet = netEther
impNDB>>NDB.localNet = netArpa
// Allocate but do not initialize context for Pup process.
// It will get reset by later AltIOReset
pupCtx = Allocate(sysZone, lenPupCtx)
]
// ---------------------------------------------------------------------------
and Punt(string) be
// ---------------------------------------------------------------------------
[
Ws(string)
Ding(dsp)
Dismiss(500) //5 seconds to let user see message
finish
]
// ---------------------------------------------------------------------------
and CantParse(stringVec,switchVec) be
// ---------------------------------------------------------------------------
PutTemplate(dsp, "*nCan't parse *"$S$C$US*" -- ignored",
stringVec, (switchVec!0 eq 0? $*s,$/), switchVec)