:TITLE[Initialize]; *Last edited: 1 May 1981 by Fiala %RM assignments are subject to a number of constraints: 1) Must not smash the registers needed to continue LoadRAM; these are LP, LPhi, xfTemp, and xfTemp1 (RM 66, 67, 72, 73); RTemp1 must be set even before continuing LoadRAM. 2) Must leave PageCount as RM 37 to agree with Initial. 3) Registers needed valid after DeviceInit must not be in the range 40-57, which is used as a buffer during DeviceInit; nor may any of the constants initialized by RegInit1 (AllOnes, R400, MDS, MDShi) appear in this area. 4) BootType may not be in the range 0-17 because it is referenced by BootTask (task 1, 2, or 3). xCNT (35) is used throughout init; xBuf to xBuf3 (44 - 47), RTemp and RTemp1 (52 - 53) are also used except during DeviceInit. % RV[PageCount,37]; *Count of available real pages in system **DON'T MOVE--MUST AGREE WITH INITIAL** RV[BootType,36]; *even => hard boot, odd => soft boot (n.i.); *negative => ether, positive => disk *200 disk partition 2 *RM address must not be < 20b nor 40b to 57b. RV4[iniBf0,iniBf1,iniBf2,iniBf3,14]; *Registers for map and storage initialization RV[CompFlag,5]; RV2[ZWord,ZWordhi,6]; *Base reg RV[MapAddr,10]; *current map location RV[RealPage,11]; *current real storage page *In addition to the registers below, RTemp, RTemp1, and DMA are used prior *to DiskBoot/EtherBoot code; xCNT, DevIndex, contemp, DMA, and DMAhi must *not be in 40-57 area. *34 was formerly used in DeviceInit RV[Assigned,65]; *used in DeviceInit RV[DevIndex,12]; *used in DeviceInit and DiskBoot RM[ErrorCnt,IP[RTemp]]; *used in DiskBoot RM[ErrorCountx,IP[RTemp1]]; *used in DiskBoot MC[ReturnOnSE,100000]; *FFault bit 0=crash on MC2 errors, 1=return *The DTab macro formats device table entries. A DTab entry consists of the *task and uPC value for the device's init routine (0 if no init routine). *To add a new controller to the system, it is only necessary to add an entry *to the device table (and add the controller's microcode). M@[DTab,IMData[LH[#1] RH[LShift[#2,4],#3] At[DTabLoc]] Set[DTabLoc,Add[DTabLoc,1]]]; Set[DTabLoc,DTabBase]; DTab[12000,0,0]; *DES board DTab[127000,0,0]; *FP board **NOTE: The CDC is an optional device; perhaps we should require software to **manually start the controller's microcode with JRAM 50000b+cdcInitLoc and **not initialize the device here, so that this table won't change when the **uCode is not present. DTab[127400,cdcInitLoc,cdcTask]; *Color display = 53400b; DTab[3400,EtherInitLoc,eiTask]; *New Ethernet input = 3400b DTab[3000,0,EOTask]; *New Ethernet output=3000b(No init required) DTab[1000,DisplayInitLoc,DpTask]; *Display (UTVFC) = 1000b DTab[1400,DiskInitLoc,rdcTask]; *Disk (Alto RDC) = 1400b DTab[2400,DiskInitLoc,rdcTask]; *Disk (Alto RDC) = 2400b (kludge if service late is on) DTab[0,0,0]; *final table entry must be zero OnPage[InitPage]; %KGO, EGO, and KGOP2 are Midas starting addresses which can be entered in any task. Initial sends control to KGO if the disk is ready, else to EGOx, where EGOx and KGOP2x are suitable starting addresses only if the current task is the emulator (or tasks 1 to 3?). ***EGOx AND KGOx PLACEMENT IS KNOWN TO MAKELOADERFILE COMMAND FILES*** On keyboard boot, Display.Mc leaves KB0 word in T (T registers of unused tasks safely hold data across a boot; possibly MNBR or SALUF also are unsmashed but not sure). 1's in KB0 represent keys up, 0's keys down; bits are: 5, 4, 6, E, 7, D, U, V, 0, K, -, P, /, \, LF, BS. "0" (177577b) is interpreted here as a partition 2 disk boot; BS (177776b) is ether boot; all other values do a partition 1 disk boot. % KGOP2: xBuf _ LoA[Add[InitBase,0]], GoTo[.+3]; EGO: xBuf _ LoA[Add[InitBase,4]], Skip; KGO: xBuf _ LoA[Add[InitBase,6]], At[InitBase,3]; xBuf _ (xBuf) or (HiA[InitBase,BootTask]); XNotify: APCTask&APC _ xBuf, GoTo[iniRET]; *BootTask .le. 3, so it can address all emulator RM registers except *RM 0 to 17b, but SetTask here checks against illegal RM refs. SetTask[BootTask]; BootType _ T, At[InitBase,6]; T _ (BootType) xnor (200C); *Must modify T so next boot not same LU _ (BootType) xnor (1C), Skip[ALU#0]; *Par 2 boot on "0" key KGOP2x: BootType _ 200C, GoTo[Start], At[InitBase,0]; *KGO on partition 2 BootType _ T _ 0C, GoTo[Start,ALU#0]; *Ether boot on BS key EGOx: BootType _ 100000C, GoTo[Start], At[InitBase,4]; *Ether boot *SoftGO: BootType _ 1C, GoTo[?], At[InitBase,2]; *Boot failures loop after putting code in maintenance panel; *repeats previous kind of boot remembered in BootType. InitFail: Call[iPNIP]; GoTo[Start]; SetTask[0]; *Begin here as any task. Quiesce tasks 15 to 1 by notifying each one at Qx, *which clears device register 0 and notifies the next task until ctask is 0. *All devices are supposed to be disabled by outputting 0 to register 0, but *the EtherNet controller has a bug requiring an extra output, which is done *first below for all tasks. Start: xBuf _ IP[xBuf]C, At[InitBase,5]; StkP _ xBuf; Stack _ HiA[Qloc,15]; Stack _ (Stack) or (LoA[Qloc]); QNotify: Stack&+1 _ 0C; Stack&+1 _ 300C; *Output a 300 to device 0 for this task (in case this is the ethernet task); *then output a 0 to device 0; finally point task's TPC at BadWakeup. Output[Stack,0]; Nop; Output[Stack,0]; APCTask&APC _ Stack; LoadPageExternal[InitPage], Return; *Start and QNext notify here. Qx: T _ LdF[Stack,0,4], CallP[QNext], At[Qloc]; *BadWakeup on non-overlay page to remain intact after init ucode is *overwritten. Wakeup from a device that isn't reset properly comes here. BadWakeup: SetFault, GoTo[.]; OnPage[InitPage]; QNext: Stack _ (Stack) - (10000C), GoTo[QNotify,ALU#0]; *Now do notify for timer initialization. xBuf _ LoA[TimerInitLoc]; xBuf _ (xBuf) or (HiA[TimerInitLoc,TTask]), Call[XNotify]; *Return here in task 0 after timer task blocks. :IF[NoOverlays]; ******************************* *Test the map as a memory, then determine the amount of real storage and *set up the first N map entries to point to this storage (initialize *remaining map entries to VACANT), then clear storage. iMap: CompFlag _ (Zero) - 1; *CompFlag is originally -1, so iRWMap tests map entries with LogSE=WP=0, *Dirty=Ref=1, and complement of address; then CompFlag is 0 to test with *these bits complemented. imCompx: MapAddr _ T _ 140000C; imAloop: T _ (CompFlag) xor T; xBuf _ T, Call[iRWMap]; *T _ xBuf on Return from iRWMap *RealPage _ max real page + 1 for later; this second map write reads back *what was written with the first map write. RealPage _ 10000C, Call[iRWMap]; PageCount _ IP[FFault]C, Call[imCheckMap]; *Crash if data bad LU _ CompFlag, GoTo[imAloop,Carry']; T _ CompFlag _ Zero, GoTo[imCompx,ALU#0]; StkP _ PageCount, PageCount _ T, NoRegILockOK; MapAddr _ 140000C; *carries beyond max VM cause ALUCY *At this point the map has been tested somewhat with each bit correctly *assuming both its 1 and 0 states. Next, write each map entry with 0 flags *and the corresponding real page number, and fill first 5 quadwords of each *real page with their page numbers and complements and some constants *selected to make all the check bits 1 and 0. Go through storage backwards *so that hole in 96k modules will not screw up non-hole banks. imFloop: RealPage _ T _ (RealPage) - 1, Call[imFloop1]; Call[BlockSet]; *fills iniBf with T PStore4[ZWord,iniBf0,0]; *store page number T _ (Zero) xnor T, Call[BlockSet]; PStore4[ZWord,iniBf0,4], Call[ZBlockSet]; *Store page no. complement iniBf0 _ 100000C, Call[iniRET]; *Wait for ZWord write PStore4[ZWord,iniBf0,10], Call[ZBlockSet]; *Store 100000,0,0,0 iniBf1 _ 1C, Call[iniRET]; *Wait for ZWord1 write PStore4[ZWord,iniBf0,14], Call[ZBlockSet]; *Store 0,1,0,0 iniBf2 _ 40000C; T _ 20C; PStore4[ZWord,iniBf0], GoTo[imFloop]; *Store 0,0,40000,0 imFloop1: xBuf _ T, Skip[ALU>=0]; T _ RealPage _ 170000C, GoTo[imTloop]; *SUBROUTINE iRWMap writes the data in xBuf into map location MapAddr *and returns xBuf in T, map entry in xBuf1 to xBuf3. iRWMap: T _ (MapAddr) and (37400C); ZWordhi _ T; T _ LSh[MapAddr,10]; ZWord _ T; XMap[ZWord,xBuf,0]; xBuf _ T _ xBuf, Return; *interlock *Sweep upward through storage and map and use any real pages discovered. *Set up base register, set map entry, LogSE on (FFAULT[0] _ 1). This informs *the fault handler that the test program is willing to take the fault; the *fault handler RETURNs rather than sending control to Midas. imTloop: T _ (RealPage) and not (70000C); xBuf _ T, Call[iRWMap]; Stack _ (Stack) or (ReturnOnSE), Call[iChkPg]; *Return here on fault, or when iChkPage detects a problem. imPageBad: T _ RealPage _ (RealPage) + 1; Stack _ (Stack) and not (ReturnOnSE), GoTo[imTloop,Carry']; *Fall through here after handling the maximum amount of real storage Nop; *This loop marks that portion of the map with no corresponding storage vacant. imMarkVacant: xBuf _ 60000C; Call[iRWMap]; MapAddr _ (MapAddr) + 1; *Loop over all map entries T _ LHMask[PageCount], GoTo[imMarkVacant,Carry']; *Zap all storage by filling with zeroes; initialize ZWord/ZWordhi to point *one larger than the largest legal address. ZWordhi _ T; T _ LSh[PageCount,10]; ZWord _ T, Call[ZBlockSet]; *Loop zeroing all storage ZWord _ (ZWord) - (4C); GoTo[ZapS1,Carry]; ZWordhi _ (ZWordhi) - (400C); LU _ (PageCount) - (MinPageCount), Skip[ALU<0]; PStore4[ZWord,iniBf0,0], Return; T _ NotEnoughMemory, DblGoTo[InitFail,RegInit1,ALU<0]; ZapS1: PStore4[ZWord,iniBf0,0], Return; iChkPg: PFetch4[ZWord,iniBf0,0]; *Fetch will cause fault if page bad T _ LdF[RealPage,4,14]; *page address LU _ (iniBf0) xor T; PFetch4[ZWord,iniBf0,4], Skip[ALU=0]; LU _ iniBf0, Return; *page number didn't compare LU _ (iniBf0) xnor T; *check page complement *fetch from other 3 quadwords to provoke a fault PFetch4[ZWord,iniBf0,10], Skip[ALU=0]; LU _ iniBf0, Return; PFetch4[ZWord,iniBf0,14]; T _ 20C; PFetch4[ZWord,iniBf0]; LU _ iniBf0; *Page is good. ***Remove the xBuf _ to enable single-error logging*** xBuf _ (xBuf) and not (100000C), Call[iRWMap]; *turn off LogSE MapAddr _ (MapAddr) + 1; *go to the next map location PageCount _ (PageCount) + 1, GoTo[imPageBad]; *SUBROUTINE imCheckMap compares (MapAddr xor CompFlag) against xBuf imCheckMap: T _ LSh[xBuf3,10]; *flags, card, blk.0 bits T _ (RHMask[xBuf1]) or T; T _ (MapAddr) xor T; T _ (CompFlag) xnor T; *note, Map data is complemented, so we xnor UseCTask, Skip[ALU=0]; T _ BadMap, GoTo[InitFail]; *Some map entry was bad MapAddr _ T _ (MapAddr) + 1, Return; :ELSE; ***************************************** *Memory initialization was supposed to have been completed by Initial, but *zero 0-777b and 177000b-177777b here because of apparent Initial bug. ZWordhi _ 0C; ZWord _ 177000C, Call[ZBlockSet]; PStore4[ZWord,iniBf0,0]; ZWord _ (ZWord) + (4C); Skip[Carry]; Return; *Loop ZWord _ 1000C, Call[.+1]; ZWord _ (ZWord) - (4C); Skip[Carry']; PStore4[ZWord,iniBf0,0], Return; *Loop Nop; *Memory initialization was completed by Initial. *Wait for user to view MP left by Initial or previous boot that failed. *Outer loop repeats 2^14 times, so wait is 2^14 * 13.7 usec ~ 0.22 sec T _ xBuf _ 40000C, Call[MPWait]; xBuf _ (xBuf) + 1, GoTo[RegInit1,R<0]; *This subroutine accepts 0 in T and executes 135 cycles before returning MPWait: xBuf1 _ (Zero) + T; xBuf1 _ (xBuf1) + (2000C), GoTo[.,Carry']; *Execute 65 times Return; :ENDIF; **************************************** *Here after devices are quiescent, RM is zeroed, timer task initialized, and *(debugging system only) map and storage are initialized. Initialize RM *constants and start 256 us clock update. RegInit1: AllOnes _ (Zero) - 1; R400 _ 400C; MDShi _ T _ 0C; MDS _ T; *MDS = RMZero **High Base registers = MDShi and common to both Alto and Mesa emulators are **initialized here so that eventually a procedure which moves MDShi can be **written. *TimerBasehi must be initialized before making RTCLOW even. RTemp _ Sub[IP[TimerBasehi],1]C, Call[IniTS]; RTemp _ Add[LShift[eiTask,4],6]C, Call[IniTS]; *eMDS600hi RTemp _ Add[LShift[cdcTask,4],12]C, Call[IniTS]; *cdcMDS400hi RTemp _ Add[LShift[And[DpTask,14],4],76]C, Call[IniTS]; *vMDShi Stack&-2 _ T; *vMDS420hi Stack&-2 _ T; *vMDS177000hi Stack&-2 _ T; *rdcMDS520hi RTemp _ Add[LShift[rdcTask,4],16]C, Call[IniTS]; *rdcDCBhi *making RTCLOW even starts RTC updating, which is safe now since storage has *been initialized and the timer reference to VM 430 will not cause a fault. RTemp _ Sub[IP[RTCLOW],1]C, Call[IniTS]; *Copy the page count into RTCLOW+1 (RM 326) for the Lisp emulator. T _ PageCount, Call[IniSp1]; DeviceInit: T _ StartDeviceInit, CallP[iPNIP]; :UNLESS[NoOverlays]; *************************** *Wait for user to view StartDeviceInit, indicating that Initial is complete *and that this microcode has commenced. T _ xBuf _ 40000C, Call[MPWait]; *Wait for user to view MP xBuf _ (xBuf) + 1, Skip[R<0]; GoTo[MPWait]; :ENDIF; **************************************** %RM 40-57 are a "slot table" with one entry per potential io controller. First, the table is filled with dummy task numbers which are clocked out to the controllers. Then, each task is interrogated for it's Device ID, and these names are put in the table. Next, for each slot, the device ID is looked up in the DTab table (in IM) of potential devices, and if a match is found, the DTab entry is put into the slot table. When all slots have been looked up, the task numbers are clocked out to the controllers, and the associated initialization routines are called in turn. % xCNT _ 57C; xCNT _ T _ (StkP _ xCNT) + 1, Call[.+1]; *StkP = 57b, xCNT = T = 60b here; write 60-77 into RM 40-57 (StkP counts *mod 20b, so StkP+1 when StkP .eq. 57 is 40b). LU _ (xCNT) xor (77C); Stack&+1 _ T, Skip[ALU=0]; xCNT _ T _ (xCNT) + 1, Return; Assigned _ 0C; *Bit mask of asigned tasks *Send dummy controller addresses to devices; wind up with (n lsh 14b) + 3 in *RM (40b+n). xCNT _ 57C, Call[ClockOutPattern]; *StkP = 57b here; read controller ID's from register 0 of all devices xCNT _ T _ 177400C, Call[iniRET]; *allow xCNT & T to be written Input[Stack]; xCNT _ T _ (xCNT) + (20C), Skip[R>=0]; DMA _ 400C, Return; *Advance to next device; init DMA for later *StkP is now back at 40b since it wraps around the last time it was bumped. *Have 3000b, 3400b, 1055b, 1417b, etc. followed by 177777b for all undefined *slots. *Look up each slot table entry in the device table *Scan devices nearest the CPU first xCNT _ 17C; DI4x: DevIndex _ HiA[DTabBase]; *base of device table in IM DevIndex _ (DevIndex) or (LoA[DTabBase]); DI4y: T _ 0C, Call[GetCon]; *get device ID from table LU _ (LHMask[Stack]) xor T; *compare to high 8 bits of slot table entry LU _ T, GoTo[DevFound,ALU=0]; *check for end of table (zero entry) DevIndex _ (DevIndex) + 1, GoTo[DI4y,ALU#0]; DI4u: Stack _ 17C; *end of table reached without match - set slot's task to 17 (unused) DI4z: xCNT _ (xCNT) - 1; *check for all slots processed Stack&+1, DblGoTo[DI4x,DI5,ALU>=0]; *set to next slot DevFound: DMA _ (DMA) or (200C); T _ 1C, Call[GetCon]; Stack _ T; Stack _ LSh[Stack,4]; *10:13b _ task number about to be assigned CycleControl _ Stack, Stack _ T, NoRegILockOK; T _ WFA[AllOnes]; LU _ (Assigned) and T; *Replace slot table entry with device table entry if task available Assigned _ (Assigned) or T, GoTo[DI4z,ALU=0]; GoTo[DI4u]; *Keep looking if task already assigned *Have 6, 174427b, 174172b, 174070b, and 17b to end of table here DI5: xCNT _ 57C, Call[ClockOutPattern]; *Clock out new controller ID's %Here the table has task and uPC for existing controllers and 170000b for non-existent or undefined controllers. NOTE: StkP is 57b, so entries are handled in the order 57, 56, ..., 41. Since DisplayInit may jump to LoadRAM, **OLD LOADRAM** RTemp1 (53) must be even and xBuf-xBuf3 and RTemp (44-47 and 52) will be smashed, so the display controller must be in chasis slots 0 to 3 or LoadRAM will smash table entries not yet handled, and there must be fewer than 13b controllers mounted or RTemp1 might not be even. **NEW LOADRAM** RTemp1 (53) must be even and yBuf-yBuf2 (50-52) will be smashed, so the display controller must be in chasis slots 0 to 7, and there must be fewer than 13b controllers mounted or RTemp1 might not be even. % T _ 17C; *DpTask transfers to task 0 to roll in or pass over the CSL monitor overlay. *It continues initialization by transferring to DI6 with xCNT in T rather *than by simply returning as other device initialization routines do. DI6: xCNT _ T, Call[.+1]; *Setup TPC for loop below *Loop here to call all the init routines T _ xCNT _ (xCNT) - 1, Skip[R>=0]; ErrorCnt _ 10C, GoTo[BootEmulators]; *Set up retry count *Unless InitPC = 0 (no init required), call device init routine and loop LU _ LdF[(Stack),4,14]; APCTask&APC _ Stack&-1, Skip[ALU#0]; MNBR _ BootType; iniRET: Return; IniTS: StkP _ RTemp; IniSp1: Stack&+1 _ T, Return; ZBlockSet: iniBf0 _ T _ 0C, Skip; BlockSet: iniBf0 _ T; iniBf1 _ T; iniBf2 _ T; iniBf3 _ T, GoTo[iniRET]; iPNIP: LoadPage[PNIPPage]; GoToP[PNIP]; ClockOutPattern: *Call with 57C in xCNT StkP _ xCNT; xCNT _ 17C; *go through the slot table backwards COP1: DevIndex _ 3C; *DevIndex used for loop count COP2: T _ (Stack) xor (1C); *complement bit DevIndex _ (DevIndex) - 1, GenSRClock; *send bit Stack _ RCy[Stack,1], GoTo[COP2,ALU>=0]; *get next bit xCNT _ (xCNT) - 1; *all slot table entries done? Stack&-1, GoTo[COP1,ALU>=0]; *get next word DMAhi _ 0C, Return; *DMAhi _ 0 for EtherBoot and DiskBoot GetCon: APCTask&APC _ DevIndex; ReadCS; T _ CSData, Return, DispTable[1,1,0]; *Must be even placement BootEmulators: BootType, T _ StartEtherBoot, NoRegILockOK, GoTo[DiskBoot,R>=0]; *Setup here is VM 604 _ 400, VM 605 _ 1, VM 610 _ 377, VM 600 _ 0; *then start the Ethernet controller and wait for VM 600 # 0. *DMAhi,,DMA were setup as 0,,600 earlier for this code. EtherBoot: xBuf1 _ 1C, Call[iPNIP]; xBuf _ 400C; EtherBootx: PStore2[DMA,xBuf,4], Task; *VM 604 = eiCLoc _ 400, eiBLoc _ 1 xBuf2 _ 377C; *ESLOC _ 377 (serial no. for breath-of-life packets) PStore1[DMA,xBuf2,10], Call[iniRET]; PStore1[DMA,RMZero,0]; *ePLoc _ 0 (status word) RTemp _ LoA[eiStartLoc], Call[eStartRead]; *Here (in task 0) after Ether has started and tasked T _ (DMA) + (2C); PFetch1[DMA,AC1,0], Call[iniRET]; LU _ AC1; AC1 _ (AC1) xor (377C), GoTo[.-3,ALU=0]; *Wait for packet PFetch1[MDS,AC2,2]; AC2 _ (AC2) - T; *AC2 _ (AC2) - (Breath-of-life) AC0 _ cEtherBoot, GoTo[EtherBootx,ALU#0]; *got the breath of life!!!! start Alto emulator with PC=5 and complement *of KB1 word in AC0 (=10b for NetExec, =100b for MesaNetExec); PCB _ 5C; Booted: T _ PageCount, Call[iPNIP]; :IF[FinalOverlay]; ***************************** LoadPageExternal[LRJPage]; RTemp1 _ 0C, GoToExternal[LRJContinue]; :ELSE; ***************************************** LoadPage[neStartPage]; GoToP[StartNova]; :ENDIF; **************************************** EStartRead: RTemp _ (RTemp) or (HiA[eiStartLoc,eiTask]); LoadPage[eePage]; RTemp1 _ 300C, GoTo[eIOReset]; *Disable EtherNet input/output DiskBoot: T _ StartDiskBoot; DMA _ 1000C, Call[iPNIP]; *Read disk Sector 0 into page 0 (starting at location 1). DiskBootx: ErrorCountx _ 20C, Call[ZBlockSet]; *word 520 - not used by disk *word 521 - IOCB pointer *word 522 - disk status *word 523 = -1 to force a seek T _ (R400) or (120C); PStore4[MDS,iniBf0], Call[iniRET]; *520-523 _ 0,0,0,0 *Set up the IOCB at 1000b iniBf2 _ 44000C; *disk command goes at location 1002 (read, read, read) iniBf3 _ 2000C; *header goes at 2000 (unlike ALTO) PStore4[DMA,iniBf0,0], Call[iniRET]; *1000-1003 _ 0,0,44000,2000 iniBf2 _ 400C; iniBf2 _ (iniBf2) + (2C); *label goes at 402 iniBf3 _ 1C; *data goes at 1 PStore2[DMA,iniBf2,4], Call[iniRET]; *1004-1005 _ 402,1 *Since we will initialize the interrupt system later, we do not need to worry *about 1006 or 1007; 1008 is unused PStore1[DMA,iniBf3,11]; *iniBf1 = 1.. Disk address 0, with RESTORE bit at 1009 *Start the disk iniBf1 _ 1000C, Call[iniRET]; *word 521 - IOCB pointer iniBf2 _ 0C; T _ (R400) + (120C); PStore4[MDS,iniBf0], Call[iniRET]; *520-523 _ 0,1000,0,1 *Wait for the disk to store good status in the DCB, retry if status is bad DWSet: DevIndex _ 40000C; *loop count for status wait DiskWait: PFetch1[DMA,xCNT,1]; *fetch status word at 1001b T _ 17C, Call[iniRET]; LU _ (LdF[xCNT,4,4]) xor T; LU _ LdF[xCNT,10,10], GoTo[StatusStored,ALU=0]; DevIndex _ (DevIndex) - 1, GoTo[DiskWait,R>=0]; ErrorCountx _ (ErrorCountx) - 1, GoTo[DWSet,R>=0]; T _ NoDiskStatus, GoTo[InitFail]; *timed out waiting for disk to store status StatusStored: ErrorCnt _ (ErrorCnt) - 1, Skip[ALU#0]; PCB _ 1C, GoTo[Booted]; *Good status--send control to VM 1 T _ BadBoot, Skip[ALU<0]; GoTo[DiskBootx]; GoTo[InitFail]; %PNIP displays the number in T in the maintenance panel and returns, where T is meaningfully in the range 0 to 9999d (0 to 23417b). Does not task unless called from task 0. Its registers (RTemp and RTemp1) should not conflict with those for the Midas Kernel or with any used by tasks 14 to 17 because of calls from Fault.Mc, which might subsequently go to Midas; any io task that calls PNIP and expects to continue should be wary of the fact that PNIP's registers are defined for task 0 and might conflict. The loop below uses the top bits of RTemp to space successive IncMPanel's. **ClearMPanel and IncMPanel may be illegal in the same mi with branch burp. **For large numbers, map/storage refresh may fail when called by an io task. % OnPage[PNIPPage]; PNIP: UseCTask, RTemp _ T; T _ APCTask&APC, ClearMPanel, Call[.+1]; PNIPl: RTemp _ (RTemp) + (40000C), GoTo[.,R>=0]; RTemp _ (LdF[RTemp,2,16]) - 1; RTemp1 _ T, Skip[ALU>=0]; APCTask&APC _ RTemp1, GoTo[PFExit]; LU _ LdF[RTemp1,0,4]; Skip[ALU=0]; *Skip if emulator (tasking allowed) IncMPanel, GoTo[PNIPl]; *else non-skip IncMPanel, Return; %DoInt ORs bits from T into NWW and sets IntPending. Uses registers 0 and 1 in whatever task calls. DoIntR is the same, but with the bits from register 0 rather than T. % RV[IntTemp1,0]; RV[IntTemp2,1]; DoInt: IntTemp1 _ T, At[DoIntLoc]; *Abs placement for CSLKeyboard overlay DoIntR: IntTemp2 _ IP[NWW]C; T _ (SStkP&NStkP) xor (377C); StkP _ IntTemp2, IntTemp2 _ T, NoRegILockOK; T _ (IntTemp1) and not (100000C); Stack _ (Stack) or T, Skip[ALU#0]; *set bits in NWW StkP _ IntTemp2, Return; *Restore StkP and return IntTemp1 _ IP[RSImage]C; StkP _ IntTemp1; T _ Stack _ (Stack) or (IntPendingBit); *Set IntPending LU _ StkP _ IntTemp2, RS232 _ T, Return; :END[Initialize];e6(1795)\18351f1 3f0 4f1 13f0 752f1 14f0 5f1 4f0 33f1 38f0 4f1 43f0