<> <> <> DIRECTORY Basics USING [LowByte], ColorDisplayDorado USING [RNIL], ColorDisplayHeadDorado, MonitorToolDefs USING [MonitorParam, MonitorParamRec], Real USING [LargestNumber, RoundC], Terminal USING [Current, TurnOffColorDisplay], WindowManager USING [ScreenPos, StartColorViewers, StopColorViewers]; MonitorToolOps: CEDAR PROGRAM IMPORTS Real, Basics, WindowManager, Terminal, ColorDisplayHeadDorado EXPORTS MonitorToolDefs SHARES ColorDisplayHeadDorado = { OPEN ColorDisplayHeadDorado ; <> <<-- screenWidth, screenHeight: REAL; --visible pixels, visible lines per frame>> <<-- refreshRate: REAL; --field refresh rate in frames per second>> <<-- interlace: BOOLEAN _ TRUE; --monitor to scan interlaced ??>> <<-- hBlankTime, vBlankTime: REAL; --blanking time in microseconds>> <> hWindowPixels: INTEGER _ 32; --hardware counts 32 pixel clocks before counting out margin mCounterOverflow: INTEGER _ 32; --hardware counts 32 pixel clocks after margin counter overflows before channel ON marginPipelineLength: INTEGER _ 5; --there are 5 pixel clocks in the pipeline from margin counter overflow to video. hBlankEarly: [0..377B] _ 4; --number of pixels before HSync which will be blanked. Must be even!! <> pixelTime, pixelFreq: PUBLIC REAL; --desired pixel time in nanoseconds, rate in MHz truePixeltime, truePixelfreq: PUBLIC REAL; --actual pixel time in nanoseconds, rate in MHz lineTime, lineFreq: PUBLIC REAL; --desired line time in microseconds, rate in KHz trueLinetime, trueLinefreq: PUBLIC REAL; --actual line time in microseconds, rate in KHz fieldTime, fieldFreq: PUBLIC REAL; --desired time in microseconds for one field; rate in Hz leftMarginOffset: NAT; --this is added to the desired left margin for the microcode. Usually, the left margin is = 0. hBlankPixels, hSyncPixels: INTEGER; truePixels: INTEGER; <> hRamMaxAddr: PUBLIC CARDINAL; hBLeadLength: PUBLIC [0..377B]; hSTrailAddr: PUBLIC [0..377B]; hBTrailLength: PUBLIC CARDINAL; <> vbToVS: PUBLIC [0..377B]; defaultVBtoVS: [0..377B] _ 0; vsToVS: PUBLIC [0..377B]; defaultVStoVS: [0..377B] _ 3; vsToVB: PUBLIC CARDINAL; visibleLines: PUBLIC CARDINAL; <> refFreq, nextFreq, bestFreq, fDiff, bestDiff: PUBLIC REAL; trueMul, nextMul, bestMul: PUBLIC [0..377B]; trueZero, bestZero, trueDiv, nextDiv, bestDiv: PUBLIC [0..17B]; mp: MonitorToolDefs.MonitorParam; sw: CARDINAL; sh: CARDINAL; rr: CARDINAL; hbt: REAL ; vbt: REAL ; DoMonitorParams: PUBLIC PROCEDURE [screenWidth, screenHeight, refreshRate: CARDINAL, hBlankTime, vBlankTime: REAL, NTSCBoard: BOOLEAN _ FALSE, interlace: BOOLEAN _ TRUE] RETURNS [MonitorToolDefs.MonitorParam] = { mp: MonitorToolDefs.MonitorParam _ NEW[MonitorToolDefs.MonitorParamRec]; sw _ screenWidth; sh _ screenHeight; rr _ refreshRate; hbt _ hBlankTime; vbt _ vBlankTime; visibleLines _ Real.RoundC[IF interlace THEN screenHeight/2 ELSE screenHeight]; fieldFreq _ IF interlace THEN refreshRate*2 ELSE refreshRate; fieldTime _ 1.0/fieldFreq; lineTime _ (fieldTime - vBlankTime)/visibleLines; --assumes VBtoVS = 0 lineFreq _ 1.0/lineTime; truePixels _ screenWidth+hBlankEarly; --line is "longer" by hBlankEarly pixels pixelTime _ (lineTime - hBlankTime)/truePixels; pixelFreq _ 1.0/pixelTime; <> [zero: trueZero, mul: trueMul, div: trueDiv, bestF: truePixelfreq] _ FreqToMulDiv[pixelFreq, NTSCBoard]; <> truePixeltime _ 1.0/truePixelfreq; trueLinetime _ truePixeltime*truePixels+hBlankTime; trueLinefreq _ 1.0/trueLinetime; hRamMaxAddr _ Real.RoundC[(trueLinetime/truePixeltime)/2] - 1; hBLeadLength _ (hBlankEarly/2)+1; -- +1 for one cycle of pipelined delay forming HBlank hSyncPixels _ (Real.RoundC[(hBlankTime * 0.60)/truePixeltime]/2)*2; --make it even hSTrailAddr _ Basics.LowByte[(hSyncPixels/2)- 2]; -- -2 for pipeline advance of HSync by two HRam ticks (maxAddress and addressZero) hBlankPixels _ (Real.RoundC[hBlankTime/truePixeltime]/2)*2; --make it even number of pixels hBTrailLength _ (hBlankPixels-hSyncPixels)/2; leftMarginOffset_hBlankPixels+hBlankEarly-hWindowPixels-mCounterOverflow-marginPipelineLength; vbToVS _ defaultVBtoVS; vsToVS _ defaultVStoVS; vsToVB _ Real.RoundC[vBlankTime/trueLinetime] - vsToVS; --monitor specs call for VBlank to begin simultaneous with VSync mp^ _ [hRes: screenWidth, vRes: screenHeight, vc: [VBtoVS: vbToVS, VStoVS: vsToVS, VStoVB: vsToVB, VisibleLines: visibleLines], hc: [HRamMaxAddr: hRamMaxAddr, HBLeadLength: hBLeadLength, HSTrailAddr: hSTrailAddr, HBTrailLength: hBTrailLength], cc: [zero: trueZero, mul: trueMul, div: trueDiv], lmarg: leftMarginOffset, truePixelFreq: truePixelfreq, truePixelTime: truePixeltime]; RETURN[mp]; }; SetMonitorParams: PUBLIC PROCEDURE [bpp: CARDINAL _ 8, pos: WindowManager.ScreenPos _ left, mp: MonitorToolDefs.MonitorParam] = TRUSTED { WindowManager.StopColorViewers[]; width _ mp.hRes; -- must be a multiple of 32 height _ mp.vRes; -- must be a multiple of 2 WindowManager.StartColorViewers[pos,bpp]; ColorDisplayHeadDorado.TurnOff[]; IF bpp=24 THEN { --mimic what the DisplayHead does in full color mode lmul, ldiv: [0..377B]; [ , lmul, ldiv, ] _ FreqToMulDiv[freq: mp.truePixelFreq*2, NTSCBoard: FALSE]; --run the clock twice as fast mp.cc _ [0, lmul, ldiv]; mp.lmarg _ 2*mp.lmarg+40B--HWindow-- + 40B--marginCounter--; --adjust leftMargin mp.hc.HRamMaxAddr _ 2*mp.hc.HRamMaxAddr; -- double all HRam parameters mp.hc.HBLeadLength _ 2*mp.hc.HBLeadLength; mp.hc.HSTrailAddr _ 2*mp.hc.HSTrailAddr; mp.hc.HBTrailLength _ 2*mp.hc.HBTrailLength; }; color.vc _ mp.vc; color.hc _ mp.hc; color.clk _ mp.cc; ColorDisplayHeadDorado.TurnOn[]; LMarg[mp.lmarg]; --only works if turned on }; StartMonitor: PUBLIC PROCEDURE [screenWidth, screenHeight, refreshRate, bitsPerPixel: CARDINAL, hBlankTime, vBlankTime: REAL, pos: WindowManager.ScreenPos _ left, NTSCBoard: BOOLEAN _ FALSE, interlace: BOOLEAN _ TRUE] = { mp _ DoMonitorParams[screenWidth, screenHeight, refreshRate, hBlankTime*1E-6, vBlankTime*1E-6, NTSCBoard, interlace]; SetMonitorParams[bitsPerPixel, pos, mp]; }; Start640Monitor: PUBLIC PROCEDURE [bitsPerPixel: CARDINAL _ 8, pos: WindowManager.ScreenPos _ left] = { WindowManager.StopColorViewers[]; ColorDisplayHeadDorado.displayType _ standard; --approx. 640 by 480 pixels ColorDisplayHeadDorado.width _ 640; -- must be a multiple of 32 ColorDisplayHeadDorado.height _ 480; -- must be a multiple of 2 Terminal.TurnOffColorDisplay[Terminal.Current[]]; -- must force a disconnect WindowManager.StartColorViewers[pos,bitsPerPixel]; }; Start1024Monitor: PUBLIC PROCEDURE [bitsPerPixel: CARDINAL _ 8, pos: WindowManager.ScreenPos _ left] = { Terminal.TurnOffColorDisplay[Terminal.Current[]]; -- must force a disconnect ColorDisplayHeadDorado.displayType _ highResolution; --approx. 1024 by 768 pixels WindowManager.StartColorViewers[pos,bitsPerPixel]; StartMonitor[1024, 768, 30, bitsPerPixel, 6, 850, pos]; }; FreqToMulDiv: PROCEDURE [freq: REAL, NTSCBoard: BOOLEAN] RETURNS [zero: [0..17B], mul: [0..377B], div: [0..17B], bestF: REAL] = { firstZero, lastZero, currentZero: [0..17B]; IF NTSCBoard THEN {firstZero_1; lastZero _ 16B} ELSE {firstZero_0; lastZero _ 0}; bestDiff _ Real.LargestNumber; --start with maximum difference FOR currentZero _ firstZero, currentZero+2 UNTIL currentZero>lastZero DO refFreq _ 5002750/(16-currentZero); FOR nextMul IN [0..121] DO FOR nextDiv IN [0..15] DO nextFreq _ refFreq*(241 - nextMul)/(16-nextDiv); fDiff _ nextFreq-freq; IF fDiff < 0 THEN fDiff _ -fDiff; IF fDiff < bestDiff THEN { bestDiff _ fDiff; bestZero _ currentZero; bestMul _ nextMul; bestDiv _ nextDiv; bestFreq _ nextFreq; }; ENDLOOP; ENDLOOP; ENDLOOP; RETURN [bestZero, bestMul,bestDiv,bestFreq]; }; MulDivToFreq: PROCEDURE [zero: [0..17B] _ 0, mul: [0..377B], div: [0..17B]] RETURNS [freq: REAL] = { refFreq _ 5002750/(16-zero); freq _ refFreq*(241 - mul)/(16-div); }; LMarg: PROCEDURE [lmarg: CARDINAL] = TRUSTED { IF mcb.channelA#ColorDisplayDorado.RNIL THEN channelA.leftMargin _ lmarg; IF mcb.channelB#ColorDisplayDorado.RNIL THEN channelB.leftMargin _ lmarg; }; }.