Building MAME 0.1 for MS-DOS / DJGPP

So as promised, a while back I had built a GCC / Binutils 2.8.1 cross compiler toolchain suitable for building old Allegro based programs, such as MAME.  Of course the #1 reason why I’d want such a thing is that being able to do native builds on modern machines means that things compile in seconds, rather than an hour + compiling inside of DOSBox.

Why not use a more up to date version of both GCC/Binutils?  Well the problem is that the pre EGCS tools ended up with macro and inline assembly directives that were dumped along the way so that later versions simply will not assemble any of the later video code in Allegro, and a lot of the C needs updating too.  And it was easier to just get the older tool chain working.

It took a bit of messing around building certain portions inside of each step of the tools, but after a while I had a satisfactory chain capable of building what I had needed.

So for our fun, we will need my cross DJGPP v2 tool chain for win32, MAME 0.1, Allegro 3.12 and Synthetic Audio Library (SEAL) Development Kit 1.0.7 .

Lib Allegro is already pre-built in my cross compiler tool chain, all that I needed to add was SEAL, with only one change, 1.0.7 is expecting an EGCS compiler, which this is not, so the -mpentium flag won’t work, however -m486 will work fine.

Otherwise, in MAME all I did was alter some include paths to pickup both Allegro and SEAL, and in no time I had an executable.  And the best part is checking via DOSBox, it runs, with sound!

MAME 0.1 on DOSBox PACMAN hiding

Thankfully MAME has been really good about preserving prior releases, along with their source tree, and it’s pretty cool to be able to rebuild this using the era correct vintage tools, and I can’t stress how much more tolerable it is to build on faster equipment.

Updated my DooM port

x68000 still won’t build on this, lots more to either separate out or just fork out.  No biggie.

The big plus is for GCC 2.x and higher that use DJGPP v2 runtimes is that the allegro music and sound work.  It tests faster than Watcom 10/11 or Open Watcom ..  probably DMX vs Allegro I suspect …

Things to do..

  • Upload my GCC cross toolchain
  • Upload the Freedoom build chain (again)
  • Test on real machines, the 486 and the P3

So yeah.  Limited progress.

Also it’s nice being able to cross build Allegro 3.12 in 10-15 seconds vs the hour+++ in emulation.

Project is in the djgppv1 cross thing

git access to clone

git clone git:// crossdjgppv1-DooM

make with:

make -f makefile.djgpp_v2

and you should be good to go

dosdoom 0.2 recovered

While cruising around at looking for something else, I saw this thread: ‘Recovered’ DOSDoom 0.2.

So I quickly built it with my MinGW32-DJGPP using GCC 3.4.5.  And this version needs the Allegro library as it has sound effects audio!  Although building Allegro needed GCC and Binutils 2.8.1.  Using other versions just led to nothing but trouble.  I ended up just installing DJGPP on DOSBox to build Allegro which took … a whlie to build.  Although being able to cross compile dosdoom from Windows was far far far quicker.

So yeah, it runs.  With sound.  It’s great.  Allegro integration isn’t anywhere as near complete at this point it’s just the sound files.  I took a much later version of dosdoom’s MIDI code, which required the Allegro timer, which interfered with my older timer IRQ hook.  Converting the whole thing to use the Allegro timer, and keyboard wasn’t too difficult, and that gives my DooM source fork a really full feeling when using DJGPP v2.

Although I’m having issues uploading from China at the moment.

GCC 1.27 & MS-DOS

Inspired by Building and using a 29-year-old compiler on a modern system, i thought I too could get this ancient version of GCC working.  At the time I never had bothered with the older version as I had always assumed that there were many fixes and adaptations to GCC  for it to run on MS-DOS via GO32/DJGPP.  However after doing this, its obvious that GO32/DJGPP was rather built around GCC’s stock output, which would sure make a lot more sense.

And it turns out that the target machine being an i386 Sequent running BSD is the best match, both in turns of underscores, and debugging format.  At first I had tried the AT&T SYSV i386 target, however it couldn’t link anything from the standard libraries that DJGPP has as they all have a leading underscore.  After starting to mess with internal macros to turn things on and off, and re-define how various portions of assembly are emittied, I found the Sequent target and went with that and everything was fine, and using the existing build infrastructure for GCC 1.39 I now could actually run hello world!

gcc_v1 -v -E hello.c -o hello.i
gcc version 1.39
cpp_v1 -v -undef -D__GNUC__ -DGNUDOS -Dunix -Di386 -D__unix__ -D__i386__ hello.c -o hello.i
GNU CPP version 1.39
gcc_v1 -v -S hello.i -o hello.s
gcc version 1.39
cc1_v1 hello.i -quiet -version -o hello.s
GNU C version 1.27 (80386, BSD syntax) compiled by GNU C version 5.1.0.
gcc_v1 -v -c hello.s -o hello.o
gcc version 1.39
as -o hello.o hello.s
gcc_v1 -v -o hello hello.o
gcc version 1.39
ld -o hello C:/dos/xdjgpp.v1/lib/crt0.o hello.o -lc

go32 version 1.12.maint3 Copyright (C) 1994 DJ Delorie

hello from DJGPP v1/GCC 1.39!

Wasn’t that great?  Then going through my ‘test’ programs I went to try to build the infocom interpreter, and that is when things went off the rails.

funcs.o: Undefined symbol __udivsi3 referenced from text segment
options.o: Undefined symbol __divsi3 referenced from text segment
options.o: Undefined symbol __divsi3 referenced from text segment
print.o: Undefined symbol __divsi3 referenced from text segment
print.o: Undefined symbol __udivsi3 referenced from text segment
support.o: Undefined symbol __divsi3 referenced from text segment
gcc_v1: Program ld got fatal signal 1.

I’ve had some issues with GCC and these ‘built in’ functions before.  This was an early major stumbling block back in the x68000 GCC days, where after a lot of searching I was able to find 68000 versions of various math routines that were in the native Hudson Soft assembler to link in.  While GCC 1.x does have a libgnu/gnulib to include these functions it warns you over and over to not use GCC to build them, but rather the native CC.  But the problem is that I don’t have a native CC.

But I managed to save myself after googling around by finding srt0.c from 386BSD.  Namely these two:

.globl ___udivsi3
movl 4(%esp),%eax
xorl %edx,%edx
divl 8(%esp)

.globl ___divsi3
movl 4(%esp),%eax
xorl %edx,%edx
idivl 8(%esp)

I ended up having to removing a single underscore, but now I could link infocom, and even better it runs!

Wanting to try something far more exciting, I went ahead and tried to build DooM.  However GCC 1.27 has an issue with m_fixed.c  I fired up GDB to at least take a look, although I’m not sure where the fault lies.

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Breakpoint 1, 0x752c5ad5 in msvcrt!_exit () from C:\WINDOWS\System32\msvcrt.dll
(gdb) bt
#0 0x752c5ad5 in msvcrt!_exit () from C:\WINDOWS\System32\msvcrt.dll
#1 0x752bb379 in msvcrt!abort () from C:\WINDOWS\System32\msvcrt.dll
#2 0x0045805c in final (first=0xe066a0, file=0x75312688 <msvcrt!_iob+128>, write_symbols=NO_DEBUG, optimize=0)
at final.c:653
#3 0x00403198 in rest_of_compilation (decl=0x722718) at toplev.c:1296
#4 0x0040fbce in finish_function () at c-decl.c:3272
#5 0x004040c0 in yyparse () at c-parse.y:224
#6 0x0040239d in compile_file (name=0xe00def "C:/dos/xdjgpp.v1/tmp/cca02992.cpp") at toplev.c:837
#7 0x00403a33 in main (argc=11, argv=0xe00f90, envp=0xe01598) at toplev.c:1556

With the code being:
if (! constrain_operands (insn_code_number))
abort ();

So I assume some error with constrain_operands? Not that it makes it any better.  However I know this one file compiles fine with 1.39, and since we are on the i386 another alternative is just to used the assembly version that was hiding in the readme..

DooM mostly built by GCC 1.27

And much to my amazement, it works!  Keeping in mind that this is using an a.out tool chain, along with the last DPMI enabled GO32 extender.

Considering the compiler dates back from September 5th, 1988 it’s really great to see it running.

I’ll have to upload source (GCC 1.27/DooM) & binaries later.  But I imagine it should also run on EMX/RSX for a Win32 version.

Started to re-build my MS-DOS machine


Good news, it actually works!  I was using the version 1.1 WAD, so honestly weird crashes really aren’t unexpected.  I haven’t looked much at what to do with audio, but I was really impressed compared to the Qauake II wars, it was really surprising to not only see DooM run on the first shot in real metal, but the keyboard works as well.  Well enough for me to pick a level, and get killed.

Naturally it doesn’t work under Windows, however it runs fine with MS-DOS mode.

Porting Catacomb3D to MS-DOS (DJGPP v1/GO32).

Catacomb 3-D for GO32

No really, it’s Catacomb 3-D: The Descent.  First ported to 32-bit SDL by NotStiller.  Me being the person I am, I fixed a slight bug regarding binary files on Windows, and MS-DOS, then cleaned up some of the C++ syntax (yuck!) making it far more C89 friendly.  And of course, hot off the heels of DooM for GO32 DPMI, I was able to get it to build and run using GCC 1.39 and GO32.

I know most people really won’t care, but I found it kind of interesting.  I should try to see if it’ll run on actual hardware, just as a comparison of tightly optimized Borland C++ / Assembly vs 100% pure C on DJGPP.  The best tech of 1991 for sure!

At current I just put the source up, you can git it here.

Uploaded my cross DJGPP v1 environment to sourceforge

project is here.

I also put up the source for my ‘null doom‘, for anyone who ever needs some massaged source to DooM that will compile with a C compiler, instead of needing something that can understand C++ style comments, although I know in cccp.c there is the ability to turn on cplusplus style processing.  However since I did want something that would compile without altering the compiler (too much) I thought it was best to just change all the comments.

And a quick download link to the zip file with the source & binaries.
Download crossdjgppv1
Download crossdjgppv1

Null DooM, GCC 1.39, GO32 and DPMI


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:

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.

DJGPP memory fouled

free: memory fouled

free: memory fouled

If you ever get this fun error while trying to exit or shell a program with DJGPP:

combinelo: memory fouled

free: memory fouled

You are mixing libraries built with a different version of the DJGPP runtime.  In my case, I built the allegro library with GCC to use the older binutils but I’m cross compiling with GCC 5, so it’s using the newer runtime.

In my case I just needed to replace the contents of the lib directory with, and I was good to go.  I guess I could re-compile allegro, but that takes the better part of forever on DOSBox, and once was good enough.