I was so tired I ended up sleeping through the whole thing. Sometimes it’s hard being on the other side of the planet. But for anyone interested in Windows programming it’ll be super interesting in how much has changed, and yet how much things haven’t changed.
As an added bonus, 65scribe has also blessed us with not only another great retrospective on iMacs, but also our favorite museum in Ontario, but left us with a cliff hanger (minor spoiler!).
I never knew about the artic blue ice thing before. Maybe it’s a coincidence, but who knows?!
So a few months ago, gattilorenz had told me he managed to work out how to do direct video under Xenix, and was able to get DooM running! He made the source available, and I meant to do something back then, but I must have gotten distracted.
I’ve gone ahead and created a qemu disk image (if you convert it, it does run on VMware, so probably far more 386 capable emulators than I can imagine), along with an old Qemu exe for some stand alone fun on archive.org.
There is no sound, nor music. I should look closer one day, and see if I can drive some direct music to an Adlib since it’s just IO ports, and maybe grab all the direct sound code from viti95’s FastDoom?
For the impatient the short story is this on a SIMH LGP prompt:
SET CPU LGP30
SET CPU TAPE
SET CPU MANUAL
G -T 4500
Naturally you’ll need the game as well which is currently on FTP at ftp.informatik.uni-stuttgart.de . Obviously thanks to our google overlords FTP is no longer integrated in the browser because the browser is only http, not gopher, telnet, ftp .. who needs to be universal?
You’ll find it in the /pub/cm/lgp30/papertapes/Games directory.
Important things is that your yes/no should be inputted as y’ or n’ The game will stop SIMH so you need to ‘g’ to start again.
Although this comes up time and time again, I found this hacker news post, that actually has a picture of Mel, showing that he was in fact a real person.
Well back before, I had been looking into old linkers for 386 OMF, I knew I’d found some fun with some old GNU tools going back to the heyday of Xenix 386. As kind of expected the tools used to build Xenix, along with it’s SDK were in fact Microsoft C/MASM. So yes way back in 1987 Microsoft not only has MASM386, but they also had a 32bit Microsoft C 5.00. Let that sink in for a moment as OS/2 had been forced into 16-bit land despite FOOTBALL, and Windows/386 being a 386 VM86 multitasker. So in a weird way all the parts were in existence.
I tested this on MinGW with some simple stuff, and sure enough it links just fine. Considering its what is on the GCC on Xenix port I’m sure it’s pretty solid.
Now this is more fun, and again kind of sad that GCC didn’t take on the ability to target other assemblers (just look at the x68000!), Maybe they didn’t see GAS for OMF, or just didn’t know. Instead a more aggressive choice was made, to alter the binary output. Linking on OS/2 with EMX involved 2 very different and incompatible paths, the first one is the ancient Unix i386 a.out format, which then a utility called emxbind will convert into a loader & stub that OS/2 can run. Think of it as an OS/2 extender to take simple Unix programs (which is what they are) to run on OS/2. Neat!
The second more ‘native’ approach is to convert the binary a.out files into what is known as OMF files, which non GNU linkers like Wlink from Watcom or Link386 from Microsoft can then link into direct native EXE’s or DLL’s.
There had been an experimental ELF build of the EMX toolchain on OS/2 but I think it may have died? So as crazy as it seems bigger and crazier programs need to be built on systems like Windows or Linux and linked outside of OS/2 to get around the old memory limits. It’s really hard to say as I’ve never used it, although being able to do the link outside of OS/2 would be an advantage.
I’ve found 2 programs to convert the a.out objects into OMF, the first and oldest being o2obj. The one drawback I’ve had is that this doesn’t play so well with the Watcom 386 OMF linker. Instead the much later RSXNT/LIBC0.6 project’semxomf. I’ve done some painful hacking but it appears to do what it should do. A simple omfdump seems to be spilling stuff out.
Of course the alternative is to use a 64bit linker, and since a.out has been pulled from binutils the only real hope is the Watcom linker which is now running in a 64bit address space. And the Watcom chain won’t understand ancient i386 a.out, however Microsoft 386 OMF it certainly will, although it appears to be based around something later than the aforementioned o2obj, which is why I ahd to do the emxomf.
I know as this stands it’s not very satisfying but I kind of wanted to push this out the door as I’d been hacking from time to time on it, and didn’t want to leave it to rot completely. The EMX tools remind me of the NeXT stuff where everyone goes native platform wild never imagining a day when remaining portable would mean it’d be easier to target more software.
The one thing I wonder about sometimes if there was some kind of secret Microsoft extended DOS/Windows that relied on OMF & Link386 that predated the NT team and their switch to COFF? Obviously it’d be super obsolete and would have been something like the first PharLap 386 stuff. But I’ve only owned a disk dump of v4, and a legit copy of TNT v6. Old 386/DPMI/Extender tools are hard to find.
Linkers & loaders, along with binary formats are too hard for me, but I thought I’d share at least what I’d been able to conjure with MinGW. I’ll have to touch on EMX to native OMF linking later.
This is a bit cheating, but I broke down and did some dump/exports of a building system to get the file layout. Since the MiG phase was totally done native, I didn’t bother with that, or trying to ‘fix’ the nested Makefiles, rather I just dumped the output and worked with that. I guess I could make my own Makefile but for now it’s a stupid script. I used the a.out build tools for Linux as the objects are all the same anyways.
Since there is no Makefile it won’t run in parallel. About 20 seconds or so later you’ll get a linked ‘a.out’ but it won’t run. The script xport.cmd is rigged for me and Qemu 0.10.5 to create a tar file to extract inside of mach and perform the native link.
Obviously this means you can us modern UI’s tools and everything else as you are now on the outside! If you can force your build to use my ancient tools you can even do the build. Nice!
Doing a rebuild of the kernel in Qemu the 2.5.8 -O2 build shaved a whole second off the build, so yes it actually did something.
Things to do would be cross linking, fixing the drivers that don’t build, and probably improving stuff like bigger disks, filesystems and memory… or networking!.. .but that’s all too complicated for me!
One of the great things about Windows 11 was the inclusion of the Windows Subsystem for Linux or WSL. It wasn’t available at launch but it started with v1 a simple ELF loader and an implementation of the Linux kernel on the NTOS kernel. Being a re-implementation of Linux it was great for what did work, however many things did not. Compared to other Unix subsystems for NT over the years however WSLv1 was the best no question.
Not being enough however, Microsoft took a page out of the old WinOS/2 days and stubbed a Linux kernel to run under Hyper-V, allowing it to run far more applications, and for me giving the ability to use applications that alter memory space, and allowing i386/x32 applications to run. You could happily export your X-11 display to a Windows based X server, and get applications that way. But this isn’t 1993 so it was very limiting.
The big change is the ability to use RDP to hook both Wayland and Pulse Audio bringing Linux ‘desktop’ X11 applications to the Windows desktop. Also added in is virtual GPU capabilities allowing accelerated 3D, along with CUDA applications to run (although with a performance penalty.
The downshot for me, is that my existing Debian 10 install was not picking this up, and was somehow picking up a VMware
I have no idea how or why it was picking this up. While I did have the VMware Player installed, the newer versions backend through Hyper-V.
I did find this article, which gave me a path to get where I wanted, although the transition of an existing v2 instance didn’t work for me. Maybe Debian 10 is too weird. I don’t know.
Not sure where how to proceed I backed up my home directory and un-installed VMware Player and purged my existing Debian 10. I installed that Ubuntu Community Preview which promises to include all the new and exciting features.
$ glxinfo -B
name of display: :0
display: :0 screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
Vendor: Microsoft Corporation (0xffffffff)
Device: D3D12 (NVIDIA GeForce RTX 2070) (0xffffffff)
Video memory: 40710MB
Unified memory: no
Preferred profile: core (0x1)
Max core profile version: 3.3
Max compat profile version: 3.1
Max GLES1 profile version: 1.1
Max GLES profile version: 3.0
OpenGL vendor string: Microsoft Corporation
OpenGL renderer string: D3D12 (NVIDIA GeForce RTX 2070)
OpenGL core profile version string: 3.3 (Core Profile) Mesa 21.0.3
OpenGL core profile shading language version string: 3.30
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL version string: 3.1 Mesa 21.0.3
OpenGL shading language version string: 1.40
OpenGL context flags: (none)
OpenGL ES profile version string: OpenGL ES 3.0 Mesa 21.0.3
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00
Now this is looking MUCH better.
Now compare this to a native version of FuMark:
So it’s a 50% haircut. Ouch.
Gaming however using steam (yes steam runs!) reveals some other deeper issues. The mouse tracking is WAY off. So for FPS stuff you’ll spend a lot of time staring at the ceiling or the floors. The next issue is there is no mouselock, so things that rely on being able to move the mouse far beyond a screen length is impossible to play. To be fair it’s a preview, and so far I have to admit Windows 11 feels more like a technical preview. Also I don’t know what the deal is or anything about profiling it but KOTOR2 is insanely slow. Although at least with 3d acceleration running it’s not 1 frame every 5 seconds.
With all the controversy over 64bit pinball, and where and how things appeared, then disappeared to the discovery that the x64 version was a thing, but it was left off the install manifest but shipped on CD, along with my simple script to just extract it, the problem was that ARM32/64 users were left in the cold.
Don’t get me wrong, the original 32bit exe runs fine under emulation, but who wants emulation when you can have NATIVE CODE?! You’d have to try to find the source code (lol good luck!) or reverse engineer the program. And that’s what happened, enter:
I’m using Visual Studio 2019 to build this, and it was great it *just worked*. Hurray!
There is also a rebuild going on for SDL to bring Space Cadet Pin Ball to Linux and beyond. The only downside is that it uses a number of ‘new C++ features’ locking out older platforms. I’d done some work to dumb it down although there is a bit of this new fangled C++ I’m unsure of what is going on. So that means, unfortunately Itanium users are left in the dark, as Visual Studio 2010 is too old.
It sure may not look like much but it was an adventure getting here.
First, what is it? Well it’s the very simple NS32016 from here, with a few minor changes. I expanded the RAM from 256kb to a whopping 8MB. Then I added simple character I/O allowing me to print messages to the screen. Next looking at the toolchain page, I used my old Linux to Windows GCC 4 cross compiler to build the appropriate Canadian cross compiler to the NS3216.
Building the tools
A while back, I had built a cross compiler from Linux to Windows using GCC 4.1 as the basis as it was the last version that didn’t have massive external dependencies. NS32016 support was dropped some time in the late 3.x or early 4.x GCC so it means we need to go old anyways. I arbitrary picked GCC 2.8.1 for this build, while using the recommended Binutils 2.27
GCC 2.8.1 doesn’t quite know what we are doing so there is some flags we need to run off in auto-config.h namely
#define HAVE_BCMP 1
#define HAVE_BCOPY 1
#define HAVE_BZERO 1
#define HAVE_INDEX 1
#define HAVE_KILL 1
#define HAVE_RINDEX 1
#define HAVE_SYS_RESOURCE_H 1
#define HAVE_SYS_TIMES_H 1
You can just comment them out, or remove those lines all together.
When it came to building GCC, I did run into issues with GCC 7/8 trying to build GCC 2.8.1. I found it much easier to either have that Linux 4.1 compiler, or if you have access to Wine or WSL you can just run the Win32 binaries for the gen phases.
./configure --prefix=/cross --target=ns32k-pc532-netbsd --host=i686-mingw32
make CC=i686-mingw32-gcc xgcc cccp cc1 cc1obj
If you can run your own Win32 exe’s on Linux it’ll run just fine using the Linux to Windows GCC 4 cross. Otherwise you will need to either patch GCC or make your own GCC 4 hosted Linux to Linux cross compiler like this:
make CC=i686-mingw32-gcc HOST_CC=i586-linux-gcc xgcc cccp cc1 cc1obj
Hopefully that worked enough, and now you have your cross compiler. Now it’s time to build libgcc1.a
Again you really want to be able to run the resulting programs on Linux but I guess you could script it out. Naturally if you wanted to just use Linux, it’d be easier to make that cross compiler directly, although I’m not sure how much of GCC 2.8.1 I want to fight, or just get GCC 4 running on Linux and use that to port.
# setting the stack 256k under 8MB
# setting the stack 256k under 8MB
I used a bit of the C example, and added some hooks that GCC was expecting namely a __main call that is made from main before it does anything (a place to init memory perhaps?), a place to catch an explicit exit call, along with setting the stack of course.
Patching InfoTaskForce without malloc / disk access
It’s not going to win any awards, but it was really great to get it to run a simple program written in GCC. Looking for something more fun, I took the old InfoTaskForce interpreter from ’87, and dug up my modification to run on cisco routers, and cooked up this version, that adds enough of printf from Linux, a bogus malloc that just allocates from a fixed memory array (otherwise you have to actually know about your platform), and a fun trick with later binutils where you can import a binary file directly as an object!
Since I don’t have any file I/O being able to have the game data in RAM is crucial. I tried to tweak it so you could build the same working thing on Windows (maybe others?).
So for anyone who wants to look at the standalone adventure Win32 hosted tools are here, although the emulator should be somewhat portable.