Grüße, weiter gehts mit Vesa und den Tücken des Protected Modes.
Erstmal geht es um die Funktion AX=4F00 -> GET SuperVGA INFORMATION, die hier letztlich stellvertretend für so ziemlich alle Softwareinterrupts steht, die einen Zeiger für den Datenaustausch erwarten - in diesem Fall über die Register es:di.
Da der Interrupt im Realmode arbeitet habe ich natürlich über int $31, ax $100 ALLOCATE DOS MEMORY BLOCK Speicher im Bereich unter 1MB reserviert, praktischerweise bekomme ich gleich noch die RealMode Segmentadresse zu dem reservierten Speicher mitgeliefert - was ich auch erfolgreich für die Soundausgabe (DMA) nutze.
Tja und nun erstmal ein kleines Bild:
Erklärung dazu:
Hinter dem 'hi' steht ersteinmal die Adresse des Realmodesegments und darunter seht ihr jede Menge erfolgreich (79 (=$004F) bedeutet Int $10, AX $4F00 war erfolgreich) fehlgeschlagene ('blah' - eigentlich sollte da 'VESA' stehen) Aufrufe.
Und einen erfolgreich erfolgreichen: offenbar ist das mit der Zeigerübergabe an einen RM Int nicht ganz so einfach - sprich: wenn ihr einen Interruptaufruf aus einem PM Programm tätigen wollt braucht ihr die Funktion INT $31, AX $0300 Simulate Real Mode Interrupt.
Die Borland Pascal eigene Routine der Dos Unit funktioniert an der Stelle leider nicht.
und nun ein wenig QT:
erstmal das was geht
type DPMI_RMRegisters=record
EDI,ESI,EBP,RES,EBX,EDX,ECX,EAX:longint;
flags,ES,DS,FS,GS,IP,CS,SP,SS:word;
end;
function DPMI_SimulateRealModeInterrupt(IntNR:byte;var RMRegisters:DPMI_RMRegisters):boolean;
assembler;
asm
mov AX,$0300
mov BL,IntNR
xor BH,BH
xor CX,CX {Ich habe nicht vor etwas über den Stack zurückzugeben, daher CX=0}
les DI,RMRegisters
int $31
mov AX,$FF
jnc @end
mov AX,00
@end:
end;
t_Vesa^.Signature:='Blah';
t_Vesa^.Version:=0;
{erschtmal alles nullen}
DPMI_REGS.ESI:=0;DPMI_REGS.EBP:=0;DPMI_REGS.RES:=0;DPMI_REGS.EDX:=0;DPMI_REGS.ECX:=0;DPMI_REGS.EBX:=0;
DPMI_REGS.flags:=0;DPMI_REGS.DS:=0;DPMI_REGS.FS:=0;DPMI_REGS.GS:=0;DPMI_REGS.IP:=0;DPMI_REGS.CS:=0;
DPMI_REGS.SP:=0;DPMI_REGS.SS:=0;
DPMI_REGS.EAX:=$4F00;
DPMI_REGS.ES:=realseg;
DPMI_REGS.EDI:=0;
writeln(DPMI_SimulateRealModeInterrupt($10,DPMI_REGS));
Writeln('int$31 mit RM Pointer: ',DPMI_REGS.EAX,' 79=4F ',t_vesa^.Signature);
Alles anzeigen
Und nun die Gesamtheit:
unit DPMI;
interface
var DPMI_active:boolean; {wird beim Start Initialisiert}
type DPMI_RMRegisters=record
EDI,ESI,EBP,RES,EBX,EDX,ECX,EAX:longint;
flags,ES,DS,FS,GS,IP,CS,SP,SS:word;
end;
function DPMI_AllocateDosMemoryBlock(size:word;var PoinTR:pointer;var Realseg:word):boolean;
{Reserviert Speicher im Bereich <1MB nötig für RM Ints und DMA,
liefert einen Pascal Pointer und das dazugehörige
RealMode Segment zurück}
function DPMI_FreeDosMemoryBlock(var PoinTR:pointer):boolean; {gibt den Speicher wieder frei}
function DPMI_SegmentToDescriptor(RM:word;var PoinTR:Pointer):boolean;
function DPMI_SimulateRealModeInterrupt(IntNR:byte;var RMRegisters:DPMI_RMRegisters):boolean;
implementation
function DPMI_AllocateDosMemoryBlock(size:word;var PoinTR:pointer;var Realseg:word):boolean;
var helper:array[0..1]of word absolute PoinTR; {muss nochmal nachschauen wie asm mit var Parametern funktioniert}
var help2:word; {wurden afair als Zeiger behandelt}
var help3:word;
var ret:boolean;
begin
asm
mov ret,00
mov ax,$0100
mov bx,size
shr bx,4
int $31
jc @end
mov ret,$FF
mov help2,ax
mov help3,dx
@end:
end;
helper[1]:=help3; {helper liegt per absolute auf der Gleichen Speicheradresse wie}
helper[0]:=0; {PoinTR - einfachere Typkonvertierung}
{Protected Mode Pointer in Pascal sind 16+16Bit->Selektor+Offset}
realseg:=help2; {Das Realmoderegister}
DPMI_AllocateDosMemoryBlock:=ret; {Rückgabecode - Bool: $00=false;$FF=true}
end;
function DPMI_FreeDosMemoryBlock(var PoinTR:pointer):boolean;
var helper:array[0..1]of word absolute PoinTR;
var help2:word;
var ret:boolean;
begin
help2:=helper[1];
asm
mov ret,00
mov ax,$0101
mov dx,help2
int $31
jc @end
mov ret,$FF
@end:
end;
PoinTR:=nil;
DPMI_FreeDosMemoryBlock:=ret;
end;
function DPMI_SegmentToDescriptor(RM:word;var PoinTR:Pointer):boolean;
var helper:array[0..1]of word absolute PoinTR;
var help2:word;
var ret:boolean;
begin
asm
mov ret,$00
mov AX,$0002
mov BX,RM
int $31
jc @end
mov help2,AX
mov ret,$FF
@end:
end;
helper[1]:=help2;
helper[0]:=0;
DPMI_SegmentToDescriptor:=ret;
end;
function DPMI_SimulateRealModeInterrupt(IntNR:byte;var RMRegisters:DPMI_RMRegisters):boolean;
assembler;
asm
mov AX,$0300
mov BL,IntNR
xor BH,BH
xor CX,CX
les DI,RMRegisters
int $31
mov AX,$FF
jnc @end
mov AX,00
@end:
end;
begin
asm
mov ax,$0400 {Versionsabfrage für den DPMI Server}
int $31
mov DPMI_active,$FF {bool: $FF=true; $00=false}
cmp ax,90 {BP7 hat einen DPMI Server in Version 0.90, darauf teste ich}
jz @end
mov DPMI_active,$00
@end:
end;
end.
(* {DPMI Server Installcheck}
function DPMI_active:boolean;assembler; {liefert aus irgendeinem Grund im realmode}
asm {einen installierten DMPI zurück, aber im protected mode nichts}
mov ax,$1687
int $2F
mov test,ax
mov testproc,cl
mov testmaj,dh
mov testmin,dl
end;
*)
Alles anzeigen
Unit Graphics;
Interface
function InitVesa:boolean;
implementation
uses DPMI,DOS,crt;
function InitVesa:boolean;
type Vesa_ControllerInformation=record
Signature :array[0..3]of char; {Preload with 'VBE2' for VBE2 Informations}
Version :word;
OEMNamePTR :Pointer;
CapabilitiesFlags :longint; {D0 - 0 Dac is 6 Bit, 1 Dac is switchable to 8 Bit (resetted to 6Bit on Modechanges)}
{D1 - 0 VGA Compatible, 1 not VGA Compatible}
{D2 - 0 Normal Ramdac, 1 use blank Bit on Function $09}
SupportedModesPTR :array[0..1]of word; {terminated with $FFFF}
MemorySize64 :Word; {Use function 01 for available Memory}
Buffer :array[0..491]of byte;
end;
type t_Modelist=array[0..$FFF]of word;
var Modelist:^t_Modelist;
var t_Vesa:^Vesa_ControllerInformation;
var t_VesaPTR:Pointer absolute t_Vesa;
var DPMI_REGS:DPMI_RMRegisters;
var REGS:Registers;
var realseg:word;
var realsegptr:Pointer;
var realsegptrhelp:array[0..1]of word absolute realsegptr;
var ret:byte;
var halp:word;
begin
{Sattdessen einfach stumpf den Mode Setzen und hoffen das es läuft? Dann per 4F0A die Interfaces für Funktion 5/7/9 holen?}
if DPMI_AllocateDosMemoryBlock(sizeOf(t_Vesa^),Pointer(t_Vesa),Realseg) then
begin
writeln('hi ', realseg);
t_Vesa^.Signature:='Blah';
t_Vesa^.Version:=0;
REGS.AX:=$4F00;
REGS.DI:=0;
REGS.ES:=seg(t_vesa^);
INTR($10,REGS);
Writeln('Pascal mit PM Pointer: ',REGS.AX,' 79=4F ',t_vesa^.Signature);
t_Vesa^.Signature:='Blah';
t_Vesa^.Version:=0;
REGS.AX:=$4F00;
REGS.DI:=0;
REGS.ES:=Realseg;
INTR($10,REGS);
Writeln('Pascal mit RM Pointer: ',REGS.AX,' 79=4F ',t_vesa^.Signature);
t_Vesa^.Signature:='Blah';
t_Vesa^.Version:=0;
realsegptrhelp[0]:=realseg;
realsegptrhelp[1]:=0;
asm
push es
push di
mov ret,$ff
les di,t_vesa
mov ax,$4F00
int $10
mov halp,AX
cmp AX,$004F
je @end
mov ret,00
@end:
pop di
pop es
end;
Writeln('Assembler mit PM Pointer: ',halp,' 79=4F ',t_vesa^.Signature);
t_Vesa^.Signature:='Blah';
t_Vesa^.Version:=0;
asm
push es
push di
mov ret,$ff
les di,realsegPTR
mov ax,$4F00
int $10
mov halp,AX
cmp AX,$004F
je @end
mov ret,00
@end:
pop di
pop es
end;
Writeln('Assembler mit RM Pointer: ',halp,' 79=4F ',t_vesa^.Signature);
t_Vesa^.Signature:='Blah';
t_Vesa^.Version:=0;
{erschtmal alles nullen}
DPMI_REGS.ESI:=0;DPMI_REGS.EBP:=0;DPMI_REGS.RES:=0;DPMI_REGS.EDX:=0;DPMI_REGS.ECX:=0;DPMI_REGS.EBX:=0;
DPMI_REGS.flags:=0;DPMI_REGS.DS:=0;DPMI_REGS.FS:=0;DPMI_REGS.GS:=0;DPMI_REGS.IP:=0;DPMI_REGS.CS:=0;
DPMI_REGS.SP:=0;DPMI_REGS.SS:=0;
DPMI_REGS.EAX:=$4F00;
DPMI_REGS.ES:=realseg;
DPMI_REGS.EDI:=0;
writeln(DPMI_SimulateRealModeInterrupt($10,DPMI_REGS));
Writeln('int$31 mit RM Pointer: ',DPMI_REGS.EAX,' 79=4F ',t_vesa^.Signature);
{ if ret then begin
DPMI_SegmentToDescriptor(t_Vesa^.SupportedModesPTR[1]+(t_Vesa^.SupportedModesPTR[0]shr 4),Pointer(Modelist));
{DPMI_SegmentToDescriptor($A000,Pointer(Modelist));
realseg:=0;
while ((realseg<$1000)and(Modelist^[realseg]<>$FFFF))and(Modelist^[realseg]<>$0101) do
begin;writeln(Modelist^[realseg]);inc(realseg);readkey;end;
{search Modelist for 101}
{ end;}
end;
end;
end.
Alles anzeigen