*----------------------------------------------------------- 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!