// SpruceUtilsRes.Bcpl -- Resident Utilities
// Errors 100 (old Spruce), 2500
get "SpruceFiles.D"
//get "Spruce.D"
get "SpruceInLdOutLd.d" // InLd/OutLd messages for spooler <-> service communication
// get "SprucePrinters.d"
get "SpruceDoc.d"
// get "SpruceFont.d"
// get "SpruceBand.d"
get "spruceMisc.d"
get "AltofileSys.D"
get "PressFile.D"
compileif newname SpruceSw then [ manifest [ SpruceSw = true ] ]
manifest SprintSw = not SpruceSw
// defined here
external
[
EarOn // sets up Ether "Ear"
LoadBase
InitRam
IsOverlayPresent
Max
Min
Overlay
SetRMR
SprintUserFinishProc
SwapOnSpoolRequest
SwappedOut
SwapSystem
Umax
Umin
]
// incoming procedures
external
[
// OS
CallSwat
DisableInterrupts
EnableInterrupts
GotoLabel
InLd
MoveBlock
OutLd
StartIO
Zero
// Sprint
RestartSprint
// SpruceError
SpruceCondition
SpruceError
Scream
SpruceTrap
// SpruceMl
Usc; InitFrameRuntime
// SpruceEarMl
PollEther
ResetEther
// ISF
IndexedPageIO
// LoadRam
LoadRam
// SpruceLoadOrbitMC
LoadOrbitMC
]
// Incoming statics
external
[
canContinue
Capabilities
CurRMR
Debug
DebugSystem
didContinue
earMask
errorPending
inMsg
knockResult // if on, somebody knocked
lvUserFinishProc
lvSwatContextProc
numActiveOverlays
numMustPrint
numPrinted
numFilesSpooled
outMsg
overLayout
OverlayTable
OverlayTop
printDoc
restartFrame
RunFile
savedSCP
sprintFPRD
spruceFPRD
SprintSavedUFP
stopsPrinting
tickCount
tickCount0
tickMask
tridentDisk
tridentDrive
tridentUsed
Which
xmFonts
]
manifest verticalInterval = #421
manifest DiskCommand = #521
manifest [
EmulatorBankControlReg = #177740 // 177740+0, Emulator is task 0
OrbitBankControlReg = #177741 // 177740+1, Orbit is task 1
XMFontsSetting = 1 // 00, 01 are normal and alternate banks
]
// Procedures
let Umax(a,b) = Usc(a,b) > 0? a, b
and Umin(a,b) = Usc(a,b) < 0? a, b
and SwappedOut() be SpruceError(105)
and InitRam(adr, rmr; numargs na) be
[
// compileif SpruceSw then [
if adr ne 0 & LoadRam(adr, false) ne 0 then SpruceError(210)
// ]
if na > 1 then CurRMR = rmr
SetRMR(CurRMR) // Enable emulator, (orbit), T80 tasks
StartIO(#100000) // Get back in
// Boot will reinitialize system -- to suppress, must set RMR at point of suppression
compileif TridentSw then
[ if tridentUsed&tridentDisk then StartIO(#40) // restart T80
]
compileif SprintSw then
[ if xmFonts then [ @OrbitBankControlReg = XMFontsSetting
@EmulatorBankControlReg = XMFontsSetting ] ]
]
and SetRMR(x) = ( table [ #61010; #1401 ])(x, #20)
compileif SprintSw then [
let Overlay(overlayNo, overlayLevel, lvInitRoutine; numargs na) = valof
[
// overlayNo: index into OverlayTable identifying disk location of overlay's code
// if 0, don't load new overlay
// overlayLevel: omitted or 0: put new overlay at end of overlay space
// otherwise, replace overlays [overlayLevel to numActiveOverlays]
// lvInitRoutine: if supplied and non-zero, pointer to static that will contain an
// initialization routine after the overlay arrives. The overlay routine and all that
// follows it will be returned to free storage after the routine executes.
// returns overlayLevel of new overlay
// See SprintInstall, SpruceInstall, SpruceInit for overlay initialization code
if na<2 % overlayLevel eq -1 then overlayLevel = numActiveOverlays+1
if na<3 then lvInitRoutine = 0
if overlayLevel le numActiveOverlays &
overlayNo eq overLayout>>OVLayout↑overlayLevel.overlayNo then
[ overlayLevel = overlayLevel+1; overlayNo = 0 ] // just release higher ones
let oldOverlayTop = OverlayTop
// If anything is going away, take care of that (reset OverlayTop, mark routines swapped out)
for level = numActiveOverlays by -1 to overlayLevel do
[
let ovReloc= overLayout>>OVLayout↑level.bottom
OverlayTop = ovReloc
ovReloc = ovReloc + ovReloc!3
for p=1 to (ovReloc!0)*2 by 2 do @(ovReloc!p)=SwappedOut
]
numActiveOverlays = overlayLevel-(overlayNo? 0, 1)
if overlayNo eq 0 resultis overlayLevel // don't load new
let bottom = OverlayTop
overLayout>>OVLayout↑overlayLevel.bottom = bottom
overLayout>>OVLayout↑overlayLevel.overlayNo = overlayNo
let pn=OverlayTable!overlayNo
let npg=OverlayTable!(overlayNo+1)-pn
IndexedPageIO(RunFile>>SPruceFile.map, pn, OverlayTop, npg, isfRead)
let ovReloc=OverlayTop+OverlayTop!3
let nRel=ovReloc!0 *2
for p=1 to nRel by 2 do
@(ovReloc!p)=ovReloc!(p+1)+OverlayTop+16
OverlayTop=OverlayTop+OverlayTop!4
// Call init routine, if any. Then release its space, relocating reloc table.
// Init routine statics are not subsequently marked "swapped out".
if lvInitRoutine then
[
let bot=@lvInitRoutine
bot() // call the routine
MoveBlock(bot, ovReloc, nRel+1)
bottom!3 = bottom!3 - (ovReloc-bot) // reloc table pointer
OverlayTop=ovReloc+nRel+1
]
resultis overlayLevel
]
and IsOverlayPresent(overlayNo) = valof
[
for i = 1 to numActiveOverlays do
if overLayout>>OVLayout↑i.overlayNo eq overlayNo resultis i
resultis false
]
and LoadBase() be // be sure T80 is in if necessary, Base is in, Init is in
[
let iT8 = IsOverlayPresent(OVT80)
compileif TridentSw then
[ if tridentUsed¬ iT8 then [ Overlay(OVT80, 1); iT8=1 ] ]
if IsOverlayPresent(OVBase) ne iT8+1 then Overlay(OVBase, iT8+1)
Overlay(OVInit, iT8+2, lv LoadOrbitMC) // conditional on non-existence
]
and SprintUserFinishProc() be
[
compileif ReportSw then
[
if Report then
[
GetTime(lv Report>>REP.totalTime)
//Send it out over the ether to 3#200#31
if DoEtherReport then EventReport(Report, size REP/16, table [ #1600; #0; #31 ] )
]
]
@lvSwatContextProc = savedSCP
if inMsg>>FP.leaderVirtualDa then // called from Spooler, RAM is loaded
[ SetRMR(#177776); StartIO(#100000) ] // Silent boot
@lvUserFinishProc=SprintSavedUFP
]
and SwapSystem(canContinue) be
[
// First, OutLd
EarOn(0) // precautionary
InitFrameRuntime(false) // turn off use of microcoded GetFrame, return (if on)
// Be sure disk activity is terminated
while @DiskCommand do [] // Model 31
(@lvSwatContextProc)(0) // Trident
DisableInterrupts()
let oldDid = didContinue
didContinue = canContinue
// ~~ note using printDoc static here
let fileCode = printDoc>>DocG.PressFile>>SPruceFile.fileCode
outMsg>>TOSpoolerMsg.stopsPrinting = stopsPrinting
let code = oldDid%canContinue? OutLd(sprintFPRD, inMsg), 0
Which = lv sprintFPRD
if code then // Return from spooler
[
EnableInterrupts()
InitFrameRuntime(true) // use microcoded frame allocation
errorPending = 0
InitRam(0) // Restart RAM tasks
// continue if possible and requested, else restart
EarOn(1) // print may limit duty cycle by calling EarOn(2)
Capabilities = inMsg>>TOPrinterMsg.Capabilities // might have been changed while we were away
if inMsg>>TOPrinterMsg.inProgress & canContinue &
(inMsg>>TOPrinterMsg.fileCode eq fileCode) then
[
Zero(outMsg, 18)
numPrinted = 0
let n = inMsg>>TOPrinterMsg.numSpooled
if n then
[
numFilesSpooled = n
numMustPrint = inMsg>>TOPrinterMsg.numMustPrint
DebugSystem = inMsg>>TOPrinterMsg.DebugSystem
]
return
]
GotoLabel(restartFrame, RestartSprint)
]
// outMsg is set up by caller with description of reason for termination
unless inMsg>>FP.leaderVirtualDa finish // first time, system now installed
SetRMR(#177776)
StartIO(#100000) // Silent boot -- turn off tasks
InLd(spruceFPRD, outMsg) // Bye....
]
and SwapOnSpoolRequest() be
[
// DebugSystem's 20 bit suppresses spooler activation
if (DebugSystem) ne 0 return // never swap
// ** knockResult is true if interrupt routines have detected spool request
if knockResult&numPrinted<numMustPrint then
knockResult = knockResult+1 // 0 if was -1
unless knockResult return
// Spooling status request has been received and replied to, or ESC was down on kbd -- Swap
DisableInterrupts(); knockResult = false; EnableInterrupts() // ??
outMsg>>TOSpoolerMsg.inProgressCode =
printDoc>>DocG.PressFile>>SPruceFile.fileCode
outMsg>>TOSpoolerMsg.completionCode = CCKnock
SwapSystem(true)
]
// Reset ether interface.
// code:
// 0 -- disable Ether and Timer interrupts
// 1 -- enable Ether and Timer interrupts, allow Ether to restart after each interrupt
// 2 -- enable Ether and Timer interrupts, allow Ether to restart only each tickCount
// clock ticks
// return local host
// tickCount has following properties:
// <=0: PollEther routine may restart receiver after processing possible packet
// =0: Ticker will call PollEther, which will then be allowed to restart receiveru;
// Ticker will reset PollEther to small positive value limiting polling duty cycle
// >0: Ticker will not call PollEther, but will count down tickCount
and EarOn(code) = valof
[
DisableInterrupts()
let res = ResetEther(code? earMask, 0) // ether will cause/not cause interrupts on its channel
knockResult = false
tickCount = 0
if code then PollEther() // turn receiver on
switchon code into
[
case 0:
@verticalInterval = @verticalInterval & (-1 xor tickMask) // decouple Ticker
endcase
case 2: tickCount = tickCount0 // enables Ticker control of ether receiver -- fall thru
case 1:
@verticalInterval = @verticalInterval % tickMask
endcase
default: CallSwat("Repair EarOn call")
]
EnableInterrupts()
resultis res // return host
]
and Max(a,b) = a>b? a, b
and Min(a,b) = a<b? a,b
] // SprintSw
compileif true then [
let HighStack() = valof for i = @#335 to #177677 do if @i resultis i
]
// DCS, January 21, 1978 12:09 AM, from SpruceUtils, others
// March 10, 1978 9:06 AM, add LoadBase for OVInit
// March 15, 1978 10:36 AM, Trident bug in LoadBase
// May 11, 1978 6:27 PM, modify SwapOnSpoolRequest to assume interrupt-driven Ether poll
// May 12, 1978 11:14 AM, add tickMask control, ticker
// August 28, 1978 8:34 PM, EarOn(code) replaces EarOn(mask) -- Ticker moves to assembly code
// September 4, 1978 5:33 PM, simplify SwapOnSp...., allow to respond more readily to ESC
// September 5, 1978 9:25 AM, InitRam no longer sets up for silent boot
// September 25, 1978 9:27 AM, Ether interrupt does not schedule Ticker()
// January 28, 1979 4:11 PM, wait for disk activity to cease before executing SwapSystem code
// August 1, 1979 12:14 AM, pass bin stuff thru inld/outld
// August 9, 1979 10:02 AM, pass Capabilities thru TOPrinterMsg
// August 29, 1979 12:56 PM, stop passing bin stuff thru inld/outld
// January 29, 1980 4:21 PM, init routine for OVInit in LoadBase
// InitRam does LoadRam for Sprint, too and takes RMR parm
// /