The GO32 provides an interface to the DOS extender, DOS memory access, I/O ports and processor access. Some of this functions work with all modes of the extender, other only with DPMI.
The DOS memory access is done by the dosmem* functions and it's strongly recommended to use this functions.
Example:
function shift_state : byte; begin { $40:$17 contains the current contents of the shift, alt and strg keys } dosmemget($40,$17,shift_state,1); end;
The I/O port access is done by the inport* and outport* functions. It's not necessary to use this functions but it makes life easier. FPKPascal doesn't support the PORT array.
There are some functions to access the segment registers, which makes your work easier, look for get_*.
The GO32 unit supports you to redirect interrupts, the method via setintvec and getintvec doesn't work with FPKPascal. This is now done by the function set_pm_interrupt and get_pm_interrupt.
Example how to redirect the interrupt 8h.
{ the unit CRT _is_ needed because the program doesn't get an interrupt while DOS is active } uses go32,crt; var timer : longint; ds : word;
procedure s; { interrupt; comes with the next version of FPKPascal }
begin asm { save used registers } pushl %eax pushw %ds { load ds } { prefix for cs } .byte 0x2e movw ALAB,%ax movw %ax,%ds end; inc(timer); asm { restore processor state } popw %ds popl %eax leave { call old interrupt } ljmp %cs:OLDINT iret { we need some data in the code segment, since only CS is set in the } { entry point of the procedure } ALAB: .word 0 { old vector as 48 bit pointer (16:32) } OLDINT: .long 0 .word 0 end; end; var oldint,myint : tseginfo; i : longint; begin timer:=0; { save old interrupt } get_pm_interrupt(8,oldint); ds:=get_ds; asm { copy some data to the code segment } movw _DS,%ax movw %ax,ALAB movl _OLDINT,%eax movl %eax,OLDINT movw _OLDINT+4,%ax movw %ax,OLDINT+4 end; { new handler } myint.segment:=get_cs; myint.offset:=@s; { install the handler } set_pm_interrupt(8,myint); { do something } for i:=1 to 10000 do writeln(timer); { install the old handler } set_pm_interrupt(8,oldint); end.
{ this works only with real DPMI } function allocate_ldt_descriptors(count : word) : word; procedure free_ldt_descriptor(d : word); function segment_to_descriptor(seg : word) : word; function get_next_selector_increment_value : word; function get_segment_base_address(d : word) : longint; procedure set_segment_base_address(d : word;s : longint); procedure set_segment_limit(d : word;s : longint); function create_code_segment_alias_descriptor(seg : word) : word; function get_linear_addr(phys_addr : longint;size : longint) : longint;
{ is needed for functions which need a real mode buffer } function global_dos_alloc(bytes : longint) : longint; procedure global_dos_free(selector : word);
procedure disable;
Clears the interrupt flag with CLD and disables the interrupts.
See also: enable
var { puts count bytes from data to ptr(seg:ofs) of the DOS memory } dosmemput : procedure(seg : word;ofs : word;var data;count : longint); { gets count bytes from ptr(seg:ofs) of the DOS memory to data } dosmemget : procedure(seg : word;ofs : word;var data;count : longint); { moves count bytes from ptr(sseg:sofs) to ptr(dseg:dofs) } dosmemmove : procedure(sseg,sofs,dseg,dofs : word;count : longint); { fills count bytes beginning with ptr(seg:ofs) with c } dosmemfillchar : procedure(seg,ofs : word;count : longint;c : char); { fills count words beginning with ptr(seg:ofs) with w } { this function is esspecially by the CRT unit used } dosmemfillword : procedure(seg,ofs : word;count : longint;w : word);
This procedure variables give you access to the DOS memory in each mode of the DOS extender, it's strongly recommended to use this functions.
The procedures variables are assigned by the startup code of the GO32 unit to the correct procedures.
uses go32; var b : byte; begin dosmemget($40,$49,b,1); writeln('The current screen mode is: ',b); end.
See also: dosmemselector, seg_move, seg_fillchar, seg_fillword
var dosmemselector : word;
Selector to the DOS memory, the whole DOS memory is mapped to a single segment.
uses go32; var l : longint; begin ... { Move the contents of l to the frame buffer } seg_move(get_ds,longint(@l),dosmemselector,$b800*16+12); end.
NOTE: This function works only in DPMI mode
See also: dosmem*, seg_move, seg_fillchar, seg_fillword
procedure enable;
Sets the interrupt flag with STI and allows the processor to handle interrupts.
See also: disable
procedure get_meminfo(var meminfo : tmeminfo);
Returns the current state of memory allocation of the DOS extender.
NOTE: This procedure has nothing to do with the pascal function maxavail and memavail.
See also: tmeminfo
procedure get_pm_interrupt(vector : byte;var intaddr : tseginfo);
Returns the address of the current protected mode handler for the interrupt vector.
See also: interrupt redirection, set_pm_interrupt, tseginfo
function get_run_mode : word;
This function returns the mode which the extender is currently running (see rm_xxxx). The function is mostly used to determine if DPMI is supported.
uses go32; begin if get_run_mode=rm_dpmi then writeln('DPMI available') else writeln('No DPMI available'); end.
function get_cs : word; function get_ds : word; function get_ss : word;
This functions returns the value of the segment registers.
function inportb(port : word) : byte; function inportw(port : word) : word; function inportl(port : word) : longint;
Reads a byte, word or longint from the given I/O port.
See also: outport*
procedure outportb(port : word;data : byte); procedure outportw(port : word;data : word); procedure outportl(port : word;data : longint);
Writes a byte, word or longint from the given port.
See also: inport*
procedure realintr(intnr : word;var regs : trealregs);
NOTE: This procedure works only in DPMI mode
rm_unknown = 0; rm_raw = 1; { raw (without HIMEM) } rm_xms = 2; { XMS (for example with HIMEM, without EMM386) } rm_vcpi = 3; { VCPI (for example HIMEM and EMM386) } rm_dpmi = 4; { DPMI (for example DOS box or 386Max) }
This constants are returned by the get_run_mode which determines the mode which the DOS extender is running.
procedure seg_fillchar(seg : word;ofs : longint;count : longint;c : char); procedure seg_fillword(seg : word;ofs : longint;count : longint;w : word);
Fills a memory area specified by a 48 bit pointer with the given number of chars or words.
NOTE: Be careful using this function in non DPMI mode.
See also: seg_move
procedure seg_move(sseg : word;source : longint;dseg : word;dest : longint;count : longint);
This procedure copies data where the source and destination are specified by 48 bit pointers. For example, this function is used by the DPMI version of dosmemget and dosmemput.
NOTE: The procedure checks only for overlapping if source selector=destination selector. Be also careful using this function in non DPMI mode.
See also: seg_fill*
procedure set_pm_interrupt(vector : byte;const intaddr : tseginfo);
Sets a new protected mode handler for the interrupt vector.
See also: interrupt redirection, get_pm_interrupt, tseginfo
type tmeminfo = record available_memory : longint; available_pages : longint; available_lockable_pages : longint; linear_space : longint; unlocked_pages : longint; available_physical_pages : longint; total_physical_pages : longint; free_linear_space : longint; max_pages_in_paging_file : longint; reserved : array[0..2] of longint; end;
Returns informations about the memory allocation etc.
NOTE: The value of a field is zero if the value is unknown, it's only guaranted, that available_memory contains a valid value.
See also: get_meminfo
type trealregs=record realedi,realesi,realebp,realres, realebx,realedx,realecx,realeax : longint; realflags, reales,realds,realfs,realgs,realip,realcs,realsp,realss : word; end;
This data structure is used to pass register values to an real mode interrupt handler.
See also: realintr
type tseginfo = record offset : pointer; segment : word; end;
This record is used to store a 48-bit pointer.
See also: get_pm_interrupt, set_pm_interrupt
Copyright (c) 1996,97 by Florian Klaempfl