erged from fixbranch

This commit is contained in:
michael 2000-09-24 08:21:35 +00:00
parent 404e950ed4
commit 4867ef1577
26 changed files with 1629 additions and 1334 deletions

View File

@ -1,118 +1,126 @@
{ example for :
global_dos_alloc()
global_dos_free()
trealregs / registers record
realintr()
DOS memory access
dosmemput()
dosmemget()
int31error variable
}
{ This program demonstrates the usage of DOS real mode memory by executing a
software interrupt which needs a buffer to store data into. Because these
interrupts are real mode funcs, the buffer must be located in real mode
memory space (first MB of memory). Such memory can only be allocated by
the global_dos_alloc() and global_dos_free() functions of the GO32 unit.
In more detail this program tries to detect a VESA 2.0 BIOS extension of
your graphics card and outputs its version.
Here's the necessary interrupt call description:
Int 10h 4f00h : VESA BIOS extension installation check
Input : AX = 4F00h
ES:DI = pointer to 512 byte information buffer
Output : AX = 004Fh if successful
ES:DI = pointer to filled buffer
Buffer structure : (relevant to this example)
must be 'VESA' in the first 4 chars of the buffer to be valid
VBE version in the next word
Note : to request VBE 2.0 information, the first 4 bytes of the buffer must
contain 'VBE2' prior to the interrupt call.
(this makes the problem a bit tougher; we first have to copy the
buffer with the 'VBE2' id to dos memory...)
}
uses go32;
{ The following 2 functions are wrappers to the GO32 global_dos_alloc() and
global_dos_free() functions to simplify their usage }
{ Function : dosalloc }
{ Input : size of a real mode location }
{ Output : selector and segment of a real mode location }
procedure dosalloc(var selector : word; var segment : word; size : longint);
var res : longint;
begin
{ try to allocate real mode memory }
res := global_dos_alloc(size);
{ the lower 16 bits of the result contain the selector to the allocated
memory block }
selector := word(res);
{ the upper 16 bits contain the real mode segment address of this block;
the offset is always 0, so we don't need to return this }
segment := word(res shr 16);
end;
{ Function : dosfree }
{ Input : selector of a real mode block }
{ Output : none }
{ Description : de-allocates a previously allocated real mode memory }
procedure dosfree(selector : word);
begin
{ call the GO32 function with the selector }
global_dos_free(selector);
end;
type VBEInfoBuf = record
Signature : array[0..3] of char; { contains 'VESA' if successful }
Version : Word;
reserved : array[0..505] of byte; { pad to 512 bytes length }
end;
var selector, { selector to our real mode buffer }
segment : Word; { real mode segment address of buffer }
r : trealregs; { register structure to issue a software interrupt }
infobuf : VBEInfoBuf;
begin
{ first we reset the registers and infobuf variable }
fillchar(r, sizeof(r), 0);
fillchar(infobuf, sizeof(VBEInfoBuf), 0);
{ allocate real mode memory }
dosalloc(selector, segment, sizeof(VBEInfoBuf));
{ check if an error occured during allocation }
if (int31error<>0) then begin
Writeln('Error while allocating real mode memory, halting');
halt;
end;
{ request VBE 2.0 information, fill out information buffer }
infobuf.Signature := 'VBE2';
{ copy buffer to the allocated real mode memory }
dosmemput(segment, 0, infobuf, sizeof(infobuf));
{ issue the interrupt; remember : DI = 0 }
r.ax := $4f00; r.es := segment;
realintr($10, r);
{ copy buffer to our infobuf variable again }
dosmemget(segment, 0, infobuf, sizeof(infobuf));
{ free allocated real mode memory, because we don't need it anymore }
dosfree(selector);
{ check if interrupt call was successful }
if (r.ax <> $4f) then begin
{ write message and exit, because the infobuf doesn't contain any
useful data we could tell the user }
Writeln('VBE BIOS extension not available, function call failed');
halt;
end;
{ check if buffer is valid }
if (infobuf.signature[0] = 'V') and (infobuf.signature[1] = 'E') and
(infobuf.signature[2] = 'S') and (infobuf.signature[3] = 'A') then begin
Writeln('VBE version ', hi(infobuf.version), '.', lo(infobuf.version), ' detected');
end;
{ This program demonstrates the usage of DOS real mode memory by
executing a software interrupt which needs a buffer to store data
into. Because these interrupts are real mode funcs, the buffer must
be located in real mode memory space (first MB of memory). Such
memory can only be allocated by the global_dos_alloc() and
global_dos_free() functions of the GO32 unit.
In more detail this program tries to detect a VESA 2.0 BIOS
extension of your graphics card and outputs its version.
Here's the necessary interrupt call description:
Int 10h 4f00h : VESA BIOS extension installation check
Input : AX = 4F00h
ES:DI = pointer to 512 byte information buffer
Output : AX = 004Fh if successful
ES:DI = pointer to filled buffer
Buffer structure : (relevant to this example)
must be 'VESA' in the first 4 chars of the buffer to be
valid VBE version in the next word
Note : to request VBE 2.0 information, the first 4 bytes of the
buffer must contain 'VBE2' prior to the interrupt call.
(this makes the problem a bit tougher; we first have to copy the
buffer with the 'VBE2' id to dos memory...)
}
uses
go32;
{The following 2 functions are wrappers to the GO32
global_dos_alloc() and global_dos_free() functions to simplify their
usage }
{ Function : dosalloc }
{ Input : size of a real mode location }
{ Output : selector and segment of a real mode location }
procedure dosalloc(var selector : word;
var segment : word; size : longint);
var
res : longint;
begin
{ try to allocate real mode memory }
res := global_dos_alloc(size);
{ the lower 16 bits of the result contain the selector to the
allocated memory block }
selector := word(res);
{ the upper 16 bits contain the real mode segment address of
this block; the offset is always 0, so we don't need to return
this }
segment := word(res shr 16);
end;
{ Function : dosfree }
{ Input : selector of a real mode block }
{ Output : none }
{ Description : de-allocates a previously allocated real mode
memory}
procedure dosfree(selector : word);
begin
{ call the GO32 function with the selector }
global_dos_free(selector);
end;
type
VBEInfoBuf = packed record
{ contains 'VESA' if successful }
Signature : array[0..3] of char;
Version : Word;
{ pad to 512 bytes length }
reserved : array[0..505] of byte;
end;
var
{ selector to our real mode buffer }
selector,
{ real mode segment address of buffer }
segment : Word;
{ register structure to issue a software interrupt }
r : trealregs;
infobuf : VBEInfoBuf;
begin
{ first we reset the registers and infobuf variable }
fillchar(r, sizeof(r), 0);
fillchar(infobuf, sizeof(VBEInfoBuf), 0);
{ allocate real mode memory }
dosalloc(selector, segment, sizeof(VBEInfoBuf));
{ check if an error occured during allocation }
if (int31error<>0) then begin
Writeln('Error while allocating real mode memory, halting');
halt;
end;
{ request VBE 2.0 information, fill out information buffer }
infobuf.Signature := 'VBE2';
{ copy buffer to the allocated real mode memory }
dosmemput(segment, 0, infobuf, sizeof(infobuf));
{ issue the interrupt; remember : DI = 0 }
r.ax := $4f00; r.es := segment;
realintr($10, r);
{ copy buffer to our infobuf variable again }
dosmemget(segment, 0, infobuf, sizeof(infobuf));
{ free allocated real mode memory, because we don't need it
anymore }
dosfree(selector);
{ check if interrupt call was successful }
if (r.ax <> $4f) then begin
{ write message and exit, because the infobuf doesn't contain
any useful data we could tell the user }
Writeln('VBE BIOS extension not available, function call ',
'failed');
halt;
end;
{ check if buffer is valid }
if (infobuf.signature[0] = 'V') and
(infobuf.signature[1] = 'E') and
(infobuf.signature[2] = 'S') and
(infobuf.signature[3] = 'A') then begin
Writeln('VBE version ', hi(infobuf.version), '.',
lo(infobuf.version), ' detected');
end;
end.

View File

@ -1,52 +1,59 @@
Program buffer;
uses go32;
procedure dosalloc(var selector : word; var segment : word; size : longint);
var res : longint;
begin
res := global_dos_alloc(size);
selector := word(res);
segment := word(res shr 16);
end;
procedure dosfree(selector : word);
begin
global_dos_free(selector);
end;
type VBEInfoBuf = record
Signature : array[0..3] of char;
Version : Word;
reserved : array[0..505] of byte;
end;
var selector,
segment : Word;
r : trealregs;
infobuf : VBEInfoBuf;
begin
fillchar(r, sizeof(r), 0);
fillchar(infobuf, sizeof(VBEInfoBuf), 0);
dosalloc(selector, segment, sizeof(VBEInfoBuf));
if (int31error<>0) then begin
Writeln('Error while allocating real mode memory, halting');
halt;
end;
infobuf.Signature := 'VBE2';
dosmemput(segment, 0, infobuf, sizeof(infobuf));
r.ax := $4f00; r.es := segment;
realintr($10, r);
dosmemget(segment, 0, infobuf, sizeof(infobuf));
dosfree(selector);
if (r.ax <> $4f) then begin
Writeln('VBE BIOS extension not available, function call failed');
halt;
end;
if (infobuf.signature[0] = 'V') and (infobuf.signature[1] = 'E') and
(infobuf.signature[2] = 'S') and (infobuf.signature[3] = 'A') then begin
Writeln('VBE version ', hi(infobuf.version), '.', lo(infobuf.version), ' detected');
end;
uses
go32;
procedure dosalloc(var selector : word;
var segment : word; size : longint);
var
res : longint;
begin
res := global_dos_alloc(size);
selector := word(res);
segment := word(res shr 16);
end;
procedure dosfree(selector : word);
begin
global_dos_free(selector);
end;
type
VBEInfoBuf = packed record
Signature : array[0..3] of char;
Version : Word;
reserved : array[0..505] of byte;
end;
var
selector,
segment : Word;
r : trealregs;
infobuf : VBEInfoBuf;
begin
fillchar(r, sizeof(r), 0);
fillchar(infobuf, sizeof(VBEInfoBuf), 0);
dosalloc(selector, segment, sizeof(VBEInfoBuf));
if (int31error<>0) then begin
Writeln('Error while allocating real mode memory, halting');
halt;
end;
infobuf.Signature := 'VBE2';
dosmemput(segment, 0, infobuf, sizeof(infobuf));
r.ax := $4f00; r.es := segment;
realintr($10, r);
dosmemget(segment, 0, infobuf, sizeof(infobuf));
dosfree(selector);
if (r.ax <> $4f) then begin
Writeln('VBE BIOS extension not available, function call ',
'failed');
halt;
end;
if (infobuf.signature[0] = 'V') and
(infobuf.signature[1] = 'E') and
(infobuf.signature[2] = 'S') and
(infobuf.signature[3] = 'A') then begin
Writeln('VBE version ', hi(infobuf.version), '.',
lo(infobuf.version), ' detected');
end;
end.

View File

@ -1,227 +1,238 @@
{ example for :
get_rm_callback()
free_rm_callback()
realintr()
Callbacks
lock_code()
unlock_code()
lock_data()
unlock_data()
trealregs record
tseginfo record
}
{ This program tries to give an example how to install a callback procedure
with the help of the GO32 unit.
It installs a callback which is supplied by any Mircosoft compatible
mouse driver; at a specified mouse action this routine is called. This
callback must provide the services explained in the docs. The main callback
has to be in assembly, because it isn't possible to do these services with
pascal alone. But is written as general as possible to provide maximum
re-usability for other applications and hence it simply calls a normal
pascal user procedure in addition to some initialization and callback
service code, so you don't need to hassle around with it too much.
Notes to this user procedure :
*) it should not last too long to execute it
*) ALL data and code touched in this proc MUST be locked BEFORE it is called
the first time
Used software interrupt calls (rough descriptions, only what's used):
Int 33h 0000h - Mircosoft Mouse driver : Reset mouse
Input : AX = 0000h
Return : AX = FFFFh if successful
BX = number of buttons (if FFFFh then mouse has 2 buttons)
Int 33h 0001h - Mircosoft Mouse driver : Show mouse cursor
Input : AX = 0001h
Return : Mouse cursor shown on screen
Int 33h 0002h - Mircosoft mouse driver : Hide mouse cursor
Input : AX = 0002h
Return : Hides mouse cursor again
Int 33h 000Ch - Mircosoft mouse driver : Install user callback
Input : AX = 000Ch
CX = bit mask which tells the mouse driver at which actions the
callback should be called, i.e. if button pressed, mouse moved,
...
(In this example it's set to 7Fh so that the callback is called
on every action)
ES:EDX = pointer to callback procedure to call
Note : The registers structure supplied to the callback contains valid
mouse data when the handler is called.
BX = button state information
CX = mouse X coordinates
DX = mouse Y coordinates
For more detailed information consult any mouse reference or interrupt list.
}
uses crt, { keypressed(), gotoxy(), wherey(), clrscr() }
go32;
const mouseint = $33; { the mouse interrupt number }
var mouse_regs : trealregs; { supplied register structure to the callback }
mouse_seginfo : tseginfo; { real mode 48 bit pointer to the callback }
var mouse_numbuttons : longint;{ number of mouse buttons }
mouse_action : word; { bit mask for the action which triggered the callback }
mouse_x, mouse_y : Word; { current mouse x and y coordinates }
mouse_b : Word; { button state }
userproc_installed : Longbool; { is an additional user procedure installed }
userproc_length : Longint; { length of additional user procedure }
userproc_proc : pointer; { pointer to user proc }
{$ASMMODE DIRECT}
{ callback control handler, calls a user procedure if installed }
procedure callback_handler; assembler;
asm
pushw %es
pushw %ds
pushl %edi
pushl %esi { es:edi is the pointer to real mode regs record }
{ give control to user procedure if installed }
cmpl $1, _USERPROC_INSTALLED
je .LNoCallback
pushal
movw %es, %ax { set es = ds, FPC wants this so that some procs work }
movw %ax, %ds
movw U_GO32_DOSMEMSELECTOR, %ax
movw %ax, %fs { set fs for FPC }
call *_USERPROC_PROC
popal
.LNoCallback:
popl %esi
popl %edi
popw %ds
popw %es
movl (%esi), %eax
movl %eax, %es: 42(%edi) { adjust stack }
addw $4, %es: 46(%edi)
iret
end;
{ This dummy is used to obtain the length of the callback control function.
It has to be right after the callback_handler() function.
}
procedure mouse_dummy; begin end;
{ This is the supplied user procedure. In this case we simply transform the
virtual 640x200 mouse coordinate system to a 80x25 text mode coordinate
system }
procedure textuserproc;
begin
{ the mouse_regs record contains the real mode registers now }
mouse_b := mouse_regs.bx;
mouse_x := (mouse_regs.cx shr 3) + 1;
mouse_y := (mouse_regs.dx shr 3) + 1;
end;
{ Description : Installs the mouse callback control handler and handles all
necessary mouse related initialization.
Input : userproc - pointer to a user procedure, nil if none
userproclen - length of user procedure
}
procedure install_mouse(userproc : pointer; userproclen : longint);
var r : trealregs;
begin
{ mouse driver reset }
r.eax := $0; realintr(mouseint, r);
if (r.eax <> $FFFF) then begin
Writeln('No Mircosoft compatible mouse found');
Writeln('A Mircosoft compatible mouse driver is necessary to run this example');
halt;
end;
{ obtain number of mouse buttons }
if (r.bx = $ffff) then mouse_numbuttons := 2
else mouse_numbuttons := r.bx;
Writeln(mouse_numbuttons, ' button Mircosoft compatible mouse found.');
{ check for additional user procedure, and install it if available }
if (userproc <> nil) then begin
userproc_proc := userproc;
userproc_installed := true;
userproc_length := userproclen;
{ lock code for user procedure }
lock_code(userproc_proc, userproc_length);
end else begin
{ clear variables }
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
{ lock code & data which is touched in the callback handler }
lock_data(mouse_x, sizeof(mouse_x));
lock_data(mouse_y, sizeof(mouse_y));
lock_data(mouse_b, sizeof(mouse_b));
lock_data(mouse_action, sizeof(mouse_action));
lock_data(userproc_installed, sizeof(userproc_installed));
lock_data(@userproc_proc, sizeof(userproc_proc));
lock_data(mouse_regs, sizeof(mouse_regs));
lock_data(mouse_seginfo, sizeof(mouse_seginfo));
lock_code(@callback_handler, longint(@mouse_dummy)-longint(@callback_handler));
{ allocate callback (supply registers structure) }
get_rm_callback(@callback_handler, mouse_regs, mouse_seginfo);
{ install callback }
r.eax := $0c; r.ecx := $7f; r.edx := longint(mouse_seginfo.offset);
r.es := mouse_seginfo.segment;
realintr(mouseint, r);
{ show mouse cursor }
r.eax := $01;
realintr(mouseint, r);
end;
procedure remove_mouse;
var r : trealregs;
begin
{ hide mouse cursor }
r.eax := $02; realintr(mouseint, r);
{ remove callback handler }
r.eax := $0c; r.ecx := 0; r.edx := 0; r.es := 0;
realintr(mouseint, r);
{ free callback }
free_rm_callback(mouse_seginfo);
{ check if additional userproc is installed, and clean up if needed }
if (userproc_installed) then begin
unlock_code(userproc_proc, userproc_length);
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
{ unlock used code & data }
unlock_data(mouse_x, sizeof(mouse_x));
unlock_data(mouse_y, sizeof(mouse_y));
unlock_data(mouse_b, sizeof(mouse_b));
unlock_data(mouse_action, sizeof(mouse_action));
unlock_data(@userproc_proc, sizeof(userproc_proc));
unlock_data(userproc_installed, sizeof(userproc_installed));
unlock_data(mouse_regs, sizeof(mouse_regs));
unlock_data(mouse_seginfo, sizeof(mouse_seginfo));
unlock_code(@callback_handler, longint(@mouse_dummy)-longint(@callback_handler));
fillchar(mouse_seginfo, sizeof(mouse_seginfo), 0);
end;
begin
install_mouse(@textuserproc, 400);
Writeln('Press any key to exit...');
while (not keypressed) do begin
{ write mouse state info }
gotoxy(1, wherey);
write('MouseX : ', mouse_x:2, ' MouseY : ', mouse_y:2, ' Buttons : ', mouse_b:2);
end;
remove_mouse;
{ This program tries to give an example how to install a callback
procedure with the help of the GO32 unit.
It installs a callback which is supplied by any Microsoft compatible
mouse driver; at a specified mouse action this routine is called.
This callback must provide the services explained in the docs. The
main callback has to be in assembly, because it isn't possible to do
these services with pascal alone. But is written as general as
possible to provide maximum re-usability for other applications and
hence it simply calls a normal pascal user procedure in addition to
some initialization and callback service code, so you don't need to
hassle around with it too much.
Notes to this user procedure :
*) it should not last too long to execute it
*) ALL data and code touched in this proc MUST be locked BEFORE it is
called the first time
Used software interrupt calls (rough descriptions, only what's used):
Int 33h 0000h - Microsoft Mouse driver : Reset mouse
Input : AX = 0000h
Return : AX = FFFFh if successful
BX = number of buttons (if FFFFh then mouse has 2 buttons)
Int 33h 0001h - Microsoft Mouse driver : Show mouse cursor
Input : AX = 0001h
Return : Mouse cursor shown on screen
Int 33h 0002h - Microsoft mouse driver : Hide mouse cursor
Input : AX = 0002h
Return : Hides mouse cursor again
Int 33h 000Ch - Microsoft mouse driver : Install user callback
Input : AX = 000Ch
CX = bit mask which tells the mouse driver at which actions
the callback should be called, i.e. if button pressed, mouse
moved etc.
(In this example it's set to 7Fh so that the callback is
called on every action)
ES:EDX = pointer to callback procedure to call
Note : The registers structure supplied to the callback contains
valid mouse data when the handler is called.
BX = button state information
CX = mouse X coordinates
DX = mouse Y coordinates
For more detailed information consult any mouse reference or
interrupt list.
}
{$ASMMODE ATT}
{$MODE FPC}
uses
crt,
go32;
const
{ the mouse interrupt number }
mouseint = $33;
var
{ supplied register structure to the callback }
mouse_regs : trealregs; external name '___v2prt0_rmcb_regs';
{ real mode 48 bit pointer to the callback }
mouse_seginfo : tseginfo;
var
{ number of mouse buttons }
mouse_numbuttons : longint;
{ bit mask for the action which triggered the callback }
mouse_action : word;
{ current mouse x and y coordinates }
mouse_x, mouse_y : Word;
{ button state }
mouse_b : Word;
{ is an additional user procedure installed }
userproc_installed : Longbool;
{ length of additional user procedure }
userproc_length : Longint;
{ pointer to user proc }
userproc_proc : pointer;
{ callback control handler, calls a user procedure if installed }
{ callback control handler, calls a user procedure if installed }
procedure callback_handler; assembler;
asm
pushw %ds
pushl %eax
movw %es, %ax
movw %ax, %ds
{ give control to user procedure if installed }
cmpl $1, USERPROC_INSTALLED
jne .LNoCallback
pushal
movw DOSmemSELECTOR, %ax
movw %ax, %fs { set fs for FPC }
call *USERPROC_PROC
popal
.LNoCallback:
popl %eax
popw %ds
pushl %eax
movl (%esi), %eax
movl %eax, %es: 42(%edi) { adjust stack }
addw $4, %es:46(%edi)
popl %eax
iret
end;
{ This dummy is used to obtain the length of the callback control
function. It has to be right after the callback_handler() function.
}
procedure mouse_dummy; begin end;
{ This is the supplied user procedure. In this case we simply
transform the virtual 640x200 mouse coordinate system to a 80x25
text mode coordinate system }
procedure textuserproc;
begin
{ the mouse_regs record contains the real mode registers now }
mouse_b := mouse_regs.bx;
mouse_x := (mouse_regs.cx shr 3) + 1;
mouse_y := (mouse_regs.dx shr 3) + 1;
end;
{ Description : Installs the mouse callback control handler and
handles all necessary mouse related initialization.
Input : userproc - pointer to a user procedure, nil if none
userproclen - length of user procedure
}
procedure install_mouse(userproc : pointer; userproclen : longint);
var r : trealregs;
begin
{ mouse driver reset }
r.eax := $0; realintr(mouseint, r);
if (r.eax <> $FFFF) then begin
Writeln('No Microsoft compatible mouse found');
Writeln('A Microsoft compatible mouse driver is necessary ',
'to run this example');
halt;
end;
{ obtain number of mouse buttons }
if (r.bx = $ffff) then mouse_numbuttons := 2
else mouse_numbuttons := r.bx;
Writeln(mouse_numbuttons, ' button Microsoft compatible mouse ',
' found.');
{ check for additional user procedure, and install it if
available }
if (userproc <> nil) then begin
userproc_proc := userproc;
userproc_installed := true;
userproc_length := userproclen;
{ lock code for user procedure }
lock_code(userproc_proc, userproc_length);
end else begin
{ clear variables }
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
{ lock code & data which is touched in the callback handler }
lock_data(mouse_x, sizeof(mouse_x));
lock_data(mouse_y, sizeof(mouse_y));
lock_data(mouse_b, sizeof(mouse_b));
lock_data(mouse_action, sizeof(mouse_action));
lock_data(userproc_installed, sizeof(userproc_installed));
lock_data(userproc_proc, sizeof(userproc_proc));
lock_data(mouse_regs, sizeof(mouse_regs));
lock_data(mouse_seginfo, sizeof(mouse_seginfo));
lock_code(@callback_handler,
longint(@mouse_dummy)-longint(@callback_handler));
{ allocate callback (supply registers structure) }
get_rm_callback(@callback_handler, mouse_regs, mouse_seginfo);
{ install callback }
r.eax := $0c; r.ecx := $7f;
r.edx := longint(mouse_seginfo.offset);
r.es := mouse_seginfo.segment;
realintr(mouseint, r);
{ show mouse cursor }
r.eax := $01;
realintr(mouseint, r);
end;
procedure remove_mouse;
var
r : trealregs;
begin
{ hide mouse cursor }
r.eax := $02; realintr(mouseint, r);
{ remove callback handler }
r.eax := $0c; r.ecx := 0; r.edx := 0; r.es := 0;
realintr(mouseint, r);
{ free callback }
free_rm_callback(mouse_seginfo);
{ check if additional userproc is installed, and clean up if
needed }
if (userproc_installed) then begin
unlock_code(userproc_proc, userproc_length);
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
{ unlock used code & data }
unlock_data(mouse_x, sizeof(mouse_x));
unlock_data(mouse_y, sizeof(mouse_y));
unlock_data(mouse_b, sizeof(mouse_b));
unlock_data(mouse_action, sizeof(mouse_action));
unlock_data(userproc_proc, sizeof(userproc_proc));
unlock_data(userproc_installed, sizeof(userproc_installed));
unlock_data(mouse_regs, sizeof(mouse_regs));
unlock_data(mouse_seginfo, sizeof(mouse_seginfo));
unlock_code(@callback_handler,
longint(@mouse_dummy)-longint(@callback_handler));
fillchar(mouse_seginfo, sizeof(mouse_seginfo), 0);
end;
begin
install_mouse(@textuserproc, 400);
Writeln('Press any key to exit...');
while (not keypressed) do begin
{ write mouse state info }
gotoxy(1, wherey);
write('MouseX : ', mouse_x:2, ' MouseY : ', mouse_y:2,
' Buttons : ', mouse_b:2);
end;
remove_mouse;
end.

View File

@ -1,147 +1,145 @@
Program callback;
uses crt,
go32;
const mouseint = $33;
var mouse_regs : trealregs;
mouse_seginfo : tseginfo;
var mouse_numbuttons : longint;
mouse_action : word;
mouse_x, mouse_y : Word;
mouse_b : Word;
userproc_installed : Longbool;
userproc_length : Longint;
userproc_proc : pointer;
{$ASMMODE DIRECT}
procedure callback_handler; assembler;
asm
pushw %es
pushw %ds
pushl %edi
pushl %esi
cmpl $1, _USERPROC_INSTALLED
je .LNoCallback
pushal
movw %es, %ax
movw %ax, %ds
movw U_GO32_DOSMEMSELECTOR, %ax
movw %ax, %fs
call *_USERPROC_PROC
popal
.LNoCallback:
popl %esi
popl %edi
popw %ds
popw %es
movl (%esi), %eax
movl %eax, %es: 42(%edi)
addw $4, %es: 46(%edi)
iret
end;
procedure mouse_dummy; begin end;
procedure textuserproc;
begin
mouse_b := mouse_regs.bx;
mouse_x := (mouse_regs.cx shr 3) + 1;
mouse_y := (mouse_regs.dx shr 3) + 1;
end;
procedure install_mouse (userproc : pointer;
userproclen : longint);
var r : trealregs;
begin
r.eax := $0; realintr(mouseint, r);
if (r.eax <> $FFFF) then begin
Writeln('No Mircosoft compatible mouse found');
Write('A Mircosoft compatible mouse driver is');
writeln(' necessary to run this example');
halt;
end;
if (r.bx = $ffff) then mouse_numbuttons := 2
else mouse_numbuttons := r.bx;
Writeln(mouse_numbuttons,
' button Mircosoft compatible mouse found.');
if (userproc <> nil) then begin
userproc_proc := userproc;
userproc_installed := true;
userproc_length := userproclen;
lock_code(userproc_proc, userproc_length);
end else begin
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
lock_data(mouse_x, sizeof(mouse_x));
lock_data(mouse_y, sizeof(mouse_y));
lock_data(mouse_b, sizeof(mouse_b));
lock_data(mouse_action, sizeof(mouse_action));
lock_data(userproc_installed, sizeof(userproc_installed));
lock_data(@userproc_proc, sizeof(userproc_proc));
lock_data(mouse_regs, sizeof(mouse_regs));
lock_data(mouse_seginfo, sizeof(mouse_seginfo));
lock_code(@callback_handler,
longint(@mouse_dummy)
- longint(@callback_handler));
get_rm_callback(@callback_handler, mouse_regs, mouse_seginfo);
r.eax := $0c; r.ecx := $7f; r.edx := longint(mouse_seginfo.offset);
r.es := mouse_seginfo.segment;
realintr(mouseint, r);
r.eax := $01;
realintr(mouseint, r);
end;
procedure remove_mouse;
var r : trealregs;
begin
r.eax := $02; realintr(mouseint, r);
r.eax := $0c; r.ecx := 0; r.edx := 0; r.es := 0;
realintr(mouseint, r);
free_rm_callback(mouse_seginfo);
if (userproc_installed) then begin
unlock_code(userproc_proc, userproc_length);
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
unlock_data(mouse_x, sizeof(mouse_x));
unlock_data(mouse_y, sizeof(mouse_y));
unlock_data(mouse_b, sizeof(mouse_b));
unlock_data(mouse_action, sizeof(mouse_action));
unlock_data(@userproc_proc, sizeof(userproc_proc));
unlock_data(userproc_installed,
sizeof(userproc_installed));
unlock_data(mouse_regs, sizeof(mouse_regs));
unlock_data(mouse_seginfo, sizeof(mouse_seginfo));
unlock_code(@callback_handler,
longint(@mouse_dummy)
- longint(@callback_handler));
fillchar(mouse_seginfo, sizeof(mouse_seginfo), 0);
end;
begin
install_mouse(@textuserproc, 400);
Writeln('Press any key to exit...');
while (not keypressed) do begin
{ write mouse state info }
gotoxy(1, wherey);
write('MouseX : ', mouse_x:2,
' MouseY : ', mouse_y:2,
' Buttons : ', mouse_b:2);
end;
remove_mouse;
{$ASMMODE ATT}
{$MODE FPC}
uses
crt,
go32;
const
mouseint = $33;
var
mouse_regs : trealregs; external name '___v2prt0_rmcb_regs';
mouse_seginfo : tseginfo;
var
mouse_numbuttons : longint;
mouse_action : word;
mouse_x, mouse_y : Word;
mouse_b : Word;
userproc_installed : Longbool;
userproc_length : Longint;
userproc_proc : pointer;
procedure callback_handler; assembler;
asm
pushw %ds
pushl %eax
movw %es, %ax
movw %ax, %ds
cmpl $1, USERPROC_INSTALLED
jne .LNoCallback
pushal
movw DOSmemSELECTOR, %ax
movw %ax, %fs
call *USERPROC_PROC
popal
.LNoCallback:
popl %eax
popw %ds
pushl %eax
movl (%esi), %eax
movl %eax, %es: 42(%edi)
addw $4, %es:46(%edi)
popl %eax
iret
end;
procedure mouse_dummy; begin end;
procedure textuserproc;
begin
mouse_b := mouse_regs.bx;
mouse_x := (mouse_regs.cx shr 3) + 1;
mouse_y := (mouse_regs.dx shr 3) + 1;
end;
procedure install_mouse(userproc : pointer; userproclen : longint);
var r : trealregs;
begin
r.eax := $0; realintr(mouseint, r);
if (r.eax <> $FFFF) then begin
Writeln('No Microsoft compatible mouse found');
Writeln('A Microsoft compatible mouse driver is necessary ',
'to run this example');
halt;
end;
if (r.bx = $ffff) then mouse_numbuttons := 2
else mouse_numbuttons := r.bx;
Writeln(mouse_numbuttons, ' button Microsoft compatible mouse ',
' found.');
if (userproc <> nil) then begin
userproc_proc := userproc;
userproc_installed := true;
userproc_length := userproclen;
lock_code(userproc_proc, userproc_length);
end else begin
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
lock_data(mouse_x, sizeof(mouse_x));
lock_data(mouse_y, sizeof(mouse_y));
lock_data(mouse_b, sizeof(mouse_b));
lock_data(mouse_action, sizeof(mouse_action));
lock_data(userproc_installed, sizeof(userproc_installed));
lock_data(userproc_proc, sizeof(userproc_proc));
lock_data(mouse_regs, sizeof(mouse_regs));
lock_data(mouse_seginfo, sizeof(mouse_seginfo));
lock_code(@callback_handler,
longint(@mouse_dummy)-longint(@callback_handler));
get_rm_callback(@callback_handler, mouse_regs, mouse_seginfo);
r.eax := $0c; r.ecx := $7f;
r.edx := longint(mouse_seginfo.offset);
r.es := mouse_seginfo.segment;
realintr(mouseint, r);
r.eax := $01;
realintr(mouseint, r);
end;
procedure remove_mouse;
var
r : trealregs;
begin
r.eax := $02; realintr(mouseint, r);
r.eax := $0c; r.ecx := 0; r.edx := 0; r.es := 0;
realintr(mouseint, r);
free_rm_callback(mouse_seginfo);
if (userproc_installed) then begin
unlock_code(userproc_proc, userproc_length);
userproc_proc := nil;
userproc_length := 0;
userproc_installed := false;
end;
unlock_data(mouse_x, sizeof(mouse_x));
unlock_data(mouse_y, sizeof(mouse_y));
unlock_data(mouse_b, sizeof(mouse_b));
unlock_data(mouse_action, sizeof(mouse_action));
unlock_data(userproc_proc, sizeof(userproc_proc));
unlock_data(userproc_installed, sizeof(userproc_installed));
unlock_data(mouse_regs, sizeof(mouse_regs));
unlock_data(mouse_seginfo, sizeof(mouse_seginfo));
unlock_code(@callback_handler,
longint(@mouse_dummy)-longint(@callback_handler));
fillchar(mouse_seginfo, sizeof(mouse_seginfo), 0);
end;
begin
install_mouse(@textuserproc, 400);
Writeln('Press any key to exit...');
while (not keypressed) do begin
gotoxy(1, wherey);
write('MouseX : ', mouse_x:2, ' MouseY : ', mouse_y:2,
' Buttons : ', mouse_b:2);
end;
remove_mouse;
end.

View File

@ -1,33 +1,32 @@
{ example for :
realintr()
flags constants
trealregs record
}
{ This example demonstrates the use of the flag constants in conjunction with
an interrupt call
In detail it checks if APM (advanced power management) is available.
Int 15h 5300h - APM specification : Installation check
Input : AX = 5300h
BX = device id of system BIOS (= 0000h)
Return : Carry clear if successful
AH = major version (BCD)
AL = minor version (BCD)
}
uses go32;
var r : trealregs;
begin
{ set register values and issue real mode interrupt call }
r.ax := $5300;
r.bx := 0;
realintr($15, r);
{ check if carry clear and write a suited message }
if ((r.flags and carryflag)=0) then begin
Writeln('APM v', (r.ah and $f), '.', (r.al shr 4), (r.al and $f), ' detected');
end else
Writeln('APM not present');
{ This example demonstrates the use of the flag constants in
conjunction with an interrupt call
In detail it checks if APM (advanced power management) is
available.
Int 15h 5300h - APM specification : Installation check
Input : AX = 5300h
BX = device id of system BIOS (= 0000h)
Return : Carry clear if successful
AH = major version (BCD)
AL = minor version (BCD)
}
uses
go32;
var
r : trealregs;
begin
{ set register values and issue real mode interrupt call }
r.ax := $5300;
r.bx := 0;
realintr($15, r);
{ check if carry clear and write a suited message }
if ((r.flags and carryflag)=0) then begin
Writeln('APM v', (r.ah and $f), '.',
(r.al shr 4), (r.al and $f), ' detected');
end else
Writeln('APM not present');
end.

View File

@ -1,18 +1,16 @@
Program flags;
uses go32;
var r : trealregs;
begin
r.ax := $5300;
r.bx := 0;
realintr($15, r);
{ check if carry clear and write a suited message }
if ((r.flags and carryflag)=0) then begin
Writeln('APM v',(r.ah and $f),
'.', (r.al shr 4), (r.al and $f),
' detected');
end else
Writeln('APM not present');
uses
go32;
var
r : trealregs;
begin
r.ax := $5300;
r.bx := 0;
realintr($15, r);
if ((r.flags and carryflag)=0) then begin
Writeln('APM v', (r.ah and $f), '.',
(r.al shr 4), (r.al and $f), ' detected');
end else
Writeln('APM not present');
end.

View File

@ -1,19 +1,25 @@
{ example program for
get_run_mode() + constants
}
{ Simply write a message according to the current environment }
uses go32;
begin
{ depending on the detected environment we simply write another message
}
case (get_run_mode) of
rm_unknown : Writeln('Unknown environment found');
rm_raw : Writeln('You are currently running in raw mode (without HIMEM)');
rm_xms : Writeln('You are currently using HIMEM.SYS only');
rm_vcpi : Writeln('VCPI server detected. You''re using HIMEM and EMM386');
rm_dpmi : Writeln('DPMI detected. You''re using a DPMI host like a windows DOS box or CWSDPMI');
end;
{ Simply write a message according to the current environment }
uses
go32;
begin
{ depending on the detected environment we simply write
another message Note: in go32v2 this will always be rm_dpmi. }
case (get_run_mode) of
rm_unknown :
Writeln('Unknown environment found');
rm_raw :
Writeln('You are currently running in raw mode ',
'(without HIMEM)');
rm_xms :
Writeln('You are currently using HIMEM.SYS only');
rm_vcpi :
Writeln('VCPI server detected. You''re using HIMEM and ',
'EMM386');
rm_dpmi :
Writeln('DPMI detected. You''re using a DPMI host like ',
'a windows DOS box or CWSDPMI');
end;
end.

View File

@ -1,26 +1,20 @@
Program getrunmd;
uses go32;
begin
{
depending on the detected environment,
we simply write another message
}
case (get_run_mode) of
rm_unknown :
Writeln('Unknown environment found');
rm_raw :
Writeln('You are currently running in raw mode',
' (without HIMEM)');
rm_xms :
Writeln('You are currently using HIMEM.SYS only');
rm_vcpi :
Writeln('VCPI server detected.',
' You''re using HIMEM and EMM386');
rm_dpmi :
Writeln('DPMI detected.',
' You''re using a DPMI host like ',
'a windows DOS box or CWSDPMI');
end;
uses
go32;
begin
case (get_run_mode) of
rm_unknown :
Writeln('Unknown environment found');
rm_raw :
Writeln('You are currently running in raw mode ',
'(without HIMEM)');
rm_xms :
Writeln('You are currently using HIMEM.SYS only');
rm_vcpi :
Writeln('VCPI server detected. You''re using HIMEM and ',
'EMM386');
rm_dpmi :
Writeln('DPMI detected. You''re using a DPMI host like ',
'a windows DOS box or CWSDPMI');
end;
end.

68
docs/go32ex/intpm.pas Normal file
View File

@ -0,0 +1,68 @@
{ This example shows how to redirect a software interrupt by
changing the protected mode handler of the DPMI host.
In more detail it hooks interrupt 1Ch which is called every
time the timer interrupt (int 08) is executed. This is the
preferred way to hook the timer, because int 1Ch is a software
interrupt which doesn't need so much initialization stuff
compared to hooking a hardware interrupt.
}
uses
crt,
go32;
const
{ interrupt number we want to hook }
int1c = $1c;
var
{ 48 bit pointer to old interrupt handler }
oldint1c : tseginfo;
{ 48 bit pointer to new interrupt handler }
newint1c : tseginfo;
{ increased every time the interrupt is called }
int1c_counter : Longint;
{ the current data selector }
int1c_ds : Word; external name '___v2prt0_ds_alias';
{ the actual handler code }
procedure int1c_handler; assembler;
asm
cli
{ save all registers }
pushw %ds
pushw %ax
{ prepare segment registers for FPC procedure }
movw %cs:int1c_ds, %ax
movw %ax, %ds
{ simply increase the counter by one }
incl int1c_counter
{ restore registers }
popw %ax
popw %ds
sti
iret
end;
var i : Longint;
begin
{ insert right handler data into new handler variable }
newint1c.offset := @int1c_handler;
newint1c.segment := get_cs;
{ get the old handler }
get_pm_interrupt(int1c, oldint1c);
Writeln('-- Press any key to exit --');
{ set new handler }
set_pm_interrupt(int1c, newint1c);
{ write the number of interrupts occured }
while (not keypressed) do begin
gotoxy(1, wherey);
write('Number of interrupts occured : ', int1c_counter);
end;
{ restore old handler }
set_pm_interrupt(int1c, oldint1c);
end.

View File

@ -1,27 +1,30 @@
Program int_pm;
uses
crt,
go32;
uses crt, go32;
const
int1c = $1c;
const int1c = $1c;
var
oldint1c : tseginfo;
newint1c : tseginfo;
var oldint1c : tseginfo;
newint1c : tseginfo;
int1c_counter : Longint;
int1c_counter : Longint;
int1c_ds : Word; external name '___v2prt0_ds_alias';
{$ASMMODE DIRECT}
procedure int1c_handler; assembler;
asm
cli
pushw %ds
pushw %ax
movw %cs:INT1C_DS, %ax
movw %cs:int1c_ds, %ax
movw %ax, %ds
incl _INT1C_COUNTER
incl int1c_counter
popw %ax
popw %ds
sti
iret
INT1C_DS: .word 0
end;
var i : Longint;
@ -30,16 +33,11 @@ begin
newint1c.offset := @int1c_handler;
newint1c.segment := get_cs;
get_pm_interrupt(int1c, oldint1c);
asm
movw %ds, %ax
movw %ax, INT1C_DS
end;
Writeln('-- Press any key to exit --');
set_pm_interrupt(int1c, newint1c);
while (not keypressed) do begin
gotoxy(1, wherey);
write('Number of interrupts occured : ',
int1c_counter);
gotoxy(1, wherey);
write('Number of interrupts occured : ', int1c_counter);
end;
set_pm_interrupt(int1c, oldint1c);
end.

View File

@ -1,118 +1,119 @@
{ example for : Interrupt redirection (Hardware interrupts)
set_pm_interrupt()
get_pm_interrupt()
lock_code()
lock_data()
unlock_code()
unlock_data()
tseginfo record
}
{ This example demonstrates how to chain to a hardware interrupt.
In more detail, it hooks the keyboard interrupt, calls a user procedure
which in this case simply turns the PC speaker on and off. Then the old
interrupt is called.
}
uses crt, { readkey() }
go32;
const kbdint = $9; { keyboard is IRQ 1 -> interrupt 9 }
var oldint9_handler : tseginfo; { holds old PM interrupt handler address }
newint9_handler : tseginfo; { new PM interrupt handler }
clickproc : pointer; { pointer to interrupt handler }
{$ASMMODE DIRECT}
{ interrupt handler }
procedure int9_handler; assembler;
asm
cli
{ save all registers, because we don't know which the compiler uses for
the called procedure }
pushal
{ set up to call a FPC procedure }
movw %cs:INT9_DS, %ax
movw %ax, %ds
movw %ax, %es
movw U_GO32_DOSMEMSELECTOR, %ax
movw %ax, %fs
{ call user procedure }
call *_CLICKPROC
{ restore all registers }
popal
ljmp %cs:OLDHANDLER { call old handler }
{ we don't need to do anything more, because the old interrupt handler
does this for us (send EOI command, iret, sti...) }
INT9_DS: .word 0
OLDHANDLER:
.long 0
.word 0
end;
{ dummy procedure to retrieve exact length of handler, for locking and
unlocking functions }
procedure int9_dummy; begin end;
{ demo user procedure, simply clicks on every keypress }
procedure clicker;
begin
sound(500); delay(10); nosound;
end;
{ dummy procedure to retrieve exact length of user procedure for locking and
unlocking functions }
procedure clicker_dummy; begin end;
{ installs our new handler }
procedure install_click;
begin
clickproc := @clicker;
{ lock used code and data }
lock_data(clickproc, sizeof(clickproc));
lock_data(dosmemselector, sizeof(dosmemselector));
lock_code(@clicker, longint(@clicker_dummy)-longint(@clicker));
lock_code(@int9_handler, longint(@int9_dummy)-longint(@int9_handler));
{ fill in new handler's 48 bit pointer }
newint9_handler.offset := @int9_handler;
newint9_handler.segment := get_cs;
{ get old PM interrupt handler }
get_pm_interrupt(kbdint, oldint9_handler);
{ store old PM interrupt handlers address in interrupt handler }
asm
movw %ds, %ax
movw %ax, INT9_DS
movl _OLDINT9_HANDLER, %eax
movl %eax, OLDHANDLER
movw 4+_OLDINT9_HANDLER, %ax
movw %ax, 4+OLDHANDLER
end;
{ set the new interrupt handler }
set_pm_interrupt(kbdint, newint9_handler);
end;
{ deinstalls our interrupt handler }
procedure remove_click;
begin
{ set old handler }
set_pm_interrupt(kbdint, oldint9_handler);
{ unlock used code & data }
unlock_data(dosmemselector, sizeof(dosmemselector));
unlock_data(clickproc, sizeof(clickproc));
unlock_code(@clicker, longint(@clicker_dummy)-longint(@clicker));
unlock_code(@int9_handler, longint(@int9_dummy)-longint(@int9_handler));
end;
var ch : char;
begin
install_click;
Writeln('Enter any message. Press return when finished');
while (ch <> #13) do begin
ch := readkey; write(ch);
end;
remove_click;
{ This example demonstrates how to chain to a hardware interrupt.
In more detail, it hooks the keyboard interrupt, calls a user
procedure which in this case simply turns the PC speaker on and off.
Then the old interrupt is called.
}
{$ASMMODE ATT}
{$MODE FPC}
uses
crt,
go32;
const
{ keyboard is IRQ 1 -> interrupt 9 }
kbdint = $9;
var
{ holds old PM interrupt handler address }
oldint9_handler : tseginfo;
{ new PM interrupt handler }
newint9_handler : tseginfo;
{ pointer to interrupt handler }
clickproc : pointer;
{ the data segment selector }
backupDS : Word; external name '___v2prt0_ds_alias';
{ interrupt handler }
procedure int9_handler; assembler;
asm
cli
{ save all registers, because we don't know which the compiler
uses for the called procedure }
pushl %ds
pushl %es
pushl %fs
pushl %gs
pushal
{ set up to call a FPC procedure }
movw %cs:backupDS, %ax
movw %ax, %ds
movw %ax, %es
movw dosmemselector, %ax
movw %ax, %fs
{ call user procedure }
call *clickproc
{ restore all registers }
popal
popl %gs
popl %fs
popl %es
popl %ds
{ note: in go32v2 mode %cs=%ds=%es !!!}
ljmp %cs:oldint9_handler { call old handler }
{ we don't need to do anything more, because the old interrupt
handler does this for us (send EOI command, iret, sti...) }
end;
{ dummy procedure to retrieve exact length of handler, for locking
and unlocking functions }
procedure int9_dummy; begin end;
{ demo user procedure, simply clicks on every keypress }
procedure clicker;
begin
sound(500); delay(10); nosound;
end;
{ dummy procedure to retrieve exact length of user procedure for
locking and unlocking functions }
procedure clicker_dummy; begin end;
{ installs our new handler }
procedure install_click;
begin
clickproc := @clicker;
{ lock used code and data }
lock_data(clickproc, sizeof(clickproc));
lock_data(dosmemselector, sizeof(dosmemselector));
lock_code(@clicker,
longint(@clicker_dummy) - longint(@clicker));
lock_code(@int9_handler,
longint(@int9_dummy)-longint(@int9_handler));
{ fill in new handler's 48 bit pointer }
newint9_handler.offset := @int9_handler;
newint9_handler.segment := get_cs;
{ get old PM interrupt handler }
get_pm_interrupt(kbdint, oldint9_handler);
{ set the new interrupt handler }
set_pm_interrupt(kbdint, newint9_handler);
end;
{ deinstalls our interrupt handler }
procedure remove_click;
begin
{ set old handler }
set_pm_interrupt(kbdint, oldint9_handler);
{ unlock used code & data }
unlock_data(dosmemselector, sizeof(dosmemselector));
unlock_data(clickproc, sizeof(clickproc));
unlock_code(@clicker,
longint(@clicker_dummy)-longint(@clicker));
unlock_code(@int9_handler,
longint(@int9_dummy)-longint(@int9_handler));
end;
var
ch : char;
begin
install_click;
Writeln('Enter any message. Press return when finished');
while (ch <> #13) do begin
ch := readkey; write(ch);
end;
remove_click;
end.

View File

@ -1,91 +1,85 @@
Program Keyclick;
uses crt,
go32;
const kbdint = $9;
var oldint9_handler : tseginfo;
newint9_handler : tseginfo;
clickproc : pointer;
{$ASMMODE DIRECT}
procedure int9_handler; assembler;
asm
cli
pushal
movw %cs:INT9_DS, %ax
movw %ax, %ds
movw %ax, %es
movw U_GO32_DOSMEMSELECTOR, %ax
movw %ax, %fs
call *_CLICKPROC
popal
ljmp %cs:OLDHANDLER
INT9_DS: .word 0
OLDHANDLER:
.long 0
.word 0
end;
procedure int9_dummy; begin end;
procedure clicker;
begin
sound(500); delay(10); nosound;
end;
procedure clicker_dummy; begin end;
procedure install_click;
begin
clickproc := @clicker;
lock_data(clickproc, sizeof(clickproc));
lock_data(dosmemselector, sizeof(dosmemselector));
lock_code(@clicker,
longint(@clicker_dummy)-longint(@clicker));
lock_code(@int9_handler,
longint(@int9_dummy)
- longint(@int9_handler));
newint9_handler.offset := @int9_handler;
newint9_handler.segment := get_cs;
get_pm_interrupt(kbdint, oldint9_handler);
asm
movw %ds, %ax
movw %ax, INT9_DS
movl _OLDINT9_HANDLER, %eax
movl %eax, OLDHANDLER
movw 4+_OLDINT9_HANDLER, %ax
movw %ax, 4+OLDHANDLER
end;
set_pm_interrupt(kbdint, newint9_handler);
end;
procedure remove_click;
begin
set_pm_interrupt(kbdint, oldint9_handler);
unlock_data(dosmemselector, sizeof(dosmemselector));
unlock_data(clickproc, sizeof(clickproc));
unlock_code(@clicker,
longint(@clicker_dummy)
- longint(@clicker));
unlock_code(@int9_handler,
longint(@int9_dummy)
- longint(@int9_handler));
end;
var ch : char;
begin
install_click;
Writeln('Enter any message.',
' Press return when finished');
while (ch <> #13) do begin
ch := readkey; write(ch);
end;
remove_click;
end.
{$ASMMODE ATT}
{$MODE FPC}
uses
crt,
go32;
const
kbdint = $9;
var
oldint9_handler : tseginfo;
newint9_handler : tseginfo;
clickproc : pointer;
backupDS : Word; external name '___v2prt0_ds_alias';
procedure int9_handler; assembler;
asm
cli
pushl %ds
pushl %es
pushl %fs
pushl %gs
pushal
movw %cs:backupDS, %ax
movw %ax, %ds
movw %ax, %es
movw dosmemselector, %ax
movw %ax, %fs
call *clickproc
popal
popl %gs
popl %fs
popl %es
popl %ds
ljmp %cs:oldint9_handler
end;
procedure int9_dummy; begin end;
procedure clicker;
begin
sound(500); delay(10); nosound;
end;
procedure clicker_dummy; begin end;
procedure install_click;
begin
clickproc := @clicker;
lock_data(clickproc, sizeof(clickproc));
lock_data(dosmemselector, sizeof(dosmemselector));
lock_code(@clicker,
longint(@clicker_dummy) - longint(@clicker));
lock_code(@int9_handler,
longint(@int9_dummy)-longint(@int9_handler));
newint9_handler.offset := @int9_handler;
newint9_handler.segment := get_cs;
get_pm_interrupt(kbdint, oldint9_handler);
set_pm_interrupt(kbdint, newint9_handler);
end;
procedure remove_click;
begin
set_pm_interrupt(kbdint, oldint9_handler);
unlock_data(dosmemselector, sizeof(dosmemselector));
unlock_data(clickproc, sizeof(clickproc));
unlock_code(@clicker,
longint(@clicker_dummy)-longint(@clicker));
unlock_code(@int9_handler,
longint(@int9_dummy)-longint(@int9_handler));
end;
var
ch : char;
begin
install_click;
Writeln('Enter any message. Press return when finished');
while (ch <> #13) do begin
ch := readkey; write(ch);
end;
remove_click;
end.

View File

@ -1,43 +1,49 @@
{ example for
tmeminfo record
int31error var
get_meminfo()
get_page_size()
}
{ Shows how to obtain memory information via get_meminfo();
notice the checks if any of the returned information is invalid (-1)
}
uses go32;
var meminfo : tmeminfo;
begin
get_meminfo(meminfo);
if (int31error <> 0) then begin
Writeln('Error getting DPMI memory information... Halting');
Writeln('DPMI error number : ', int31error);
end else begin
with meminfo do begin
Writeln('Largest available free block : ', available_memory div 1024, ' kbytes');
if (available_pages <> -1) then
Writeln('Maximum available unlocked pages : ', available_pages);
if (available_lockable_pages <> -1) then
Writeln('Maximum lockable available pages : ', available_lockable_pages);
if (linear_space <> -1) then
Writeln('Linear address space size : ', linear_space*get_page_size div 1024, ' kbytes');
if (unlocked_pages <> -1) then
Writeln('Total number of unlocked pages : ', unlocked_pages);
if (available_physical_pages <> -1) then
Writeln('Total number of free pages : ', available_physical_pages);
if (total_physical_pages <> -1) then
Writeln('Total number of physical pages : ', total_physical_pages);
if (free_linear_space <> -1) then
Writeln('Free linear address space : ', free_linear_space*get_page_size div 1024, ' kbytes');
if (max_pages_in_paging_file <> -1) then
Writeln('Maximum size of paging file : ', max_pages_in_paging_file*get_page_size div 1024, ' kbytes');
end;
end;
{ Shows how to obtain memory information via get_meminfo();
notice the checks if any of the returned information is invalid (-1)
}
uses
go32;
var
meminfo : tmeminfo;
begin
get_meminfo(meminfo);
if (int31error <> 0) then begin
Writeln('Error getting DPMI memory information... Halting');
Writeln('DPMI error number : ', int31error);
end else begin
with meminfo do begin
Writeln('Largest available free block : ',
available_memory div 1024, ' kbytes');
if (available_pages <> -1) then
Writeln('Maximum available unlocked pages : ',
available_pages);
if (available_lockable_pages <> -1) then
Writeln('Maximum lockable available pages : ',
available_lockable_pages);
if (linear_space <> -1) then
Writeln('Linear address space size : ',
linear_space*get_page_size div 1024, ' kbytes');
if (unlocked_pages <> -1) then
Writeln('Total number of unlocked pages : ',
unlocked_pages);
if (available_physical_pages <> -1) then
Writeln('Total number of free pages : ',
available_physical_pages);
if (total_physical_pages <> -1) then
Writeln('Total number of physical pages : ',
total_physical_pages);
if (free_linear_space <> -1) then
Writeln('Free linear address space : ',
free_linear_space*get_page_size div 1024,
' kbytes');
if (max_pages_in_paging_file <> -1) then
Writeln('Maximum size of paging file : ',
max_pages_in_paging_file*get_page_size div 1024,
' kbytes');
end;
end;
end.

View File

@ -1,47 +1,44 @@
Program meminf;
uses go32;
var meminfo : tmeminfo;
begin
get_meminfo(meminfo);
if (int31error <> 0) then
begin
Writeln('Error getting DPMI memory information... Halting');
Writeln('DPMI error number : ', int31error);
end
else
with meminfo do
begin
Writeln('Largest available free block : ',
available_memory div 1024, ' kbytes');
if (available_pages <> -1) then
Writeln('Maximum available unlocked pages : ',
available_pages);
if (available_lockable_pages <> -1) then
Writeln('Maximum lockable available pages : ',
available_lockable_pages);
if (linear_space <> -1) then
Writeln('Linear address space size : ',
linear_space*get_page_size div 1024,
' kbytes');
if (unlocked_pages <> -1) then
Writeln('Total number of unlocked pages : ',
unlocked_pages);
if (available_physical_pages <> -1) then
Writeln('Total number of free pages : ',
available_physical_pages);
if (total_physical_pages <> -1) then
Writeln('Total number of physical pages : ',
total_physical_pages);
if (free_linear_space <> -1) then
Writeln('Free linear address space : ',
free_linear_space*get_page_size div 1024,
' kbytes');
if (max_pages_in_paging_file <> -1) then
Writeln('Maximum size of paging file : ',
max_pages_in_paging_file*get_page_size div 1024,
' kbytes');
end;
uses
go32;
var
meminfo : tmeminfo;
begin
get_meminfo(meminfo);
if (int31error <> 0) then begin
Writeln('Error getting DPMI memory information... Halting');
Writeln('DPMI error number : ', int31error);
end else begin
with meminfo do begin
Writeln('Largest available free block : ',
available_memory div 1024, ' kbytes');
if (available_pages <> -1) then
Writeln('Maximum available unlocked pages : ',
available_pages);
if (available_lockable_pages <> -1) then
Writeln('Maximum lockable available pages : ',
available_lockable_pages);
if (linear_space <> -1) then
Writeln('Linear address space size : ',
linear_space*get_page_size div 1024, ' kbytes');
if (unlocked_pages <> -1) then
Writeln('Total number of unlocked pages : ',
unlocked_pages);
if (available_physical_pages <> -1) then
Writeln('Total number of free pages : ',
available_physical_pages);
if (total_physical_pages <> -1) then
Writeln('Total number of physical pages : ',
total_physical_pages);
if (free_linear_space <> -1) then
Writeln('Free linear address space : ',
free_linear_space*get_page_size div 1024,
' kbytes');
if (max_pages_in_paging_file <> -1) then
Writeln('Maximum size of paging file : ',
max_pages_in_paging_file*get_page_size div 1024,
' kbytes');
end;
end;
end.

View File

@ -1,19 +1,16 @@
{ example for : outport*()
I/O access
}
{ This example demonstrates the use of the outport functions.
It simply turns the PC's internal speaker on for 50 ms and off again.
}
uses crt,
go32;
begin
{ turn on speaker }
outportb($61, $ff);
{ wait a little bit }
delay(50);
{ turn it off again }
outportb($61, $0);
{ This example demonstrates the use of the outport functions.
It simply turns the PC's internal speaker on for 50 ms and off again
}
uses
crt,
go32;
begin
{ turn on speaker }
outportb($61, $ff);
{ wait a little bit }
delay(50);
{ turn it off again }
outportb($61, $0);
end.

View File

@ -1,12 +1,9 @@
program outport;
uses crt, go32;
begin
{ turn on speaker }
outportb($61, $ff);
{ wait a little bit }
delay(50);
{ turn it off again }
outportb($61, $0);
uses
crt,
go32;
begin
outportb($61, $ff);
delay(50);
outportb($61, $0);
end.

102
docs/go32ex/rmpmint.pas Normal file
View File

@ -0,0 +1,102 @@
{ This example shows the difference between protected and real mode
interrupts; it redirects the protected mode handler to an own handler
which returns an impossible function result and calls it afterwards.
Then the real mode handler is called directly, to show the difference
between the two.
Used Interrupt:
get DOS version Int 21h / function 30h
Input: AH = $30
AL = $1
Return: AL = major version number
AH = minor version number
}
uses
crt,
go32;
var
r : trealregs;
{ temporary variable used for the protected mode int call }
axreg : Word;
oldint21h : tseginfo;
newint21h : tseginfo;
{ this is our int 21h protected mode interupt handler. It catches
the function call to get the DOS version, all other int 21h calls
are redirected to the old handler; it is written in assembly
because the old handler can't be called with pascal }
procedure int21h_handler; assembler;
asm
cmpw $0x3001, %ax
jne .LCallOld
movw $0x3112, %ax
iret
.LCallOld:
ljmp %cs:oldint21h
end;
{ a small helper procedure, which waits for a keypress }
procedure resume;
begin
Writeln;
Write('-- press any key to resume --'); readkey;
gotoxy(1, wherey); clreol;
end;
begin
{ see the text messages for further detail }
clrscr;
Writeln('Executing real mode interrupt');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('Executing protected mode interrupt without our own',
' handler');
Writeln;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, axreg
end;
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('As you can see the DPMI hosts default protected mode',
'handler');
Writeln('simply redirects it to the real mode handler');
resume;
Writeln('Now exchanging the protected mode interrupt with our ',
'own handler');
resume;
newint21h.offset := @int21h_handler;
newint21h.segment := get_cs;
get_pm_interrupt($21, oldint21h);
set_pm_interrupt($21, newint21h);
Writeln('Executing real mode interrupt again');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
Writeln;
Writeln('See, it didn''t change in any way.');
resume;
Writeln('Now calling protected mode interrupt');
resume;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, axreg
end;
Writeln('DOS v', lo(axreg),'.',hi(axreg), ' detected');
Writeln;
Writeln('Now you can see that there''s a distinction between ',
'the two ways of calling interrupts...');
set_pm_interrupt($21, oldint21h);
end.

View File

@ -1,92 +1,80 @@
Program rmpm_int;
uses
crt,
go32;
uses crt, go32;
{$ASMMODE DIRECT}
var r : trealregs;
axreg : Word;
oldint21h : tseginfo;
newint21h : tseginfo;
var
r : trealregs;
axreg : Word;
oldint21h : tseginfo;
newint21h : tseginfo;
procedure int21h_handler; assembler;
asm
cmpw $0x3001, %ax
jne CallOld
movw $0x3112, %ax
iret
cmpw $0x3001, %ax
jne .LCallOld
movw $0x3112, %ax
iret
CallOld:
ljmp %cs:OLDHANDLER
OLDHANDLER: .long 0
.word 0
.LCallOld:
ljmp %cs:oldint21h
end;
procedure resume;
begin
Writeln;
Write('-- press any key to resume --'); readkey;
gotoxy(1, wherey); clreol;
Writeln;
Write('-- press any key to resume --'); readkey;
gotoxy(1, wherey); clreol;
end;
begin
clrscr;
Writeln('Executing real mode interrupt');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('Executing protected mode interrupt',
' without our own handler');
Writeln;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, _AXREG
end;
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('As you can see the DPMI hosts',
' default protected mode handler');
Writeln('simply redirects it to the real mode handler');
resume;
Writeln('Now exchanging the protected mode',
'interrupt with our own handler');
resume;
clrscr;
Writeln('Executing real mode interrupt');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('Executing protected mode interrupt without our own',
' handler');
Writeln;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, axreg
end;
Writeln('DOS v', r.al,'.',r.ah, ' detected');
resume;
Writeln('As you can see the DPMI hosts default protected mode',
'handler');
Writeln('simply redirects it to the real mode handler');
resume;
Writeln('Now exchanging the protected mode interrupt with our ',
'own handler');
resume;
newint21h.offset := @int21h_handler;
newint21h.segment := get_cs;
get_pm_interrupt($21, oldint21h);
asm
movl _OLDINT21H, %eax
movl %eax, OLDHANDLER
movw 4+_OLDINT21H, %ax
movw %ax, 4+OLDHANDLER
end;
set_pm_interrupt($21, newint21h);
newint21h.offset := @int21h_handler;
newint21h.segment := get_cs;
get_pm_interrupt($21, oldint21h);
set_pm_interrupt($21, newint21h);
Writeln('Executing real mode interrupt again');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
Writeln;
Writeln('See, it didn''t change in any way.');
resume;
Writeln('Now calling protected mode interrupt');
resume;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, _AXREG
end;
Writeln('DOS v', lo(axreg),'.',hi(axreg), ' detected');
Writeln;
Writeln('Now you can see that there''s',
' a distinction between the two ways of ');
Writeln('calling interrupts...');
set_pm_interrupt($21, oldint21h);
Writeln('Executing real mode interrupt again');
resume;
r.ah := $30; r.al := $01; realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
Writeln;
Writeln('See, it didn''t change in any way.');
resume;
Writeln('Now calling protected mode interrupt');
resume;
asm
movb $0x30, %ah
movb $0x01, %al
int $0x21
movw %ax, axreg
end;
Writeln('DOS v', lo(axreg),'.',hi(axreg), ' detected');
Writeln;
Writeln('Now you can see that there''s a distinction between ',
'the two ways of calling interrupts...');
set_pm_interrupt($21, oldint21h);
end.

150
docs/go32ex/seldes.pas Normal file
View File

@ -0,0 +1,150 @@
{
This example demonstrates the usage of descriptors and the effects of
changing its limit and base address.
In more detail, the program fills the region described by an
allocated descriptor in text screen memory with various characters.
Before doing this it saves the entire screen contents to the heap and
restores it afterwards.
Some additional background:
The text screen of a VGA card has it's address space at $B800:0;
screen memory is organized in a linear fashion, e.g. the second line
comes directly after the first, where each cell occupies 2 bytes of
memory (1 byte character data, 1 byte attributes). It is 32 kb in
size.
Hence the offset of a single memory cell from its origin is:
Y * columns * 2 + X * 2
where X and Y mark the point and columns is the number of character
cells per line
}
{$mode delphi}
uses
crt,
go32;
const
{ screen x and y dimensions }
maxx = 80;
maxy = 25;
{ bytes used for every character cell }
bytespercell = 2;
{ screen size in bytes }
screensize = maxx * maxy * bytespercell;
{ the linear address of $B800:0 }
linB8000 = $B800 * 16;
type
string80 = string[80];
var
{ holds the old screen contents }
text_save : array[0..screensize-1] of byte;
{ old cursor x and y coordinates }
text_oldx, text_oldy : Word;
{ selector to the text mode screen }
text_sel : Word;
{ prints a status message on the first line of the screen and then
waits for a keypress }
procedure status(s : string80);
begin
gotoxy(1, 1); clreol; write(s); readkey;
end;
{ writes some descriptor info on the last 2 lines }
procedure selinfo(sel : Word);
begin
gotoxy(1, 24);
clreol; writeln('Descriptor base address : $',
hexstr(get_segment_base_address(sel), 8));
clreol; write('Descriptor limit : ', get_segment_limit(sel));
end;
{ returns a 2 byte character cell, which includes character data
and its color attributes }
function makechar(ch : char; color : byte) : Word;
begin
result := byte(ch) or (color shl 8);
end;
begin
{ save original screen contents to variable, this time by using
seg_move() and the dosmemselector variable }
seg_move(dosmemselector, linB8000, get_ds, longint(@text_save),
screensize);
{ additionally we have to save the old screen cursor
coordinates }
text_oldx := wherex; text_oldy := wherey;
{ clear the whole screen }
seg_fillword(dosmemselector, linB8000, screensize div 2,
makechar(' ', Black or (Black shl 4)));
{ output message }
status('Creating selector ''text_sel'' to a part of ' +
'text screen memory');
{ allocate descriptor }
text_sel := allocate_ldt_descriptors(1);
{ set its base address to the linear address of the text screen
+ the byte size of one line (=maxx * bytespercell * 1) }
set_segment_base_address(text_sel,
linB8000 + bytespercell * maxx * 1);
{ the limit is set to the screensize reduced by one (a must be)
and the number of lines we don't want to have touched (first
line + lower 2 lines) }
set_segment_limit(text_sel, screensize - 1 - bytespercell *
maxx * 3);
{ write descriptor info }
selinfo(text_sel);
status('and clearing entire memory selected by ''text_sel''' +
' descriptor');
{ fill the entire selected memory with single characters }
seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2,
makechar(' ', LightBlue shl 4));
status('Notice that only the memory described by the ' +
'descriptor changed, nothing else');
status('Now reducing it''s limit and base and setting it''s ' +
'described memory');
{ set the base address of the descriptor (increase it by the
byte size of one line) }
set_segment_base_address(text_sel,
get_segment_base_address(text_sel) + bytespercell * maxx);
{ decrease the limit by byte size of 2 lines (1 line because
base address changed, one line on the lower end) }
set_segment_limit(text_sel,
get_segment_limit(text_sel) - bytespercell * maxx * 2);
{ write descriptor info }
selinfo(text_sel);
status('Notice that the base addr increased by one line but ' +
'the limit decreased by 2 lines');
status('This should give you the hint that the limit is ' +
'relative to the base');
{ fill the descriptor area }
seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2,
makechar(#176, LightMagenta or Brown shl 4));
status('Now let''s get crazy and copy 10 lines of data from ' +
'the previously saved screen');
{ copy memory from the data segment to screen }
seg_move(get_ds, longint(@text_save), text_sel,
maxx * bytespercell * 2, maxx * bytespercell * 10);
status('At last freeing the descriptor and restoring the old ' +
' screen contents..');
status('I hope this little program may give you some hints ' +
'on working with descriptors');
{ free the descriptor so that it can be used for things }
free_ldt_descriptor(text_sel);
{ restore old state }
seg_move(get_ds, longint(@text_save), dosmemselector,
linB8000, screensize);
gotoxy(text_oldx, text_oldy);
end.

View File

@ -1,40 +1,36 @@
Program sel_des;
{$mode delphi}
uses
crt,
go32;
uses crt,
go32;
const
maxx = 80;
maxy = 25;
bytespercell = 2;
screensize = maxx * maxy * bytespercell;
const maxx = 80;
maxy = 25;
bytespercell = 2;
screensize = maxx * maxy * bytespercell;
linB8000 = $B800 * 16;
linB8000 = $B800 * 16;
type string80 = string[80];
type
string80 = string[80];
var
text_save : array[0..screensize-1] of byte;
text_oldx, text_oldy : Word;
text_save : array[0..screensize-1] of byte;
text_oldx, text_oldy : Word;
text_sel : Word;
text_sel : Word;
procedure status(s : string80);
begin
gotoxy(1, 1);
clreol;
write(s);
readkey;
gotoxy(1, 1); clreol; write(s); readkey;
end;
procedure selinfo(sel : Word);
begin
gotoxy(1, 24);
clreol;
writeln('Descriptor base address : $',
hexstr(get_segment_base_address(sel), 8));
clreol;
write('Descriptor limit : ',
get_segment_limit(sel));
gotoxy(1, 24);
clreol; writeln('Descriptor base address : $',
hexstr(get_segment_base_address(sel), 8));
clreol; write('Descriptor limit : ', get_segment_limit(sel));
end;
function makechar(ch : char; color : byte) : Word;
@ -43,59 +39,53 @@ begin
end;
begin
seg_move(dosmemselector, linB8000,
get_ds, longint(@text_save), screensize);
text_oldx := wherex; text_oldy := wherey;
seg_fillword(dosmemselector, linB8000,
screensize div 2,
makechar(' ', Black or (Black shl 4)));
status('Creating selector ' +
'''text_sel'' to a part of text screen memory');
text_sel := allocate_ldt_descriptors(1);
set_segment_base_address(text_sel, linB8000
+ bytespercell * maxx * 1);
set_segment_limit(text_sel,
screensize-1-bytespercell*maxx*3);
selinfo(text_sel);
seg_move(dosmemselector, linB8000, get_ds, longint(@text_save),
screensize);
text_oldx := wherex; text_oldy := wherey;
seg_fillword(dosmemselector, linB8000, screensize div 2,
makechar(' ', Black or (Black shl 4)));
status('Creating selector ''text_sel'' to a part of ' +
'text screen memory');
text_sel := allocate_ldt_descriptors(1);
set_segment_base_address(text_sel,
linB8000 + bytespercell * maxx * 1);
set_segment_limit(text_sel, screensize - 1 - bytespercell *
maxx * 3);
selinfo(text_sel);
status('and clearing entire memory ' +
'selected by ''text_sel'' descriptor');
seg_fillword(text_sel, 0,
(get_segment_limit(text_sel)+1) div 2,
makechar(' ', LightBlue shl 4));
status('and clearing entire memory selected by ''text_sel''' +
' descriptor');
seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2,
makechar(' ', LightBlue shl 4));
status('Notice that only the memory described'+
' by the descriptor changed, nothing else');
status('Notice that only the memory described by the' +
' descriptor changed, nothing else');
status('Now reducing it''s limit and base and '+
'setting it''s described memory');
set_segment_base_address(text_sel,
get_segment_base_address(text_sel)
+ bytespercell * maxx);
set_segment_limit(text_sel,
get_segment_limit(text_sel)
- bytespercell * maxx * 2);
selinfo(text_sel);
status('Notice that the base addr increased by '+
'one line but the limit decreased by 2 lines');
status('This should give you the hint that the '+
'limit is relative to the base');
seg_fillword(text_sel, 0,
(get_segment_limit(text_sel)+1) div 2,
makechar(#176, LightMagenta or Brown shl 4));
status('Now reducing it''s limit and base and setting it''s ' +
'described memory');
set_segment_base_address(text_sel,
get_segment_base_address(text_sel) + bytespercell * maxx);
set_segment_limit(text_sel,
get_segment_limit(text_sel) - bytespercell * maxx * 2);
selinfo(text_sel);
status('Notice that the base addr increased by one line but ' +
'the limit decreased by 2 lines');
status('This should give you the hint that the limit is ' +
'relative to the base');
seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2,
makechar(#176, LightMagenta or Brown shl 4));
status('Now let''s get crazy and copy 10 lines'+
' of data from the previously saved screen');
seg_move(get_ds, longint(@text_save),
text_sel, maxx * bytespercell * 2,
maxx * bytespercell * 10);
status('Now let''s get crazy and copy 10 lines of data from ' +
'the previously saved screen');
seg_move(get_ds, longint(@text_save), text_sel,
maxx * bytespercell * 2, maxx * bytespercell * 10);
status('At last freeing the descriptor and '+
'restoring the old screen contents..');
status('I hope this little program may give '+
'you some hints on working with descriptors');
free_ldt_descriptor(text_sel);
seg_move(get_ds, longint(@text_save),
dosmemselector, linB8000, screensize);
gotoxy(text_oldx, text_oldy);
status('At last freeing the descriptor and restoring the old '+
' screen contents..');
status('I hope this little program may give you some hints on '+
'working with descriptors');
free_ldt_descriptor(text_sel);
seg_move(get_ds, longint(@text_save), dosmemselector,
linB8000, screensize);
gotoxy(text_oldx, text_oldy);
end.

View File

@ -1,35 +1,25 @@
{ example program to call
software interrupts
realintr()
trealregs type
}
{ Executes a real mode software interrupt
Exactly the interrupt call to get the DOS version.
get DOS version Int 21h / function 30h
Input: AH = $30
AL = $1
Return: AL = major version number
AH = minor version number
}
uses go32; { realintr, trealregs }
var r : trealregs;
begin
{ get DOS version Int 21h / function 30h
Input: AH = $30
AL = $1
Return: AL = major version number
AH = minor version number
}
r.ah := $30;
r.al := $01;
realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
{ Executes a real mode software interrupt
Exactly the interrupt call to get the DOS version.
get DOS version Int 21h / function 30h
Input:
AH = $30
AL = $1
Return:
AL = major version number
AH = minor version number
}
uses
go32;
var
r : trealregs;
begin
r.ah := $30;
r.al := $01;
realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
end.

View File

@ -1,11 +1,12 @@
Program softint;
uses go32;
var r : trealregs;
begin
r.al := $01;
realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
uses
go32;
var
r : trealregs;
begin
r.ah := $30;
r.al := $01;
realintr($21, r);
Writeln('DOS v', r.al,'.',r.ah, ' detected');
end.

View File

@ -1,80 +1,83 @@
{ Example for : dosmemmove()
dosmemfillchar()
dosmemget()
DOS memory access
}
{ This example copies around some blocks of memory in DOS memory space.
In more detail, the program copies a string randomly to the text mode
screen. Aditionally it messes around a bit with the color attributes of
the string.
Before doing this it saves the entire screen contents to the heap and
restores it afterwards.
Some additional background:
The text screen of a VGA card has it's address space at $B800:0; screen
memory is organized in a linear fashion, e.g. the second line comes
directly after the first, where each cell occupies 2 bytes of memory
(1 byte character data, 1 byte attributes). It is 32 kb in size.
Hence the offset of a single memory cell from its origin is:
Y*columns*2 + X*2
where X and Y mark the point and columns is the number of character cells
per line
}
uses crt, { keypressed(), gotoxy(), randomize(), random(), wherex(),
wherey() }
go32;
const columns = 80; { number of columns on screen }
rows = 25; { number of rows on screen }
screensize = rows*columns*2;
text = '! Hello world !'; { sample text string }
var textofs : Longint;
save_screen : array[0..screensize-1] of byte; { this variable holds the
entire screen contents }
curx, cury : Integer; { These two hold the previous cursor coordinates }
begin
randomize;
{ save screen contents to save_screen variable }
dosmemget($B800, 0, save_screen, screensize);
{ save current cursor coordinates }
curx := wherex; cury := wherey;
{ This is our demo text }
gotoxy(1, 1); Write(text);
{ calculate the address in offscreen memory (to be sure it won't be over
written by the copy process later, we don't put it exactly at the end
of the visible screen area) }
textofs := screensize + length(text)*2;
{ copy it to offscreen memory }
dosmemmove($B800, 0, $B800, textofs, length(text)*2);
{ clear the screen by writing zeros on the whole visible screen }
dosmemfillchar($B800, 0, screensize, #0);
while (not keypressed) do begin
{ set the attribute field (byte 2 of every cell) of the text in
offscreen memory to random values }
dosmemfillchar($B800, textofs + random(length(text))*2 + 1,
1, char(random(255)));
{ copy the string from offscreen to visibly screen by calculating
it's destination address randomly }
dosmemmove($B800, textofs,
$B800, random(columns)*2+random(rows)*columns*2,
length(text)*2);
{ small delay, else it is too fast (remove it if you want...) }
delay(1);
end;
{ clear the keyboard buffer }
readkey;
{ wait for a keypress }
readkey;
{ restore old screen contents afterwards }
dosmemput($B800, 0, save_screen, screensize);
gotoxy(curx, cury);
{ This example copies around some blocks of memory in DOS memory
space.
In more detail, the program copies a string randomly to the text
mode screen. Aditionally it messes around a bit with the color
attributes of the string.
Before doing this it saves the entire screen contents to the heap
and restores it afterwards.
Some additional background:
The text screen of a VGA card has it's address space at $B800:0;
screen memory is organized in a linear fashion, e.g. the second line
comes directly after the first, where each cell occupies 2 bytes of
memory (1 byte character data, 1 byte attributes). It is 32 kb in
size.
Hence the offset of a single memory cell from its origin is:
Y*columns*2 + X*2
where X and Y mark the point and columns is the number of character
cells per line
}
uses
crt,
go32;
const
{ number of columns on screen }
columns = 80;
{ number of rows on screen }
rows = 25;
screensize = rows*columns*2;
{ sample text string }
text = '! Hello world !';
var
textofs : Longint;
{ this variable holds the entire screen contents }
save_screen : array[0..screensize-1] of byte;
{ These two hold the previous cursor coordinates }
curx, cury : Integer;
begin
randomize;
{ save screen contents to save_screen variable }
dosmemget($B800, 0, save_screen, screensize);
{ save current cursor coordinates }
curx := wherex; cury := wherey;
{ This is our demo text }
gotoxy(1, 1); Write(text);
{ calculate the address in offscreen memory (to be sure it will
not be overwritten by the copy process later, we don't put it
exactly at the end of the visible screen area) }
textofs := screensize + length(text)*2;
{ copy it to offscreen memory }
dosmemmove($B800, 0, $B800, textofs, length(text)*2);
{ clear the screen by writing zeros on the whole visible screen}
dosmemfillchar($B800, 0, screensize, #0);
while (not keypressed) do begin
{ set the attribute field (byte 2 of every cell) of the
text in offscreen memory to random values }
dosmemfillchar($B800, textofs + random(length(text))*2 + 1,
1, char(random(255)));
{ copy the string from offscreen to visibly screen by calculating
it's destination address randomly }
dosmemmove($B800, textofs, $B800,
random(columns)*2+random(rows)*columns*2,
length(text)*2);
{ small delay, else it is too fast }
delay(1);
end;
{ clear the keyboard buffer }
readkey;
{ wait for a keypress }
readkey;
{ restore old screen contents afterwards }
dosmemput($B800, 0, save_screen, screensize);
gotoxy(curx, cury);
end.

View File

@ -1,37 +1,37 @@
Program textmess;
uses crt, go32;
const columns = 80;
rows = 25;
screensize = rows*columns*2;
text = '! Hello world !';
var textofs : Longint;
save_screen : array[0..screensize-1] of byte;
curx, cury : Integer;
begin
randomize;
dosmemget($B800, 0, save_screen, screensize);
curx := wherex; cury := wherey;
gotoxy(1, 1); Write(text);
textofs := screensize + length(text)*2;
dosmemmove($B800, 0, $B800, textofs, length(text)*2);
dosmemfillchar($B800, 0, screensize, #0);
while (not keypressed) do
begin
dosmemfillchar($B800,
textofs + random(length(text))*2 + 1,
1, char(random(255)));
dosmemmove($B800, textofs, $B800,
random(columns)*2+random(rows)*columns*2,
length(text)*2);
delay(1);
end;
readkey;
readkey;
dosmemput($B800, 0, save_screen, screensize);
gotoxy(curx, cury);
uses
crt,
go32;
const
columns = 80;
rows = 25;
screensize = rows*columns*2;
text = '! Hello world !';
var
textofs : Longint;
save_screen : array[0..screensize-1] of byte;
curx, cury : Integer;
begin
randomize;
dosmemget($B800, 0, save_screen, screensize);
curx := wherex; cury := wherey;
gotoxy(1, 1); Write(text);
textofs := screensize + length(text)*2;
dosmemmove($B800, 0, $B800, textofs, length(text)*2);
dosmemfillchar($B800, 0, screensize, #0);
while (not keypressed) do begin
dosmemfillchar($B800, textofs + random(length(text))*2 + 1,
1, char(random(255)));
dosmemmove($B800, textofs, $B800,
random(columns)*2+random(rows)*columns*2,
length(text)*2);
delay(1);
end;
readkey;
readkey;
dosmemput($B800, 0, save_screen, screensize);
gotoxy(curx, cury);
end.

View File

@ -1,35 +1,30 @@
{ example for :
Selectors and descriptors
segment_to_descriptor()
seg_fillchar()
realintr()
trealregs record
}
{ This example demonstrates the use of the segment_to_descriptor() function.
It switches to VGA mode 13h (320x200x256 color), creates a selector to the
memory (based at $A000:0000), clears this memory with color 15 (white) and
waits until the enter key is pressed
}
uses go32;
var vgasel : Word;
r : trealregs;
begin
{ set VGA mode 13h }
r.eax := $13; realintr($10, r);
{ allocate descriptor to VGA memory quickly; it could be done with
allocate_ldt_descriptors() too, but we would have to initialize it
by ourselves... unlike segment_to_descriptor() which automatically sets
the limit and the base address correctly }
vgasel := segment_to_descriptor($A000);
{ simply fill the screen memory with color 15 }
seg_fillchar(vgasel, 0, 64000, #15);
{ wait for a return press }
readln;
{ back to text mode }
r.eax := $3; realintr($10, r);
{ don't deallocate vgasel, that can't be done }
{This example demonstrates the use of the segment_to_descriptor()
function.
It switches to VGA mode 13h (320x200x256 color), creates a selector
to the memory (based at $A000:0000), clears this memory with color
15 (white) and waits until the enter key is pressed }
uses go32;
var
vgasel : Word;
r : trealregs;
begin
{ set VGA mode 13h }
r.eax := $13; realintr($10, r);
{ allocate descriptor to VGA memory quickly; it could be done
with allocate_ldt_descriptors() too, but we would have to
initialize it by ourselves... unlike segment_to_descriptor()
which automatically sets the limit and the base address
correctly }
vgasel := segment_to_descriptor($A000);
{ simply fill the screen memory with color 15 }
seg_fillchar(vgasel, 0, 64000, #15);
{ wait for a return press }
readln;
{ back to text mode }
r.eax := $3; realintr($10, r);
{ don't deallocate vgasel, that can't be done }
end.

View File

@ -1,17 +1,14 @@
Program svgasel;
uses go32;
var vgasel : Word;
r : trealregs;
begin
r.eax := $13; realintr($10, r);
vgasel := segment_to_descriptor($A000);
{ simply fill the screen memory with color 15 }
seg_fillchar(vgasel, 0, 64000, #15);
readln;
{ back to text mode }
r.eax := $3;
realintr($10, r);
uses
go32;
var
vgasel : Word;
r : trealregs;
begin
r.eax := $13; realintr($10, r);
vgasel := segment_to_descriptor($A000);
seg_fillchar(vgasel, 0, 64000, #15);
readln;
r.eax := $3; realintr($10, r);
end.