:IF[WithTOR]; ************************************ TITLE[No.UTVFC.in.TOR]; :ELSE; ******************************************* Set[LFMonitor,1]; *Avoid error when inserting DisplayDefs. INSERT[DisplayDefs]; *Defs file common to DisplayInit and Display TITLE[DisplayInit]; *Ed Fiala 5 May 1982 %Jump to DisplayInit from DeviceInit running as DisplayTask. Determine the terminal configuration from bits 10..14b of the UTVFC ID register: LF Dallas keyboard/LF monitor = 3 (resident); CSLF CSL keyboard/LF monitor = 11b (1st overlay); and CSL CSL keyboard/CSL monitor = 5 (2nd overlay). Initialization for all of these is contained here (overwritten by a subsequent overlay, so code size is not a major issue). The LF microcode is resident; drivers for other configurations are in overlays which overwrite the resident if they are loaded. Initialization begins by loading the appropriate overlay into IMX and moving LoadRAM's pointer past the last overlay. Monitors require a certain time/scanline, and this time 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 1088 bits forward scan and 352 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, and blanked area. The UTVFC limits image size to 1024 bits. 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 too much software flexibility is permissible. 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 percent to 78 percent (= 6 percent faster). However, at present all microcode systems use 77 fields/sec. For the CSL monitor, very little variation in the 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 1088 x 861, but this microcode reduces its capability to 1024 x 808--the reduction to 808 is desirable because the monitors will also be used by Alto compatible microcode, so it is desirable to adjust them to be full-screen at 808 scanlines. All terminal drivers are built from Display.Mc which contains conditional assemblies for code specific to a keyboard or monitor; CSLDisplay.Mc, LFDisplay.Mc, and CSLFDisplay.Mc set the switches to an appropriate value and INSERT[Display]. Differences among the drivers appear in the code for putting out data for each scanline. The Dallas and CSL keyboard drivers are entirely different. Also, HRAM initialization below is different. 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, 1088 bits (= 420b nibbles) are in forward scan, 352 bits (= 130b nibbles) are horizontal sync; ML appears 1/2 * 550b nibbles after ending horizontal sync. Since data begins at AAR=0, ML should appear at 0b+264b-number of blanked nibbles following horizontal sync. Total vert blanking = vVSStart + vSyncLength + vBlankLength + 21d scanlines. % SetTask[DisplayTask]; *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]; vKeyboardHi _ 0C, Call[vCRout]; Output[vSLC,vBufStart]; *Start_nibble 44b, ForceAARLoad'_0 *Setup a quadword with IncNC&Blank in each word so that an IOFetch4 can be *used instead of four Output's to generate NClk's needed when loading HRAM. *Since tasking does not occur during HRAM initialization, refresh is delayed *by only 0.4 msec with IOFetch4 instead of 1.0 msec with four Output's. *This could conceivably be important. T _ vDBuf0 _ IncNC&Blank, Call[vQIni]; vKeyboard _ HiA[KeyboardAddress]; vKeyboard _ (vKeyboard) or (LoA[KeyboardAddress]); PStore4[vKeyboard,vDBuf0,0]; **5 mi after the Output above vSLC _ LoA[Task0NotifyLocA]; Input[vDBuf3,0]; *Controller ID code in bits 10:14b LU _ (vDBuf3) and (140C); *Test for LF monitor/LF keyboard LU _ (vDBuf3) and (100C), GoTo[vLoadOverlay,ALU#0]; *Jump if CSL keyboard *For LF/LF terminal, skip the two overlays in storage so that LRJ's registers *will point at the overlay after that. Must switch to task 0 to access LRJ's *registers. vNotify: vSLC _ (vSLC) or (HiA[Task0NotifyLocA]); vNotify1: APCTask&APC _ vSLC, GoTo[vAddr7777]; *Here if CSL keyboard; continue LoadRAM if LF monitor, else skip one more *overlay and then continue LoadRAM. LoadRAM continues at Task0NotifyLocC or *at vContinueInitLoc as specified to MakeLoaderFile in Pilot.Mlf. vLoadOverlay: vSLC _ LoA[LRJContinue], Skip[ALU#0]; vSLC _ LoA[Task0NotifyLocC], GoTo[vNotify]; *LF monitor, CSL kyboard vSLC _ (vSLC) or (HiA[LRJContinue]), GoTo[vNotify1]; SetTask[0]; %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. % vLPCarry: Skip[Carry']; LPhi _ (LPhi) + (400C) + 1; vAddr7777: T _ 170000C, Return; vSkipOverlay: T _ APCTask&APC; RTemp _ T; T _ xfTemp; LP _ (LP) + T, Call[vLPCarry]; vSkipOvLp: PFetch1[LP,xfTemp,0]; LP _ (LP) + (3C), Call[vLPCarry]; xfTemp _ (LdF[xfTemp,0,14]) xnor T; APCTask&APC _ RTemp, Skip[ALU=0]; GoTo[vSkipOvLp]; vIRet: Return; *For the Star keyboard/LF monitor configuration, skip both overlays. *LP+xfTemp points to next word of memory to be loaded into IM. *The 1st overlay skipped is for the Star keyboard/CSL monitor. UseCTask, Call[vSkipOverlay], At[Task0NotifyLocA]; *LoadRAM continues here after loading the LF monitor/CSL keyboard overlay. *Skip the 2nd display overlay (for the CSL keyboard/CSL monitor). UseCTask, Call[vSkipOverlay], At[Task0NotifyLocB]; *The LoadRAM pointer (LP+xfTemp) is now advanced over both terminal overlays, *and the appropriate microcode has been loaded onto the display page. *The 2nd overlay specifies vOverlayLoadedLoc as its starting address. *Notify DisplayTask at vContinueInit. RTemp _ LoA[vContinueInitLoc], At[vOverlayLoadedLoc]; T _ RTemp _ (RTemp) or (HiA[vContinueInitLoc,DisplayTask]); vNotifyBack: T _ (APCTask&APC _ RTemp) - T, Call[vIRet]; *Task 0 will resume here when it next runs, 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[vSLCountLoc]), Skip[Carry]; RTemp _ (HiA[vSLCountLoc,DisplayTask]), Return; APCTask&APC _ RTemp, Call[vIRet]; *Next time task 0 runs, pass control back to DeviceInit. LoadPage[InitPage]; GoToP[DI5a]; *Here to skip 1st overlay and load the 2nd (CSL keyboard and monitor). UseCTask, Call[vSkipOverlay], At[Task0NotifyLocC]; *Now continue LoadRAM to load the 2nd overlay. RTemp _ LoA[LRJContinue]; RTemp _ (RTemp) or (HiA[LRJContinue]), GoTo[vNotifyBack]; SetTask[DisplayTask]; vContinueInit: vDBuf0 _ 40000C, At[vContinueInitLoc]; *to load AAR vCnt _ 0C; vCR _ IncNC&Blank, Call[vCRout]; *Increment NClk bit Output[vCnt,vHCRam], Call[vNClk]; *NClk to load AAR_nibble 44b Output[vDBuf0,vBufStart]; *ForceAARLoad'_1, ForceIARLoad'_0 Output[vDBuf0,vLdIAR]; *Load IAR from Start LU _ (vDBuf3) and (40C); *Only vDBuf3[10:14b] .eq. 5 has *the 40b bit set, so this tests *for CSL monitor vCnt _ 44C, GoTo[vLFInit,ALU=0]; *Load HRam, starting at nibble 44 *CSL monitor 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) vSLC _ 2C, Call[vOutNClk]; vSLC _ Add[140000,15000]C; vCSBHi _ 0C, 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 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 most 1024 bits are visible, 352 must be blanked with horizontal sync true, and the other 64 bits are blanked, divided arbitrarily between the left and right parts of the display. The code below sets up 256 nibbles data, 16 nibbles blanking, and 88 nibbles horizontal sync. % vLFInit: vCSBHi _ 0C; T _ 251C, Call[vOutNClk0]; * 44 - 251 _ 0 vSLC _ 1C, Call[vOutNClk]; *252 _ 1 (ML .eq. midline) T _ 376C, Call[vOutNClk0]; *253 - 376 _ 0 vSLC _ 10C, Call[vOutNClk]; *377 _ 10 (SetC--start blanking) T _ 12C, Call[vOutNClk0]; * 0 - 12 _ 0 vSLC _ 4C; T _ 135C, Call[vOutNClk]; * 13 - 135 _ 4 (Hor sync) T _ 145C, Call[vOutNClk0]; *136 - 145 _ 0 vSLC _ 2C, Call[vOutNClk]; *272 _ 2 (Switch--end blanking) %HRam has just been initialized to 652 forward and 104 reverse = 756 bits/scanline for CSL monitors or to 1088 forward and 352 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 cycles. 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. In addition, the code below will setup the vCrystal register with a value indicative of the rate at which the high resolution timer in Timer.Mc is counting (presently 4 every 2560 cycles). The default value is 320, representing 1 ticks/640 cycles at 40 mHz processor clock, equivalent to 1 tick/64 microseconds. Currently envisioned values are as follows: 640 1280 2560 cycles/tick 40 mHz 320 160 80 44.5 356 178 89 50 400 200 100 The value in vCrystal can be read by the READR Misc opcode. % vSLC _ Add[140000,0]C; vSwiI: Output[vSLC,vBufStart]; Output[vSLC,vLdIAR]; *IAR _ Start vSLC _ (Zero) - 1; vCR _ AllowWU&Blank, Call[vCRout]; *Call sets up loop *Count scanlines here until stopped by the emulator. Nop; *IOStrobe in 1st mi won't work T _ vSLC _ (vSLC) + 1, IOStrobe, GoTo[vIRet]; *Emulator restarts DisplayTask here Input[vDBuf0,0], At[vSLCountLoc]; LU _ (vDBuf0) and (40C); vSLC _ (vSLC) - (2000C), GoTo[vCSLThresholds,ALU#0]; *LF thresholds are now 351d and 206d, respectively. vSLC _ (vSLC) - (316C); *206d LU _ (vSLC) - (210C), DblGoTo[v50mhz,v40x,ALU<0]; *136d *CSL thresholds are now 22d and -89d, respectively. vCSLThresholds: LU _ (vSLC) + (131C); *89d LU _ (vSLC) - (26C), GoTo[v40x,ALU>=0]; *22d *Store 2 x processor crystal speed in vCrystal. v50mhz: vCrystal _ 310C, GoTo[vSetTimer]; *50.0 mhz crystal (400d/2) v40x: vCrystal _ 262C, Skip[ALU<0]; *44.5 mhz crystal (356/2) vCrystal _ 240C, GoTo[vSetTimer]; *40.0 mhz crystal (320/2) vSetTimer: vCrystal _ LSh[vCrystal,1]; T _ vDBuf0 _ 0C, Call[vQIni]; vCSB _ ZeroDataBuffer; *Using vCSB as temporary BR here *Zero the 20b-word storage buffer used for IOFetch4/16 when display is off. *(?Suspicious that Initial doesn't zero core, so have to do it here?) PStore4[vCSB,vDBuf0,0]; PStore4[vCSB,vDBuf0,4]; PStore4[vCSB,vDBuf0,10]; PStore4[vCSB,vDBuf0,14]; T _ vMsgStatus _ 0C, Call[.+1]; *Call sets up loop *Zero cursor memory (32 bits/scanline x 32 scanlines); must zero (most of) *the cursor memory because only 16 x 16 of it will be used later. **NOTE: Blanking must be on when loading the cursor memory. **NOTE: This code must finish execution before the page on which it resides **is overwritten by the Pilot2 code. vCurIni: vSLC _ 6C; *8-2 nibbles/scanline Output[vMsgStatus,vCursor0]; vMsgStatus _ (vMsgStatus) + (4C); Output[vDBuf0,vCursorMem0]; vSLC _ (vSLC) - 1, GoTo[.-3,R>=0]; vMsgStatus _ (vMsgStatus) + (4000C); vMsgStatus _ (vMsgStatus) and (174000C), Skip[Carry]; *GoTo here allows 5 mi after Output-Output, avoiding hardware problem. vCSB _ (vCSB) or (LoA[CSBAddress]), GoTo[vAddr7777]; *Wind up here with vMsgStatus .eq. 0 vCSB _ HiA[CSBAddress], Call[.-1]; *Set keyboard words 177034-177047 to -1 (177044-177047 unused by CSL keyboard) T _ vDBuf0 _ (Zero) - 1, Call[vQIni]; vCR _ AllowWU; PStore4[vKeyboard,vDBuf0,0]; *Buttons at vKeyboard+3 PStore4[vKeyboard,vDBuf0,4]; *KB0-KB3 PStore4[vKeyboard,vDBuf0,10]; *KB4-KB7 * vMouseDx _ T _ 0C; *Not initializing these seems harmless * vMouseDy _ 0C; * vMsg _ 0C; T _ vMsgStatus _ 0C; 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; *The vKeyboard quadword contains IncNC&Blank in IOFetch4[vKeyboard,vfCReg,0], Return; *all four words 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: vCnt _ (vCnt) + 1; LU _ (RHMask[vCnt]) xor T; Output[vSLC,vHCRam], Skip[ALU#0]; T _ (Zero) + T + 1, GoTo[vNClk]; IOFetch4[vKeyboard,vfCReg,0], GoTo[vOutNClk]; vQIni: vDBuf1 _ T; vDBuf2 _ T, UseCTask; vDBuf3 _ T, Return; % vClrBf: IOFetch16[vCSB,vfBuf0,0]; IOStrobe; IOFetch16[vCSB,vfBuf0,0]; IOFetch16[vCSB,vfBuf0,0]; IOFetch16[vCSB,vfBuf0,0], Return; *Clear the two ping-pong buffers and block (not needed unless a white area *is to be shown to the right of the active display) vSLC _ 140000C; Output[vSLC,vBufStart]; *ForceIARLoad'_ForceAARLoad'_Start_0 T _ vMsgStatus _ 0C; Output[vSLC,vLdIAR], Call[vClrBf]; *IAR _ Start vButtons _ T, Call[vClrBf]; *Call sets up loop % END[DisplayInit]; (2048)\f5 :ENDIF; ****************************************** \f5