Modifying Microsoft Flight Simulator 4 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.
Update: June 2019 I now have a project page describing the many plugins and apps I have written for X-Plane and home cockpits.
FS4 from 1989
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 640x350
DOSBox emulation in 2017
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 640x350 is when displayed on a large 1920x1080 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.
DOSBox memory dumps
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
memory.cpp.
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.
North and East encoding
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:
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:
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
Synchronizing over the network
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!
Configuring the 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.
Automatic startup
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.
Video
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!
Source code
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 640x350 used by FS4 most closely matches the aspect ratio of my 1920x1080 monitors, and the round instrument dials are still circular. You
can use the 800x600 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!
Photos
Share
Blog article posted June 2017
Google Developer Advocate 2014-2023
X-Plane plugins and apps for flight simulation
IoT water meter monitoring
IoT computer vision monitoring
Tiny and cheap offline Wikipedia project 2017
Outdoor augmented reality research
Tinmith 1998-2007
Outdoor augmented reality 3D modelling
Tinmith 1998-2007