This is Part 2 in a series of articles about building Win3mu — a Windows 3 emulator. In Part 1 I explained my (ir)rationale for starting this project. This post covers some initial thoughts on how to build it.
As mentioned I’ve previously written two other emulators. Since I’ll be referring to them occasionally here’s a little background:
Both were Microbee emulators – FPGABee and iMicrobee. The Microbee was an Australian built Z-80 based home computer from the 80s. As a teenager I wrote and sold games for it through the company who produced it.
FPGABee is a hardware implementation using an FPGA and written in VHDL. You can read more about that project here.
FPGABee is a hardware emulation of a Microbee.
iMicrobee is written in C# and while I never released it, I did have it running on Windows and iOS.
Called “iMicrobee” because it was intended for iOS but this is it running under Windows.
This is a no brainer — iMicrobee was written in C# and was a joy to work on.
I could certainly squeeze more performance from C/C++ but this is supposed to be a fun learning project. C# provides so many benefits and its excellent interop capabilities mean that calling the Windows API directly is not a problem.
For example, the entire user-interface for my music software Cantabile is written in C# and uses P/Invokes to directly call the Windows API.
P/Invoke is certainly up to the job.
Cantabile’s entire UI was built in C# without using WinForms or WPF
One thing I really plan to leverage from C# is reflection with custom attributes to define how calls from the 16-bit code are mapped to implementation functions. Once it’s all working I’ll probably replace the reflection code with dynamically generated methods since reflection can be slow.
However…
For most emulators performance is a critical factor. For this project, not so much. Windows programs typically don’t burn CPU like a DOS game and the performance of today’s PCs far exceeds the machines I’m trying to emulate.
The challenge here is just getting it to work. When it comes to simplicity vs performance, simplicity will win out. I can always performance tune later if necessary.
Rebuilding the entire Window API is a daunting prospect so I won’t be doing that. I’ll be building just the bits I need when I need them.
I’m not expecting to run MS Office, development tools or utility programs nor does it need to support custom drivers or anything else too complicated. A basic Window’s API should suffice for most of these games.
Also, I’ll be aiming for “just make it work” and not “match every nuance of the real thing”.
One thing I noticed when I started looking up details on these old API’s is there’s not much information online — it’s all been superseded by 32/64-bit documentation.
So I’ve unpacked some boxes from the garage and found:
Surprisingly good condition considering how much they were used back in the day.
I’ve also setup a couple of different VM’s with DOS, Windows 3, Windows 98 and XP so I can build and debug some test program to check out things as I go.
For iMicrobee I ported an existing Z-80 emulation from C to C#. This time I want to do it all myself. I’ll be targeting the 80186 instruction set but it’ll be running in a kind of pseudo-protected mode like a 286. More on this later.
Since you can’t do much without the CPU this will be the obvious starting point.
Once the CPU is up and running I’ll need to be able to load some code to run.
16-bit Windows programs use the now misnamed “New Executable Format” aka “NE” files. I’ve found some documentation but it’s not complete so some experimentation is on the cards. In the end it’ll need to handle all the gory details — headers, code and data segments, code relocations, resources etc…
If you’ve ever programmed for Windows, you’ll be familiar with its three main modules: Kernel, User and GDI. This is where the bulk of the work lies.
There’s a few other ancillary modules that’ll be needed too like KEYBOARD.DRV for reading key states and MMSYSTEM.DLL for playing sounds.
It’s been so long since I wrote 16-bit Windows code that initially I forgot about DOS.
Many 16-bit Windows programs use the infamous Int 21h for file access and other environment related functions so they’ll need to be implemented too.
Underneath Windows 3 lurked DOS.
I used to have a copy of Ray Duncan’s Advanced MS-DOS Programming but I couldn’t find it (I think I donated it to the local library). Never-the-less I’ve found enough documentation online for this.
iMicrobee has a debugger for the Z-80 code. It was a simple command driven tool (a bit like gdb) and gave the ability to look at the system from the emulated side as opposed to the emulating side.
I can probably get away without it for this project but suspect it will be extremely useful. Besides I’d like to do a better job than the last one I wrote.
Have you ever tried debugging a debugger that’s debugging code running on an emulated CPU that’s running under a debugger? For added fun, make sure the keys for step into, step out and step over are different in each debugger.
Remember 8.3 filenames?
I’m not going to provide support for long file names. I’m might not even support the short versions of long file name. Also I’m going to sandbox the entire 16-bit program to a virtual file system with paths mapped to specific directories on the host machine.
Also, since Windows 3 didn’t have a concept of per-user folders, I’d like to provide support for separate read/write folders so the 16-bit programs can be stored in the Program Files directory and saved files (eg: high-score files etc…) can be written somewhere user specific.
Initially a 16-bit program will be launched by passing the .exe file as a command line parameter to the emulator. Later it would be nice if this was a little more integrated with Windows Explorer.
x64 Windows doesn’t even display icons for 16-bit apps
Since it would be uncool to create file associations for “.exe” I was thinking of renaming the 16-bit programs to .exe16, registering a file association and perhaps also a shell extension to render their icons.
Listing everything out like that you can see there’s a fair bit involved in getting this to work. At least I can break it down and do it bit by bit.
And the first bit will be the CPU which will be the topic for Part 3 — continue reading.
Hi, I’m Brad Robinson — an independent software developer living in Sydney Australia. I write software for musicians and as an indie developer I rely on word of mouth.
If you enjoyed this article please consider sharing it by hitting the “recommend heart” below or by sharing on Facebook/Twitter. It’s a small gesture but makes a real difference.
Also, if your feed is lacking in hex dumps, disassembly listings and screen shots of old Windows 3 games you might like to follow me on Twitter.
Continue reading… Part 3 The CPU