Browse Source

+ Initial implementation

michael 27 years ago
parent
commit
c1fcd42fd3
47 changed files with 3966 additions and 0 deletions
  1. 54 0
      docs/go32ex/Makefile
  2. 7 0
      docs/go32ex/README
  3. 118 0
      docs/go32ex/buffer.pas
  4. 52 0
      docs/go32ex/buffer.pp
  5. 56 0
      docs/go32ex/buffer.tex
  6. 227 0
      docs/go32ex/callback.pas
  7. 147 0
      docs/go32ex/callback.pp
  8. 151 0
      docs/go32ex/callback.tex
  9. 12 0
      docs/go32ex/changeext
  10. 33 0
      docs/go32ex/flags.pas
  11. 18 0
      docs/go32ex/flags.pp
  12. 22 0
      docs/go32ex/flags.tex
  13. 2 0
      docs/go32ex/foot.tex
  14. 19 0
      docs/go32ex/getrunmd.pas
  15. 26 0
      docs/go32ex/getrunmd.pp
  16. 30 0
      docs/go32ex/getrunmd.tex
  17. 1361 0
      docs/go32ex/go32.txt
  18. 3 0
      docs/go32ex/head.tex
  19. 72 0
      docs/go32ex/int_pm.pas
  20. 45 0
      docs/go32ex/int_pm.pp
  21. 49 0
      docs/go32ex/int_pm.tex
  22. 118 0
      docs/go32ex/keyclick.pas
  23. 91 0
      docs/go32ex/keyclick.pp
  24. 96 0
      docs/go32ex/keyclick.tex
  25. 43 0
      docs/go32ex/meminfo.pas
  26. 47 0
      docs/go32ex/meminfo.pp
  27. 51 0
      docs/go32ex/meminfo.tex
  28. 31 0
      docs/go32ex/noexampl.txt
  29. 19 0
      docs/go32ex/outport.pas
  30. 12 0
      docs/go32ex/outport.pp
  31. 16 0
      docs/go32ex/outport.tex
  32. 5 0
      docs/go32ex/pp2tex
  33. 120 0
      docs/go32ex/rmpm_int.pas
  34. 92 0
      docs/go32ex/rmpm_int.pp
  35. 96 0
      docs/go32ex/rmpm_int.tex
  36. 127 0
      docs/go32ex/sel_des.pas
  37. 101 0
      docs/go32ex/sel_des.pp
  38. 105 0
      docs/go32ex/sel_des.tex
  39. 35 0
      docs/go32ex/softint.pas
  40. 11 0
      docs/go32ex/softint.pp
  41. 15 0
      docs/go32ex/softint.tex
  42. 80 0
      docs/go32ex/textmess.pas
  43. 37 0
      docs/go32ex/textmess.pp
  44. 41 0
      docs/go32ex/textmess.tex
  45. 35 0
      docs/go32ex/vgasel.pas
  46. 17 0
      docs/go32ex/vgasel.pp
  47. 21 0
      docs/go32ex/vgasel.tex

+ 54 - 0
docs/go32ex/Makefile

@@ -0,0 +1,54 @@
+#######################################################################
+#
+# Makefile to compile all examples and convert them to LaTeX
+# 
+#######################################################################
+
+# Compiler
+PP=ppc386
+
+# Unit directory
+# UNITDIR=/usr/lib/ppc/0.99.0/linuxunits
+
+
+# Any options you wish to pass.
+PPOPTS=
+
+# Script to convert the programs to LaTeX examples which can be included.
+PP2TEX=pp2tex
+
+# Script to collect all examples in 1 file.
+MAKETEX=make1tex
+
+#######################################################################
+# No need to edit after this line.
+#######################################################################
+
+ifdef UNITDIR
+PPOPTS:=$(PPOPTS) -Up$(UNITDIR);
+endif
+
+.SUFFIXES: .pp .tex
+
+.PHONY: all tex clean
+
+OBJECTS=buffer callback flags getrunmd int_pm keyclick meminfo outport \
+  rmpm_int sel_des softint textmess vgasel 
+
+TEXOBJECTS=$(addsuffix .tex, $(OBJECTS))
+
+all : $(OBJECTS)
+
+tex : $(TEXOBJECTS)
+
+onetex : tex
+	$(MAKETEX) $(TEXOBJECTS)
+
+clean : 
+	rm -f *.o *.s $(OBJECTS) $(TEXOBJECTS)
+ 
+$(OBJECTS): %: %.pp
+	$(PP) $(PPOPTS) $*
+
+$(TEXOBJECTS): %.tex: %.pp head.tex foot.tex
+	$(PP2TEX) $*

+ 7 - 0
docs/go32ex/README

@@ -0,0 +1,7 @@
+These example were contributed by thomas schatzl.
+
+From each example there are 2 files, one with an extension .pas, and
+one with extension .pp. The .pas files are the original files. The .pp files
+have been stripped of comments to save some space and have been modified to
+fit more or less on a printed page.
+

+ 118 - 0
docs/go32ex/buffer.pas

@@ -0,0 +1,118 @@
+{ 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;
+end.

+ 52 - 0
docs/go32ex/buffer.pp

@@ -0,0 +1,52 @@
+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;
+end.

+ 56 - 0
docs/go32ex/buffer.tex

@@ -0,0 +1,56 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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;
+end.\end{verbatim}
+\end{FPCList}

+ 227 - 0
docs/go32ex/callback.pas

@@ -0,0 +1,227 @@
+{ 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;
+end.

+ 147 - 0
docs/go32ex/callback.pp

@@ -0,0 +1,147 @@
+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;
+end.

+ 151 - 0
docs/go32ex/callback.tex

@@ -0,0 +1,151 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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;
+end.\end{verbatim}
+\end{FPCList}

+ 12 - 0
docs/go32ex/changeext

@@ -0,0 +1,12 @@
+#!/bin/csh
+set fromext = $1
+set toext = $2
+shift
+shift
+foreach f ( $* )
+ set fromname = `basename $f $fromext`$fromext
+ if ( $f == $fromname ) then
+   set toname = `basename $f $fromext`$toext
+   mv $f $toname
+ endif
+end

+ 33 - 0
docs/go32ex/flags.pas

@@ -0,0 +1,33 @@
+{ 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');
+end.

+ 18 - 0
docs/go32ex/flags.pp

@@ -0,0 +1,18 @@
+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');
+end.

+ 22 - 0
docs/go32ex/flags.tex

@@ -0,0 +1,22 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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');
+end.\end{verbatim}
+\end{FPCList}

+ 2 - 0
docs/go32ex/foot.tex

@@ -0,0 +1,2 @@
+\end{verbatim}
+\end{FPCList}

+ 19 - 0
docs/go32ex/getrunmd.pas

@@ -0,0 +1,19 @@
+{ 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;
+end.

+ 26 - 0
docs/go32ex/getrunmd.pp

@@ -0,0 +1,26 @@
+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;
+end.

+ 30 - 0
docs/go32ex/getrunmd.tex

@@ -0,0 +1,30 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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;
+end.\end{verbatim}
+\end{FPCList}

+ 1361 - 0
docs/go32ex/go32.txt

@@ -0,0 +1,1361 @@
+The GO32 unit.
+
+This chapter of the documentation describe the GO32 unit for the Free Pascal compiler under DOS.
+
+This unit was first written for DOS by Florian Klämpfl.
+
+This chapter is divided in three sections.
+The first section is an introduction to the GO32 unit. The second section lists the pre-defined constants, types and variables.
+The third section describes the functions which appear in the interface part of the GO32 unit.
+
+A lot of function descriptions were made by Thomas Schatzl, for which my thanks.
+
+Introduction
+
+These docs contain information about the GO32 unit. Only the GO32V2 DPMI mode is discussed by me here due to the fact that new applications shouldn't be created with the older GO32V1 model. The former is much more advanced and better.
+Additionally a lot of functions only work in DPMI mode anyway.
+
+I hope the following explanations and introductions aren't too confusing at all. If you notice an error or bug send it to the FPC mailing list or directly to me.
+
+So let's get started and happy and error free coding I wish you....
+
+                                Thomas Schatzl, 25. August 1998
+
+
+Protected mode memory organization
+
+What is DPMI
+
+The DOS Protected Mode Interface helps you with various aspects of protected mode programming. These are roughly divided into descriptor handling, access to DOS memory, management of interrupts and exceptions, calls to real mode functions and other stuff. Additionally it automatically provides swapping to disk for memory intensive applications.
+
+A DPMI host (either a Windows DOS box or CWSDPMI.EXE) provides these functions for your programs.
+
+Selectors and descriptors
+
+Descriptors are a bit like real mode segments; they describe (as the name implies) a memory area in protected mode. A descriptor contains information about segment length, its base address and the attributes of it (i.e. type, access rights, ...).
+
+These descriptors are stored internally in a so-called descriptor table, which is basically an array of such descriptors.
+
+Selectors are roughly an index into this table.
+
+Because these 'segments' can be up to 4 GB in size, 32 bits aren't sufficient anymore to describe a single memory location like in real mode. 48 bits are now needed to do this, a 32 bit address and a 16 bit sized selector. The GO32 unit provides the tseginfo record to store such a pointer.
+
+But due to the fact that most of the time data is stored and accessed in the %ds selector, FPC assumes that all pointers point to a memory location of this selector. So a single pointer is still only 32 bits in size. This value represents the offset from the data segment base address to this memory location.
+
+FPC specialities (some collected tips and hints)
+
+The %ds and %es selector MUST always contain the same value or some system routines may crash when called.
+The %fs selector is preloaded with the DOSMEMSELECTOR variable at startup, and it MUST be restored after use, because again FPC relys on this for some functions.
+Luckily we asm programmers can still use the %gs selector for our own purposes, but for how long ?
+
+See also:
+tseginfo, dosmemselector, DOS memory access, get_cs(), get_ds(), get_ss()
+allocate_ldt_descriptors(), free_ldt_descriptors(), segment_to_descriptor()
+get_next_selector_increment_value(), get_segment_base_address(),
+set_segment_base_address(), set_segment_limit(),
+create_code_segment_alias_descriptor()
+
+DOS memory access
+
+
+DOS memory is accessed by the predefined DOSmemselector selector; the GO32 unit additionally provides some functions to help you with standard tasks, like copying memory from heap to DOS memory and the likes.
+Because of this it is strongly recommened to use them, but you are still free to use the provided standard memory accessing functions which use 48 bit pointers.
+The third, but only thought for compatibility purposes, is using the mem[]-arrays. These arrays map the whole 1 Mb DOS space. They shouldn't be used within new programs.
+
+To convert a segment:offset real mode address to a protected mode linear address you have to multiply the segment by 16 and add its offset. This linear address can be used in combination with the DOSMEMSELECTOR variable.
+
+See also:
+Selectors and descriptors, dosmemselector, dosmemget(), dosmemput(), dosmemmove(), dosmemfillchar(), dosmemfillword(), mem[]-arrays(), seg_move(), seg_fillchar(), seg_fillword()
+
+I/O port access
+
+The I/O port access is done via the various inport() and outport() functions which are available.
+Additionally Free Pascal supports the Turbo Pascal PORT[]-arrays but it is by no means recommened to use them, because they're only for compatibility purposes.
+
+See also:
+outport*(), inport*(), PORT[]-arrays
+
+Processor access
+
+These are some functions to access various segment registers (%cs, %ds, %ss) which makes your work a bit easier.
+
+See also:
+Selectors and descriptors, get_cs(), get_ds(), get_ss()
+
+Interrupt redirection
+
+Interrupts are program interruption requests, which in one or another way get to the processor; there's a distinction between software and hardware interrupts. The former are explicitely called by an 'int' instruction and are a bit comparable to normal functions. Hardware interrupts come from external devices like the keyboard or mouse. These functions are called handlers.
+
+Handling interrupts with DPMI
+
+The interrupt functions are real-mode procedures; they normally can't be called in protected mode without the risk of an protection fault. So the DPMI host creates an interrupt descriptor table for the application. Initially all software interrupts (except for int 31h, 2Fh and 21h function 4Ch) or external hardware interrupts are simply directed to a handler that reflects the interrupt in real-mode, i.e. the DPMI host's default handlers switch the CPU to real-mode, issue the interrupt and switch back to protected mode. The contents of general registers and flags are passed to the real mode handler and the modified registers and flags are returned to the protected mode handler. Segment registers and stack pointer are not passed between modes.
+
+Protected mode interrupts vs. Real mode interrupts
+
+As mentioned before, there's a distinction between real mode interrupts and protected mode interrupts; the latter are protected mode programs, while the former must be real mode programs.
+To call a protected mode interrupt handler, an assembly 'int' call must be issued, while the other is called via the realintr() or intr() function.
+Consequently, a real mode interrupt then must either reside in DOS memory (<1MB) or the application must allocate a real mode callback address via the get_rm_callback() function.
+
+Creating own interrupt handlers
+
+Interrupt redirection with FPC pascal is done via the set_pm_interrupt() for protected mode interrupts or via the set_rm_interrupt() for real mode
+interrupts.
+
+Disabling interrupts
+
+The GO32 unit provides the two procedures disable() and enable() to disable and enable all interrupts.
+
+Hardware interrupts
+
+Hardware interrupts are generated by hardware devices when something unusual happens; this could be a keypress or a mouse move or any other action. This is done to minimize CPU time, else the CPU would have to check all installed hardware for data in a big loop (this method is called 'polling') and this would take much time.
+
+A standard IBM-PC has two interrupt controllers, that are responsible for these hardware interrupts: both allow up to 8 different interrupt sources (IRQs, interrupt requests). The second controller is connected to the first through IRQ 2 for compatibility reasons, e.g. if controller 1 gets an IRQ 2, he hands the IRQ over to controller 2.
+Because of this up to 15 different hardware interrupt sources can be handled.
+
+IRQ 0 through IRQ 7 are mapped to interrupts 8h to Fh and the second controller (IRQ 8 to 15) is mapped to interrupt 70h to 77h.
+
+All of the code and data touched by these handlers MUST be locked (via the various locking functions) to avoid page faults at interrupt time. Because hardware interrupts are called (as in real mode) with interrupts disabled, the handler has to enable them before it returns to normal program execution.
+Additionally a hardware interrupt must send an EOI (end of interrupt) command to the responsible controller; this is acomplished by sending the value 20h to port 20h (for the first controller) or A0h (for the second controller).
+
+Software interrupts
+
+Ordinarily, a handler installed with set_pm_interrupt only services software interrupts that are executed in protected mode; real mode software interrupts can be redirected by set_rm_interrupt.
+
+See also
+set_rm_interrupt(), get_rm_interrupt(), set_pm_interrupt(), get_pm_interrupt(), lock_data(), lock_code(), enable(), disable(), outport*()
+
+Real mode callbacks
+
+The callback mechanism can be thought of as the converse of calling a real mode procedure (i.e. interrupt), which allows your program to pass information to a real mode program, or obtain services from it in a manner that's transparent to the real mode program.
+
+In order to make a real mode callback available, you must first get the real mode callback address of your procedure and the selector and offset of a register data structure. This real mode callback address (this is a segment:offset address) can be passed to a real mode program via a software interrupt, a DOS memory block or any other convenient mechanism.
+
+When the real mode program calls the callback (via a far call), the DPMI host saves the registers contents in the supplied register data structure, switches into protected mode, and enters the callback routine with the following conditions:
+
+* interrupts disabled
+* %CS:%EIP = 48 bit pointer specified in the original call to get_rm_callback()
+* %DS:%ESI = 48 bit pointer to to real mode SS:SP
+* %ES:%EDI = 48 bit pointer of real mode register data structure
+* %SS:%ESP = locked protected mode stack
+* All other registers undefined
+
+The callback procedure can then extract its parameters from the real mode register data structure and/or copy parameters from the real mode stack to the protected mode stack. Recall that the segment register fields of the real mode register data structure contain segment or paragraph addresses that are not valid in protected mode. Far pointers passed in the real mode register data structure must be translated to virtual addresses before they can be used with a protected mode program.
+
+The callback procedure exits by executing an IRET with the address of the real mode register data structure in %ES:%EDI, passing information back to the real mode caller by modifying the contents of the real mode register data structure and/or manipulating the contents of the real mode stack. The callback procedure is responsible for setting the proper address for resumption of real mode execution into the real mode register data structure; typically, this is accomplished by extracting the return address from the real mode stack and placing it into the %CS:%EIP fields of the real mode register data structure. After the IRET, the DPMI host switches the CPU back into real mode, loads ALL registers with the contents of the real mode register data structure, and finally returns control to the real mode program.
+
+All variables and code touched by the callback procedure MUST be locked to prevent page faults.
+
+See also:
+Segment and descriptors, tseginfo, trealregs, get_rm_callback(), free_rm_callback(), lock_code(), lock_data()
+
+Types, Variables and Constants
+
+Constants
+
+Constants returned by get_run_mode()
+
+Tells you under what memory environment (e.g. memory manager) the program currently runs.
+
+rm_unknown = 0; { unknown }
+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) }
+
+Note: GO32V2 _always_ creates DPMI programs, so you need a suitable DPMI host like CWSDPMI.EXE or a Windows DOS box. So you don't need to check it, these constants are only useful in GO32V1 mode.
+
+Processor flags constants
+
+They are provided for a simple check with the flags identifier in the trealregs type. To check a single flag, simply do an AND operation with the flag you want to check. It's set if the result is the same as the flag value.
+
+const
+	carryflag     = $001;
+	parityflag    = $004;
+	auxcarryflag  = $010;
+	zeroflag      = $040;
+	signflag      = $080;
+	trapflag      = $100;
+	interruptflag = $200;
+	directionflag = $400;
+	overflowflag  = $800;
+
+Predefined types
+
+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;
+
+Holds information about the memory allocation, etc.
+
+Record entry		     Description
+available_memory         Largest available free block in bytes
+available_pages			 Maximum unlocked page allocation in pages
+available_lockable_pages Maximum locked page allocation in pages
+linear_space			 Linear address space size in pages
+unlocked_pages			 Total number of unlocked pages
+available_physical_pages Total number of free pages
+total_physical_pages     Total number of physical pages
+free_linear_space        Free linear address space in pages
+max_pages_in_paging_file Size of paging file/partition in pages
+
+NOTE: The value of a field is -1 (0ffffffffh) if the value is unknown, it's only guaranteed, that available_memory contains a valid value.
+
+The size of the pages can be determined by the get_page_size() function.
+
+type
+    trealregs = record
+              case Integer of
+                   1: { 32-bit } (EDI, ESI, EBP, Res, EBX, EDX, ECX, EAX: Longint;
+                                  Flags, ES, DS, FS, GS, IP, CS, SP, SS: Word);
+                   2: { 16-bit } (DI, DI2, SI, SI2, BP, BP2, R1, R2: Word;
+                                  BX, BX2, DX, DX2, CX, CX2, AX, AX2: Word);
+                   3: { 8-bit }  (stuff: array[1..4] of Longint;
+                                  BL, BH, BL2, BH2, DL, DH, DL2, DH2,
+                                  CL, CH, CL2, CH2, AL, AH, AL2, AH2: Byte);
+                   4: { Compat } (RealEDI, RealESI, RealEBP, RealRES,
+                                  RealEBX, RealEDX, RealECX, RealEAX: Longint;
+                                  RealFlags,
+                                  RealES, RealDS, RealFS, RealGS,
+                                  RealIP, RealCS, RealSP, RealSS: Word);
+    end;
+
+    registers = trealregs;
+
+These two types contain the data structure to pass register values to a interrupt handler or real mode callback.
+
+type
+    tseginfo = record
+             offset : Pointer;
+             segment : Word;
+    end;
+
+This record is used to store a full 48-bit pointer. This may be either a protected mode selector:offset address or in real mode a segment:offset address, depending on application.
+
+See also:
+Selectors and descriptors, DOS memory access, Interrupt redirection
+
+Variables.
+
+var
+   dosmemselector : Word;
+
+Selector to the DOS memory. The whole DOS memory is automatically mapped to this single descriptor at startup. This selector is the recommened way to access DOS memory.
+
+var
+	int31error : Word;
+
+This variable holds the result of a DPMI interrupt call. Any nonzero value must be treated as a critical failure.
+
+Functions and Procedures
+
+Descriptor handling
+
+function allocate_ldt_descriptors (count : Word) : Word;
+
+Allocates a number of new descriptors.
+
+Parameters:
+count - specifies the number of requested unique descriptors
+
+Return value:
+Base selector
+
+Notes:
+The descriptors allocated must be initialized by the application with other function calls. This function returns descriptors with a limit and size value set to zero.
+If more than one descriptor was requested, the function returns a base selector referencing the first of a contiguous array of descriptors. The selector values for subsequent descriptors in the array can be calculated by adding the value returned by the get_next_selector_increment_value() function.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, free_ldt_descriptors(), get_next_selector_increment_value(), segment_to_descriptor(), create_code_segment_alias_descriptor(), set_segment_limit(), set_segment_base_address()
+
+function free_ldt_descriptor (des : Word) : boolean;
+
+Frees a previously allocated descriptor.
+
+Parameters:
+des - The descriptor to be freed
+
+Return value:
+True if successful, false otherwise
+
+Notes:
+After this call this selector is invalid and must not be used for any memory operations anymore. Each descriptor allocated with allocate_ltd_descriptor() must be freed individually with this function, even if it was previously allocated as a part of a contiguous array of descriptors.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, allocate_ldt_descriptors(), get_next_selector_increment_value()
+
+function segment_to_descriptor (seg : Word) : Word;
+
+Maps a real mode segment (paragraph) address onto an descriptor that can be used by a protected mode program to access the same memory.
+
+Parameters:
+seg - the real mode segment you want the descriptor to
+
+Return values:
+Descriptor to real mode segment address.
+
+Notes:
+The returned descriptors limit will be set to 64 kB. Multiple calls to this function with the same segment address will return the same selector.
+Descriptors created by this function can never be modified or freed. Programs which need to examine various real mode addresses using the same selector should use the function allocate_ldt_descriptors() and change the base address as necessary.
+
+Errors:
+Check int31error variable.
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, allocate_ldt_descriptors(), free_ldt_descriptor(), set_segment_base_address()
+
+function get_next_selector_increment_value : Word;
+
+Returns the selector increment value when allocating multiple subsequent descriptors via allocate_ldt_descriptors().
+
+Parameters:
+none
+
+Return value:
+Selector increment value
+
+Notes:
+Because allocate_ldt_descriptors() only returns the selector for the first descriptor and so the value returned by this function can be used to calculate the selectors for subsequent descriptors in the array.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, allocate_ldt_descriptors(), free_ldt_descriptor()
+
+function get_segment_base_address (d : Word) : Longint;
+
+Returns the 32-bit linear base address from the descriptor table for the specified segment.
+
+Parameters:
+d - selector of the descriptor you want the base address
+
+Return values:
+Linear base address of specified descriptor
+
+Errors:
+Check int31error variable.
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, allocate_ldt_descriptors(), set_segment_base_address(), allocate_ldt_descriptors(), set_segment_limit(), get_segment_limit()
+
+function set_segment_base_address (d : Word; s : Longint) : boolean;
+
+Sets the 32-bit linear base address of a descriptor.
+
+Parameters:
+d - selector
+s - new base address of the descriptor
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, allocate_ldt_descriptors(), get_segment_base_address(), allocate_ldt_descriptors(), set_segment_limit(), get_segment_base_address(), get_segment_limit()
+
+function get_segment_limit (d : Word) : Longint;
+
+Returns a descriptors segment limit
+
+Parameters
+d - selector
+
+Return value:
+Limit of the descriptor in bytes
+
+Notes:
+none
+
+Errors:
+Returns zero if descriptor is invalid
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, allocate_ldt_descriptors(), set_segment_limit(), set_segment_base_address(), get_segment_base_address()
+
+
+function set_segment_limit (d : Word; s : Longint) : boolean;
+
+Sets the limit of a descriptor.
+
+Parameters:
+d - selector
+s - new limit of the descriptor
+
+Return values:
+Returns true if successful, else false.
+
+Notes:
+The new limit specified must be the byte length of the segment - 1. Segment limits bigger than or equal to 1MB must be page aligned, they must have the lower 12 bits set.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, allocate_ldt_descriptors(), set_segment_base_address(), get_segment_limit(), set_segment_limit()
+
+function set_descriptor_access_right (d : Word; w : Word) : Longint;
+
+Sets the access rights of a descriptor
+
+Parameters:
+d - selector
+w - new descriptor access rights
+
+Return values:
+?? (* this is a bug. This function doesn't return anything useful *)
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+See also:
+Selectors and descriptors, int31error, get_descriptor_access_rights()
+
+function get_descriptor_access_right (d : Word) : Longint;
+
+Gets the access rights of a descriptor
+
+Parameters:
+d - selector to descriptor
+
+Return value:
+Access rights bit field
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, set_descriptor_access_rights()
+
+
+function create_code_segment_alias_descriptor (seg : Word) : Word;
+
+Creates a new descriptor that has the same base and limit as the specified descriptor.
+
+Parameters:
+seg - selector
+
+Return values:
+Data selector (alias)
+
+Notes:
+In effect, the function returns a copy of the descriptor. The descriptor alias returned by this function will not track changes to the original descriptor. In other words, if an alias is created with this function, and the base or limit of the original segment is then changed, the two descriptors will no longer map the same memory.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, int31error, allocate_ldt_descriptors(), set_segment_limit(), set_segment_base_address()
+
+Extended memory management services
+
+function get_meminfo (var meminfo : tmeminfo) : boolean;
+
+Returns information about the amount of available physical memory, linear address space, and disk space for page swapping.
+
+Parameters:
+meminfo - buffer to fill memory information into
+
+Return values:
+Due to an implementation bug this function always returns false, but it always succeeds.
+
+Notes:
+Only the first field of the returned structure is guaranteed to contain a valid value. Any fields that are not supported by the DPMI host will be set by the host to -1 (0FFFFFFFFH) to indicate that the information is not available. The size of the pages used by the DPMI host can be obtained with the get_page_size() function.
+
+Errors:
+Check the int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+int31error, tmeminfo, get_page_size()
+
+
+function allocate_memory_block (size:Longint):Longint;
+
+Allocates a block of linear memory.
+
+Parameters:
+size - Size of requested linear memory block in bytes
+
+Returned values:
+?? blockhandle - the memory handle to this memory block
+Linear address of the requested memory.
+
+Notes:
+WARNING: According to my DPMI docs this function is not implemented correctly. Normally you should also get a blockhandle to this block after successful operation. This handle is used to free the memory block afterwards or use this handle for other purposes. So this block can't be deallocated and is henceforth unusuable !
+
+This function doesn't allocate any descriptors for this block, it's the applications resposibility to allocate and initialize for accessing this memory.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+free_memory_block()
+
+function free_memory_block (blockhandle : Longint) : boolean;
+
+Frees a previously allocated memory block
+
+Parameters:
+blockhandle - the handle to the memory area to free
+
+Return value:
+True if successful, false otherwise.
+
+Notes:
+Frees memory that was previously allocated with allocate_memory_block(). This function doesn't free any descriptors mapped to this block, it's the application's responsibility.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+allocate_memory_block()
+
+function request_linear_region (linearaddr, size : Longint; var blockhandle : Longint) : boolean;
+
+!!!!!! DOESN'T WORK AT ALL, AND WON'T IN THE FUTURE BECAUSE IT IS A DPMI 1.0 FUNCTION !!!!!!! (a good reason to skip this description)
+
+function map_device_in_memory_block (handle, offset, pagecount, device : Longint) : boolean;
+
+!!!!!! DOESN'T WORK AT ALL, AND WON'T IN THE FUTURE BECAUSE IT IS A DPMI 1.0 FUNCTION !!!!!!! (a good reason to skip this description)
+
+
+function get_linear_addr (phys_addr : Longint; size : Longint) : Longint;
+
+Converts a physical address into a linear address.
+
+Parameters:
+phys_addr - physical address of device
+size - size of region to map in bytes
+
+Return value:
+Linear address that can be used to access the physical memory.
+
+Notes:
+It's the applications resposibility to allocate and set up a descriptor for access to the memory. This function shouldn't be used to map real mode addresses.
+
+Errors:
+Check int31error variable.
+
+Example:
+
+See also:
+Selectors and descriptors, DOS memory access, int31error, allocate_ldt_descriptors(), set_segment_limit(), set_segment_base_address()
+
+
+DOS memory management
+
+function global_dos_alloc (bytes : Longint) : Longint;
+
+Allocates a block of DOS real mode memory
+
+Parameters:
+bytes - size of requested real mode memory
+
+Return values:
+The high word of the returned value contains the selector to the allocated DOS memory block, the low word the corresponding real mode segment value. The offset value is always zero.
+
+Notes:
+
+This function allocates memory from DOS memory pool, i.e. memory below the 1 MB boundary that is controlled by DOS. Such memory blocks are typically used to exchange data with real mode programs, TSRs, or device drivers.
+The function returns both the real mode segment base address of the block and one descriptor that can be used by protected mode applications to access the block.
+This function should only used for temporary buffers to get real mode information (e.g. interrupts that need a data structure in ES:(E)DI), because every single block needs an unique selector.
+The returned selector should only be freed by a global_dos_free() call.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, int31error, global_dos_free()
+
+function global_dos_free (selector : Word) : boolean;
+
+Frees a previously allocated DOS memory block
+
+Parameters:
+selector - selector to the DOS memory block
+
+Return value:
+True if successful, false otherwise
+
+Notes:
+The descriptor allocated for the memory block is automatically freed and hence invalid for further use. This function should only be used for memory allocated by global_dos_alloc().
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, int31error, global_dos_alloc()
+
+procedure dosmemput (seg : Word; ofs : Word; var data; count : Longint);
+
+Copies heap data to DOS real mode memory.
+
+Parameters:
+seg - destination real mode segment
+ofs - destination real mode offset
+data - source
+count - number of bytes to copy
+
+Return value:
+none
+
+Notes:
+No range checking is performed.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+DOS memory access, dosmemget(), dosmemmove(), dosmemfillchar(), dosmemfillword(), seg_move(), seg_fillchar(), seg_fillword()
+
+procedure dosmemget (seg : Word; ofs : Word; var data; count : Longint);
+
+Copies data from the DOS memory onto the heap.
+
+Parameters:
+seg - source real mode segment
+ofs - source real mode offset
+data - destination
+count - number of bytes to copy
+
+Notes:
+No range checking is performed.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+DOS memory access, dosmemput(), dosmemmove(), dosmemfillchar(), dosmemfillword(), seg_move(), seg_fillchar(), seg_fillword()
+
+procedure dosmemmove (sseg, sofs, dseg, dofs : Word; count : Longint);
+
+Copies count bytes of data between two DOS real mode memory locations.
+
+Parameters:
+sseg - source real mode segment
+sofs - source real mode offset
+dseg - destination real mode segment
+dofs - destination real mode offset
+count - number of bytes to copy
+
+Return values:
+none
+
+Notes:
+No range check is performed in any way.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, dosmemput(), dosmemget(), dosmemfillchar(), dosmemfillword(), seg_move(), seg_fillchar(), seg_fillword()
+
+procedure dosmemfillchar (seg, ofs : Word; count : Longint; c : char);
+
+Sets a region of DOS memory to a specific byte value
+
+Parameters:
+seg - real mode segment
+ofs - real mode offset
+count - number of bytes to set
+c - value to set memory to
+
+Return values:
+none
+
+Notes:
+No range check is performed.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, dosmemput(), dosmemget(), dosmemmove(), dosmemfillword(), seg_move(), seg_fillchar(), seg_fillword()
+
+procedure dosmemfillword(seg, ofs : Word; count : Longint; w : Word);
+
+Sets a region of DOS memory to a specific word value
+
+Parameters:
+seg - real mode segment
+ofs - real mode offset
+count - number of words to set
+w - value to set memory to
+
+Return values:
+none
+
+Notes:
+No range check is performed.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, dosmemput(), dosmemget(), dosmemmove(), dosmemfillchar(), seg_move(), seg_fillchar(), seg_fillword()
+
+
+Interrupt management services
+
+
+function get_rm_interrupt (vector : byte; var intaddr : tseginfo) : boolean;
+
+Returns the contents of the current machine's real mode interrupt vector for the specified interrupt.
+
+Parameters:
+vector - interrupt vector number
+intaddr - buffer to store real mode segment:offset address
+
+Return values:
+True if successful, false otherwise
+
+Notes:
+The returned address is a real mode segment address, which isn't valid in protected mode.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Interrupt redirection, int31error, set_rm_interrupt(), set_pm_interrupt(), get_pm_interrupt()
+
+function set_rm_interrupt (vector : byte; const intaddr : tseginfo) : boolean;
+
+Sets a real mode interrupt handler
+
+Parameters:
+vector - the interrupt vector number to set
+intaddr - address of new interrupt vector
+
+Return values:
+True if successful, otherwise false.
+
+Notes:
+The address supplied MUST be a real mode segment address, not a selector:offset address. So the interrupt handler must either reside in DOS memory (below 1 Mb boundary) or the application must allocate a real mode callback address with get_rm_callback().
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Interrupt redirection, int31error, get_rm_interrupt(), set_pm_interrupt(), get_pm_interrupt(), get_rm_callback()
+
+function get_pm_interrupt (vector : byte; var intaddr : tseginfo) : boolean;
+
+Returns the address of a current protected mode interrupt handler
+
+Parameters:
+vector - interrupt handler number you want the address to
+intaddr - buffer to store address
+
+Return values:
+True if successful, false if not.
+
+Notes:
+The returned address is a protected mode selector:offset address.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Interrupt redirection, int31error, set_pm_interrupt(), set_rm_interrupt(), get_rm_interrupt()
+
+function set_pm_interrupt (vector : byte; const intaddr : tseginfo) : boolean;
+
+Sets the address of the protected mode handler for an interrupt
+
+Parameters:
+vector - number of protected mode interrupt to set
+intaddr - selector:offset address to the interrupt vector
+
+Return values:
+True if successful, false otherwise.
+
+Notes:
+The address supplied must be a valid selector:offset protected mode address.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Interrupt redirection, int31error, get_pm_interrupt(), set_rm_interrupt(), get_rm_interrupt()
+
+procedure disable;
+
+Disables all hardware interrupts by execution a CLI instruction.
+
+Parameters:
+none
+
+Return values:
+none
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Interrupt redirection, enable()
+
+procedure enable;
+
+Enables all hardware interrupts by executing a STI instruction.
+
+Parameters:
+none
+
+Return values:
+none
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Interrupt redirection, disable()
+
+
+
+Translation services
+
+
+function realintr(intnr : Word; var regs : trealregs) : boolean;
+
+Simulates an interrupt in real mode
+
+Parameters:
+intnr - interrupt number to issue in real mode
+regs - registers data structure
+
+Return values:
+The supplied registers data structure contains the values that were returned by the real mode interrupt.
+True if successful, false if not.
+
+Notes:
+The function transfers control to the address specified by the real mode interrupt vector of intnr. The real mode handler must return by executing an IRET.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Interrupts, trealregs
+
+function get_rm_callback (pm_func : pointer; const reg : trealregs; var rmcb : tseginfo) : boolean;
+
+Returns a unique real mode segment:offset address, known as a "real mode callback," that will transfer control from real mode to a protected mode procedure.
+
+Parameters:
+pm_func - pointer to the protected mode callback function
+reg - supplied registers structure
+rmcb - buffer to real mode address of callback function
+
+Return values:
+True if successful, otherwise false.
+
+Notes:
+Callback addresses obtained with this function can be passed by a protected mode program for example to an interrupt handler, device driver, or TSR, so that the real mode program can call procedures within the
+protected mode program or notify the protected mode program of an event.
+The contents of the supplied regs structure is not valid after function call, but only at the time of the actual callback.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Callbacks, int31error, free_rm_callback()
+
+
+function free_rm_callback (var intaddr : tseginfo) : boolean;
+
+Releases a real mode callback address that was previously allocated with the get_rm_callback() function.
+
+Parameters:
+intaddr - real mode address buffer returned by get_rm_callback()
+
+Return values:
+True if successful, false if not
+
+Notes:
+A callback should be released immediately when it is no longer used.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+Callbacks, int31error, set_rm_interrupt(), get_rm_callback()
+
+
+Page management
+
+
+function lock_linear_region (linearaddr, size : Longint) : boolean;
+
+Locks a memory region to prevent swapping of it
+
+Parameters:
+linearaddr - the linear address of the memory are to be locked
+size - size in bytes to be locked
+
+Return value:
+True if successful, false otherwise
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, int31error, lock_data(), lock_code(), unlock_linear_region(), unlock_data(), unlock_code()
+
+function lock_data (var data; size : Longint) : boolean;
+
+Locks a memory range which resides in the data segment selector
+
+Parameters:
+data - address of data to be locked
+size - length of data to be locked
+
+Return values:
+True if successful, false otherwise
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, int31error, lock_linear_region(), lock_code(), unlock_linear_region(), unlock_data(), unlock_code()
+
+function lock_code (functionaddr : pointer; size : Longint) : boolean;
+
+Locks a memory range which is in the code segment selector.
+
+Parameters:
+functionaddr - address of the function to be lockd
+size - size in bytes to be locked
+
+Return values:
+True if successful, false otherwise
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, int31error, lock_linear_region(), lock_data(), unlock_linear_region(), unlock_data(), unlock_code()
+
+
+function unlock_linear_region (linearaddr, size : Longint) : boolean;
+
+Unlocks a previously locked linear region range to allow it to be swapped out again if needed.
+
+Parameters:
+linearaddr - linear address of the memory to be unlocked
+size - size bytes to be unlocked
+
+Return values:
+True if successful, false otherwise
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, int31error, unlock_data(), unlock_code(), lock_linear_region(), lock_data(), lock_code()
+
+
+function unlock_data (var data; size : Longint) : boolean;
+
+Unlocks a memory range which resides in the data segment selector.
+
+Paramters:
+data - address of memory to be unlocked
+size - size bytes to be unlocked
+
+Return values:
+True if successful, false otherwise
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, int31error, unlock_linear_region(), unlock_code(), lock_linear_region(), lock_data(), lock_code()
+
+
+function unlock_code (functionaddr : pointer; size : Longint) : boolean;
+
+Unlocks a memory range which resides in the code segment selector.
+
+Parameters:
+functionaddr - address of function to be unlocked
+size - size bytes to be unlocked
+
+Return value:
+True if successful, false otherwise
+
+Notes:
+none
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, int31error, unlock_linear_region(), unlock_data(), lock_linear_region(), lock_data(), lock_code()
+
+function get_page_size : Longint;
+
+Returns the size of a single memory page
+
+Parameters:
+none
+
+Return value:
+Size of a single page in bytes
+
+Notes:
+The returned size is typically 4096 bytes.
+
+Errors:
+Check int31error variable
+
+Example:
+(* not my job *)
+
+See also:
+tmeminfo, get_meminfo()
+
+
+Miscellanous
+
+
+procedure seg_move (sseg : Word; source : Longint; dseg : Word; dest : Longint; count : Longint);
+
+Copies data between two memory locations
+
+Parameters:
+sseg - source selector
+source - source offset
+dseg - destination selector
+dest - destination offset
+count - size in bytes to copy
+
+Return values:
+none
+
+Notes:
+Overlapping is only checked if the source selector is equal to the destination selector. No range check is done.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, seg_fillchar(), seg_fillword(), dosmemfillchar(), dosmemfillword(), dosmemget(), dosmemput(), dosmemmove()
+
+
+procedure seg_fillchar (seg : Word; ofs : Longint; count : Longint; c : char);
+
+Sets a memory area to a specific value.
+
+Parameters:
+seg - selector to memory area
+ofs - offset to memory
+count - number of bytes to set
+c - byte data which is set
+
+Return values:
+none
+
+Notes:
+No range check is done in any way.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, seg_move(), seg_fillword(), dosmemfillchar(), dosmemfillword(), dosmemget(), dosmemput(), dosmemmove()
+
+procedure seg_fillword (seg : Word; ofs : Longint; count : Longint; w : Word);
+
+Sets a memory area to a specific value.
+
+Parameters:
+seg - selector to memory area
+ofs - offset to memory
+count - number of words to set
+w - word data which is set
+
+Return values:
+none
+
+Notes:
+No range check is done in any way.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selectors and descriptors, DOS memory access, seg_move(), seg_fillchar(), dosmemfillchar(), dosmemfillword(), dosmemget(), dosmemput(), dosmemmove()
+
+
+function get_cs : Word;
+
+Returns the cs selector
+
+Parameters:
+none
+
+Return values:
+The content of the cs segment register
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selector and descriptors, Processor access, int31error, get_ds, get_ss
+
+function get_ds : Word;
+
+Returns the ds selector
+
+Parameters:
+none
+
+Return values:
+The content of the ds segment register
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selector and descriptors, Processor access, int31error, get_cs, get_ss
+
+function get_ss : Word;
+
+Returns the ss selector
+
+Parameters:
+none
+
+Return values:
+The content of the ss segment register
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+Selector and descriptors, Processor access, int31error, get_ds, get_cs
+
+function inportb (port : Word) : byte;
+function inportw (port : Word) : Word;
+function inportl (port : Word) : Longint;
+
+Reads data from the selected I/O port
+
+Parameters:
+port - the I/O port number which is read
+
+Return values:
+Current I/O port value
+
+Notes:
+The returned data is either be byte, word or longint sized, dependant of the function.
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+I/O port access, outport*()
+
+procedure outportb (port : Word; data : byte);
+procedure outportw (port : Word; data : Word);
+procedure outportl (port : Word; data : Longint);
+
+Sends data to the specified I/O port
+
+Parameters:
+port - the I/O port number to send data to
+data - value sent to I/O port
+
+Return values:
+none
+
+Notes:
+The difference between these functions is the size of the sent data (either byte, word or longint sized)
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+I/O port access, inport*()
+
+function get_run_mode : Word;
+
+Returns the current mode your application runs with
+
+Parameters:
+none
+
+Return values:
+One of the constants used by this function
+
+Notes:
+none
+
+Errors:
+none
+
+Example:
+(* not my job *)
+
+See also:
+DPMI, constants returned by get_run_mode

+ 3 - 0
docs/go32ex/head.tex

@@ -0,0 +1,3 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}

+ 72 - 0
docs/go32ex/int_pm.pas

@@ -0,0 +1,72 @@
+{ example for :
+          set_pm_interrupt()
+          get_pm_interrupt()
+          Interrupt redirection
+          Software interrupt
+          tseginfo record
+          get_cs()
+}
+
+{ 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, { wherey(), keypressed() }
+     go32;
+
+const int1c = $1c; { interrupt number we want to hook }
+
+var oldint1c : tseginfo; { 48 bit pointer to old interrupt handler }
+    newint1c : tseginfo; { 48 bit pointer to new interrupt handler }
+
+    int1c_counter : Longint; { increased every time the interrupt is called  }
+
+{$ASMMODE DIRECT}
+{ 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
+INT1C_DS: .word 0
+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);
+     { store necessary data into the handler }
+     asm
+        movw %ds, %ax
+        movw %ax, INT1C_DS
+     end;
+     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.

+ 45 - 0
docs/go32ex/int_pm.pp

@@ -0,0 +1,45 @@
+Program int_pm;
+
+uses crt, go32;
+
+const int1c = $1c; 
+
+var oldint1c : tseginfo;
+    newint1c : tseginfo;
+    int1c_counter : Longint;
+
+{$ASMMODE DIRECT}
+procedure int1c_handler; assembler;
+asm
+   cli
+   pushw %ds
+   pushw %ax
+   movw %cs:INT1C_DS, %ax
+   movw %ax, %ds
+   incl _INT1C_COUNTER
+   popw %ax
+   popw %ds
+   sti
+   iret
+INT1C_DS: .word 0
+end;
+
+var i : Longint;
+
+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);
+     end;
+     set_pm_interrupt(int1c, oldint1c);
+end.

+ 49 - 0
docs/go32ex/int_pm.tex

@@ -0,0 +1,49 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+Program int_pm;
+
+uses crt, go32;
+
+const int1c = $1c; 
+
+var oldint1c : tseginfo;
+    newint1c : tseginfo;
+    int1c_counter : Longint;
+
+{$ASMMODE DIRECT}
+procedure int1c_handler; assembler;
+asm
+   cli
+   pushw %ds
+   pushw %ax
+   movw %cs:INT1C_DS, %ax
+   movw %ax, %ds
+   incl _INT1C_COUNTER
+   popw %ax
+   popw %ds
+   sti
+   iret
+INT1C_DS: .word 0
+end;
+
+var i : Longint;
+
+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);
+     end;
+     set_pm_interrupt(int1c, oldint1c);
+end.\end{verbatim}
+\end{FPCList}

+ 118 - 0
docs/go32ex/keyclick.pas

@@ -0,0 +1,118 @@
+{ 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;
+end.

+ 91 - 0
docs/go32ex/keyclick.pp

@@ -0,0 +1,91 @@
+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.

+ 96 - 0
docs/go32ex/keyclick.tex

@@ -0,0 +1,96 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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.
+\end{verbatim}
+\end{FPCList}

+ 43 - 0
docs/go32ex/meminfo.pas

@@ -0,0 +1,43 @@
+{ 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;
+end.

+ 47 - 0
docs/go32ex/meminfo.pp

@@ -0,0 +1,47 @@
+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;
+end.

+ 51 - 0
docs/go32ex/meminfo.tex

@@ -0,0 +1,51 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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;
+end.\end{verbatim}
+\end{FPCList}

+ 31 - 0
docs/go32ex/noexampl.txt

@@ -0,0 +1,31 @@
+{ no example for the following funcs, sorry : }
+
+{ I don't know a good reason why to allocate more than one descriptor at once }
+    function get_next_selector_increment_value : word;
+
+{ can't think of any suitable example }
+    function create_code_segment_alias_descriptor(seg : word) : word;
+
+{ too complicated, because a lot of code overhead is required to
+  demonstrate this (e.g. VBE 2 LFB requires too much of 'pre-explanations') }
+    function get_linear_addr(phys_addr : longint;size : longint) : longint;
+
+{ will come soon (I hope), needs some extra time }
+    function get_exception_handler( ... ) : boolean;
+    function set_exception_handler( ... ) : boolean;
+
+{ too much work for me ... :-)  and I don't know a good reason to change a
+  real mode interrupt vector }
+    function get_rm_interrupt(vector : byte;var intaddr : tseginfo) : boolean;
+    function set_rm_interrupt(vector : byte;const intaddr : tseginfo) : boolean;
+
+{ no example for these two because the first is buggy, and the second without
+  the first is useless }
+allocate_memory_block(), free_memory_block()
+
+{ these don't work at all, because they're DPMI 1.0 only, they will never work
+  because CWSDPMI is a 0.9 DPMI host }
+get_rm_exception_handler(), set_rm_exception_handler(),
+get_pm_exception_handler(), set_pm_exception_handler(),
+request_linear_region(), get_page_attributes(), set_page_attributes(),
+map_device_in_memory_block(), perhaps more

+ 19 - 0
docs/go32ex/outport.pas

@@ -0,0 +1,19 @@
+{ 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);
+end.

+ 12 - 0
docs/go32ex/outport.pp

@@ -0,0 +1,12 @@
+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);
+end.

+ 16 - 0
docs/go32ex/outport.tex

@@ -0,0 +1,16 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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);
+end.\end{verbatim}
+\end{FPCList}

+ 5 - 0
docs/go32ex/pp2tex

@@ -0,0 +1,5 @@
+#!/bin/sh
+# Simply paste a header and footer to the program.
+cat head.tex >  $1.tex
+cat $1.pp    >> $1.tex
+cat foot.tex >> $1.tex

+ 120 - 0
docs/go32ex/rmpm_int.pas

@@ -0,0 +1,120 @@
+{ example for :
+          interrupt redirection
+          software vs. hardware interrupts
+          set_pm_interrupt()
+          get_pm_interrupt()
+          get_cs()
+          tseginfo
+          trealregs
+          processor access
+          get_cs(), get_ds(), get_ss()
+}
+
+{ 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, { used for clreol(), gotoxy() }
+     go32;
+
+{$ASMMODE DIRECT}
+
+var r : trealregs;
+    axreg : Word; { temporary variable used for the protected mode int call }
+
+    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 CallOld
+   movw $0x3112, %ax
+   iret
+
+CallOld:
+   ljmp %cs:OLDHANDLER
+
+OLDHANDLER: .long 0
+            .word 0
+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);
+     { storing old handler address in interrupt handler }
+     asm
+        movl _OLDINT21H, %eax
+        movl %eax, OLDHANDLER
+        movw 4+_OLDINT21H, %ax
+        movw %ax, 4+OLDHANDLER
+     end;
+     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);
+end.

+ 92 - 0
docs/go32ex/rmpm_int.pp

@@ -0,0 +1,92 @@
+Program rmpm_int;
+
+uses crt, go32;
+
+{$ASMMODE DIRECT}
+
+var r : trealregs;
+    axreg : Word; 
+
+    oldint21h : tseginfo;
+    newint21h : tseginfo;
+
+procedure int21h_handler; assembler;
+asm
+   cmpw $0x3001, %ax
+   jne CallOld
+   movw $0x3112, %ax
+   iret
+
+CallOld:
+   ljmp %cs:OLDHANDLER
+
+OLDHANDLER: .long 0
+            .word 0
+end;
+
+procedure resume;
+begin
+     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;
+
+     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);
+
+     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);
+end.

+ 96 - 0
docs/go32ex/rmpm_int.tex

@@ -0,0 +1,96 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+Program rmpm_int;
+
+uses crt, go32;
+
+{$ASMMODE DIRECT}
+
+var r : trealregs;
+    axreg : Word; 
+
+    oldint21h : tseginfo;
+    newint21h : tseginfo;
+
+procedure int21h_handler; assembler;
+asm
+   cmpw $0x3001, %ax
+   jne CallOld
+   movw $0x3112, %ax
+   iret
+
+CallOld:
+   ljmp %cs:OLDHANDLER
+
+OLDHANDLER: .long 0
+            .word 0
+end;
+
+procedure resume;
+begin
+     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;
+
+     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);
+
+     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);
+end.\end{verbatim}
+\end{FPCList}

+ 127 - 0
docs/go32ex/sel_des.pas

@@ -0,0 +1,127 @@
+{ example for :
+          Selectors and descriptors
+          DOS memory access
+          allocate_ldt_descriptors()
+          free_ldt_descriptors()
+          get_segment_base_address()
+          set_segment_base_address()
+          get_segment_limit()
+          set_segment_limit()
+          seg_move()
+          seg_fillword()
+}
+{ 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
+}
+
+uses crt,  { color constants, clreol(), gotoxy(), wherex(), wherey() }
+     go32;
+
+const maxx = 80; { screen x and y dimensions }
+      maxy = 25;
+      bytespercell = 2; { bytes used for every character cell }
+      screensize = maxx * maxy * bytespercell; { screen size in bytes }
+
+      linB8000 = $B800 * 16; { the linear address of $B800:0 }
+
+type string80 = string[80];
+
+var
+    text_save : array[0..screensize-1] of byte; { holds the old screen contents }
+    text_oldx, text_oldy : Word; { old cursor x and y coordinates }
+
+    text_sel : Word; { selector to the text mode screen }
+
+{ 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.

+ 101 - 0
docs/go32ex/sel_des.pp

@@ -0,0 +1,101 @@
+Program sel_des;
+
+uses crt,
+     go32;
+
+const maxx = 80;
+      maxy = 25;
+      bytespercell = 2;
+      screensize = maxx * maxy * bytespercell;
+
+      linB8000 = $B800 * 16;
+
+type string80 = string[80];
+
+var
+    text_save : array[0..screensize-1] of byte;
+    text_oldx, text_oldy : Word;
+
+    text_sel : Word;
+
+procedure status(s : string80);
+begin
+  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));
+end;
+
+function makechar(ch : char; color : byte) : Word;
+begin
+     result := byte(ch) or (color shl 8);
+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);
+
+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('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('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.

+ 105 - 0
docs/go32ex/sel_des.tex

@@ -0,0 +1,105 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+Program sel_des;
+
+uses crt,
+     go32;
+
+const maxx = 80;
+      maxy = 25;
+      bytespercell = 2;
+      screensize = maxx * maxy * bytespercell;
+
+      linB8000 = $B800 * 16;
+
+type string80 = string[80];
+
+var
+    text_save : array[0..screensize-1] of byte;
+    text_oldx, text_oldy : Word;
+
+    text_sel : Word;
+
+procedure status(s : string80);
+begin
+  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));
+end;
+
+function makechar(ch : char; color : byte) : Word;
+begin
+     result := byte(ch) or (color shl 8);
+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);
+
+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('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('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.\end{verbatim}
+\end{FPCList}

+ 35 - 0
docs/go32ex/softint.pas

@@ -0,0 +1,35 @@
+{ 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');
+end.

+ 11 - 0
docs/go32ex/softint.pp

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

+ 15 - 0
docs/go32ex/softint.tex

@@ -0,0 +1,15 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+Program softint;
+
+uses go32;
+
+var r : trealregs;
+
+begin
+     r.al := $01;
+     realintr($21, r);
+     Writeln('DOS v', r.al,'.',r.ah, ' detected');
+end.\end{verbatim}
+\end{FPCList}

+ 80 - 0
docs/go32ex/textmess.pas

@@ -0,0 +1,80 @@
+{ 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);
+end.

+ 37 - 0
docs/go32ex/textmess.pp

@@ -0,0 +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);
+end.

+ 41 - 0
docs/go32ex/textmess.tex

@@ -0,0 +1,41 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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);
+end.\end{verbatim}
+\end{FPCList}

+ 35 - 0
docs/go32ex/vgasel.pas

@@ -0,0 +1,35 @@
+{ 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 }
+end.

+ 17 - 0
docs/go32ex/vgasel.pp

@@ -0,0 +1,17 @@
+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);
+end.

+ 21 - 0
docs/go32ex/vgasel.tex

@@ -0,0 +1,21 @@
+\begin{FPCList}
+\item[Example]
+\begin{verbatim}
+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);
+end.\end{verbatim}
+\end{FPCList}