Oberon/ETH Oberon/2.3.7/DisplayTool.Mod
< Oberon | ETH Oberon
(* ETH Oberon, Copyright 1990-2003 Computer Systems Institute, ETH Zurich, CH-8092 Zurich.
Refer to the license.txt file provided with this distribution. *)
MODULE DisplayTool;
IMPORT V86, SYSTEM, MathL, Kernel (*, Log, Texts, Oberon, In *);
CONST
textsDebug = TRUE;
CONST
GTFLockVF = 1; (* Lock to vertical frequency *)
GTFLockHF = 2; (* Lock to horizontal frequency *)
GTFLockPF = 3; (* Lock to pixel clock frequency *)
TYPE
GTFConstants = RECORD
margin: LONGREAL; (* Margin size as percentage of display *)
cellGran: LONGREAL; (* Character cell granularity *)
minPorch: LONGREAL; (* Minimum front porch in lines/chars *)
vSyncRqd: LONGREAL; (* Width of V sync in lines *)
hSync: LONGREAL; (* Width of H sync as percent of total *)
minVSyncBP: LONGREAL; (* Minimum vertical sync + back porch (us) *)
m: LONGREAL; (* Blanking formula gradient *)
c: LONGREAL; (* Blanking formula offset *)
k: LONGREAL; (* Blanking formula scaling factor *)
j: LONGREAL; (* Blanking formula scaling factor weight *)
END;
GTFHCRTC = RECORD
hTotal: LONGINT; (* Horizontal total *)
hDisp: LONGINT; (* Horizontal displayed *)
hSyncStart: LONGINT; (* Horizontal sync start *)
hSyncEnd: LONGINT; (* Horizontal sync end *)
hFrontPorch: LONGINT; (* Horizontal front porch *)
hSyncWidth: LONGINT; (* Horizontal sync width *)
hBackPorch: LONGINT; (* Horizontal back porch *)
END;
GTFVCRTC = RECORD
vTotal: LONGINT; (* Vertical total *)
vDisp: LONGINT; (* Vertical displayed *)
vSyncStart: LONGINT; (* Vertical sync start *)
vSyncEnd: LONGINT; (* Vertical sync end *)
vFrontPorch: LONGINT; (* Vertical front porch *)
vSyncWidth: LONGINT; (* Vertical sync width *)
vBackPorch: LONGINT; (* Vertical back porch *)
END;
GTFTimings = RECORD
h: GTFHCRTC; (* Horizontal CRTC paremeters *)
v: GTFVCRTC; (* Vertical CRTC parameters *)
hSyncPol: CHAR; (* Horizontal sync polarity *)
vSyncPol: CHAR; (* Vertical sync polarity *)
interlace: CHAR; (* 'I' for Interlace, 'N' for Non *)
vFreq: LONGREAL; (* Vertical frequency (Hz) *)
hFreq: LONGREAL; (* Horizontal frequency (KHz) *)
dotClock: LONGREAL; (* Pixel clock (Mhz) *)
END;
VAR
GC: GTFConstants;
TYPE
VBEString = ARRAY 32 OF CHAR;
VideoMode = POINTER TO VideoModeDesc;
VideoModeDesc = RECORD
modeNr: LONGINT;
(* mandatory for all VBE revisions *)
modeAttr, winAAttr, winBAttr: SET;
winGranularity, winSize, winASeg, winBSeg, bytesPerScanLine: LONGINT;
winFuncPtr: LONGINT;
(* mandatory for VBE 1.2 and above *)
xRes, yRes, xCharSize, yCharSize, nrOfPlanes, bitsPerPixel, nrOfBanks: LONGINT;
memoryModel, bankSize, nrOfImgPages: LONGINT;
(* direct color fields (for direct/6 and YUV/7) *)
redMaskSize, redFieldPos: LONGINT;
greenMaskSize, greenFieldPos: LONGINT;
blueMaskSize, blueFieldPos: LONGINT;
rsvdMaskSize, rsvdFieldPos: LONGINT;
directColorModeInfo: SET;
(* mandatory for VBE 2.0 and above *)
physBasePtr: LONGINT;
(* mandatory for VBE 3.0 and above *)
linBytesPerScanLine, bnkNrOfImgPages, linNrOfImgPages: LONGINT;
linRedMaskSize, linRedFieldPos: LONGINT;
linGreenMaskSize, linGreenFieldPos: LONGINT;
linBlueMaskSize, linBlueFieldPos: LONGINT;
linRsvdMaskSize, linRsvdFieldPos, maxPixelClock: LONGINT;
next: VideoMode
END;
VBEControllerInfo = RECORD
sig: ARRAY 5 OF CHAR;
version, oemSoftwareRev, totalMem: LONGINT;
oemString, oemVendor, oemProductName, oemProductRev: VBEString;
dac8, vga, extDac, stereo, stereoEVC, available: BOOLEAN;
vmodes: VideoMode
END;
VAR
Width*, Height*, Depth*, Hz*: LONGINT;
HSyncStart, HSyncEnd, VSyncStart, VSyncEnd: LONGINT;
vbe: VBEControllerInfo;
(* W: Texts.Writer;
T: Texts.Text; *)
PROCEDURE LogStr(s: ARRAY OF CHAR);
BEGIN
(* IF textsDebug THEN Texts.WriteString(W, s); Texts.Append(T, W.buf)
ELSE Log.Str(s)
END *)
END LogStr;
PROCEDURE LogHex(x: LONGINT);
BEGIN
(* IF textsDebug THEN Texts.WriteHex(W, x); Texts.Append(T, W.buf)
ELSE Log.Hex(x)
END *)
END LogHex;
PROCEDURE LogInt(x: LONGINT);
BEGIN
(* IF textsDebug THEN Texts.WriteInt(W, x, 0); Texts.Append(T, W.buf)
ELSE Log.Int(x)
END *)
END LogInt;
PROCEDURE LogLn;
BEGIN
(* IF textsDebug THEN Texts.WriteLn(W); Texts.Append(T, W.buf)
ELSE Log.Ln
END *)
END LogLn;
(* GTF *)
PROCEDURE pow(x: LONGREAL; n: LONGINT): LONGREAL;
VAR s: LONGREAL;
BEGIN
s := 1;
WHILE n > 0 DO s := s * x; DEC(n) END;
RETURN s
END pow;
PROCEDURE Round(v: LONGREAL): LONGREAL;
BEGIN
RETURN ENTIER(v + 0.5)
END Round;
PROCEDURE GetInternalConstants(VAR c: GTFConstants);
BEGIN
c.margin := GC.margin; c.cellGran := Round(GC.cellGran);
c.minPorch := Round(GC.minPorch); c.vSyncRqd := Round(GC.vSyncRqd);
c.hSync := GC.hSync; c.minVSyncBP := GC.minVSyncBP;
IF GC.k = 0 THEN c.k := 0.001 ELSE c.k := GC.k END;
c.m := (c.k / 256) * GC.m; c.c := (GC.c - GC.j) * (c.k / 256) + GC.j;
c.j := GC.j;
END GetInternalConstants;
(****************************************************************************
*
* Function: GTF_calcTimings
* Parameters: hPixels - X resolution
* vLines - Y resolution
* freq - Frequency (Hz, KHz or MHz depending on type)
* type - 1 - vertical, 2 - horizontal, 3 - dot clock
* margins - True if margins should be generated
* interlace - True if interlaced timings to be generated
* t - Place to store the resulting timings
*
* Description: Calculates a set of GTF timing parameters given a specified
* resolution and vertical frequency. The horizontal frequency
* and dot clock will be automatically generated by this
* routines.
*
* For interlaced modes the CRTC parameters are calculated for
* a single field, so will be half what would be used in
* a non-interlaced mode.
*
****************************************************************************)
PROCEDURE GTFCalcTimings(hPixels, vLines, freq: LONGREAL; type: LONGINT; wantMargins, wantInterlace: BOOLEAN;
VAR t: GTFTimings);
VAR
interlace,vFieldRate,hPeriod: LONGREAL;
topMarginLines,botMarginLines: LONGREAL;
leftMarginPixels,rightMarginPixels: LONGREAL;
hPeriodEst,vSyncBP,vBackPorch: LONGREAL;
vTotalLines,vFieldRateEst: LONGREAL;
hTotalPixels,hTotalActivePixels,hBlankPixels: LONGREAL;
idealDutyCycle,hSyncWidth,hSyncBP,hBackPorch: LONGREAL;
idealHPeriod: LONGREAL;
vFreq,hFreq,dotClock: LONGREAL;
c: GTFConstants;
BEGIN
GetInternalConstants(c);
vFreq := freq; hFreq := freq; dotClock := freq;
(* Round pixels to character cell granularity *)
hPixels := Round(hPixels / c.cellGran) * c.cellGran;
(* For interlaced mode halve the vertical parameters, and double the required field refresh rate. *)
IF wantInterlace THEN
vLines := Round(vLines / 2);
vFieldRate := vFreq * 2;
dotClock := dotClock * 2;
interlace := 0.5;
ELSE vFieldRate := vFreq; interlace := 0
END;
(* Determine the lines for margins *)
IF wantMargins THEN
topMarginLines := Round(c.margin / 100 * vLines);
botMarginLines := Round(c.margin / 100 * vLines)
ELSE topMarginLines := 0; botMarginLines := 0
END;
IF type # GTFLockPF THEN
IF type = GTFLockVF THEN
(* Estimate the horizontal period *)
hPeriodEst := ((1/vFieldRate)-(c.minVSyncBP/1000000))/
(vLines+(2*topMarginLines)+c.minPorch+interlace)*1000000;
(* Find the number of lines in vSync + back porch *)
vSyncBP := Round(c.minVSyncBP / hPeriodEst);
ELSIF type = GTFLockHF THEN
(* Find the number of lines in vSync + back porch *)
vSyncBP := Round((c.minVSyncBP * hFreq) / 1000);
END;
(* Find the number of lines in the V back porch alone *)
vBackPorch := vSyncBP - c.vSyncRqd;
(* Find the total number of lines in the vertical period *)
vTotalLines := vLines + topMarginLines + botMarginLines + vSyncBP
+ interlace + c.minPorch;
IF type = GTFLockVF THEN
(* Estimate the vertical frequency *)
vFieldRateEst := 1000000 / (hPeriodEst * vTotalLines);
(* Find the actual horizontal period *)
hPeriod := (hPeriodEst * vFieldRateEst) / vFieldRate;
(* Find the actual vertical field frequency *)
vFieldRate := 1000000 / (hPeriod * vTotalLines);
ELSIF type = GTFLockHF THEN
(* Find the actual vertical field frequency *)
vFieldRate := (hFreq / vTotalLines) * 1000;
END
END;
(* Find the number of pixels in the left and right margins *)
IF wantMargins THEN
leftMarginPixels := Round(hPixels * c.margin) / (100 * c.cellGran);
rightMarginPixels := Round(hPixels * c.margin) / (100 * c.cellGran);
ELSE leftMarginPixels := 0; rightMarginPixels := 0
END;
(* Find the total number of active pixels in image + margins *)
hTotalActivePixels := hPixels + leftMarginPixels + rightMarginPixels;
IF type = GTFLockVF THEN
(* Find the ideal blanking duty cycle *)
idealDutyCycle := c.c - ((c.m * hPeriod) / 1000)
ELSIF type = GTFLockHF THEN
(* Find the ideal blanking duty cycle *)
idealDutyCycle := c.c - (c.m / hFreq);
ELSIF type = GTFLockPF THEN
(* Find ideal horizontal period from blanking duty cycle formula *)
idealHPeriod := (((c.c - 100) + (MathL.sqrt((pow(100-c.c,2)) +
(0.4 * c.m * (hTotalActivePixels + rightMarginPixels +
leftMarginPixels) / dotClock)))) / (2 * c.m)) * 1000;
(* Find the ideal blanking duty cycle *)
idealDutyCycle := c.c - ((c.m * idealHPeriod) / 1000);
END;
(* Find the number of pixels in blanking time *)
hBlankPixels := Round((hTotalActivePixels * idealDutyCycle) /
((100 - idealDutyCycle) * c.cellGran)) * c.cellGran;
(* Find the total number of pixels *)
hTotalPixels := hTotalActivePixels + hBlankPixels;
(* Find the horizontal back porch *)
hBackPorch := Round((hBlankPixels / 2) / c.cellGran) * c.cellGran;
(* Find the horizontal sync width *)
hSyncWidth := Round(((c.hSync/100) * hTotalPixels) / c.cellGran) * c.cellGran;
(* Find the horizontal sync + back porch *)
hSyncBP := hBackPorch + hSyncWidth;
IF type = GTFLockPF THEN
(* Find the horizontal frequency *)
hFreq := (dotClock / hTotalPixels) * 1000;
(* Find the number of lines in vSync + back porch *)
vSyncBP := Round((c.minVSyncBP * hFreq) / 1000);
(* Find the number of lines in the V back porch alone *)
vBackPorch := vSyncBP - c.vSyncRqd;
(* Find the total number of lines in the vertical period *)
vTotalLines := vLines + topMarginLines + botMarginLines + vSyncBP
+ interlace + c.minPorch;
(* Find the actual vertical field frequency *)
vFieldRate := (hFreq / vTotalLines) * 1000;
ELSE
IF type = GTFLockVF THEN
(* Find the horizontal frequency *)
hFreq := 1000 / hPeriod;
ELSIF type = GTFLockHF THEN
(* Find the horizontal frequency *)
hPeriod := 1000 / hFreq;
END;
(* Find the pixel clock frequency *)
dotClock := hTotalPixels / hPeriod;
END;
(* Find the vertical frame frequency *)
IF wantInterlace THEN vFreq := vFieldRate / 2; dotClock := dotClock / 2;
ELSE vFreq := vFieldRate
END;
(* Return the computed frequencies *)
t.vFreq := vFreq;
t.hFreq := hFreq;
t.dotClock := dotClock;
(* Determine the vertical timing parameters *)
t.h.hTotal := ENTIER(hTotalPixels);
t.h.hDisp := ENTIER(hTotalActivePixels);
t.h.hSyncStart := ENTIER(t.h.hTotal - hSyncBP);
t.h.hSyncEnd := ENTIER(t.h.hTotal - hBackPorch);
t.h.hFrontPorch := t.h.hSyncStart - t.h.hDisp;
t.h.hSyncWidth := ENTIER(hSyncWidth);
t.h.hBackPorch := ENTIER(hBackPorch);
(* Determine the vertical timing parameters *)
t.v.vTotal := ENTIER(vTotalLines);
t.v.vDisp := ENTIER(vLines);
t.v.vSyncStart := ENTIER(t.v.vTotal - vSyncBP);
t.v.vSyncEnd := ENTIER(t.v.vTotal - vBackPorch);
t.v.vFrontPorch := t.v.vSyncStart - t.v.vDisp;
t.v.vSyncWidth := ENTIER(c.vSyncRqd);
t.v.vBackPorch := ENTIER(vBackPorch);
(* Mark as GTF timing using the sync polarities *)
IF wantInterlace THEN t.interlace := 'I' ELSE t.interlace := 'N' END;
t.hSyncPol := '-';
t.vSyncPol := '+';
END GTFCalcTimings;
(* VBE *)
PROCEDURE CopyVBEString(adr: LONGINT; VAR s: ARRAY OF CHAR);
VAR adr0, i: LONGINT; adr1: INTEGER;
BEGIN
SYSTEM.GET(adr+2, adr1); adr0 := LONG(adr1) * 16;
SYSTEM.GET(adr, adr1); adr0 := adr0+adr1;
i := -1;
REPEAT INC(i); SYSTEM.GET(adr0, s[i]); INC(adr0) UNTIL s[i] = 0X
END CopyVBEString;
PROCEDURE UpDown*;
BEGIN
END UpDown;
PROCEDURE LeftRight*;
BEGIN
END LeftRight;
PROCEDURE ChangeHz*;
BEGIN
END ChangeHz;
PROCEDURE Set*;
BEGIN
END Set;
PROCEDURE SetVideoMode*(modeNr, vFreq: LONGINT; blank, linear: BOOLEAN; VAR res: LONGINT);
VAR vmem, adr: LONGINT; flags: SET; p: VideoMode; regs: V86.Regs; t: GTFTimings;
BEGIN
modeNr := modeNr MOD 200H; res := 0;
Kernel.NewDMA(256, adr, vmem); (* allocate DMA buffer *)
ASSERT(vmem MOD 16 = 0); ASSERT(vmem < 100000H); (* sanity *)
ASSERT(adr = vmem); (* implementation restriction *)
p := vbe.vmodes;
WHILE (p # NIL) & (p.modeNr # modeNr) DO p := p.next END;
IF p # NIL THEN
IF (vbe.version >= 300H) & (vFreq > 0) THEN
GTFCalcTimings(p.xRes, p.yRes, vFreq, GTFLockVF, FALSE, FALSE, t);
regs.EAX := 4F0BH; regs.EBX := 0;
regs.ECX := vFreq*t.h.hTotal*t.v.vTotal; regs.EDX := modeNr;
V86.Video(regs); ASSERT(regs.EAX = 4FH, 100);
SYSTEM.PUT(vmem, SYSTEM.VAL(INTEGER, t.h.hTotal));
SYSTEM.PUT(vmem+2, SYSTEM.VAL(INTEGER, t.h.hSyncStart));
SYSTEM.PUT(vmem+4, SYSTEM.VAL(INTEGER, t.h.hSyncEnd));
SYSTEM.PUT(vmem+6, SYSTEM.VAL(INTEGER, t.v.vTotal));
SYSTEM.PUT(vmem+8, SYSTEM.VAL(INTEGER, t.v.vSyncStart));
SYSTEM.PUT(vmem+10, SYSTEM.VAL(INTEGER, t.v.vSyncEnd));
flags := {};
IF t.interlace = "I" THEN INCL(flags, 1) END;
IF t.hSyncPol = "-" THEN INCL(flags, 2) END;
IF t.vSyncPol = "-" THEN INCL(flags, 3) END;
SYSTEM.PUT(vmem+12, SYSTEM.VAL(CHAR, flags));
SYSTEM.PUT(vmem+13, regs.ECX);
SYSTEM.PUT(vmem+17, SYSTEM.VAL(INTEGER, vFreq*100));
regs.EBX := 800H
ELSE regs.EBX := 0
END;
regs.EAX := 4F02H; INC(regs.EBX, modeNr);
IF ~blank THEN INC(regs.EBX, 8000H) END;
IF linear THEN INC(regs.EBX, 4000H) END;
regs.ES := SHORT(vmem DIV 16); regs.EDI := 0;
V86.Video(regs); ASSERT(regs.EAX MOD 10000H= 4FH, 101);
ELSE res := 1
END;
Kernel.DisposeDMA(256, vmem); (* deallocate DMA buffer *)
END SetVideoMode;
PROCEDURE GetFrameBuffer*(modeNr: LONGINT; VAR physAdr, size: LONGINT);
VAR p: VideoMode;
BEGIN
modeNr := modeNr MOD 200H;
p := vbe.vmodes;
WHILE (p # NIL) & (p.modeNr # modeNr) DO p := p.next END;
IF p = NIL THEN physAdr := -1; size := 0 ELSE physAdr := p.physBasePtr; size := vbe.totalMem END
END GetFrameBuffer;
PROCEDURE SearchVideoMode*(width, height, depth: LONGINT): LONGINT;
VAR modeNr: LONGINT; p: VideoMode;
BEGIN
p := vbe.vmodes;
WHILE (p # NIL) & ((p.xRes # width) OR (p.yRes # height) OR (p.bitsPerPixel # depth)) DO p := p.next END;
IF p # NIL THEN modeNr := p.modeNr ELSE modeNr := 0 END;
RETURN modeNr;
END SearchVideoMode;
PROCEDURE GetCurrentVideoMode*(): LONGINT;
VAR regs: V86.Regs;
BEGIN
regs.EAX := 4F03H;
V86.Video(regs);
RETURN regs.EBX
END GetCurrentVideoMode;
PROCEDURE ShowVideoModes;
VAR p: VideoMode;
BEGIN
LogStr("VideoModes"); LogLn;
p := vbe.vmodes;
WHILE p # NIL DO
LogStr("Mode: "); LogHex(p.modeNr); LogLn;
LogStr("mode attributes: "); LogLn;
LogStr(" "); IF ~(0 IN p.modeAttr) THEN LogStr("no ") END; LogStr("HW support"); LogLn;
LogStr(" "); IF ~(2 IN p.modeAttr) THEN LogStr("no ") END; LogStr("TTY output support"); LogLn;
LogStr(" "); IF 3 IN p.modeAttr THEN LogStr("color") ELSE LogStr("monochrome") END; LogLn;
LogStr(" "); IF 4 IN p.modeAttr THEN LogStr("graphics") ELSE LogStr("text") END; LogLn;
LogStr(" "); IF ~(5 IN p.modeAttr) THEN LogStr("not ") END; LogStr("VGA compatible"); LogLn;
LogStr(" "); IF 6 IN p.modeAttr THEN LogStr("no ") END; LogStr("VGA comp. windowing"); LogLn;
LogStr(" "); IF ~(7 IN p.modeAttr) THEN LogStr("no ") END; LogStr("linear frame buffer available"); LogLn;
LogStr(" "); IF ~(8 IN p.modeAttr) THEN LogStr("no ") END; LogStr("double scanning available"); LogLn;
LogStr(" "); IF ~(9 IN p.modeAttr) THEN LogStr("no ") END; LogStr("interlacing available"); LogLn;
LogStr(" "); IF ~(10 IN p.modeAttr) THEN LogStr("no ") END; LogStr("HW triple buffering support"); LogLn;
LogStr(" "); IF ~(11 IN p.modeAttr) THEN LogStr("no ") END; LogStr("HW stereoscopic support"); LogLn;
LogStr(" "); IF ~(12 IN p.modeAttr) THEN LogStr("no ") END; LogStr("dual display start address support"); LogLn;
LogStr("window A attributes: "); LogLn;
IF 0 IN p.winAAttr THEN LogStr(" relocatable window") ELSE LogStr(" single non-relocatable window") END; LogLn;
LogStr(" Window "); IF ~(1 IN p.winAAttr) THEN LogStr("not ") END; LogStr("readable"); LogLn;
LogStr(" Window "); IF ~(2 IN p.winAAttr) THEN LogStr("not ") END; LogStr("writeable"); LogLn;
LogStr("window B attributes: "); LogLn;
IF 0 IN p.winBAttr THEN LogStr(" relocatable window") ELSE LogStr(" single non-relocatable window") END; LogLn;
LogStr(" Window "); IF ~(1 IN p.winBAttr) THEN LogStr("not ") END; LogStr("readable"); LogLn;
LogStr(" Window "); IF ~(2 IN p.winBAttr) THEN LogStr("not ") END; LogStr("writeable"); LogLn;
LogStr("window granularity in KB: "); LogInt(p.winGranularity); LogLn;
LogStr("window size: "); LogInt(p.winSize); LogLn;
LogStr("window A start segment: "); LogHex(p.winASeg); LogLn;
LogStr("window B start segment: "); LogHex(p.winBSeg); LogLn;
LogStr("real mode pointer to window function: "); LogHex(p.winFuncPtr); LogLn;
LogStr("bytes per scan line: "); LogInt(p.bytesPerScanLine); LogLn;
IF vbe.version >= 102H THEN (* VBE 1.2 and above *)
LogStr("horizontal resolution: "); LogInt(p.xRes); LogLn;
LogStr("vertical resolution: "); LogInt(p.yRes); LogLn;
LogStr("character cell width: "); LogInt(p.xCharSize); LogLn;
LogStr("character cell height: "); LogInt(p.yCharSize); LogLn;
LogStr("planes: "); LogInt(p.nrOfPlanes); LogLn;
LogStr("bits per pixel: "); LogInt(p.bitsPerPixel); LogLn;
LogStr("number of banks: "); LogInt(p.nrOfBanks); LogLn;
LogStr("memory model: "); LogInt(p.memoryModel); LogStr(", ");
CASE p.memoryModel OF
0: LogStr("text mode")
| 1: LogStr("CGA graphics")
| 2: LogStr("Hercules graphics")
| 3: LogStr("planar")
| 4: LogStr("packed pixel")
| 5: LogStr("non-chain 4, 256 color")
| 6: LogStr("direct color")
| 7: LogStr("YUV")
| 8..0FH: LogStr("reserverd (VESA)")
ELSE LogStr("OEM defined")
END;
LogLn;
LogStr("bank size: "); LogInt(p.bankSize); LogLn;
LogStr("number of images: "); LogInt(p.nrOfImgPages); LogLn;
IF (p.memoryModel = 6) OR (p.memoryModel = 7) THEN
LogStr("red mask size: "); LogInt(p.redMaskSize); LogLn;
LogStr("red field position: "); LogInt(p.redFieldPos); LogLn;
LogStr("green mask size: "); LogInt(p.greenMaskSize); LogLn;
LogStr("green field position: "); LogInt(p.greenFieldPos); LogLn;
LogStr("blue mask size: "); LogInt(p.blueMaskSize); LogLn;
LogStr("blue field position: "); LogInt(p.blueFieldPos); LogLn;
LogStr("reserved mask size: "); LogInt(p.rsvdMaskSize); LogLn;
LogStr("reserved field position: "); LogInt(p.rsvdFieldPos); LogLn;
LogStr("direct color mode information: "); LogLn;
LogStr(" color ramp "); IF 0 IN p.directColorModeInfo THEN LogStr("programmable") ELSE LogStr("fixed") END; LogLn;
LogStr(" reserved field "); IF 1 IN p.directColorModeInfo THEN LogStr("usable") ELSE LogStr("reserved") END; LogLn
END
END;
IF vbe.version >= 200H THEN
LogStr("start address of linear frame buffer: "); LogHex(p.physBasePtr); LogLn
END;
IF vbe.version >= 300H THEN
LogStr("linear bytes per scan line: "); LogInt(p.linBytesPerScanLine); LogLn;
LogStr("# images for banked modes: "); LogInt(p.bnkNrOfImgPages); LogLn;
LogStr("# images for linear modes: "); LogInt(p.linNrOfImgPages); LogLn;
LogStr("linear red mask size: "); LogInt(p.linRedMaskSize); LogLn;
LogStr("linear red field position: "); LogInt(p.linRedFieldPos); LogLn;
LogStr("linear green mask size: "); LogInt(p.linGreenMaskSize); LogLn;
LogStr("linear green field position: "); LogInt(p.linGreenFieldPos); LogLn;
LogStr("linear blue mask size: "); LogInt(p.linBlueMaskSize); LogLn;
LogStr("linear blue field position: "); LogInt(p.linBlueFieldPos); LogLn;
LogStr("linear reserved mask size: "); LogInt(p.linRsvdMaskSize); LogLn;
LogStr("linear reserved field position: "); LogInt(p.linRsvdFieldPos); LogLn;
LogStr("maximum pixel clock (Hz): "); LogInt(p.maxPixelClock); LogLn
END;
p := p.next
END
END ShowVideoModes;
PROCEDURE ShowVesaInfo*;
BEGIN
LogStr("VESA signature: "); LogStr(vbe.sig); LogLn;
LogStr("version: "); LogHex(vbe.version); LogLn;
LogStr("OEM: "); LogStr(vbe.oemString); LogLn;
LogStr("OEM vendor: "); LogStr(vbe.oemVendor); LogLn;
LogStr("OEM product: "); LogStr(vbe.oemProductName); LogLn;
LogStr("OEM product revision: "); LogStr(vbe.oemProductRev); LogLn;
LogStr("OEM software revision: "); LogHex(vbe.oemSoftwareRev); LogLn;
LogStr("total memory (MB): "); LogInt(vbe.totalMem DIV (1024 * 1024)); LogLn;
LogStr("Capabilities: ");
IF vbe.dac8 THEN LogStr("8-bit DAC") ELSE LogStr("6-bit DAC") END; LogStr(", ");
IF ~vbe.vga THEN LogStr("not VGA comp") ELSE LogStr("VGA comp") END; LogStr(", ");
IF vbe.extDac THEN LogStr("extended RAMDAC") ELSE LogStr("normal RAMDAC") END; LogStr(", ");
IF vbe.stereo THEN LogStr("stereoscopic support") ELSE LogStr("no stereoscopic support") END; LogStr(", ");
IF vbe.stereoEVC THEN LogStr("stereo. over VESA EVC") ELSE LogStr("stereo. over external VESA conn.") END; LogLn;
ShowVideoModes
END ShowVesaInfo;
PROCEDURE GetModeInfo(p: VideoMode);
VAR adr, vmem: LONGINT; regs: V86.Regs; vali: INTEGER; valc: CHAR;
BEGIN
Kernel.NewDMA(256, adr, vmem); (* allocate DMA buffer *)
ASSERT(vmem MOD 16 = 0); ASSERT(vmem < 100000H); (* sanity *)
ASSERT(adr = vmem); (* implementation restriction *)
regs.EAX := 4F01H; regs.ECX := p.modeNr;
regs.ES := SHORT(vmem DIV 16); regs.EDI := 0;
V86.Video(regs);
SYSTEM.GET(vmem, vali); p.modeAttr := SYSTEM.VAL(SET, vali);
SYSTEM.GET(vmem+2, valc); p.winAAttr := SYSTEM.VAL(SET, valc);
SYSTEM.GET(vmem+3, valc); p.winBAttr := SYSTEM.VAL(SET, valc);
SYSTEM.GET(vmem+4, vali); p.winGranularity := vali;
SYSTEM.GET(vmem+6, vali); p.winSize := vali;
SYSTEM.GET(vmem+8, vali); p.winASeg := vali;
SYSTEM.GET(vmem+10, vali); p.winBSeg := vali;
SYSTEM.GET(vmem+12, p.winFuncPtr);
SYSTEM.GET(vmem+16, vali); p.bytesPerScanLine := vali;
SYSTEM.GET(vmem+18, vali); p.xRes := vali;
SYSTEM.GET(vmem+20, vali); p.yRes := vali;
SYSTEM.GET(vmem+22, valc); p.xCharSize := ORD(valc);
SYSTEM.GET(vmem+23, valc); p.yCharSize := ORD(valc);
SYSTEM.GET(vmem+24, valc); p.nrOfPlanes := ORD(valc);
SYSTEM.GET(vmem+25, valc); p.bitsPerPixel := ORD(valc);
SYSTEM.GET(vmem+26, valc); p.nrOfBanks := ORD(valc);
SYSTEM.GET(vmem+27, valc); p.memoryModel := ORD(valc);
SYSTEM.GET(vmem+28, valc); p.bankSize := ORD(valc);
SYSTEM.GET(vmem+29, valc); p.nrOfImgPages := ORD(valc);
SYSTEM.GET(vmem+31, valc); p.redMaskSize := ORD(valc);
SYSTEM.GET(vmem+32, valc); p.redFieldPos := ORD(valc);
SYSTEM.GET(vmem+33, valc); p.greenMaskSize := ORD(valc);
SYSTEM.GET(vmem+34, valc); p.greenFieldPos := ORD(valc);
SYSTEM.GET(vmem+35, valc); p.blueMaskSize := ORD(valc);
SYSTEM.GET(vmem+36, valc); p.blueFieldPos := ORD(valc);
SYSTEM.GET(vmem+37, valc); p.rsvdMaskSize := ORD(valc);
SYSTEM.GET(vmem+38, valc); p.rsvdFieldPos := ORD(valc);
SYSTEM.GET(vmem+39, valc); p.directColorModeInfo := SYSTEM.VAL(SET, valc);
SYSTEM.GET(vmem+40, p.physBasePtr);
SYSTEM.GET(vmem+50, vali); p.linBytesPerScanLine := vali;
SYSTEM.GET(vmem+52, valc); p.bnkNrOfImgPages := ORD(valc);
SYSTEM.GET(vmem+53, valc); p.linNrOfImgPages := ORD(valc);
SYSTEM.GET(vmem+54, valc); p.linRedMaskSize := ORD(valc);
SYSTEM.GET(vmem+55, valc); p.linRedFieldPos := ORD(valc);
SYSTEM.GET(vmem+56, valc); p.linGreenMaskSize := ORD(valc);
SYSTEM.GET(vmem+57, valc); p.linGreenFieldPos := ORD(valc);
SYSTEM.GET(vmem+58, valc); p.linBlueMaskSize := ORD(valc);
SYSTEM.GET(vmem+59, valc); p.linBlueFieldPos := ORD(valc);
SYSTEM.GET(vmem+60, valc); p.linRsvdMaskSize := ORD(valc);
SYSTEM.GET(vmem+61, valc); p.linRsvdFieldPos := ORD(valc);
SYSTEM.GET(vmem+62, p.maxPixelClock);
Kernel.DisposeDMA(256, vmem); (* deallocate DMA buffer *)
END GetModeInfo;
PROCEDURE GetVideoModes(adr: LONGINT; VAR vmode: VideoMode);
VAR adr0: LONGINT; adr1, vali: INTEGER; p: VideoMode;
BEGIN
SYSTEM.GET(adr+2, adr1); adr0 := LONG(adr1) * 16;
SYSTEM.GET(adr, adr1); adr0 := adr0+adr1;
LOOP
SYSTEM.GET(adr0, vali);
IF vali = -1 THEN EXIT END;
NEW(p); p.next := vmode; vmode := p;
p.modeNr := vali;
GetModeInfo(p);
INC(adr0, 2)
END
END GetVideoModes;
PROCEDURE GetVBEControllerInfo;
VAR adr, vmem: LONGINT; regs: V86.Regs; vali: INTEGER; vals: SET;
BEGIN
vbe.vmodes := NIL;
Kernel.NewDMA(512, adr, vmem); (* allocate DMA buffer *)
ASSERT(vmem MOD 16 = 0); ASSERT(vmem < 100000H); (* sanity *)
ASSERT(adr = vmem); (* implementation restriction *)
SYSTEM.MOVE(SYSTEM.ADR("VBE2"), vmem, 4);
regs.EAX := 4F00H; regs.ES := SHORT(vmem DIV 16); regs.EDI := 0;
V86.Video(regs);
vbe.available := regs.EAX = 4FH;
IF vbe.available THEN
SYSTEM.MOVE(vmem, SYSTEM.ADR(vbe.sig), 4); vbe.sig[4] := 0X;
SYSTEM.GET(vmem+4, vali); vbe.version := vali;
CopyVBEString(vmem+6, vbe.oemString);
SYSTEM.GET(vmem+10, vals);
vbe.dac8 := 0 IN vals; vbe.vga := ~(1 IN vals); vbe.extDac := 2 IN vals;
vbe.stereo := 3 IN vals; vbe.stereoEVC := 4 IN vals;
GetVideoModes(vmem+14, vbe.vmodes);
SYSTEM.GET(vmem+18, vali); vbe.totalMem := LONG(vali)*64*1024;
SYSTEM.GET(vmem+20, vali); vbe.oemSoftwareRev := vali;
CopyVBEString(vmem+22, vbe.oemVendor);
CopyVBEString(vmem+26, vbe.oemProductName);
CopyVBEString(vmem+30, vbe.oemProductRev)
END;
Kernel.DisposeDMA(512, vmem); (* deallocate DMA buffer *)
END GetVBEControllerInfo;
PROCEDURE GetVideoBios;
BEGIN
GetVBEControllerInfo
END GetVideoBios;
PROCEDURE InitGtf;
BEGIN
GC.margin := 1.8; GC.cellGran := 8; GC.minPorch := 1; GC.vSyncRqd := 3;
GC.hSync := 8; GC.minVSyncBP := 550; GC.m := 600; GC.c := 40; GC.k := 128; GC.j := 20
END InitGtf;
PROCEDURE Init;
BEGIN
(* IF textsDebug THEN
NEW(T); Texts.Open(T, "");
Oberon.OpenText("", T, 400, 200);
Texts.OpenWriter(W)
END; *)
InitGtf;
GetVideoBios
END Init;
(* PROCEDURE DoSearch*;
VAR w, h, d, modeNr: LONGINT;
BEGIN
In.Open; In.LongInt(w); In.LongInt(h); In.LongInt(d);
IF In.Done THEN
modeNr := SearchVideoMode(w, h, d);
LogStr("Mode Nr: "); LogHex(modeNr); LogLn
END
END DoSearch;
PROCEDURE DoGetCurrentVideoMode*;
VAR modeNr: LONGINT;
BEGIN
modeNr := GetCurrentVideoMode();
LogStr("Mode Nr: "); LogHex(modeNr); LogLn
END DoGetCurrentVideoMode;
PROCEDURE DoSetVideoMode*;
VAR modeNr, res, w, h, d, vFreq: LONGINT;
BEGIN
In.Open; In.LongInt(w); In.LongInt(h); In.LongInt(d); In.LongInt(vFreq);
IF In.Done THEN
modeNr := SearchVideoMode(w, h, d); ASSERT(modeNr # 0, 100);
SetVideoMode(modeNr, vFreq, FALSE, TRUE, res); ASSERT(res = 0, 101)
END
END DoSetVideoMode; *)
BEGIN
Init
END DisplayTool.
DisplayTool.ShowVesaInfo
DisplayTool.DoSearch 1024 768 32
DisplayTool.DoGetCurrentVideoMode
DisplayTool.DoSetVideoMode 1024 768 32 105
DisplayTool.DoSetVideoMode 1024 768 32 100
DisplayTool.DoSetVideoMode 1600 1200 16 74
DisplayTool.DoSetVideoMode 1600 1200 16 60