Porting low-level DOS code for TP/BP to GO32v2 with FPC

From Free Pascal wiki
Revision as of 18:31, 16 January 2007 by Xhajt03 (talk | contribs) (New page copying (and slightly generalizing) information provided in mailing list)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

"Low-level DOS code" refers to assembler routines, use of DOS and BIOS functions, etc. This page tries to provide hints regarding general areas of interest when porting such code originally written for TP/BP to GO32v2 target with FPC (or potentially other similar targets like WDOSX). Don't expect any detailed tutorial - messing with low-level code always requires a lot of knowledge and experience, and porting old 16-bit code written for real mode to 32-bit protected mode makes it even more demanding.

  1. Read what our manual, wiki and mailing lists contributions state on FPC calling conventions (i.e. how parameters are passed to functions/procedures and how the stack organization and processing look like) - this is certainly different from TP/BP. Among others, this implies changes of code using [bp].
  2. In general, you should use 32-bit registers rather than 16-bit registers (I believe there's even some speed penalty on some CPUs when using 16-bit registers, but more importantly, the overridden functions (as provided by the DPMI host) may even _require_ providing parameters in 32-bit registers as opposed to e.g. standard DOS functions) - i.e. eax instead of ax, etc.
  3. If you need to exchange data with the underlying 16-bit code like BIOS functions (yes, this includes your read/write sectore functions), the used memory buffer must be placed in a memory area where the 16-bit code can access it (= within the first MB of RAM) if it's your code allocating the buffer and you need to make sure that you can access it too. This is achieved using DPMI functions (read DPMI specification to find out more, or at least have a look at some FPC RTL code using these int 31h functions).
  4. In general, you don't touch any segment registers - all your data are available in flat memory model, where everything is available using 32-bit addressing and ds=es=ss (i.e. no instructions like lds/les needed, no mov es:[xx],yy, etc.). There's one exception directly related to the previous point related to sharing data with 16-bit code - if you pass parameters to/receive results from 16-bit code/functions, you need to translate the 16:16 16-bit addresses to 0:32 addresses used in 32-bit code and vice versa (as described above) and then you obviously might need to change some segment registers too immediately before/after the 16-bit function call (however, these cases are normally solved using helper functions like the DPMI support function for calling 16-bit interrupts, i.e. your code wouldn't be directly messing with segment registers anyway).
  5. Implementation of interrupt service routines or callbacks triggered from real mode requires using special features like locking of memory, etc. - read DPMI specification and potentially have a look at implementation of unit Mouse for GO32v2.