// 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>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