DOS

From Lazarus wiki
Jump to navigationJump to search

Overview

A DOS (8086) cross compiler is currently being developed in FPC trunk (the development version). It started as a hobby project meant to explore how to port FPC to a new platform.

The number of (FPC on) DOS users is probably quite low, especially since there is an FPC compiler for the more capable GO32v2 DOS extender available which runs on 80386+ processors.

Advantages over FPC for GO32V2

  • Generated code can run on 16-bit processors. Since these processors are obsolete and out of production, this is mostly useful for retrocomputing purposes. Note also that the 80186 is still in use in embedded devices: [1]
  • It's possible to write TSRs.
  • It's possible to write DOS .SYS device drivers. (Not ready yet, but should be easy to implement)
  • It allows writing a bootloader in Pascal.
  • It allows writing 16-bit BIOS code in Pascal (e.g. you can now do a project like SeaBIOS but in Pascal).
  • Real mode DOS programs are less sensitive to bugs in virtual DOS environments, since they're immune to DPMI bugs and in fact require no DPMI at all. (Provided that your program fits within the memory constraints, of course.)

Advantages over Turbo Pascal

  • Compiler is Free/Open Source software and is in active development.
  • Supports long file names.
  • Multiple memory models are supported.
  • All the extra Object Pascal features supported by FPC should work. This includes ansistrings, classes, interfaces, exceptions, generics, etc.
  • Crosscompilation is doable without running the development system in a dosbox/VM (compile/build on Windows 64-bit, only need 16-bit capable OS for running)

Limitations

The DOS platforms brings some limitations, like

  • data structures cannot be larger than 64KB
  • no simple way of pre-emptive multitasking.
  • it is unlikely the Lazarus LCL GUI will be ported to the DOS environment
    • However, an OpenGEM widget set is possible
    • When the large memory model of the i8086 code generator matures, Win16 support can also be implemented

Requirements

The compiler is a cross compiler that runs at least on Windows (both x86 and x64) and Linux. For compiling, it needs:

  • the Netwide Assembler - NASM
  • the Open Watcom linker - WLINK
  • the Open Watcom library manager - WLIB

In theory it should be able to run on any platform, supported by FPC, where NASM and the Open Watcom tools are available. This includes DOS via the GO32V2 extender. However, because the Watcom tools for DOS are compiled with a different extender, there are some issues related to long file names and the passing of long command line arguments. This might be resolved by recompiling the Watcom tools with DJGPP or by implementing a 16-bit DOS backend asm object writer and linker inside FPC.

Snapshots

There's a snapshot available here:

http://www.bttr-software.de/forum/forum_entry.php?id=12985

It is not the latest version, but contains all the necessary tools and instructions to build the cross compiler under Windows.

There are also daily snapshots available here (they don't include nasm, wlib and wlink, but are built daily):

ftp://ftp.freepascal.org/pub/fpc/snapshot/trunk/i8086-msdos/

Building a snapshot manually

  • make sure nasm, wlink and wlib are in your path
  • checkout fpc trunk:
svn checkout http://svn.freepascal.org/svn/fpc/trunk fpc
  • enter the fpc directory and build the compiler with the following command (replace /usr/bin/ppc386 with the full path to the stable (2.6.4) FPC compiler binary; replace -WmSmall with -WmMedium, -WmCompact or -WmLarge if you want to use another memory model):
make clean all OS_TARGET=msdos CPU_TARGET=i8086 OPT="-CX -XXs" CROSSOPT=-WmSmall BINUTILSPREFIX= PP=/usr/bin/ppc386
  • install the snapshot (replace linux and i386 with the OS and CPU you're using; replace INSTALL_PREFIX with the directory you want the snapshot installed):
make crossinstall OS_SOURCE=linux CPU_SOURCE=i386 OS_TARGET=msdos CPU_TARGET=i8086 PP=compiler/ppcross8086 CROSSOPT=-WmSmall BINUTILSPREFIX= INSTALL_PREFIX=/home/blablabla/fpc-i8086/snapshot/small OPT="-CX -XXs"

Updating your fpc.cfg

Add the following to your fpc.cfg to enable smartlinking and disable the default binutils prefix (so that you don't have to rename nasm, wlink and wlib to msdos-nasm, msdos-wlink and msdos-wlib):

#ifdef cpui8086
-CX
-XX
-XP
#endif

To enable building for all the memory models, build snapshots for the small (tiny uses the small snapshot), medium, compact and large memory model, and then find the lines in your fpc.cfg that specify the path to the RTL:

-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl

And update them to something similar to:

#IFDEF CPUI8086
#IFDEF FPC_MM_TINY
# the tiny memory model uses the small model libraries as well
-Fu/home/blablabla/fpc-i8086/snapshot/small/lib/fpc/$fpcversion/units/$fpctarget
-Fu/home/blablabla/fpc-i8086/snapshot/small/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/home/blablabla/fpc-i8086/snapshot/small/lib/fpc/$fpcversion/units/$fpctarget/rtl
#ENDIF
#IFDEF FPC_MM_SMALL
-Fu/home/blablabla/fpc-i8086/snapshot/small/lib/fpc/$fpcversion/units/$fpctarget
-Fu/home/blablabla/fpc-i8086/snapshot/small/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/home/blablabla/fpc-i8086/snapshot/small/lib/fpc/$fpcversion/units/$fpctarget/rtl
#ENDIF
#IFDEF FPC_MM_MEDIUM
-Fu/home/blablabla/fpc-i8086/snapshot/medium/lib/fpc/$fpcversion/units/$fpctarget
-Fu/home/blablabla/fpc-i8086/snapshot/medium/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/home/blablabla/fpc-i8086/snapshot/medium/lib/fpc/$fpcversion/units/$fpctarget/rtl
#ENDIF
#IFDEF FPC_MM_COMPACT
-Fu/home/blablabla/fpc-i8086/snapshot/compact/lib/fpc/$fpcversion/units/$fpctarget
-Fu/home/blablabla/fpc-i8086/snapshot/compact/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/home/blablabla/fpc-i8086/snapshot/compact/lib/fpc/$fpcversion/units/$fpctarget/rtl
#ENDIF
#IFDEF FPC_MM_LARGE
-Fu/home/blablabla/fpc-i8086/snapshot/large/lib/fpc/$fpcversion/units/$fpctarget
-Fu/home/blablabla/fpc-i8086/snapshot/large/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/home/blablabla/fpc-i8086/snapshot/large/lib/fpc/$fpcversion/units/$fpctarget/rtl
#ENDIF
#ELSE
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/*
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl
#ENDIF

This should enable you to build programs in any of the supported memory models with just a compiler switch:

ppcross8086 -WmTiny -Wtcom hello.pas
ppcross8086 -WmTiny -Wtexe hello.pas
ppcross8086 -WmSmall hello.pas
ppcross8086 -WmMedium hello.pas
ppcross8086 -WmCompact hello.pas
ppcross8086 -WmLarge hello.pas

And in case you're wondering - it doesn't matter which ppcross8086 compiler binary you use (i.e. from the small, medium, compact or large model snapshot). They are identical. Only the compiled units differ.

Status

The compiler has been enabled as a CPU/OS target in FPC.exe since revision 25792 (CPU: i8086, OS: msdos).

The RTL compiles. Most units from Go32v2 have been ported. Just like Go32v2, the RTL supports long file names when run under a Windows 95+/2000+ DOS box or under plain DOS with a long file names driver such as doslfn.exe. FPC demo programs such as fpctris and samegame work in all supported memory models.

Floating point support

Floating point operations require an FPU. Software FPU emulation is not yet implemented and using floating point operations on a real machine without an FPU will lead to a hang.

Nil pointer assignment checking

The small and medium memory models offer rudimentary nil pointer assignment checking. The system RTL puts a pattern of 32 bytes equal to $01 at the beginning of the data segment (DS:0000). At the end of program execution, this pattern is checked and if turns out it has changed, the message:

Nil pointer assignment

is printed on the screen. This indicates that a nil pointer assignment has happened at some time during the program execution. Unfortunately, we can't tell when exactly, only that it has happened.

New pointer types

To reflect the i8086 segmented memory model, FPC supports several pointer types:

type
  PNearInteger = ^Integer; near;
  PNearCSInteger = ^Integer; near 'CS';
  PNearDSInteger = ^Integer; near 'DS';
  PNearESInteger = ^Integer; near 'ES';
  PNearSSInteger = ^Integer; near 'SS';
  PNearFSInteger = ^Integer; near 'FS';
  PNearGSInteger = ^Integer; near 'GS';
  PFarInteger = ^Integer; far;
  PHugeInteger = ^Integer; huge;  // not yet implemented

Tested machines

Compiled programs have been tested and known to work on the following machines:

  • IBM PC 5150 (the first PC model ever), with a 4.77 MHz 8088 CPU, 512 KB RAM and a CGA card, running IBM DOS 3.30
  • HP 200LX, with a 7.91 MHz 80186 CPU, running MS-DOS 5.0
  • various boring 32-bit and 64-bit machines :)
  • DOSBox

Supported memory models

Tiny

  • Activated by the -WmTiny compiler option
  • Code + Data + Heap + Stack <= 64KB
  • CS = DS = SS
  • Pointer = NearPointer
  • CodePointer = NearPointer
  • Code starts at offset $100
  • Can produce both .com and .exe files. The binary format can be chosen with the -Wtcom and -Wtexe compiler options. The default format is .exe
  • The compiler defines: FPC_MM_TINY

Small

  • Activated by the -WmSmall compiler option. This is the default memory model, so it is chosen if you don't specify a memory model.
  • Code <= 64KB, Data + Heap + Stack <= 64KB (Code and data are in separate segments, so programs can use up to 128KB in total)
  • DS = SS
  • Pointer = NearPointer
  • CodePointer = NearPointer
  • Can produce only .exe files
  • The compiler defines: FPC_MM_SMALL

Medium

  • Activated by the -WmMedium compiler option
  • Code <= 1MB, Data + Heap + Stack <= 64KB
  • DS = SS
  • Pointer = NearPointer
  • CodePointer = FarPointer
  • Can produce only .exe files
  • The compiler defines: FPC_MM_MEDIUM

Memory models currently being developed

Work on these has started, but they're not stable yet.

Compact

  • Activated by the -WmCompact compiler option
  • Code <= 64KB, Data <= 64KB, Stack <= 64KB, Heap <= 1MB
  • Data structures cannot exceed 64KB
  • Pointer = FarPointer
  • CodePointer = NearPointer
  • Can produce only .exe files
  • The compiler defines: FPC_MM_COMPACT

Large

  • Activated by the -WmLarge compiler option. This is the memory model used by Turbo Pascal version 4 and above
  • Code <= 1MB, Data <= 64KB, Stack <= 64KB, Heap <= 1MB
  • Data structures cannot exceed 64KB
  • Pointer = FarPointer
  • CodePointer = FarPointer
  • Can produce only .exe files
  • The compiler defines: FPC_MM_LARGE

Memory models planned for the future, but not yet started

Huge

Supported calling conventions

Currently, only the Pascal calling convention is supported. All the other calling conventions are entirely untested and should not be used, because they may or may not work and may change at any time.

Pascal

This is the default calling convention. It strives for compatibility with Turbo Pascal 7.

  • Parameters are pushed on the stack left to right.
  • The callee cleans the parameters from the stack.
  • Procedures and functions must preserve DS, SS and BP and may destroy AX, BX, CX, DX, SI, DI and ES.
  • 16-bit results are returned in AX, 32-bit results in DX:AX
  • 64-bit ints are returned in AX:BX:CX:DX. Note that Turbo Pascal doesn't support int64, so this behavior is borrowed from Open Watcom's 'pascal' calling convention.

Troubleshooting

Compile error: missing .o files

Problem: If you see errors/warnings like this during compiling & linking:

test.pas(12,24) Warning: Object system.o not found, Linking may fail !
Error! E2008: cannot open system.o : No such file or directory

(and indeed there don't appear to be any .o files in your msdos units directory)

Solution: You haven't used smartlinking. You should always compile i8086-msdos programs with smartlinking, i.e. use the -XX and -CX options. Smartlinking uses .a files, nonsmartlinking uses .o files.

The reason the .o files aren't generated is because the system unit exceeds the 64kb code limit for the small and tiny memory models and is therefore impossible to compile even 'hello world' without smartlinking, so creating the .o files is a waste of time. It might work for the medium model, but then you have to build the snapshot without -CX. However, with the tight memory constraints of real mode DOS, there is little reason not to use smartlinking in every memory model. Also, the medium model still has a limit of 64k code per unit, so even there it might not work without smartlinking. It certainly hasn't been tested.

Hint: You can add these options to your fpc.cfg file, as described in the "Updating your fpc.cfg" section.