MonitorToolOps.mesa
Last Edited August 30, 1983 4:55 pm by Ken Pier
Last Edited by: Sosinski, September 14, 1983 11:31 am
DIRECTORY
ColorDisplayHeadDorado,
Real USING [RoundC, LargestNumber],
WindowManager,
Inline USING [LowByte];
MonitorToolOps: PROGRAM
IMPORTS Real, Inline, WindowManager, ColorDisplayHeadDorado
SHARES ColorDisplayHeadDorado = BEGIN
OPEN ColorDisplayHeadDorado, WindowManager;
--parameters supplied as input
screenWidth, screenHeight: REAL; --visible pixels, visible lines per frame
refreshRate: REAL; --field refresh rate in frames per second
interlace: BOOLEANTRUE; --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: REAL; --desired pixel time in nanoseconds, rate in MHz
truePixeltime, truePixelfreq: REAL; --actual pixel time in nanoseconds, rate in MHz
lineTime, lineFreq: REAL; --desired line time in microseconds, rate in KHz
trueLinetime, trueLinefreq: REAL; --actual line time in microseconds, rate in KHz
fieldTime, fieldFreq: 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: CARDINAL;
hBLeadLength: [0..377B];
hSTrailAddr: [0..377B];
hBTrailLength: CARDINAL;
--vertical values needed by microcode
vbToVS: [0..377B];
defaultVBtoVS: [0..377B] ← 0;
vsToVS: [0..377B];
defaultVStoVS: [0..377B] ← 3;
vsToVB: CARDINAL;
visibleLines: CARDINAL;
--parameters for mul/div calculation
refFreq, nextFreq, bestFreq, fDiff, bestDiff: REAL;
trueMul, nextMul, bestMul: [0..377B];
trueZero, bestZero, trueDiv, nextDiv, bestDiv: [0..17B];
MonitorParam: TYPE = REF MonitorParamRec;
MonitorParamRec: TYPE = RECORD [hRes: CARDINAL, vRes: CARDINAL, vc: VControl, hc: HControl, cc: CControl, lmarg: CARDINAL, truePixelFreq, truePixelTime: REAL];
mp: MonitorParam;
sw: CARDINAL;
sh: CARDINAL;
rr: CARDINAL;
hbt: REAL ;
vbt: REAL ;
DoMonitorParams: PROCEDURE [screenWidth, screenHeight, refreshRate: CARDINAL, hBlankTime, vBlankTime: REAL, NTSCBoard: BOOLEANFALSE, interlace: BOOLEANTRUE] RETURNS [MonitorParam] = {
mp: MonitorParam ← NEW[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 ← Inline.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: PROCEDURE [bpp: CARDINAL ← 8, mp: MonitorParam] = {
WindowManager.StopColorViewers[];
displayType ← IF bpp#24 THEN Hitachi3619 ELSE Standard525;
screenwidth ← mp.hRes; -- must be a multiple of 32
screenheight ← mp.vRes; -- must be a multiple of 2
WindowManager.StartColorViewers[left,bpp];
ColorDisplayHeadDorado.TurnOff[];
color.vcontrol ← mp.vc;
color.hcontrol ← mp.hc;
color.ccontrol ← mp.cc;
ColorDisplayHeadDorado.TurnOn[];
LMarg[mp.lmarg]; --only works if turned on
};
StartMonitor: PROCEDURE [screenWidth, screenHeight, refreshRate, bitsPerPixel: CARDINAL, hBlankTime, vBlankTime: REAL, NTSCBoard: BOOLEANFALSE, interlace: BOOLEANTRUE] = {
mp ← DoMonitorParams[screenWidth, screenHeight, refreshRate, hBlankTime*1E-6, vBlankTime*1E-6, NTSCBoard, interlace];
SetMonitorParams[bitsPerPixel, mp];
};
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] = {
IF mcb.achanCB#rpNIL THEN achan.leftMargin ← lmarg;
IF mcb.bchanCB#rpNIL THEN bchan.leftMargin ← lmarg;
};
END.