Modifying MS Flight Simulator 4 (1989) to run on three immersive monitors

How I modified DOSBox and the original Microsoft Flight Simulator 4 from 1989 to run on my immersive multi-display flight simulator set up.

Back in 1989, I was introduced to Microsoft Flight Simulator version 4.
I thought it was incredible that I could fly around
in a 3D environment, and this was something that got me interested in 3D graphics. However, I always had trouble flying the plane,
because I only had a 14 inch CRT monitor, and you had a small field of view out the front of the plane. Since you couldn’t see left
or right, you were missing important flying cues, and it made flying much more difficult than in a real plane. I’ve seen some people try to use
joystick hats or head trackers, but those always require you to look forwards even if you are virtually looking another direction – it is not
intuitive for your brain to understand. So at the time I realized this was a problem, and I’d seen commercial immersive
flight simulators in books, but they were too expensive, so I had to wait a few decades for things to become a bit more affordable! However,
recently in 2017 I built my own immersive indoor flight simulator,
using three large 42″ televisions and X-Plane 11. This provides a much
more realistic experience, and it is finally the flight simulator I was always looking for.

Microsoft Flight Simulator 4 from 1989, running at 640×350

I’m a bit of a fan of emulators, so I used DOSBox on Linux to start up Microsoft Flight Simulator version 4 on a big monitor. It is amazing
how low-res 640×350 is when displayed on a large 1920×1080 display, although you didn’t notice it as much on a 14 inch CRT,
which is smaller than many laptops these days. DOSBox supports emulating old analog PC joysticks, so I was able to configure FS4 to
use my yoke and throttle. I always wanted to have one of those as a kid as well, and it worked great. While there wasn’t much
for graphics, it worked with a nice smooth frame rate, and it was pretty cool.

But then I started to think about how even better it would be to run FS4 on all three monitors,
just like I’m doing with X-Plane now. In 1989, computers only supported a single small display, and definitely not three of them!
The concept of using a cluster of machines was done in expensive commercial simulators even back then, but FS4 didn’t support anything
like that. FS4 supports the ability to do multiplayer over an RS-232 cable. However, there is no way to set the camera viewpoint to the remote
aircraft, so that was not going to be a help in building a cluster. There was nothing else built into FS4 that could support what I wanted, and DOS machines
back in 1989 didn’t support networking or anything else either. All seemed hopeless with this ancient software.

Since I’m running the whole thing within a DOSBox emulator, I now have access to networking and modern tools to try and achieve
what I want however. DOS games were very simple in that they didn’t use much of an operating system, and wrote everything directly
to unprotected memory. I figured that the developer would have written the X Y Z and Heading Pitch Roll values to some kind of struct
in a consistent location in memory. If I could work out the memory location of where the aircraft state is stored, I could intercept
this with DOSBox, send UDP packets over the network to other DOSBox instances, and write to those same memory locations.

When you dig around in the DOSBox source code, there is a simple 16mb array of 8-bit chars named MemBase in
That is the entire memory
space of the DOS machine, and only the first megabyte is actually used. So I started up FS4, paused the game, and attached gdb to
the live process and saved out a copy of the MemBase memory array. Then I entered slew mode, which allows you to reposition the aircraft
at whatever coordinates and orientation that you want. Then you use gdb to again save the MemBase memory array. I noticed that FS4’s
coordinate system seemed to have a maximum of 65535 so it was probably using 16-bit integers, and it didn’t have support for floating
point arithmetic since that was not common in 1989. So I changed the coordinates to values
like 0, 1, and 65535, in the hope they would be more obvious in the memory dump as 0x00, 0x01, and 0xFF. I was also able to reload
the dump file back into memory, and I could successfully move the viewpoint back to where it was. So in theory, this could work.

I used the Linux cmp command to compare the binary dump files. You would be surprised how little actually changes between the
dump files, and so I went through the differences to see if I could spot anything. I didn’t find any of the 0x00, 0x01, or 0xFF
changes that I was expecting, which seemed strange. After studying lots of diffs, I realized that FS4 must be using a different
encoding scheme than just raw integers. I needed a new strategy.

I decided to try just fuzzing over the memory locations that did change to see which one would have an effect. I modified DOSBox
to add the ability to receive commands from standard input, and wrote 0x00 over those locations one-by-one with a delay between them.
FS4 would crash and go crazy for some values, so I would restart it and keep looking for the desired effect. Eventually I found that
the viewpoint would change drastically when I wrote to 0x28D0. Ahah! I had found a memory location that changed the viewpoint, but
the encoding was super weird and didn’t work the way I expected. Writing zeros moved the aircraft to +16384 instead of +0 or +32767.

After trying a whole bunch of different values, I worked out how North and East coordinates are represented.
The first two bytes are the fractional component, and the second two bytes are the integer component. Intel x86
is little endian, so the least significant byte goes first. Here are some examples of raw memory locations and
how they map to coordinates:

0xFFFF = +16383d

0x0000 = +16384d

0x0101 = +16641d

0x1010 = +20496d

0x2020 = +24608d

0x0020 = +24576d

0x2000 = +16416d

0x0030 = +28672d

0x0040 = +32768d

0x0050 = +36864d

0x0060 = +40960d

0x0070 = +45056d

0x0080 = +49152d

0x0090 = +53248d

0x00A0 = +57344d

0x00B0 = +61440d

Here you can see that 0x00C0 is where the origin of the coordinate system is!

0x00C0 = +00000d

0x00D0 = +04096d

0x00E0 = +08192d

0x00F0 = +12288d

0x00FF = +16128d

The fractional part made a bit more sense, you can tell it is just the 16-bit value that is then later
divided by 65536. Here are some examples:

0xFFFF = 0.9999

0x8080 = 0.5020

0x00FF = 0.9961

0xFF00 = 0.0039

Now that I understood what was going on, understanding the angular values was much easier. These are also using
an integer representation, where the first byte is a fraction divided by 256 and added to the main angle. The second
byte is the most significant part, and there are 256 units in a full circle. Here are some examples of the most significant value:

0x00 = 0 degrees

0xA0 = 180 degrees

0xFF = 358.60 degrees

It turns out that the North, East, Altitude, Heading, Pitch, Roll values are all stored together in a contiguous memory area
from 0x28D0 to 0x28E1. Here is a breakdown of every byte and what it does:

Offset Axis Value Order
0x28D0 East Fraction LSB
0x28D1 East Fraction MSB
0x28D2 East Integer LSB
0x28D3 East Integer MSB
0x28D4 Altitude Integer LSB 1
0x28D5 Altitude Integer 2
0x28D6 Altitude Integer 3
0x28D7 Altitude Integer MSB 4
0x28D8 North Fraction LSB
0x28D9 North Fraction MSB
0x28DA North Integer LSB
0x28DB North Integer MSB
0x28DC Pitch Fraction LSB
0x28DD Pitch 256 units to a circle MSB
0x28DE Roll Fraction LSB
0x28DF Roll 256 units to a circle MSB
0x28E0 Heading Fraction LSB
0x28E1 Heading 256 units to a circle MSB

Given that there are exactly 18 bytes of memory from 0x28D0 that contain everything I need, it is pretty easy to send this to another machine.
I created my own thread in DOSBox that uses memcpy() at a 10 msec interval to capture the state of this 18 bytes of memory. In theory, this is unsafe
without synchronization against the main emulator thread, but it worked well enough for this experiment. I then take the 18 bytes of data, and
transmit it as two UDP packets to the localhost network interface with different port numbers. I tried using broadcast packets, but it is not
possible to have two processes on the same machine listening on the same port number. After implementing the receiver code in two separate DOSBox instances, I have
now managed to do a one-way push of those 18 bytes from one process to two others. Now they are perfectly synchronized, and you see three FS4
instances all showing the same viewpoint!

FS4 has keyboard shortcuts that allow you to take a viewpoint and make it look left or right. So you can manually set the left and right
DOSBox instance running on each monitor to look in the correct direction. The remaining challenge is configuring the field of view, which can only
be varied with keyboard presses, and not as a specific angle. It turns out that FS4 has the ability to do both large and fine changes to the field
of view, but we need to work out what that is. The solution is to use slew mode and adjust the orientation of the aircraft so that Heading, Pitch, and Roll all have significant values – you can now see the horizon has large gaps in it across the monitor edges. But if you gradually apply the same
zoom in/out controls to each monitor, one step at a time, you will eventually see the horizon become a straight line, and now you have the correct
field of view programmed in.

While it is possible to move the windows to the correct monitor and then use the keyboard to make all the changes to the viewpoint, this is
very tedious and it is easy to make mistakes. I wrote a script using
wmctrl and xdotool
which allows me to automate the placement of the windows
and then to send the necessary keystrokes. Now everything starts up as quickly and possible, and it is very reproducible every time I start things up.

This video shows the synchronization taking place across the three monitors, and you can see that as the aircraft flies around, everything works
just as well as it works on X-Plane 11 right now. This is the flight simulator I always wanted as a kid, although it is 28 years late! But it
is so much fun to see software written 28 years ago that was never intended to be run this way, actually work on an immersive flight simulator
like this!

I made a number of changes to DOSBox to implement my own debugger so I could do the fuzzing more easily, and then to implement the UDP transmitter
and receiver. I also added a new stretch mode
that will take any DOSBox window and make it fit exactly the desired dimensions, even if it breaks
the aspect ratio. While there are many forum postings claiming this should work, it never worked and the source code did not seem to not allow
it either. So with my patches, now I can ensure there are no seams between the windows, and I can pick any resolution that I want. However, the
default 640×350 used by FS4 most closely matches the aspect ratio of my 1920×1080 monitors, and the round instrument dials are still circular. You
can use the 800×600 driver that came out in the early 1990s, but the aspect is not as nice.

You can download my patched version of DOSBox here on github. There is a script
apt-get-deps that will download all the necessary dependencies
for an Ubuntu 16.04 machine. You will need to provide your
own FS4 directory with binaries of the game. I still have my old disks from when I bought FS4 in 1989, but you can also find it on abandonware sites on the Internet as
well. There is great web site PlanetMic where there are still fans playing the old FS4 on modern PCs,
I hope they enjoy my project!

Read More

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.