*----------------------------------------------------------- Title[DisplayAux.mc.....September 11, 1982 1:09 PM...Taft]; * Auxiliary Dorado display microcode -- required both by emulators and * by Bootstrap/Initial microcode. *----------------------------------------------------------- *----------------------------------------------------------- DisplayInitConfig: * Terminal configuration initialization, called from emulator task. * Sets DisplayConfig as follows: * Bit 0 0 = DispY controls terminal, 1 = DispM controls terminal * Bits 14:15 0 = Alto monitor * 1 = LF monitor emulating Alto monitor * 3 = LF monitor using entire screen * (This procedure returns values 0 and 1 only; but caller * is permitted to switch between 1 and 3. In PrincOps mode, * 1 and 3 are equivalent and use the entire screen.) * Returns RBase[THTRegion]; * Clobbers T *----------------------------------------------------------- Subroutine; Set[XTask, IP[EMU]]; RBase← RBase[THTRegion]; T← TStatus; * Select Status register on DispM TIOA← T; DisplayConfig← InputNoPE; * Nonzero => DispM board installed T← Statics; * Select Statics registry on DispY TIOA← T; T← LShift[106, 10]C; * Select muffler 106 Output← T; PD← DisplayConfig, TIOA[DDCStatus]; * Select Status registry on DispY * Input from Status register returns: * Bit 0 = keyboard data bit * Bits 1:14 = 0 * Bit 15 = muffler data bit = 1 iff an LF monitor is connected T← Input, Branch[.+2, ALU#0]; DisplayConfig← T AND (1C), Return; * DispY controls terminal DisplayConfig← T OR (100000C), Return; * DispM controls terminal *----------------------------------------------------------- InitHRam: * Initialize the HRam with standard waveforms for Alto or LF monitor. * Entry: RBase = THTRegion or DHTRegion * TIOA selects some DispY register * DisplayConfig[14:15] selects monitor type (see DisplayInitConfig) * Exit: TIOA[HRam] * clobbers T, xTemp0, xTemp1, xTemp2 (x = T or H) *----------------------------------------------------------- Subroutine; Set[XTask, IP[DHT]]; KnowRBase[THTRegion]; * or DHTRegion * Local register usage: * TTemp0 = HRam count * TTemp1 = address of current HRamTable entry in IM * TTemp2 = return link TTemp2← Link; TopLevel; TIOA[HRam], Call[AfterHRamTable]; * Link← HRamTable * Check consistency of horizontal waveforms defined in DisplayDefs.mc M[WFCheck, Set[T1, #1] Set[T2, #2] Set[T3, #3] Set[T4, #4] IfE[And[T1, 3], 0, , WFEr1[#5]] IfE[And[T2, 3], 0, , WFEr2[#5]] IfE[And[T3, 1], 0, , WFEr3[#5]] IfE[And[T4, 1], 0, , WFEr4[#5]] IfE[And[Sub[T1, T2, T3], 3], 2, , WFEr5[#5]] ]; M[WFEr1, ER[#1.pixels/scanline.not.multiple.of.4, 2]]; M[WFEr2, ER[#1.visible.pixels.not.multiple.of.4, 2]]; M[WFEr3, ER[#1.visible.to.sync.distance.not.even, 2]]; M[WFEr4, ER[#1.sync.width.not.even, 2]]; M[WFEr5, ER[#1.horizontal.blanking.on.odd.clock, 2]]; HorizontalWaveforms[WFCheck]; * Each entry in this table describes a group of consecutive HRam locations: * Byt0 = number of locations for Alto monitor. * Byt1 = number of locations for LF monitor emulating Alto monitor. * Byt2 = number of locations for LF monitor using entire screen. * Byt3 = HRam data value for those locations. * The last entry must be located at 0 mod 10. M[ApplyToWF, HorizontalWaveforms[#1] Data[(Byt0[RShift[WFAlto, 1]] Byt1[RShift[WFLFAlto, 1]] Byt2[RShift[WFLFFull, 1]] Byt3[#2])] ]; HRamTable: DispTable[7, 7, 2]; M[WF1, Set[WF#5, Sub[#4, 2]]]; ApplyToWF[WF1, Add[HSync!, HBlank!]]; M[WF2, Set[WF#5, Sub[#1, #2, #3, #4]]]; ApplyToWF[WF2, HBlank!]; M[WF3, Set[WF#5, Sub[Add[#2, #3], RShift[#1, 1]]]]; ApplyToWF[WF3, 0]; M[WF4, Set[WF#5, #4]]; ApplyToWF[WF4, HalfLine!]; M[WF5, Set[WF#5, Sub[RShift[#1, 1], #3, #4]]]; ApplyToWF[WF5, 0]; M[WF6, Set[WF#5, #3]]; ApplyToWF[WF6, HBlank!]; Data[(Byt0[1] Byt1[1] Byt2[1] Byt3[HSync!, HBlank!])]; * InitHRam (cont'd) AfterHRamTable: TTemp1← Link; * Must Output LoadAddress twice in case DoradoHasHRam wasn't true to begin with -- * once to turn on DoradoHasHRam and once to actually load the address !! T← LoadAddress; * Keep HRam, select address 0 Output← T, Call[OutputGetsT]; * This loop works as follows: * We first dispatch to ConfigTable+0, +2, or +6 according to whether * DisplayConfig = 0, 1, or 3; this reads Byt0, Byt1, or Byt2 of the instruction * pointed to by TTemp1. Then we dispatch to ConfigTable+4 to read the HRam data * from Byt3 of the word pointed to by TTemp1. * NOTE: in PrincOps mode, DisplayConfig = 1 has the same effect as DisplayConfig = 3. LoadHRamLoop: T← (DisplayConfig)+(DisplayConfig), TaskingOff; DoHRamDisp: TTemp0← (TTemp0)-1, BDispatch← T; Link← TTemp1, Branch[ConfigTable]; ConfigTable: DispTable[10]; T← 4C, ReadIM[0]; * DisplayConfig = 0 TTemp0← NOT (Link), Branch[DoHRamDisp]; T← 4C, ReadIM[IfE[AltoMode, 0, 2, 1]]; * DisplayConfig = 1 TTemp0← NOT (Link), Branch[DoHRamDisp]; ReadIM[3], TaskingOn; * Read HRam data T← NOT (Link), Branch[LoadHRamRun]; T← 4C, ReadIM[2]; * DisplayConfig = 3 TTemp0← NOT (Link), Branch[DoHRamDisp]; * Here with TTemp0 = count-1, T = HRam data. LoadHRamRun: TTemp0← (TTemp0)-1, Branch[.+2, R<0]; TTemp0← (TTemp0)-1, Output← T, Branch[., R>=0]; PD← (TTemp1) AND (7C); TTemp1← (TTemp1)+1, Branch[LoadHRamLoop, ALU#0]; T← ReleaseRam; Link← TTemp2, Branch[OutputGetsT]; *----------------------------------------------------------- ReadTerminal: * Code to process the next terminal input bit. This subroutine must be called * once duing every scan line. Accumulates a 32-bit message of the form: * 1,x,x,x,MessageType[0..3], Message[0..15], 1,0,0,0,0,0,0,0. * (Note that we only care about the first 25 bits and can ignore the trailing * zeroes. The "x" bits are don't care.) Messages are: * Type Content * 0 noop * 1 Keyboard Word 1, 177034 * 2 Keyboard Word 2, 177035 * 3 Keyboard Word 3, 177036 * 4 Keyboard Word 4, 177037 * 5 Keyboard Word 0, 177033 (and 177030 for Alto OS) * 6 Mouse DeltaX, DeltaY (excess-128, 8 bits each) * 7 unused * 10 Keyboard word 5, 177040 (Star keyboard only) * 11 Keyboard word 6, 177041 (Star keyboard only) * 12-16 unused * 17 Boot Message (actually, data jammed to 1 continuously) * One bit is read every scan line from Status.00. At the 24th bit after the * start bit, the message is completed and checked for validity (24th bit = 1). * If valid, a dispatch on the type causes the appropriate action in memory. * Clobbers T, Link Uses TerminalLo, TerminalHi, and updates BootTimer * to be the duration (in scan lines) of the most recent boot button push. * Restores TIOA[NLCB], and decrements TFieldAreaReg in the Return instruction. * Timing: 6 cycles if nothing interesting is going on. *----------------------------------------------------------- Set[XTask, IP[DHT]]; KnowRBase[THTRegion]; Subroutine; T← TerminalLo, TIOA[TStatus], Global; * Test TerminalHi[8] for the presence of a start bit signifying the * completion of a message, and read the new data bit from the terminal. PD← (TerminalHi) AND (200C); TerminalLo← InputNoPE, Branch[MsgComplete, ALU#0]; * Data = IOB[0] * Not end of message. Shift in the new data bit. * TerminalLo[0] = data bit, and T has former contents of TerminalLo. TerminalLo← LCY[TerminalLo, T, 1]; TerminalHi← LCY[T, TerminalHi, 1]; ReadTerminalRet: TFieldAreaReg← (TFieldAreaReg)-1, TIOA[TNLCB], Return; * ReadTerminal (cont'd) *----------------------------------------------------------- * Have a complete new message. * TerminalHi[12..15] = message type; T = data; TerminalLo[0] = flag bit. * Do not process the message if the flag bit is wrong, or if we are * in the midst of booting. *----------------------------------------------------------- MsgComplete: TerminalLo← T, Branch[MsgMalformed, R>=0]; T← (TerminalHi) AND (17C), Branch[AmidstBoot, R<0]; TerminalHi← Link; TopLevel; BigBDispatch← T; TerminalHi← A0, Link← TerminalHi, Branch[TerminalTable]; TerminalTable: DispTable[20]; TerminalLo← A0, Branch[ReadTerminalRet]; * 0 Noop, ignore T← (TReg400C) XOR (177434C), Branch[StoreTerminalLo]; * 1 Keyboard 177034 T← (TReg400C) XOR (177435C), Branch[StoreTerminalLo]; * 2 Keyboard 177035 T← (TReg400C) XOR (177436C), Branch[StoreTerminalLo]; * 3 Keyboard 177036 T← (TReg400C) XOR (177437C), Branch[StoreTerminalLo]; * 4 Keyboard 177037 T← (TReg400C) XOR (177433C), Branch[ButtonsKeyset]; * 5 Buttons/keyset 177033 T← (TReg400C) OR (LowByte[MouseXLoc]), Branch[MouseXY]; * 6 Mouse change TerminalLo← A0, Branch[ReadTerminalRet]; * 7 unused T← (TReg400C) XOR (177440C), Branch[StoreTerminalLo]; * 10 Keyboard 177040 T← (TReg400C) XOR (177441C), Branch[StoreTerminalLo]; * 11 Keyboard 177041 TerminalLo← A0, Branch[ReadTerminalRet]; * 12 unused TerminalLo← A0, Branch[ReadTerminalRet]; * 13 unused TerminalLo← A0, Branch[ReadTerminalRet]; * 14 unused TerminalLo← A0, Branch[ReadTerminalRet]; * 15 unused TerminalLo← A0, Branch[ReadTerminalRet]; * 16 unused BootTimer← 1C, Branch[SetBootFlag]; * 17 Start of boot Subroutine; * Mouse change -- data is deltaX,,deltaY as two 8-bit excess-128 numbers MouseXY: TerminalHi← Fetch← T; * Fetch MouseX T← LDF[TerminalLo, 10, 10]; * (DeltaX+128) in left byte T← T-(200C); T← T+MD; T← (Store← TerminalHi)+1, DBuf← T; Fetch← T; * Fetch MouseY TerminalLo← LDF[TerminalLo, 10, 0]; * (DeltaY+128) in right byte TerminalLo← (TerminalLo)-(200C); TerminalLo← (TerminalLo)+MD, Branch[StoreTerminalLo]; * Mouse buttons and keyset * On Alto, locations 177030-177033 all read out the same value. * The Alto OS looks at 177030 and Mesa looks at 177033, so store into those. ButtonsKeyset: ; :If[AltoMode]; ********** Alto version ********** Store← T, DBuf← TerminalLo; * Storing at 177033 T← T-(3C); * Change address to 177030 :EndIf; ********************************** * Store keyboard word. T = address, TerminalLo = data. StoreTerminalLo: TerminalLo← A0, Store← T, DBuf← TerminalLo, Branch[ReadTerminalRet]; * ReadTerminal (cont'd) *----------------------------------------------------------- * Boot message. *----------------------------------------------------------- * Actually, the terminal jams the data to a one while the boot * button is pressed in, so the message is all ones. * 24 samples after the boot button is pressed, we will come here * with what looks like a "boot message". We remember that we are in the * midst of a boot by setting TerminalHi = -1, and we start a counter * to time how long the boot button is held down. * During subsequent samples, it will appear that a complete message * has arrived at every one, since the start bit is always a one. * We get here as a result of testing TerminalHi<0 during the dispatch. * Count up the boot timer, and stay in the "amidst boot" state. * Note: if the timer reaches 177777, freeze it there (about 2.5 seconds). AmidstBoot: PD← (BootTimer)+1; BootTimer← (BootTimer)+1, XorSavedCarry; SetBootFlag: TerminalHi← T-T-1, Branch[ReadTerminalRet]; * When the boot button finally comes up, it will appear that we have a * malformed message (trailer bit = 0 rather than 1). MsgMalformed: TerminalHi← A0, Branch[.+2, R<0]; * Branch if booting TerminalLo← A0, Branch[ReadTerminalRet]; * Just flush bad message * A boot has just happened. But filter it out if it was too short ( <8 ms). * The terminal may send up to 8 bits of garbage after a boot, so fake * the start of a "noop" message that will absorb those bits. * Finally, exit the "amidst boot" state. PD← (BootTimer)-(MinimumPush); TerminalLo← 100000C, Branch[ReadTerminalRet, Carry]; BootTimer← A0, Branch[ReadTerminalRet]; * Too short, ignore *----------------------------------------------------------- OutputGetsT: * Handy global subroutine executes Output← T. *----------------------------------------------------------- Subroutine; Output← T, Return, Global;