:TITLE[Initialize]; % Edit by Ed Fiala 12 March 1982: add display of no. 'good' pages from Initial, new 10 mb Ethernet DTab entries; delete old 10 mb Ethernet DTab entries; increase viewing delay; default init for vCrystal; conditionals on DTab entries; device init changes from AMesa system; preserve refresh sequence from Initial and use normal refresh during LoadRAM calls; eliminate InitPage2, initpc, contemp, rlink0; speed up PNIP. Edit by Ed Fiala 19 February 1982: delete unused MP code defs, removed ErrorCnt, ErrorCountx, initr0-3; changed StartDeviceInit and NPages MP codes with delay so they can be seen. % RV[xCNT,20]; *Used everywhere RV[DevIndex,21]; *Used in DeviceInit RV[Assigned,23]; *Used in DeviceInit RV[rbuf0,24]; *Used in DeviceInit RV[rbuf1,25]; *Used in DeviceInit MC[NextDiskAddr,237]; RV[BootDiskAddr,37]; *Machine initialization begins here; start here from any task. SoftStart: xCNT _ HiA[Task0StartLoc], At[SoftStartLoc]; OnPage[InitPage]; xCNT _ (xCNT) or (LoA[Task0StartLoc]), GoTo[InitNotify]; Qtask: xCNT _ LoA[Qloc], At[Task0StartLoc]; *Quiesce tasks 15b to 1 xCNT _ (xCNT) or (HiA[Qloc,15]); DevIndex _ IP[DevIndex]C; StkP _ DevIndex; DevIndex _ LoA[QretLoc]; DevIndex _ (DevIndex) or (HiA[QretLoc]); InitNotify: Qloop: APCTask&APC _ xCNT; initRET: Return; *goes to Qx *Notify comes here. Leave task's TPC pointing at Qxy. Qx: APCTask&APC _ Stack, Call[PFExit], At[Qloc]; *BadWakeup is on a non-overlaid page so that it will remain intact after *initialization has completed. Wakeup from a device that isn't reset *properly comes here. BadWakeup: SetFault, GoTo[.]; Qret: LU _ LdF[xCNT,0,3], At[QretLoc]; *xCNT points to this location xCNT _ (xCNT) - (10000C), GoTo[Qloop,ALU#0]; *Zap devices. T _ RTemp1 _ 177400C; RTemp _ 300C; ZapDloop1: Output[RTemp]; *send 300 to register 0 of all devices T _ RTemp1 _ (RTemp1) + (20C); GoTo[ZapDloop1,ALU<0]; T _ RTemp1 _ 177400C; RTemp _ 0C; ZapDloop2: Output[RTemp]; *send 0 to register 0 of all devices T _ RTemp1 _ (RTemp1) + (20C); GoTo[ZapDloop2,ALU<0]; *During the Pilot1 LoadRAM, xfTemp1 was a state variable for inline refresh. *Put xfTemp1 back into Refr for regular refresh using a 2560 cycle timer. *This avoids having some RAMs go unrefreshed for a longer than normal period. T _ (xfTemp1) and not (17C); xfTemp1 _ IP[Refr]C; StkP _ xfTemp1; Stack _ T; *xfTemp1 odd for normal refresh on the LoadRAM calls during device init. *Also need RTemp1 even (to believe starting address) and ZapDloop2 above *leaves it even. xfTemp1 _ 1C; xCNT _ HiA[TimerInitLoc,16]; xCNT _ (xCNT) or (LoA[TimerInitLoc]), Call[InitNotify]; *Before initializing and starting devices, set up the RM locations that *must be valid. RegInit1: R400 _ 400C; AllOnes _ (Zero) - 1; RZero _ Zero; LoadPage[PNIPPage]; T _ StartDeviceInit, CallP[PNIP]; *Wait ~0.4 seconds for user to view StartDeviceInit 0104. Outer loop *repeats 32k times, so wait ~ 32k*123 cycles. xBuf _ 0C, Call[MPWait]; xBuf _ (xBuf) + 1, GoTo[MPWait,R>=0]; *Default vCrystal to 240b (.eq. 320d/2), appropriate with a 40 mHz processor *crystal. If the Dolphin has a UTVFC, then DisplayInit.Mc will correct the *value in vCrystal for 44.5 mHz or 50 mHz crystals. xBuf _ IP[vCrystal]C; StkP _ xBuf; Stack _ 240C; *Get next disk address from reg 237 and save in reg 37. xCNT _ NextDiskAddr; StkP _ xCNT; T _ Stack; BootDiskAddr _ T, GoTo[DeviceInit]; *Delay subroutine executes 121d (=7+2*(56+1)) cycles before returning. MPWaita: xBuf1 _ 70C, Skip; MPWait: xBuf1 _ 70C; xBuf1 _ (xBuf1) - 1, GoTo[.,R>=0]; Return; %Find and initialize all I/O devices: The idea is to use RM 40-57 as a "slot table" with one entry per potential I/O controller. First the table is filled with dummy controller addresses, and these are clocked out to the controllers. Then, each controller is interrogated for it's Device ID, and these names are put in the table. Then, for each slot, the device ID is looked up in a table (in IMX) of potential devices, and if a match is found, the entry from the device table is put into the slot table. A device table entry consists of the uPC value of the device's initialization routine (12 bits), and the task number for the controller. 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. To add a new controller to the system, simply add both a device table entry here and its driver microcode. Note that each entry should be CONDITIONAL upon having suitable microcode at the device's starting address to avoid a wild branch. A system with a DTAB entry but no driver microcode won't run on a Dolphin which has the device. NOTE: ORDERING IS IMPORTANT HERE; CURRENT ORDER IS NOT DEBUGGED VERY WELL. There are some problems: 1) The table is overlying RM 40-57 and DisplayInit.Mc may call LoadRAM. When the old LoadRAM is called, xBuf-xBuf3 (RM 44-47) and RTemp (RM 52) will be smashed and RTemp1 (RM 53) must be even. This means that the UTVFC must be in chasis slots 0 to 3 or table entries not yet handled will be smashed. For the new LoadRAM, yBuf-yBuf2 (50-52) will be smashed, so the UTVFC must be in chasis slots 0 to 7. For both old and new LoadRAM, there must be fewer than 13b controller mounted or RTemp1 might not be even (this could be fixed easily). 2) ?The order in which tasks are used up is important when allowing a device such as the CDC to coexist with the ethernet controllers. Here it is (?) necessary for the CDC DTab entry to appear before the Ethernet controller entries (or is it necessary for its board to be above?) so that its task won't be used up when it is initialized. Maybe there should be several cdcTasks to allow more flexibility? This needs some thought. % *First, a macro to allow nice formatting of the device table entries... Macro[DTab,IFE[#4,0,,IMData[LH[#1] RH[LShift[#2,4],#3] At[DTabLoc]] Set[DTabLoc,Add[DTabLoc,1]]]]; Set[DTabBase,Add[InitBase,100]]; Set[DTabLoc,DTabBase]; *DTab[5400,FDinit,FDtask,1]; *IFDC (floppy disk--not supported) *Since DES and FP boards have no init microcode, assemble unconditionally. DTab[12000,0,0,1]; *DES board DTab[127000,0,0,1]; *FP board DTab[127400,cdcInitLoc,cdcTask,WithCDC]; *Color display DTab[5000,uibInitLoc,uibTask,WithTOR]; DTab[7000,eomHiTaskInitLoc,eomHiTask,WithTOR]; DTab[7400,eomLoTaskInitLoc,eomLoTask,WithTOR]; DTab[10000,ioInitLoc,ioTask1,WithMIOC]; *1st MIOC DTab[10000,ioInitLoc,ioTask2,WithMIOC]; *2nd MIOC DTab[3400,xwInInitLoc,xiTask,With3MB]; *1st 3mb Ethernet input DTab[3000,xwOutInitLoc,xoTask,With3MB]; *1st 3mb Ethernet output DTab[3400,xwInInitLoc,xiTask2,With3MB]; *2nd 3mb Ethernet input DTab[3000,xwOutInitLoc2,xoTask2,With3MB]; *2nd 3mb Ethernet output DTab[12400,enxInitLoc,enxTask,With10MB]; *1st 10mb Ethernet DTab[12400,enxInitLoc2,enxTask2,With10MB]; *2nd 10mb Ethernet DTab[12400,enxInitLoc3,enxTask3,With10MB]; *3rd 10mb Ethernet DTab[1400,rdcInitLoc,rdcTask,1]; *SA4000 DTab[2400,rdcInitLoc,rdcTask,1]; *SA4000 kludge DTab[1000,DisplayInitLoc,DisplayTask,1]; *UTVFC ID = 1000b DTab[0,0,0,1]; *Final DTab entry must be Zero OnPage[InitPage]; DeviceInit: 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. 57b is 40b). LU _ (xCNT) xor (77C); Stack&+1 _ T, Skip[ALU=0]; xCNT _ T _ (xCNT) + 1, Return; *Send dummy controller addresses to devices; wind up with (n lsh 14b) + 3 in *RM (40b+n). Assigned _ 0C; *Bit mask of assigned tasks xCNT _ 57C, Call[ClockOutPattern]; *StkP = 57b here; read controller ID's from register 0 of all devices. xCNT _ T _ 177400C, Call[devRET]; *Allow xCNT & T to be written Input[stack]; xCNT _ T _ (xCNT) + (20C), Skip[R>=0]; *Advance to next device devRET: Return; *Loop *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 control store DevIndex _ (DevIndex) or (LoA[DTabBase]); DI4y: T _ 0C, Call[GetCon]; *Get a device ID from the device table *Compare with the slot table entry (high byte) LU _ (LHMask[Stack]) xor T; *Check for end of table (Zero entry) LU _ T, GoTo[DevFound,ALU=0]; DI4u: DevIndex _ (DevIndex) + 1, GoTo[DI4y,ALU#0]; *End of table reached without match--set slot's task to 17 (unused) Stack _ 17C; DI4z: xCNT _ (xCNT) - 1; *check for all slots processed Stack&+1, DblGoTo[DI4x,DI5,ALU>=0]; *set to next slot DevFound: T _ (SStkP&NStkP) xor (377C); rbuf0 _ T; T _ 1C, Call[GetCon]; Stack _ T; *replace slot table entry with device table entry rbuf1 _ T; *device table entry contains task assignment rbuf1 _ LSh[rbuf1,4]; *10:13b _ task number about to be assigned CycleControl _ rbuf1; T _ WFA[AllOnes]; LU _ (Assigned) and T; Assigned _ (Assigned) or T, Skip[ALU=0]; *Keep looking, task already assigned DevIndex _ (DevIndex) + 1, GoTo[DI4y]; *Write 177400 + 20b*task into RM 20b*task; this addresses the CSB for the *device automatically. StkP _ rbuf1; T _ (rbuf1) or (177400C); Stack _ T; StkP _ rbuf0, GoTo[DI4z]; *Clock out new controller ID's DI5: xCNT _ 57C, Call[ClockOutPattern]; %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. % *Call all the Init routines xCNT _ 17C; *Come here from DisplayInit DI5a: Call[devRET]; *do Call to set up TPC for loop below DI6: xCNT _ (xCNT) - 1, GoTo[BootEmulators,R<0]; LU _ LdF[Stack,4,14]; *check for Init PC = 0 (no initialization required) *Skip to call init routine for controller. APCTask&APC _ Stack&-1, Skip[ALU#0]; Nop; Return; ClockOutPattern: 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 Return; GetCon: APCTask&APC _ DevIndex; ReadCS; T _ CSData, Return, DispTable[1,1,0]; *Force even placement *Initialize Mesa registers except StkP and FFault; LoadRAM will jump to *InitEndLoc (in MesaX.Mc) which will setup these two registers and jump to *Xfer which sets up CODE, GLOBAL, etc. MC[PilotMDS,76]; BootEmulators: PrPsbIndexMask _ HiA[7774]; PrPsbIndexMask _ (PrPsbIndexMask) or (LoA[7774]), Task; prCurrentPsb _ 0C; MemStat _ Normal, Task; xfMX _ 1000C; xfMX _ (xfMX) or (376C), Task; xfWDC _ 1C; MDS _ 0C, Task; xfGFIWord _ 0C; xfXTSReg _ 0C; xfBrkByte _ 40400C; *2001b rcy 2 *NWW, RSImage, and RS232 were zeroed by Timer.Mc initialization. *Show count of 'good' pages from Initial. xBuf _ IP[xPageCount]C; StkP _ xBuf; LoadPage[PNIPPage]; T _ Stack, CallP[PNIP]; *On soft boot delay before overlaying control store because io microcode *may not be finished initializing yet and will be overwritten. xBuf _ 0C, Call[MPWaita]; xBuf _ (xBuf) + 1, GoTo[MPWaita,R>=0]; RTemp _ IP[FFault]C; StkP _ RTemp; T _ GLOBALhi _ PilotMDS; T _ GLOBALhi _ (LSh[GLOBALhi,10]) or T; LOCALhi _ T; xfTemp1 _ 1C; *Odd (normal tasking) RTemp1 _ 0C; *Even (believe starting address), .ge. 0 (resume Mesa) MDShi _ T, LoadPageExternal[LRJPage]; LOCAL _ 0C, GoToExternal[LRJContinue]; %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 must allow 800 ns after ClearMPanel and 400 ns after IncMPanel. If necessary the high two bits of RTemp can be used to increase loop time. ClearMPanel and IncMPanel may be illegal in the same mi with a true branch condition. For large numbers, map/storage refresh may fail when Called by an io task. % PNIP: RTemp _ T, ClearMPanel, At[PNIPStart]; UseCTask; T _ APCTask&APC, UseCTask, Call[PFExit]; *14 cycles after ClearMPanel and 8 cycles after IncMPanel should be safe *on the fastest machines. PNIPl: RTemp _ (LdF[RTemp,2,16]) - 1; RTemp1 _ T, Skip[ALU>=0]; APCTask&APC _ RTemp1, GoTo[PFExit]; LU _ LdF[RTemp1,0,4]; Skip[ALU=0]; IncMPanel, GoTo[PNIPl]; IncMPanel, Return; *NotifyInterrupt ORs T into NWW and sets IntPending. Uses registers *0 and 1 in whatever task Calls. RV[IntTemp1,0]; RV[IntTemp2,1]; NotifyInterrupt: IntTemp1 _ T, At[NotifyInterruptLoc]; *Save interupt mask IntTemp2 _ IP[NWW]C, Skip[ALU#0]; *Point to NWW register Return; *No change T _ (SStkP&NStkP) xor (377C); *T _ StkP StkP _ IntTemp2, IntTemp2 _ T, NoRegILockOK; T _ IntTemp1; *T _ interrupt mask Stack _ (Stack) or T; *set bits in NWW Stack&-1; *Point StkP at RSImage T _ Stack _ (Stack) or (IntPendingBit); LU _ StkP _ IntTemp2, RS232 _ T, Return; :END[Initialize];(1795)\f5