:TITLE[Initialize]; *Ed Fiala 10 September 1982 %RM assignments are subject to a number of constraints: 1) Must not smash the registers needed to continue LoadRAM; these are LP, LPhi, and xfTemp (RM 66, 67, 72); RTemp1 must be set even (to believe starting address) and xfTemp1 must be set odd (for normal tasking) before continuing LoadRAM. 2) Registers needed valid after DeviceInit or used during DeviceInit must not be in the range 40-57, which is used as a buffer during DeviceInit. Registers constrained by this are AllOnes, R400, MDS, MDShi, PCB, BootType, PageCount, xCNT, ? 3) BootType may not be in the range 0-17 because it is referenced by BootTask (task 1, 2, or 3). 4) PCB (RM 30) must not be smashed on soft boot. 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. RV[BootType,36]; *even => hard boot, odd => soft boot, where *soft boot = hard boot except preserve disk *partition and PCB for start; *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. RV[RBuf1,34]; *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]; **12400 for 10 mb Ethernet. 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,rdcInitLoc,rdcTask]; *Disk (Alto RDC) = 1400b DTab[2400,rdcInitLoc,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 BootTask's T register (because T registers of unused tasks safely hold data across a boot). 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. Soft booting transfers control between variant microcode systems (e.g., Lisp, Smalltalk, or Mesa each with an Alto emulator) without smashing storage; the disk partition and PCB are also preserved. The program initiating a soft boot first cleans up the Map (if necessary), places the microcode image and its overlays into storage, and calls xoLRJ. LoadRAM then transfers control to SoftGO (7202), the starting address; control eventually resumes at PCB+1 in the (new) Alto emulator. SoftGO is available only when NoOverlays is false (I.e., it is available in release systems but not in debugging systems--in debugging systems, storage is reinitialized here, so it doesn't make sense to return to the program.). When NoOverlays is false, all entries here assume that the good page count is in xPageCount (from Initial) and the map is set up correspondingly. The code here copies xPageCount into both StoragePages (for compatibility with old Lisp systems which look there for the count) and into PageCount for use during initialization here. When NoOverlays is true, PageCount is computed by the mini-Initial code here but xPageCount and StoragePages are not computed. **The Alto MemCfg opcode won't work. % 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 :UNLESS[NoOverlays]; *************************** SoftGO: BootType _ 1C, GoTo[Start], At[InitBase,2]; :ENDIF; **************************************** *Boot failures halt and wait for reboot. InitFail: Call[iPNIP]; GoTo[.]; 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]; ***Patch this mi and one indicated below to allow imperfect storage. 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, LoadPage[17]; T _ LSh[MapAddr,10], GoToP[.+1]; OnPage[17]; ZWord _ T; XMap[ZWord,xBuf,0]; xBuf _ T _ xBuf, Return; *interlock OnPage[InitPage]; *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; ***Patch this mi and one indicated above to allow imperfect storage. 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); T _ NotEnoughMemory, Skip[Carry']; PStore4[ZWord,iniBf0,0], Return; ZWordhi _ (ZWordhi) - (400C); LU _ (PageCount) - (MinPageCount), Skip[ALU<0]; PStore4[ZWord,iniBf0,0], Return; *Must copy PageCount into xPageCount for normal use and into StoragePages for *backward compatibility. RTemp _ Sub[IP[StoragePages],1]C, GoTo[InitFail,ALU<0]; T _ PageCount, GoTo[RegInit0]; 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; RegInit0: StkP _ RTemp, Call[IniSp1]; RTemp _ Sub[IP[xPageCount],1]C, Call[IniTS]; :ELSE; ***************************************** *Copy xPageCount (setup by Initial) into PageCount for use here and into *StoragePages for backward compatibility with Lisp and Smalltalk. PageCount _ IP[xPageCount]C; StkP _ PageCount; T _ Stack; PageCount _ IP[StoragePages]C; StkP _ PageCount, PageCount _ T, NoRegILockOK; Stack _ T; BootType, GoTo[HardContinueInit,R Even]; *Prepare to preserve the disk partition when disk initialization is called. LoadPage[XMiscPage]; RTemp _ 0C, Call[MXPar]; *Return default partition (1 or 2) BootType _ T; *Set bit 8 if partition 2; bit 15 indicates soft boot (garbage in bit 9 if *partition 1 is don't care). BootType _ (LSh[BootType,6]) + 1; *Continue refresh from its state at the end of LoadRAM. HardContinueInit: T _ (xfTemp1) and not (17C); xfTemp1 _ IP[Refr]C; StkP _ xfTemp1; Stack _ T; xfTemp1 _ 1C; *Setup LoadRAM arg for normal tasking. *Memory initialization was completed by Initial. *Wait for user to view MP left by Initial. *Outer loop repeats 24k times, so wait is 24k * 123 cycles ~ 0.302 sec xBuf _ 20000C, Call[MPWait]; xBuf _ (xBuf) + 1, GoTo[MPWait,R>=0]; LU _ (PageCount) - (MinPageCount); GoTo[RegInit1,ALU>=0]; T _ NotEnoughMemory, GoTo[InitFail]; :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 = RZero **High Base registers = MDShi and common to both Alto and Mesa emulators are **initialized here. *TimerBasehi must be initialized before initializing RConstantHi/Lo. 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 RTemp _ Add[LShift[rdcTask,4],16]C, Call[IniTS]; *rdcDCBhi Stack&-2 _ T; *rdcMDS520hi %Timer.Mc zeroed RConstantHi/Lo earlier, so RTCLow wouldn't overflow and cause a memory reference of VM 430 during storage init. Now initialize to values correct for a 40 mhz processor clock. RConstantLo, RConstantHi, and StoragePages are known to be in consecutive RM locations. Processor clock values for 2560 cycles timer: 40 mhz 656,,012172b 44.5 mhz 602,,113274b 50 mhz 530,,005330b DisplayInit will change the 40 mhz value if the processor clock is 44.5 or 50 mhz, but we initialize here in case there is no attached display. % RTemp _ Sub[IP[RConstantLo],1]C, Call[IniTS]; Stack _ LoA[012172]; Stack _ (Stack) or (HiA[012172]); T _ (R400) + (LoA[656]), Call[IniSp1]; *StoragePages (RM 326) for the Lisp emulator and Alto MEMCFG opcode. T _ PageCount, Call[IniSp1]; DeviceInit: T _ StartDeviceInit, CallP[iPNIP]; *MP code = 104d :UNLESS[NoOverlays]; *************************** *Wait ~.31 sec for user to view StartDeviceInit, indicating that Initial is *complete and that this microcode has commenced. xBuf _ 20000C, Call[MPWait]; 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 assigned 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. RM 40b represents nearest processor, 57b furthest away. *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]; 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]; RBuf1 _ T; RBuf1 _ LSh[RBuf1,4]; *10:13b _ task number about to be assigned CycleControl _ RBuf1; T _ WFA[AllOnes]; LU _ (Assigned) and T; *Replace slot table entry with device table entry if task available, else *keep looking if task already assigned. Assigned _ (Assigned) or T, Skip[ALU=0]; DevIndex _ (DevIndex) + 1, GoTo[DI4y]; T _ CSData; Stack _ T, GoTo[DI4z]; *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]; *Delay subroutine executes 121d (= 7+2*(56+1)) cycles before returning. MPWait: xBuf1 _ 70C; xBuf1 _ (xBuf1) - 1, GoTo[.,R>=0]; *Execute this mi 70b+2 times Return; 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 :IF[NoOverlays]; ******************************* BootEmulators: BootType, T _ StartEtherBoot, NoRegILockOK, GoTo[DiskBoot,R>=0]; :ELSE; ***************************************** BootEmulators: BootType, GoTo[Booted,R Odd]; BootType, T _ StartEtherBoot, NoRegILockOK, GoTo[DiskBoot,R>=0]; :ENDIF; **************************************** *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]; *114d MP code 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,RZero,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; :IF[NoOverlays]; ******************************* Booted: T _ PageCount, Call[iPNIP]; :ELSE; ***************************************** Booted: T _ GotBreathOfLife, Call[iPNIP]; *118d MP code xBuf _ 20000C, Call[MPWait]; *Delay .31 sec xBuf _ (xBuf) + 1, Skip[R<0]; GoTo[MPWait]; T _ PageCount, Call[iPNIP]; *No. of good pages in MP :ENDIF; **************************************** :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. Timing: 16*T + 20 cycles. % 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 (no tasking) 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)\21437f1 3f0 4f1 13f0 1104f1 14f0 5f1 4f0 33f1 38f0 4f1 43f0