MonitorToolOps.mesa
Last Edited July 30, 1985 5:35:21 pm PDT by Ken Pier
Diebert, April 30, 1985 12:40:19 pm PDT
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 ;
parameters supplied as input
-- 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
constant values from hardware
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!!
calculated values
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;
horizontal values needed by microcode
hRamMaxAddr: PUBLIC CARDINAL;
hBLeadLength: PUBLIC [0..377B];
hSTrailAddr: PUBLIC [0..377B];
hBTrailLength: PUBLIC CARDINAL;
vertical values needed by microcode
vbToVS: PUBLIC [0..377B];
defaultVBtoVS: [0..377B] ← 0;
vsToVS: PUBLIC [0..377B];
defaultVStoVS: [0..377B] ← 3;
vsToVB: PUBLIC CARDINAL;
visibleLines: PUBLIC CARDINAL;
parameters for mul/div calculation
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: BOOLEANFALSE, interlace: BOOLEANTRUE] 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;
calculate mul, div parameters for nearest achieveable pixel frequency
[zero: trueZero, mul: trueMul, div: trueDiv, bestF: truePixelfreq] ← FreqToMulDiv[pixelFreq, NTSCBoard];
calculate true values of parameters based on best frequency available
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: BOOLEANFALSE, interlace: BOOLEANTRUE] = {
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𡤁 lastZero ← 16B} ELSE {firstZero𡤀 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;
};
}.