INSERT[DisplayDefs]; *Defs file common to DisplayInit and Display :TITLE[DisplayInit]; *Ed Fiala 24 January 1983 %Jump to DisplayInit from DeviceInit running as DisplayTask. Determine the terminal configuration from bits 10..14b of the UTVFC ID register: LF Star keyboard/LF monitor = 3 (resident); CSLF CSL keyboard/LF monitor = 11b (1st overlay); and CSL CSL keyboard/CSL monitor = 5 (also 1st overlay). Initialization for all of these is contained here. When started by Initial, Star keyboard microcode is resident and CSL keyboard microcode resides in the next overlay--it overwrites the resident if loaded. Initialization begins by either loading the overlay into IMX or skipping LoadRAM's pointers past the overlay. When running with Midas, no overlays are in core, and the microcode is used as loaded. The Star keyboard driver is larger, requiring a 40b-word table and about 32b more mi on lfKBPage than the CSL keyboard. The CSLOverlay integer controls assembly of this source to produce the microcode configuration required. This same initialization is used for both LF and CSL keyboard drivers and monitors. Both drivers are built from Display.Mc which contains conditional assemblies for code specific to a keyboard; assembled as is, Display.Mc produces code for a CSL keyboard (either monitor); LFDisplay.Mc changes assembly switches and does INSERT[Display] to make the Star keyboard configuration. The Star and CSL keyboard drivers are entirely different, but the code for displaying a scanline is independent of which monitor is used. Also, HRAM initialization below is different. Monitors require a certain time/scanline which must be divided in a specified ratio between forward scan and horizontal sync--hardware adjustments cannot compensate for much variation, and for a particular hardware adjustment, all microcode systems should use the same operating parameters. With a 50 mhz oscillator, the LF monitor requires 1080 bits forward scan and 360 bits horizontal sync totalling 28.8 us/scanline. With a 20 mhz oscillator, the CSL monitor requires 652 bits forward and 104 bits horizontal sync totalling 38 us/scanline. The forward scan consists of blanked area, image, visible constant, and blanked area. The UTVFC limits image size of the image+visible constant to 1024 bits or less. The visible constants would be setup by initializing the pingpong buffers to some pattern, but this isn't done below (i.e., the size of the visible constant is 0). For the LF monitor, it was empirically determined that hardware adjustments could compensate for substantial sweep rate variations by adding (invisible) scanlines at the end of each field before vertical sync. In DisplayDefs.Mc, the vVSStart parameter may be varied between about 11b and 300b to control field rate. At 11b (77 fields/sec), no flicker is noticeable; at 140b (65 fields/sec), flicker is just barely noticeable; at 300b (55 fields/sec) flicker definitely degrades the picture. Increasing vVSStart without hardware adjustments spreads the picture vertically, so not much software flexibility is permissible for a given hardware adjustment. The ability to operate at less than maximum field rate is potentially of interest because the display task averages roughly 25 percent of all cycles at 77 fields/sec compared to 20 percent at 65 fields/sec, which improves the emulator's machine share from about 74 to 78 percent (= 6 percent faster). However, all systems presently use 77 fields/sec except when videotaping computer sesssions. To obtain 60 Hz rate for videotaping, change lfVSStart to lvVSStart = [1/28.8 us x 60 Hz] - [808/2] - lfSyncLength - lfBlankLength - 14 = 579 - 404 - 9 - 13 - 14 = 139d = 213b. For the CSL monitor, little variation in vertical parameters is possible; the current choice results in 60 fields/second. A CSL monitor is 608 visible bits/scanline x 808 visible scanlines; the LF monitor is 1080 x 861, but this microcode reduces its capability to 1024 x 808, compatible with the CSL display, by framing 608 visible bits by equal size blanked areas to the left and right, so the monitors must be adjusted to be full-screen at 808 scanlines. Pilot also runs the monitors at 808 scanlines for compatibility. For the CSL monitor, vBufStart = 150b, so 230b nibbles (=608 bits =38 words) of data are supplied by the task per scanline; an additional 5b nibbles of forward scan occur while blanking just before and just after horizontal sync; and there are 32b nibbles of horizonal sync. The midline bit in HRam appears 1/2 x (230b+12b+32b) = 136b nibbles after the end of horizontal sync. Since data begins at AAR=150b, ML should appear at 150b+136b-5b = nibble 301b. For the LF monitor, 1080d bits (= 416b nibbles) are in forward scan, 360d bits (= 132b nibbles) are horizontal sync; ML appears (416b+132b)/2 = 264b nibbles after horizontal sync. Since data begins at AAR=150b, ML should appear at 150b+264b-number of blanked nibbles following horizontal sync, or at AAR=434b-number of blanked nibbles following horizontal sync. Current convention is that the 608-wide screen is framed by 236 blank bits on each side. In nibbles this is 59 (73b) blanked nibbles both before and after a visible field of 230b nibbles. Total vert blanking = vVSStart + vSyncLength + vBlankLength + 14d scanlines. % *DisplayInitLoc must be odd; DisplayInitLoc to DisplayInitloc+6 are used **NOTE: These are known to MakeLoaderFile command files. Set[DpNotifyLoc,Add[DisplayInitLoc,1]]; *7610b must be even Set[DpContInitLoc,Add[DisplayInitLoc,4]]; *7613 Set[DpOvlSkipLoc,Add[DisplayInitLoc,5]]; *7614 Set[DpSLCountLoc,Add[DisplayInitLoc,6]]; *7615 SetTask[DpTask]; *Get here from DeviceInit running at the Display's task level. DisplayInit: vCR _ ClrNC&Blank, At[DisplayInitLoc]; *Clear Nibble counter *Suspicious that the nibble counter is only cleared when AllowWU is false, *so do this output twice. vSLC _ 104400C, Call[vCRout]; *Start_nibble 44b, ForceAARLoad'_0 vMDS420 _ 177000C, Call[vCRout]; Output[vSLC,vBufStart]; **5 mi after Output before PStore4 T _ vDBuf0 _ IncNC&Blank, Call[vQIni]; vMDS420 _ (vMDS420) or (30C); PStore4[vMDS420,vDBuf0,0]; vMDS _ 0C; *vMDS = vZero, so both are initialized Input[vTemp,0]; *Controller ID code in bits 10:14b :IF[CSLOverlay]; ******************************* *ID code in bits 10:14b is 3 for LF keyboard with LF display, 11 for CSL *keyboard with LF display, or 5 for CSL keyboard with CSL display. LU _ (vTemp) and (140C); vCnt _ LoA[DpOvlSkipLoc], GoTo[.+3,ALU=0]; *Notify LoadRAM at its continue-loading address to read CSL keyboard overlay. *LoadRAM reenters at DpNotifyLoc. ***RTemp1 (RM 53) has to be EVEN or be made even here, even though it lies ***within the device table manipulated by Initialize. xBuf to xBuf3 are also ***smashed by LoadRAM ????. vCnt _ LoA[LRJContinue]; vCnt _ (vCnt) or (HiA[LRJContinue]), Skip; vMPBr: vCnt _ (vCnt) or (HiA[DpOvlSkipLoc]); APCTask&APC _ vCnt; vMPRet: IncMPanel, Return; %The code for skipping overlays must be compatible with both old and new LoadRAM (which Pilot inherits from Initial), so it accepts the word displacement in xfTemp+LP but leaves xfTemp .eq. 0 and the modified displacement only in LP. % SetTask[0]; vLPCarry: Skip[Carry']; LPhi _ (LPhi) + (400C) + 1; vAddr7777: T _ 170000C, Return; T _ xfTemp, At[DpOvlSkipLoc]; *Skip CSL keyboard overlay LP _ (LP) + T; vSkpOv: PFetch1[LP,xfTemp,0]; LP _ (LP) + (3C), Call[vLPCarry]; xfTemp _ (LdF[xfTemp,0,14]) xnor T; *Check address .eq. 7777b Skip[ALU=0]; GoTo[vSkpOv]; *CSL ucode has been skipped or loaded. Notify display task to continue init. RTemp _ LoA[DpContInitLoc], At[DpNotifyLoc]; T _ RTemp _ (RTemp) or (HiA[DpContInitLoc,DpTask]); T _ (APCTask&APC _ RTemp) - T, Call[vMPRet]; *Emulator will continue here, but not until after HRAM init, when clock speed *determination for the time-of-day clock and other timers will be carried out. *The long comment later explains how this works. T _ (Zero) + T + 1; RTemp _ (RTemp) or (LoA[DpSLCountLoc]), Skip[Carry]; RTemp _ HiA[DpSLCountLoc,DpTask], Return; APCTask&APC _ RTemp, Call[vMPRet]; *Next time emulator runs, pass control back to DeviceInit. LoadPage[InitPage]; T _ xCNT, GoToP[DI6]; SetTask[DpTask]; :ENDIF; **************************************** vDBuf0 _ 40000C, At[DpContInitLoc]; *to load AAR vCR _ IncNC&Blank, Call[vNClk]; *Increment NClk bit; generate NClk ***Don't know why next mi is useful Output[vZero,vHCRam], Call[vNClk]; Output[vDBuf0,vBufStart]; *ForceAARLoad'_1, ForceIARLoad'_0 Output[vDBuf0,vLdIAR]; LU _ (vTemp) and (40C); *vTemp[10:14b] = 3 LF, 5 CSL, or 11 LF vDBA _ 44C, GoTo[vLFInit,ALU=0]; *Load HRam, starting at nibble 44 *CSL display HRAM init T _ 277C, Call[vOutNClk0]; * 44 - 277 _ 0 (150 up data) *ML at 150 + (1/2 * (230+46)) - 7 = 300 vSLC _ 1C, Call[vOutNClk]; *300 _ 1 (ML) T _ 376C, Call[vOutNClk0]; *301 - 376 _ 0 (data) vSLC _ 10C, Call[vOutNClk]; *377 _ 10 (SetC--start blanking) *46b nibbles of blanking must have 32b words of horizontal sync; the other *14b nibbles may be blanked either before or after horizontal sync; this *positions the active image left or right on the screen. T _ 4C, Call[vOutNClk0]; * 0 - 4 _ 0 (blank, no sync) vSLC _ 4C; T _ 36C, Call[vOutNClk]; * 5 - 36 _ 4 (blank, hor. sync) T _ 44C, Call[vOutNClk0]; * 37 - 44 _ 0 (blank) vFieldFill _ cslVSStart, GoTo[vSwiI]; %Since HRam is only 256 bits long, it is necessary to take advantage of the fact that the Switch bit is ignored unless blanking is in force. On each scanline, AAR is initialized to vBufSt (150b) and then cycles until SetC is turned on to start blanking and then until the Switch bit occurs. Hence, initialization must setup a total line time such that data bits+ blanking bits = 1088+352, where at least 608 of the bits must be data bits and 352 of bits must be blanked with horizontal sync true; the other 480 bits may be displayed as a constant value or blanked, as chosen, and the blanked bits may be divided arbitrarily between the left and right parts of the display. The code below shows 256 nibbles data, 16 nibbles blanking, and 88 nibbles horizontal sync. NOTE: Initializing HRam takes about 408*18 = 7344 cycles; during this time, tasking doesn't take place, so refresh will not take place. % vLFInit: vFieldFill _ lfVSStart; *Only for LF monitor :IF[IFG[WordsPerLine!,46,0,1]]; **************** *This code has the computed parameters for a 50 mhz crystal (i.e., *1080-bit forward scan, 360-bit horizontal sync with 608 bits of data): T _ 340C, Call[vOutNClk0]; * 44 - 340 _ 0 (partly redundant) *ML at 150 + (.5*550) - 73 = 341 vSLC _ 1C, Call[vOutNClk]; *341 _ 1 (ML) T _ 376C, Call[vOutNClk0]; *340 - 376 _ 0 vSLC _ 10C, Call[vOutNClk]; *377 _ 10 (SetC) T _ 72C, Call[vOutNClk0]; * 0 - 72 _ 0 (blanking--73b) vSLC _ 4C; T _ 224C, Call[vOutNClk]; * 73 - 224 _ 4 (Hor. sync--132b) T _ 317C, Call[vOutNClk0]; *225 - 317 _ 0 (blanking--73b) :ELSE; ***************************************** *This code has the computed parameters for a 50 mhz crystal (i.e., *1080-bit forward scan, 360-bit horizontal sync with 1024 bits of data): T _ 227C, Call[vOutNClk0]; * 44 - 227 _ 0 (partly redundant) *ML at 0 + (.5*550) - 34 = 230b vSLC _ 1C, Call[vOutNClk]; *230 _ 1 (ML) T _ 376C, Call[vOutNClk0]; *231 - 376 _ 0 vSLC _ 10C, Call[vOutNClk]; *377 _ 10 (SetC) T _ 6C, Call[vOutNClk0]; * 0 - 6 _ 0 (blanking--7b) vSLC _ 4C; T _ 140C, Call[vOutNClk]; * 7 - 140 _ 4 (Hor. sync--132b) T _ 147C, Call[vOutNClk0]; *141 - 147 _ 0 (blanking--7b) :ENDIF; **************************************** vSwiI: vMDS177400 _ 177400C; :IF[CSLOverlay]; ******************************* vDBuf0 _ Add[140000,vStart]C; *ForceAARLoad'_1, ForceIARLoad'_1 vSLC _ 2C, Call[vOutNClk]; *320 _ 2 (Switch--end blanking) *or 45 or 150 %HRam has just been initialized to 652 forward and 104 reverse = 756 bits/scanline for CSL monitors or to 1080 forward and 360 reverse = 1440 bits/scanline for LF monitors. This establishes a scanline time of 28.800 us (LF) or 37.800 us (CSL). We want to utilize these times to determine the unknown processor clock period by counting cycles/scanline. To discriminate 40 mhz (100 ns/cycle), 44.5 mhz (89.886 ns/cycle), and 50 mhz (80 ns/cycle) processor clocks, DisplayTask counts scanlines in a six-cycle loop while the emulator executes a six-cycle loop 65536d times. The predicted scanline count is 6*65536*C/(L-(6*C)-X), where L is time/scanline, C is processor clock period, and X is other task overhead/scanline in 100 ns units. The computation below ignores all components of X except the refresh timer at L*(18/2560). So the computations are (393216*C)/(288-6*C-2) for LF monitors or (393216*C)/(378-6*C-3) for CSL monitors. Predicted Predicted CSL LF CSL LF Scanlines Scanlines Threshold Threshold 40.0 mhz 1066 1404 .g. 1046 .g. 1375 44.5 mhz 955 1258 .g. 935 .g. 1230 50.0 mhz 850 1119 Observed counts with 40.0 mhz processor clock 1066 on a CSL monitor, 1416 with an LF monitor. % Output[vDBuf0,vBufStart]; Output[vDbuf0,vLdIAR]; **This mi probably useless vSLC _ (Zero) - 1; vCR _ AllowWU&Blank, Call[vCRout]; *Count scanlines here until stopped by the emulator. vTemp1 _ IP[RConstantLo]C; *IOStrobe in 1st mi won't work T _ vSLC _ (vSLC) + 1, IOStrobe, GoTo[vIRet]; *Emulator restarts DpTask here Input[vTemp,0], At[DpSLCountLoc]; T _ (SStkP&NStkP) xor (377C); StkP _ vTemp1, vTemp1 _ T, NoRegILockOK; LU _ (vTemp) and (40C); vSLC _ (vSLC) - (2000C), GoTo[vCSLThresholds,ALU#0]; *LF thresholds are now 351d and 206d, respectively. vSLC _ (vSLC) - (316C); *206d LU _ (vSLC) - (221C), DblGoTo[v50mhz,v40x,ALU<0]; *136d *CSL thresholds are now 22d and -89d, respectively. vCSLThresholds: vSLC _ (vSLC) + (131C); *69d LU _ (vSLC) - (157C), GoTo[v40x,ALU>=0]; *111d *See Timer.Mc for the determination of these constants. v50mhz: Stack _ HiA[5330]; Stack _ (Stack) or (LoA[5330]); Stack&+1 _ 130C, GoTo[vSetTimer]; *50 mhz crystal (530b) v40x: Stack _ HiA[113274], GoTo[v44.5,ALU<0]; *44.5 mhz crystal (602b) Stack _ HiA[12172]; Stack _ (Stack) or (LoA[12172]); Stack&+1 _ 256C, GoTo[vSetTimer]; *40 mhz crystal (656b) v44.5: Stack _ (Stack) or (LoA[113274]); Stack&+1 _ 202C, GoTo[vSetTimer]; vSetTimer: T _ Stack _ (Stack) or (400C); StkP _ vTemp1; :ELSE; ***************************************** vSLC _ 2C, Call[vOutNClk]; *272 _ 2 (Switch--end blanking) vCR _ AllowWU&Blank, Call[vCRout]; :ENDIF; **************************************** *Set keyboard words 177030-177043 to -1 (177040-177043 unused by CSL keyboard) T _ vDBuf0 _ (Zero) - 1, Call[vQIni]; T _ vMsgStatus _ 0C; *Task sets up loop PStore4[vMDS420,vDBuf0,0]; PStore4[vMDS420,vDBuf0,4]; PStore4[vMDS420,vDBuf0,10], Call[.+1]; *Call sets up loop %This code zeroes the two pingpong buffers (not needed unless a white area *is shown to the right of the active display). vSLC _ 140000C; Output[vSLC,vBufStart]; T _ vMsgStatus _ 0C; Output[vZero,vLdIAR], Call[vClrBf]; *IAR _ Start vButtons _ T, Call[vClrBf]; *This call sets up loop % *Clear cursor memory (32 bits/scanline x 32 scan lines) because in Alto *compatible mode, only 16x16 of the hardware's 32x32 cursor is used. **NOTE: Blanking must be on here. The final overlay must not overwrite this **code until it has finished. vSLC _ 6C; *8 nibbles/scan line Output[vMsgStatus,vCursor0]; vMsgStatus _ (vMsgStatus) + (4C); Output[vZero,vCursorMem0]; vSLC _ (vSLC) - 1, GoTo[.-3,R>=0]; vMsgStatus _ (vMsgStatus) + (4000C); vMsgStatus _ (vMsgStatus) and (174000C), Skip[Carry]; vMDS420 _ (vMDS420) or (20C), Return; *Wind up here with vMsgStatus .eq. 0 vMDS420 _ 400C, Call[.-1]; vCR _ AllowWU; vKeyBuffer _ T, LoadPage[DisplayPage]; vButtons _ T, GoToP[vFDone]; *End init **NOTE: An NClk is produced with an IOFetch4 rather than four Output's so **that display initialization doesn't defer memory refresh too long; as **coded, initialization runs about 0.4 msec before tasking. *SUBROUTINE vNClk generates one NClk. vNClk: UseCTask; IOFetch4[vMDS420,vfCReg,0], Return; *vMDS420 holds 177030b here vCRout: UseCTask; Output[vCR,vCReg], Return; *SUBROUTINE vOutNClk sends the pattern in vSLC to the HCRam until the *address = T; does T_T+1 prior to Return for caller. vOutNClk0: vSLC _ 0C; vOutNClk: vDBA _ (vDBA) + 1; LU _ (RHMask[vDBA]) xor T; Output[vSLC,vHCRam], Skip[ALU#0]; T _ (Zero) + T + 1, GoTo[vNClk]; IOFetch4[vMDS420,vfCReg,0], GoTo[vOutNClk]; vQIni: vDBuf1 _ T; vTemp1 _ T, UseCTask; vIRet: vTemp _ T, Return; %vClrBf: IOFetch16[vMDS177400,vfBuf0,0]; IOStrobe; IOFetch16[vMDS177400,vfBuf0,0]; IOFetch16[vMDS177400,vfBuf0,0]; IOFetch16[vMDS177400,vfBuf0,0], Return; % :END[DisplayInit]; (1792)\114f5 620f0 400f5 480f0 1f5 3729f0