[Home]

QuickBASIC 4.5 and X87 issues on modern environments

When setting up my vintage Bitwoods RBBS-PC, I faced some strange issues when trying to get the old trusty RBBS-PC (compiled using QuickBASIC 4.5) running properly on modern hardware and emulators. It turned out all these problems were 8087 related. I still haven't found the very exact root cause why QB applications fail and produce wrong results on modern environments, I but at least I've found some clues and workarounds that allow me keeping using them.

Background

Historically, pretty much all BASIC languages often provided float-point as a native data type for numbers. These had to be emulated in software and many proprietary formats and implementations were in use. It's also what made BASICs notoriously slow. In QuickBASIC 4.5 (released 1988), Microsoft shifted to use IEEE format for floating point to be compatible with new hardware. In the manual they state: ``IEEE format gives more accurate results and makes it possible to use an 8087 or 80287 math coprocessor.''

Intel, who was making 8087 co-processor chips, were promoting its use by releasing and licensing a fully accurate emulation library to encourage application developers to use co-processor features. The idea was that application developers would rely on 8087 data types and link against this library. The program would still work on a normal 8086 but slower, so the user would be encouraged to buy an 8087 eventually.

Microsoft followed this idea. The way QuickBASIC works is that it by default assumes the presence of 8087 and uses all its capabilities. On program startup it checks if the 8087 is actually present, and if not, it hooks up the emulation library code. Clever and future-proof if only it would have worked.

The problem

Originally 8087 was as a separate co-processor and its exception handling was implemented through IRQ via 8259 PIC. QuickBASIC relies heavily on 8087 exception handling (e.g. when converting between datatypes) in checking for errors.

On modern CPUs, the 8087 is fully integrated to the CPU. The 8259 PIC (later replaced by APIC) and 8087 exceptions are often just simulated and emulated somehow. Apparently, something is not working the same way any more (maybe some timing difference or just relying on some undocumented or unarchitechted stuff) as at some point QuickBASIC programs stopped working.

I've have been able to reduce the problem to a following program:

A% = VAL("99999")
PRINT A%

What it does:

In 2025, the program behaves correctly when executed on an original 8086 & 8087 PC. What happens today in modern enviroments is:

Some observations on bare-metal systems:

CPUMotherboardResult
AMD FX-6350MSI 760GA-P43 (FX)OK
AMD Geode LX 800TR2350hangs
Intel i7-3770HP Compaq Elite 8300hangs
Intel Pentium G3420ASRock B85M Pro3hangs

Workaround

QuickBASIC 4.5 run-time library uses BIOS INT 11 to check for the presence of the co-processor. Modern BIOS versions do not provide configuration options to disable the floating-point unit. However, on many BIOS versions, the INT 11 just returns the data stored at 0040:0010 (bit 1 is the co-processor bit) and that's writable RAM! And indeed this was the case on my AMD Geode system (from around 2007). I was able to force QuickBASIC to fall back to its emulation library by running the following program:

MOV AX,40
MOV DS,AX
AND BYTE PTR [10],FD
INT 20

I run this on my AUTOEXEC.BAT. Since the CPU on my AMD Geode is 500 MHz it really doesn't matter if the FPU is emulated or not; I use this machine to run 4.77 MHz IBM PC era DOS programs anyway. I just want working programs, performance is secondary.


Last updated: 2025-09-04 11:42 (EEST)