*----------------------------------------------------------- Title[InitialMain.mc...June 27, 1982 11:26 AM...Taft]; *----------------------------------------------------------- % Initial is a microprogram that executes after the first stage of Dorado's bootstrap process is complete. During stage 1, the BaseBoard forced the Bootstrap program into IM, which in turn loaded the Initial microprogram from the BaseBoard. Stage two completes the machine initialization. Then it loads emulator microcode from disk or Ethernet into main memory, and loads and starts it by means of LoadRam. The particulars of communication between the Baseboard and the processor occur in the documentation for Bootstrap.mc Second Stage Initialization --------------------------- Second stage initialization performs the following activities: It reads one last word from the baseboard. Reading this word should cause the checksum computed by the bootstrap microcode to go to zero. It initializes ALUFM. It sets MCR to disallow hold and wakeup. It writes RM, STACK, T, and IFUM with valid data -- to prevent parity errors. It initializes the memory system enough to prevent unexpected errors and to permit using VM in a simpleminded way. It sets a bit in the Baseboard, using the manifold system, which notifies the baseboard that bootstrapping proceeded ok. It reads the keyboard to decide what emulator to load, and loads that emulator from disk or Ethernet into main memory. It then calls LoadRam to load that emulator into IM/IFUM and start it. % * Force Initial to be compacted into the high part of IM, and lock out * the page containing Bootstrap. IMReserve[0, 0, LShift[FirstInitialPage, 6]]; IMReserve[BootstrapPage, 0, 100]; TopLevel; Set[XTask, IP[EMU]]; *----------------------------------------------------------- * Start here to debug: *----------------------------------------------------------- InitialDebug: ChkSum_ T XOR T, TaskingOff, Branch[Initial1], At[InitialLoc, 3]; *----------------------------------------------------------- * Enter here from Bootstrap. Tasking is off. * Check that the checksum is correct by reading one last word from the * baseboard (that should force chkSum to zero -- ignoring tag bit). *----------------------------------------------------------- Initial: At[InitialLoc], CallExternal[ReadBBLoc]; * Read checksum word -- * that should make computed sum zero * Must do IFUReset before LoadMCR, because the IFU may have powered up in a state * such that it drives the MAR bus continuously. Initial1: T_ LSH[ChkSum, 1]; * Ignore tag bit PD_ T, IFUReset; T_ Add[mcr.noWake!, mcr.disHold!]C, Branch[.+2, ALU=0]; *----------------------------------------------------------- BootstrapChecksumError: * Error in microcode loaded from BaseBoard *----------------------------------------------------------- Branch[.], Breakpoint; *----------------------------------------------------------- * At this point, the only defined ALU functions are A XOR B, A+1, NOT A, and B. * Initialize all of ALUFM. We presume these correspondences: * "AFMi" where i IN [0..17B] are symbols whose value is the contents of ALUFM * for each i. *----------------------------------------------------------- RX1_ T XOR T, LoadMCR[T, T]; * RX1_ 0; disable faults and holds RX0_ AFM0; * Value for ALUFM[0] * RX1 = ALUFM address, RX0 = value to be stored there. WriteALUF: T_ DPF[RX1, 4, 11]; * Construct LH of instruction: T_ T XOR (104C), Call[.+2]; * RSTK=0, ALUF=[RX1], BSEL=1, LC=0, ASEL=4 ALUFMRW_ RX0, ALUF[0], Branch[WriteALUFTable]; * This instruction is modified IMLHR0'POK_ T; * Modify the LH of the instruction RX1_ (RX1)+1, BigBDispatch_ RX1, Branch[.-2]; * Execute inst and then dispatch WriteALUFTable: DispTable[20]; RX0_ AFM1, Branch[WriteALUF]; RX0_ AFM2, Branch[WriteALUF]; RX0_ AFM3, Branch[WriteALUF]; RX0_ AFM4, Branch[WriteALUF]; RX0_ AFM5, Branch[WriteALUF]; RX0_ AFM6, Branch[WriteALUF]; RX0_ AFM7, Branch[WriteALUF]; RX0_ AFM10, Branch[WriteALUF]; RX0_ AFM11, Branch[WriteALUF]; RX0_ AFM12, Branch[WriteALUF]; RX0_ AFM13, Branch[WriteALUF]; RX0_ AFM14, Branch[WriteALUF]; RX0_ AFM15, Branch[WriteALUF]; RX0_ AFM16, Branch[WriteALUF]; RX0_ AFM17, Branch[WriteALUF]; *----------------------------------------------------------- * Now we can use all the "default" ALUF functions. * Initialize RM. and all four stacks. * The Notify instructions are logically part of the task initialization code below; * it doesn't hurt to do them earlier or multiple times, and it saves microcode. *----------------------------------------------------------- * Write into all words of RM to set correct parity. T_ (RX1)-1; * T_ 17 -- last inst of the dispatch table RMInitL: RX17_ RBase_ T; RX0_ T, IFUReset; RX1_ T, Notify[1]; RX2_ T, Notify[2]; RX3_ T, Notify[3]; RX4_ T, Notify[4]; RX5_ T, Notify[5]; RX6_ T, Notify[6]; RX7_ T, Notify[7]; RX10_ T, Notify[10]; RX11_ T, Notify[11]; RX12_ T, Notify[12]; RX13_ T, Notify[13]; RX14_ T, Notify[14]; RX15_ T_ T-1, Notify[15]; RX16_ T, Branch[RMInitL, ALU>=0]; * Correct parity in all words of STK (but don't change the data, in case * STK holds a boot parameter). Leave StkP=0 (value assumed below). RX17_ T_ 377C; * Init StkP value STKInitL: T_ T-1, StkP_ T; StackNoUfl_ StackNoUfl, Branch[STKInitL, ALU>=0]; *----------------------------------------------------------- * Initialize all of IFUM with correct parity. * This is not strictly necessary, but it prevents Midas's PEScan operation * from turning up zillions of bogus errors if the emulator that gets loaded * doesn't provide data for all of IFUM (as none do). *----------------------------------------------------------- RScr_ 101777C; * Start with InsSet=3, BrkIns=377 IFUMInitL: InsSetOrEvent_ RScr; * B[0]=1 loads InsSet from B[6..7] T_ LSH[RScr, 10]; * BrkIns loads from B[0..7] RScr_ (RScr)-1, BrkIns_ T; RM0_ T_ A0; * 1-cycle delay required IFUMLH_ T; * Load both halves of IFUM with zero IFUMRH_ T; T_ A0, B_ T, RScr, Branch[IFUMInitL, R<0]; * Let it settle *----------------------------------------------------------- * Bootstrap the memory system: * Set ProcSRN to zero and reset the IFU. * Set CFlags to vacant (puts proper parity into A-mem, too). * Kick-start the automata * Initialize the map w/ identity (virtual page i = physical page i). * Set TSyn to perform error correction * The task initialization code below completes the memory system * initialization by placing proper parity in MD* and getting the tags * initialized. *----------------------------------------------------------- BootMem: ProcSRN_ T, StkP+3; * StkP_ 6 to protect boot parameter NoReschedule, StkP+3, Call[ClearCacheFlags]; Call[PresetMap]; Notify[16], Call[ClearCacheFlags]; RScr2_ 200C, Call[SetTestSyn]; Notify[17], Call[ClearCacheFlags]; Call[WaitForMapBuf]; RScr_ A0, Cnt_ 17S; * do numerous mem ops B_ FaultInfo'; * Reset error indications T_ 40C, Call[LongWait]; * wait for memory RScr_ (Store_ RScr)+1, DBuf_ RScr, Branch[.-2, Cnt#0&-1]; *----------------------------------------------------------- * For each task in [1..17] this code sets TPC to TaskInit and wakes up the task. *----------------------------------------------------------- * Make sure IOReset is on before enabling tasking. This is not necessary * during normal booting, but it makes debugging this code a lot easier. T_ 2000C; T_ T OR (251C), Call[WriteManifold]; T_ (RM0)+1; * Start with task 1 TaskInitLoop: RScr_ -17C, Call[GetTaskInitPC]; * Link_ TaskInit PD_ (RScr)+(LdTPC_ T); T_ T+1, Branch[TaskInitLoop, ALU<0]; * Now allow it all to happen. * Note that all of the "Notify"s have been executed already, so as soon as * tasking is turned on, all the tasks will wake up. TaskingOn, Branch[BlessBaseBoard]; *----------------------------------------------------------- * This code is executed by each task and initializes all task-specific * registers: T, RBase, MemBase, TIOA, MD. *----------------------------------------------------------- Subroutine; GetTaskInitPC: TIOA_ RM0, CoReturn; * Zero emulator's TIOA TopLevel; Set[XTask, 1]; TaskInit: T_ A0; Pointers_ T; * RBase and MemBase RScr_ BRHi_ T; BRLo_ T, Call[ResetTags]; * will fix MD parity, too. TIOA_ RScr, Block, Branch[.]; * TIOA_ 0 Set[XTask, 0]; *----------------------------------------------------------- * Tell the baseboard that we believe we've successfully initialized * everything. Do this by placing 2261 in the DMux address register and * performing UseDMD function. Then we must reinitialize the various errors * (Initial runs with errors like RM and STACK parity errors disabled). *----------------------------------------------------------- BlessBaseBoard: T_ mcr.noWake, Call[SetMCR]; * Now allow holds, etc., but * no fault task wakeups RScr_ T_ 2000C; T_ T OR (261C), Call[WriteManifold]; * manifold 2261 => boot ok T_ (RScr) OR (253C), Call[WriteManifold]; * 2253 => turn off IOReset. T_ 77C, Call[WriteManifold]; * 0077 => enable all errors Branch[BootEmulator]; * Now go find and boot an emulator *----------------------------------------------------------- WriteManifold: * Enter with T = address to strobe using UseDMD. * Uses Cnt, T. *----------------------------------------------------------- Subroutine; Cnt_ 13S; WriteManLp: PD_ A0, MidasStrobe_ T; PD_ T-T-1, Branch[., ALU=0]; * Delay 2 cycles T_ T LSH 1, Branch[WriteManLp, Cnt#0&-1]; UseDMD, Return; TopLevel; *----------------------------------------------------------- * Now time to find and bootstrap an emulator from disk or Ethernet. * First, initialize I/O tasks we will need, and do other emulator-related * initialization required to operate the I/O tasks. *----------------------------------------------------------- BootEmulator: RBase_ RBase[AEmRegs]; R400_ 400C; * Zero out first 64K, and use it for all memory accesses: T_ A0, MemBase_ IOBR; BRLo_ T; PD_ (BRHi_ T)+1; * ALU#0 T_ (Store_ T)+1, DBuf_ 0C, Branch[., ALU#0]; * Note: Ethernet tasks are initialized later if needed TaskingOff, Call[DisplayInitConfig]; * Figure out how terminal is hooked up Call[THTInitPC]; * Init DHT or AHT to read keyboard LdTPC_ T, RBase_ RBase[RTClock]; Call[DSKInitPC]; LdTPC_ T, Wakeup[DSK]; Wakeup[JNK], Call[JNKInitPC]; * Init Junk for RTC maintenance LdTPC_ T, TaskingOn; *----------------------------------------------------------- * Microcode booting conventions: * If a boot file parameter has been supplied (see below) then boot according to it. * If one of the microcode boot keys (see below) is pressed down, then * boot the selected microcode from the Ethernet (halt if fail). * If none of the keys is down, then attempt to boot microcode from the * Initial region of the disk; if that fails, boot Alto/Mesa microcode * from the Ethernet. *----------------------------------------------------------- * Wait at least 100 ms to allow terminal to update all keyboard words. * There are 5 of these, sent at 17 ms intervals. T_ (RTClock)+(6000C); * Now + 6000B 32-microsecond ticks PD_ T-T-1, Cnt_ 1S, StkP-3; * ALU<0, StkP_ 3 PD_ (RTClock)-T, Branch[., ALU<0]; * Check to see whether we have a valid boot parameter. * If STK[2] = BootParameterSeal and STK[1]+STK[2]+STK[3] = 0, then use STK[1] * as the microcode boot file number, and boot that file from the Ethernet. T_ Stack&-1, RBase_ RBase[AEmRegs]; * T_ STK[3] T_ (Stack&-1)+T, Branch[., Cnt#0&-1]; * STK[3]+STK[2]+STK[1] T_ HighByte[BootParameterSeal], StkP+2, Branch[ReadBootKeys, ALU#0]; T_ T OR (LowByte[BootParameterSeal]); * STK[2] = BootParameterSeal? PD_ (Stack&-1) XOR T, Stack&-1_ MD; * Smash the seal after checking T_ Stack, Branch[DoEtherMicrocodeBoot, ALU=0]; Nop; ReadBootKeys: T_ (R400) XOR (177434C); * VM 177034 = first keyboard word T_ (Fetch_ T)+1; T_ (Fetch_ T)+1, ETemp0_ MD; * Remember the keys are complemented T_ (Fetch_ T)+1, ETemp1_ MD; T_ (Fetch_ T)+1, ETemp2_ MD; T_ A0, ETemp3_ MD, ETemp0, Branch[EtherBooting, R even]; * BS down? * Look at these keys only if BS is NOT down, since some of them conflict * with the boot file number for booting Alto programs from the Ethernet. PD_ LSH[ETemp3, 7], Call[CheckKey]; * [0] M Alto/Mesa PD_ LSH[ETemp1, 4], Call[CheckKey]; * [1] S Smalltalk PD_ LSH[ETemp1, 12], Call[CheckKey]; * [2] L Lisp PD_ LSH[ETemp2, 5], Call[CheckKey]; * [3] C Cedar T_ A0; * Look at alternate keys, regardless of whether or not BS is down. EtherBooting: BootDataPtr_ 1000C; * Here for placement PD_ LSH[ETemp2, 14], Call[CheckKey]; * [0] RETURN Alto/Mesa PD_ LSH[ETemp3, 14], Call[CheckKey]; * [1] right-SHIFT Smalltalk PD_ LSH[ETemp3, 12], Call[CheckKey]; * [2] [ Lisp PD_ LSH[ETemp3, 13], Call[CheckKey]; * [3] = Cedar PD_ LSH[ETemp3, 1], Call[CheckKey]; * [4] T Test * BootEmulator (cont'd) * No key down. First attempt disk microcode boot. SCall[DiskHardMicrocodeBoot]; T_ A0, Branch[.+2]; * Failed, give up on the disk ETemp0_ A0, Call[CheckChecksumAndLoad]; * Load if checksum is OK (returns T=0) * Boot microcode from the Ethernet. Desired boot file number is T+110B. GotBootKey: Stack_ T_ T+(110C); * The desired boot file number DoEtherMicrocodeBoot: BootDataPtr_ 1000C, SCall[EtherMicrocodeBoot]; * Boot microcode from Ethernet Branch[MicrocodeBootFailed]; * Failed, give up ETemp0_ A0, Call[CheckChecksumAndLoad]; * Load if checksum is OK T_ Stack; * Bad checksum; try loading it once more BootDataPtr_ 1000C, SCall[EtherMicrocodeBoot]; Branch[MicrocodeBootFailed]; * Failed, give up ETemp0_ A0, Call[CheckChecksumAndLoad]; * Load if checksum is OK MicrocodeBootFailed: Breakpoint, Branch[BootEmulator]; *----------------------------------------------------------- CheckKey: * Subroutine to assist in boot key detection. * Increments T and returns if ALU<0 (selected key is up). * Uses T+110 as the boot file number if ALU>=0 (selected key is down). *----------------------------------------------------------- Subroutine; Branch[GotBootKey, ALU>=0]; T_ T+1, Return; *----------------------------------------------------------- CheckChecksumAndLoad: * Checks the checksum of a loaded microcode image, and if it is OK then * call LoadRam on it, never to return. Returns only if the checksum is not OK. * Enter: BootDataPtr = address of last word loaded +1 * ETemp0 = 0 * Returns with T=0, if it returns at all. * Clobbers T, BootDataPtr, ETemp0 *----------------------------------------------------------- Subroutine; T_ (BootDataPtr)-(1000C)-1; * T_ (# words loaded)-1 BootDataPtr_ (BootDataPtr)-(Cnt_ T)-1; * BootDataPtr_ 1000, Cnt_ (# words loaded)-1 * Not the world's fastest checksum loop, but who cares? BootDataPtr_ (Fetch_ BootDataPtr)+1; ETemp0_ (ETemp0)+MD, Branch[.-1, Cnt#0&-1]; T_ 1000C, Branch[.+2, ALU=0]; * Done checksumming; OK? T_ A0, Return; * No TopLevel; LRFlag_ A0, BRLo_ T, Branch[LoadRam]; * Yes, dive into it!