Sunday, April 11, 2010

Soft-float (FPU emulation) with DJGPP

If you build a program using floating-point arithmetic with DJGPP and then try to run it on a box without a FPU (such as the 386, or 486SX), the program will die at the first attemt to use the floats.

The solution for this is to tell DJGPP to use floating point emulation.

While there is the -msoft-float GCC option, which seems to be recognized in the DJGPP port too, the option does not work under DJGPP.

There is a DJGPP FAQ item about FPU emulation. It turns out the easiest way is to just add -lemu to linker options.

Also, if you target the 386, add -march=i386 to compiler options. Otherwise the program might crash, as DJGPP can use an instruction that is not supported on the 386. (Not sure about 486. Is Pentium is the default target? Or the 486? Either way, it is good practice to specify -march as the lowest CPU the app needs to run on.)

TurboVision with DJGPP and DOSEMU

There's a nice port of the TUI library TurboVision to GCC. The port works on unix-like systems including linux, but it also still supports DOS (with DJGPP toolchain).

Here's a guide on how to build the DOS version.

First, grab the sources. I suggest you use the latest CVS version:
cvs -d:pserver:anonymous@tvision.cvs.sourceforge.net:/cvsroot/tvision login
(use empty password)
cvs -z3 -d:pserver:anonymous@tvision.cvs.sourceforge.net:/cvsroot/tvision co -P tvision

Then you need a DOS environment with DJGGP in it. DOSEMU + DJGPP worked ok for me (as detailed in my previous posts on the topic: 1 and 2).

Have a look into doc/install/djgpp.txt. As the file explains, you will need some extra GNU tools installed inside your DJGPP directory. Here is the list of the files that worked for me at the time of this writing:
  • djdev203.zip - basic DJGPP runtime
  • bnu219b.zip - GNU Binutils
  • gcc442b.zip - gcc
  • gpp442b.zip - g++
  • mak3791b.zip - GNU Make
  • fil41b.zip - GNU fileutils
  • txt20b.zip - GNU textutils
  • shl2011b.zip - GNU sh-utils
  • perl588b.zip - Perl

The TurboVision doc further mentions you will need GNU gettext. This is not a hard requirement -- you can build TurboVision without gettext support. If you do want to use gettext, be warned the procedure of installing GNU gettext is a bit complicated -- see the doc/install/djgpp.txt file and gnu/gtxt-010.40/djgpp/README inside the gettext archive (gtxt040b.zip).

So now all you need to do is put a copy of the TurboVision sources in a place that can be reached from your DOS environment, change to that directory and fire up configure.bat. (If building without gettext, add the --no-intl option.)

Unfortunately, you might just get this:
C:\tvision>configure
Configuring Turbo Vision v2.2.0 library

Unknown OS, you must do things by yourself at conflib.pl line 903.
Determining OS:

The reason here is that the "uname" command (part of GNU sh-utils) prints out:

c:\tvision>uname
??Unknow

instead of what the TurboVision configure script expects ("MS-DOS").

You either have to patch the configure script (hack the test if ($os=~/MS\-DOS/) to always pass, e.g. into if (1)) or change the uname command. (Quick and dirty hack to the uname command. Use the binary to overwrite the original djgpp\bin\uname.exe)

Either way, now the configure script should pass:

C:\tvision>configure --no-intl
Configuring Turbo Vision v2.2.0 library

Determining OS: DOS [djgpp]
Looking for a working gcc: gcc OK
C flags: -O2 -Wno-packed
C++ flags: -O2 -Wno-packed
Looking for the C++ compiler: gpp
Checking Architecture: x86
Looking for pointer size:  32 bits
Looking for prefix: c:/djgpp
Looking for GNU make: make
Looking for GNU ar: ar
Looking for install tool: install
Looking for xgettext: no
Checking DJGPP version: 2.0.3 OK
Checking for international support: disabled by user request.
Looking for allegro library: Bad command or filename - "allegro-config".
 no, disabling AlCon
Checking endianess: little endian

Generating Makefile
Configuring makefiles: intl/dummy/Makefile 
Configuring RHIDE: makes/rhide.env compat/rhide.env 
Configuring RHIDE: examples/rhide.env 
Generating configuration header: no changes
Extracting from makes/librhtv.imk: processing
Extracting from compat/compat.imk: processing
Processing winnt/bccmake.in => winnt/Makefile
Processing winnt/msvcmake.in => winnt/Makefile.nmk
Makefiles for examples.
Makefiles for translations.
Processing intl/gnumake.in => intl/Makefile
Processing redhat/librhtv.spec.in => redhat/librhtv-2.2.0.spec
Processing qnxrtp/tvision.qpg.in => qnxrtp/tvision.qpg

Succesful configuration!

Then fire up make. With the default DOSEMU configuration you might end up with this error:
cc1plus.exe: out of memory allocating 65536 bytes after a total of 6390696 bytes
make.exe[1]: *** [../makes/obj/iffilelen.o] Error 1
make.exe[1]: Leaving directory `c:/tvision/makes'
make.exe: *** [static-lib] Error 2

The solution is to increase the amount of DPMI memory in /etc/dosemu/dosemu.conf, e.g.: $_dpmi = (0x10000) instead of the default 0x5000.

You can that use make examples to build some sample code. Start up e.g. examples\demo\demo.exe to see if the library compiled and works fine (works best with xdosemu, don't expect it to work in dumb mode :-)).

To build your own programs with the TurboVision library, just add -IC:\tvision\include to compiler options and -Lc:\tvision\makes -lrhtv to linker options. (Substitute c:\tvision with your TurboVision sources path.)