Null DooM, GCC 1.39, GO32 and DPMI


phew.

DooM via DJGPP v1 GO32

Around the time of the x68000 port of DooM, I was cutting down the DooM source for a null/portable version.  I never could get it to actually run either using EMX or  DJGPP 1.03, as I couldn’t get it to link to save my life with a constant never ending battle of unresolved symbols. After a while I just used what I had towards the x68000 version and concentrated on getting it up and running, and just shelved the null/portable effort.

Later on I wanted to get it running again as part of messing with another cross compiler, as DooM isn’t a trivial application to port and verify correct operation. And in the process of trying to get the null version to build and run on Windows using TDM GCC, I wanted to make sure it at least kept compiling with GCC v1.x.

Once more again I was able to compile individual files but unable to link.  But this time, I just looked at the diffs for binutils, I thought it should be somewhat easy to get hosted on Windows.  Although versions may point to binutils 1.0, I had to use binutils-1.9.tar.gz even though the diffs are against Mar 24 1991, and the source for 1.9 is dated April 17 1991.

My first effort gave me a linker that would happily link, but go32 would either refuse to run the executable, or just crash.  I was going to give up again, but I found mention in another file that DJGPP actually uses the linker from G++, the C++ compiler which was a separate thing in the late ’80s and early’90’s.  This time it worked, and I could link a trivial hello world style application!

Now that I finally had a cross linker actually working, I didn’t want to compile under emulation, so looking at the other diffs, they didn’t look too extensive. I went ahead ,and took DJGPP v1.06 and patched up the compiler & assembler to get a full cross toolchain.  And in no time, I had a null version of DooM running on MS-DOS well at least tested on DOSBox.

This was fun, and all but I didn’t see any easy way to do fun things like hook interrupts so I could get the keyboard & clock like any good MS-DOS program.  DPMI greatly eased this kind of stuff, so looking at the DJGPP history, DJGPP v1 version 1.10 actually adds preliminary DPMI support!  And in the next version, DPMI was much more better supported, however the binary format had changed from a.out to COFF as part of the move to v1.11. I was able to take the memory, and DPMI portions from the final v1.12 libc, and manually build and run them against the v1.06 library / dev tools.

And much to my surprise, it actually worked!  At least having the wrong format didn’t have any effect on how GO32 worked for me.

So feeling lazy, I snagged some of the support code from Maraakate’s revamp of DooM, just to make sure of the timer code, and the keyboard code, and again verified that I can build with the keyboard & timer ISR and I’m able to play the v1.9 shareware & commercial levels fine.  I haven’t done a thing to clean up or update the DooM source itself against all the dozens of bugs and issues with Ultimate DooM, or other games like Chex Quest etc.

I’m sure 99% of people wouldn’t care but you can download it here:

Win32_DJGPPv1_DooM.7z
Download crossdjgppv1

Although I’m using DPMI to drive realtime events, if I looked further at the GO32 v1.06 environments I could either figure out how it operates it’s timer, or modify the extender directly to drive the PIC timer and keyboard as I need.  But overlooking that, the vintage 1991 software is more than capable of running DooM.

OS X 10.12 to Win32 MinGW cross compiler

Using GCC 4.1.2 because that is what I wanted.

Oh yes, it works!

It’sGCC 4.1.2 for MinGW on OS X.  Naturally I had some fun along the way.

      cp/cp-lang.o stub-objc.o cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o cp/class.o cp/decl2.o cp/error.o cp/lex.o cp/parser.o cp/ptree.o cp/rtti.o cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o cp/cp-gimplify.o tree-mudflap.o attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o c-dump.o winnt-cxx.o c-pretty-print.o c-opts.o c-pch.o c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o c-gimplify.o tree-inline.o dummy-checksum.o main.o  libbackend.a ../libcpp/libcpp.a ../libcpp/libcpp.a ./../intl/libintl.a -liconv  ../libiberty/libiberty.a

Undefined symbols for architecture x86_64:

  “_libc_name_p”, referenced from:

      _nothrow_libfn_p in except.o

ld: symbol(s) not found for architecture x86_64

clang: error: linker command failed with exit code 1 (use -v to see invocation)

make[2]: *** [cc1plus-dummy] Error 1

make[1]: *** [all-gcc] Error 2

make: *** [all] Error 2

$

 

From stack overflow:

When gperf wasn’t installed, the compilation script ran the command anyway but generated a blank ./gcc/cp/cfns.h. Since this file was newer than the source (./gcc/cp/cfns.gperf) the makefile left it alone and never regenerated the ‘real’ file when you actually had gperf. To continue, run rm ./gcc/cp/cfns.h and try again.

to dealing with duplicate inlines exact_log2 from an include gone wrong.  Not to mention more and more headers not generating.  But in the end it actually works.  As always it feels so much faster to run on OS X than Windows.  I’m sure there is stuff out there for newer versions of GCC, but I wanted to use the older toolchain and libs for some other reason.

As always it’s on my site here: OSX_16.3.0-MinGW_GCC_4.1.2.7z but I don’t think the world at large would even care.

Cross GCC from Windows to AmigaDOS

GCC 2.7 to AmigaDOS 2.04

GCC 2.7 to AmigaDOS 2.04

Yes, I know there are others.  Newer versions of GCC too!.. but I was more so curious to see if I could do it.  I know there were GCC 1.x ports to the Amiga but I can’t find source anywhere.  And for some reason the Amiga and Atari ST seem to have never been mainlined into GCC.  I would have thought 1990-1992 they would have had far more users than say SUN-2/SUN-3.

Some ‘fixes’ are described in this file:

https://raw.githubusercontent.com/sdenel/How-to-install-SimpleScalar-on-Ubuntu/master/Install-SimpleScalar.sh

Although it’s not 100%.

I downloaded the files mentioned on this GCC page, and started to massage stuff.  This was easier as GCC 2.7 & Binutils 2.8 both support Windows NT 3.5 (and much much higher!).

I may want to try to get an ancient Nethack to build, so I put it onto sourceforge…

win32-amigados_hello.7z

I’ve just tested a hello world type executable.  I’m more so amazed that it linked and executed, ‘file’ detects the objects as

x.o: raw G3 data, byte-padded

But at least the executables look right:

hi: AmigaOS loadseg()ble executable/binary

I had to hack all kinds of crap compiling eamiga.c
and eamiga_bss.c as neither generated correctly, and both had all kinds of missing and undefined things.  I’m sure on bigger projects it’d just explode, but right now I’m just amazed the linker could pick up my object, plus the 21 year old objects + libraries from that aforementioned ancient GCC port.

Oh well I was entertained for a couple hours.

Cross compiling to the Amiga with Sozobon

To start this fun voyage, I used HCC, the first usable port of Sozobon C to the Amiga I could track down.  From it’s description:

Amiga port of Sozobon, Limited’s C Compiler. Can completely compile itself, supports 32 bit ints, and optimizer can ‘registerize’ variables. Includes compiler, optimizer, tool for creating interface code for Amiga system calls, startup code, C library, include files, and library routines that work with Motorola FFP format. Uses assembler A68k, linker BLink, and provided run-time shared C library CClib.library.

From the readme

And isn’t that great?  It even supports 32 bit integers!  I had to massage things in Visual C++, as there was some weird instances of return codes missing, and the optimizer not actually mallocing it’s memory, but just blindly using pointers.  As always if you can see what is going on in a debugger it’s not too hard to make some wild guesses and get it running, and if you get lucky it may even work too…

Running the compiler

With the compiler and optimizer running (it is actually needed to run to further massage the assembly output into something the Amiga a68k assembler can read), it was time to look at an assembler.  For the heck of it, I did try a68k, and to my amazement it did actually work, once I had updated the file output call.

hcc\hcc -L hanoi.c
hcc: version 2.0 Copyright (c) 1988,1989,1991 by Sozobon, Limited.
Amiga Version 1.1 by Detlef W³rkner.
hanoi.c:

top\top -v hanoi.s h2.s
top Version 2.00 Copyright (c) 1988-1991 by Sozobon, Limited.
Amiga Version 1.1 by Detlef W³rkner.
hanoi.s:
Peephole changes (1): 8
Peephole changes (2): 1
Peephole changes (3): 0
Instructions deleted: 3
Variables registered: 0
Loop rotations : 0
Branch reversals : 0
Branches removed : 4

a68k\a68k -q100 h2.s
68000 Assembler - version 2.61 (January 11, 1990)
Copyright 1985 by Brian R. Anderson
AmigaDOS conversion copyright 1989 by Charlie Gibbs.

Assembling h2.s
PASS 1 line 59
PASS 2 line 59
End of assembly - no errors were found.
Heap usage: -w2047,80
Total hunk sizes: 94 code, 10 data, 0 BSS

linking

Wow wasn’t that fun! I haven’t seen the source code to the BLINK linker, so I just end up using a native linker, BLINK.

Towers of Hanoi

Much to my amazement, the a68k assembler functions just fine as a cross assembler, and I only had to copy the object file into the emulator, and I could happily link.

The syntax for BLINK was a little strange, mostly because I really don’t know what I’m doing.

BLink LIB:HCC.o+hanoi.o LIB LIB:HCC.lib+LIB:stubs.lib TO hanoi SC SD VERBOSE

Now to try something bigger, like the ancient 1987 vintage InfoTaskForce.  I had to add in the include files from the DICE compiler, and surprisingly, in no time, it was all compiled, and assembled the only step remaining was to run the BLINK linker.  This time it was slightly different as now we had a bunch of object files:

BLink LIB:HCC.o+fileo.o+funcso.o+infocomo.o+inito.o+inputo.o+interpo.o+ioo.o+jumpo.o+objecto.o+optionso.o+pageo.o+printo.o+propertyo.o+supporto.o+variableo.o LIB LIB:HCC.lib+LIB:stubs.lib TO infocom SC SD VERBOSE

Running that as a single line (or better in a command file) got me my executable.

Linking

And it linked without any unresolved externals.

InfoTaskForce cross compiled on Windows, linked on AmigaDOS 2.0

Running under WinUAE

And even better, it worked. Here it is running Planetfall!

I can’t imagine it being all that useful for anyone, as Sozobon C is K&R C, and well this is for the Commodore Amiga, not exactly a mainstay in this day & age.

HCC_Sozobon_win32cross.7z This link will take you to the sourceforge page, and the archive contains both source, and executables.  As mentioned I didn’t see any Amiga linker that has source code, it seems everyone use BLINK, and the team that write BLINK went on to re-write all the ‘c’ commands in AmigaDOS from BCPL/asm into C.

***

Addendum

I just discovered vlink after writing this, and now I can link a working executable under Windows 10! Since I made zero changes to vlink, and I’m not charging money, I am free to redistribute this so I’ve updated my archive, and included it.

EMX 0.9d rehosted on Win32

EMX on Win32

I know it’s utterly pointless… But yeah GCC 2.8.1 + EMX 0.9d, hosted (running) on Win32.  The main reason is that I wanted to be able use use my substantially faster Win64 machines to build stuff for OS/2.  And since I have a 4 core (+4 hyper thread), I want to be able to use make with the -j 16 flag, and say compile QuakeWorld/2 in under two seconds.

I was able to get the binutils 2.6 derived stuff to compile, along with the ‘ancient’ binutils which is notably the linker that EMX depends on.  I would imagine this ought to be able to compile PDOS, although my own simple attempt at InfoTaskForce met with spectacular failure.  While it does compile fine using an older EMX 0.8h based release.

EMX 0.9d on Windows 10 x64

EMX 0.9d on Windows 10 x64

As you can see, it can compile the dhyrstone benchmark, and run the MS-DOS version via the MS-DOS Player.

Downloads

N64 cross GCC / Binutils for Win32

Building GCC & Binutils for the Nintendo 64

I had a request to help get a GCC+Binutils running as native win32 exe’s something comperable to the ancient ‘ultra’ N64 toolchain done by Kyoto Microcomputer (resume pdf).  One interesting thing about their toolchain is that they used a common object format for MS-DOS, DOS/V and MS-DOS on the PC-98 format, along with Win32.  However the Win32 runtime doesn’t like Win64 environments.  On Win64 the exew32 driver just complains:

Can’t allocate memory (Error Code=487)

However the stubs in all the exe’s reference exegcc98 exegccv DOS extender’s along with a exegcc.  However googling around yields nothing.

Running on a x86 version of Windows, however the tools run and report gcc 2.7.2 release 1.2 and the binutils version is simply 2.6 with BFD version 2.6.  So going with this, and the request to keep it 1997 vintage I went ahead with Gcc 2.7.2.3 and Binutils 2.8.1 as they are the end of the line in both trains of code.

To configure is really a snap, as both support the Windows NT platform directly

sh configure --host=i386-winnt3.5 --target=mips-elf

I guess I should add that I build with TDM GCC 5.1, and I use the incredibly ancient MSYS-1.0.11-rc-1.  But it’s enough to bootstrap and build with!  Since my GCC is much newer, I did have to finagle some things.  Here is a quick list of my notes on what I had changed, and some justification.

Binutils 2.8.1 notes:

include/fopen-same.h

make sure this uses MS-DOS rb wb type constraints!

libiberty/xmalloc.c

There is no sbrk on my MinGW32 … so comment out all the sbrk stuff.

bfd/targmatch.sed

My sed LOVES UNIX style text files, so this one shouldn’t be in MS-DOS CRLF format.

binutils/objcopy.c

mkdir only accepts the path on Win32.  Also there is now chown.

Gcc 2.7.2.3 notes:

c-gperf.h

‘__inline’ for is_reserved_word needs to be commented out.

config/mips/mips.h

Set like the following for both ASM_FINAL_SPEC to prevent the t-mips from trying to be run.

#define ASM_FINAL_SPEC “\
+%{pipe:-}”

config/winnt/xm-winnt.h

OBJECT_SUFFIX “.o”

Just because we are on Windows NT, doesn’t mean we want an .obj object suffix.

gcc.c

__spawnv : __spawnvp work better as _spawnv : _spawnvp

obstack.h

*((void **)__o->next_free)++ = ((void *)datum);

confuses newer compilers, with this error message:

obstack.h:341:32: error: lvalue required as increment operand

replace it with with:

*(__o->next_free)++ = ((void *)datum);

So at the end I have a cross compiler, and I can generate object files, and link files that the final tool MILD can then use and produce N64 ROM images.  It’s not a 100% solution, as I don’t see any mention of MILD being GNU, however the compiler and binutils is running on Windows 10 x64!

GCC cross compiling to the N64 target

GCC cross compiling to the N64 target

I built a few demos and tested with the 1964 emulator.

And there you have it.  For anyone who cares, you can download the toolchain + source here: winnt3.5_i386-mips_elf-gcc-2.7.2.3_binutils-2.8.1.7z

Starting on an ELF cross compiler for Windows

I’m using Slackware 4.0 as a starting point, so it’s Binutils 2.9.1 and GCC 2.7.2.3 .. I verified that I can build a static hello world executable, and it runs! …

However Linux 2.0.40 has the same issue, it starts to decompress, and triggers a reboot in both Qemu and PCem.  Going in circles I guess.  I suppose the next step is to use the exact version they have in Slackware to see if Qemu can actually run that pre-built kernel, and if I can create one via cross compiling.

I should add that on Debian 7.1 I got GCC 2.7.2.3 running, and it too produces the exact same thing.

Not that I think anyone cares, but here is my pre-built toolchain with some source (The binutils was built under Linux, using a MinGW cross compiler) elfgcc_2.0.40.7z

Cross compiled Linux 1.0.9!

Linux 1.0.9 running!

Linux 1.0.9 running!

After getting Linux 0.98 to compile, I thought I’d take a stab at Linux 1.0.  I vaugely recall when it was released, and I just remember a much larger push to 1.1.  So I guess it really comes as no surprise that in the Linux kernel archives, there is simply the 1.0 tar, and 9 patch files.

I went ahead, and patched up the release, and then tried to build with GCC 2.3.3.  This however proved not to be up to the task, as 2.3.3 has issues with some of the assembly macros, so delving into the readme shows that you need to use GCC 2.4.5 or higher.  Since I wanted to keep at least the tools on par, I went ahead and build 2.4.5, and once more again used the gcc driver from 2.6.3.  I further ended up relying on headers, and checking tool versions from Debian 0.91, which also revealed that they were still using GAS 1.38 back then.

One interesting note while building piggback, which takes the compressed system object, and wraps it in an object file, is that it directly uses the magic “0x00640107”, which is for a later “Linux/i386 impure executable (OMAGIC)” filetype.  But because my binutils is so ancient, I needed to change it to “0x00000107” so that the linker would recognize it as a “386 executable not stripped” file.  As always when having no idea what I was doing, it was easier to have it make an empty object file, set the type for 12345678 and look for where it occurs in the data stream, and just match it with a known object file.  As you can see, it worked.

I don’t know if it is of any interest, but the kernel source, along with a binary is available to download linux-1.0.9.7z, and the same goes for GCC gcc-2.4.5.7z.

And of course, you’ll want the latest download, which includes the pre-built tools, qemu, and build environment to get you started.

Cross compiling Linux 0.95c+ & 0.96c from Windows

The first thing is to build GCC 2…  I couldn’t find any of the Linux patches for 2.0, 2.1 or 2.2.. I only tried to build 2.0 from source as targeting a.out i386 but it looks like the 2.0 files on the FSF’s site are missing files?

Anyways GCC 2.3.3 actually includes builtin support of Linux!  I was able to build most of it, but just like GCC 2.5.8 for OS/2 EMX, But this time I used the gcc driver from GCC 2.6.3, which added support for Windows NT 3.5 native builds, and I now had my GCC cross compiler!

D:\aoutgcc\src>gcc2 -v -c hi.c -o hi
gcc version 2.6.3 -Linux 2.3.3
cpp2 -lang-c -v -undef -D__GNUC__=2 -Dunix -Di386 -Dlinux -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386 -D__linux hi.c C:\Temp\cca09324.i
GNU CPP version 2.3.3 (80386, BSD syntax)
cc12 C:\Temp\cca09324.i -quiet -dumpbase hi.c -version -o C:\Temp\cca09324.s
GNU C version 2.3.3 (80386, BSD syntax) compiled by GNU C version 5.1.0.
a386 -o hi C:\Temp\cca09324.s

Thankfully the prior binutils and assembler I was using in my GCC 1.40 cross compiler, still cooperated just fine, and I could happily build and link just fine.

From there it was a matter of fighting the makefiles as for some reason as make calls other makefiles they are not passing variables, so I just cheated, and changed the paths, along with editing the dependencies to finding stuff in a more sane manner.  Plus all the Makefiles have include paths hard coded into the build process as expected.  After fighting for a while, it linked and even better, it runs!

linux-0-96c-71-cross-compiled-from-windows

Linux 0.96c-71 cross compiled from windows

So yeah, using the MCC hard disk image from oldlinux.org and it boots!

Cool stuff, indeed!

As an added bonus I was also able to get 0.97 & 0.98 to compile as well!

Download your copy @ MinGW-aout-linux–001_010_011_012_095_096_097_098.7z.

Porting DooM to the x68000

Getting started

DooM is without a doubt one of the most popular PC games of all time.  And thanks to it being written in C is also an incredibly portable game.  One platform that mysteriously was lacking DooM was the SHARP x68000.

After a bored day of playing with the source to Mariko’s GCC 1.42 / 1.30 that targets the x68000, I thought I would take a stab at trying to compile DooM.  Since I’m using such an ancient version of GCC the first stumbling block is that DooM is FULL of C++ style comments, which older K&R & ansi based compilers of the late 1980’s simply cannot handle.  So the first phase was to convert all the comments.

In order to convert the comments, I came across this great tool, uncrustify.  The pain is that it doesn’t seem to take wildcards, but you can use make to have it do your work for you, or just a batch file…

uncrustify.exe --replace -c 1.cfg cl_main.h

you get the idea.

The key thing is the configuration file that tells uncrustify what to do.  To convert C++ comments to C is quite simply:

cmt_cpp_to_c = true

And away we go.  Having learned the ‘null’ lesson of Quake 2 the hard way, I started out with a working copy from Windows, via GCC 1.40 for Windows/RSXNT.  I figured that by having a ‘known good’ build with the a very close compiler level would be a good start as I don’t want to fight too much with the compiler.  After it was running with minimal changes, it was time to start the real fun.

Starting the actual port aka platform issues

The first error I hit was:

Error: Couldn’t realloc lumpinfo

For some reason the SHARP/Hudson LIBC has issues doing a realloc.  I have no idea why.  Over on nfggames Neko68k had mentioned that he had a disk image with a working version of GCC, that uses different includes/libraries that was able to get further.  I wasted some time by trying to bypass the Sharp LIBC malloc function by calling the HumanOS’s malloc directly which did get further but ran into issues when switching from usermode to supervisor mode to directly access the hardware.  Once when he shared his disk image, I was able to see how his GCC setup worked, and more importantly linked, so I could alter the GCC cross compiler I was using, and get much further in terms of progress.  I could then get from failing malloc to this:

startup errors

startup errors

And from there after trying different assemblers, flags, and all kinds of other things we could finally get null DooM running on the x68000 via 68030 emulation on XM6 TypeG.

null DooM running on the x68000

null DooM running on the x68000

DooM comes to life

From there, Neko68k was able to do something amazing, add in system support!  Which to be honest would have taken me forever to do, I was more impressed that I was even able to get the null version running, but Neko68k blew me away with this:

There is no correct palette setup at this point, there is all kinds of issues but you can see the startup logo being painted!

Then with a lot of improvements, and an added keyboard driver it was starting to look like DooM!

And then Neko68k had a major breakthrough with the video, timer and keyboard, and we now have a playable port!

Issues while cross compiling

Around this time I had noticed that when I built a cross compiled version the video for me was garbled.  After some investigating it turns out that m_swap was not being compiled correctly but rather the endian order was being reversed!

 .dc.l $00000000,$40f00000

instead of:

.dc.l $40f00000,$00000000

I tried re-building, re-configuring my host setup, and I still had the same issue.  I tried downloading GCC 1.42 and building an i386 SYSV to AT&T 3b1 cross compiler as it too is 68000 based, and I got the same issue.  Maybe it’s a bug in GCC 1.x cross compilers?  I don’t know, but since the procedure is small enough, it was easier to just have the native GCC produce an assembly version which I just assemble and link without issue.

Behold! DooM on the x68030!

Yes, there is no audio, but wow it’s playable!  I do need to map the keyboard better in the emulator, but the key layout in the source is fine.

Downloads

For anyone who cares you can follow more of the porting adventure here:

http://nfggames.com/forum2/index.php?topic=6140.0

Source & binaries are here:

https://sourceforge.net/projects/x68000-doom/

And my cross compiler toolchain is here:

https://sourceforge.net/projects/gcc-1-30-x68000/