MonitorToolOps:
PROGRAM
IMPORTS Real, Basics, Process, WindowManager, ColorDisplayHeadDorado
EXPORTS MonitorToolDefs 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: 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: 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: BOOLEAN ← FALSE, interlace: BOOLEAN ← TRUE] 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 ← 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:
PROCEDURE [bpp:
CARDINAL ← 8, pos: WindowManager.ScreenPos ← left, mp: MonitorParam] = {
pri: Process.Priority ← Process.GetPriority[];
Process.SetPriority[Process.priorityBackground];
WindowManager.StopColorViewers[];
displayType ← IF bpp#24 THEN hitachi3619 ELSE ramtek525;
screenwidth ← mp.hRes; -- must be a multiple of 32
screenheight ← mp.vRes; -- must be a multiple of 2
WindowManager.StartColorViewers[pos,bpp];
ColorDisplayHeadDorado.TurnOff[];
IF fullmode
THEN {
--mimic what the DisplayHead does in full 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.vcontrol ← mp.vc;
color.hcontrol ← mp.hc;
color.ccontrol ← mp.cc;
ColorDisplayHeadDorado.TurnOn[];
LMarg[mp.lmarg]; --only works if turned on
Process.SetPriority[pri];
};
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];
};