So I missed all the updates over on doomworld about Freedoom, and deutex has been updated to support PNG files. Which certainly explains why all the assets were in PNG. I had thought they were still going the way of prBoom+ or some other ‘limit extending’ engine, but it turns out that they are wanting to target ‘vanilla’ LinuxDOOM derived engines.
So I tweeked my Makefiles where needed, and didn’t have enough Python to regenerate the text the way they do, so for now all the text assets are from a significantly older version. At any rate, here we go with the new assets:
Now what is great is that the Feeedoom folks have had the whole ‘apple pie’ stance to their project, with everything included. However they have drifted tools, build processes and other methodologies through the years. But thankfully the full archives are online, so I could go through and piece stuff together to my liking. Of course this all needs various tools, and oh boy does it ever need tools. You need:
a C pre-processor
A Unix’y build environment, I used the ancient MSYS
And probably many more I’m forgetting.
The first was to compile the levels. I used Ron Rossbach’s ancient IDBSP, a C port of iD’s command line Objective C level compiler. I did run into two slight issues, the first is that Ron’s tool expects their to be a line in the level’s dwd file telling us the name of the wad it’ll compile to, which of course is missing. The other is that I suck a makefiles, and just cheated forcing the tool to use a .wad extension on whatever .dwg it converts. And with that out of the way, I had the levels all built.
However that is where I found out the hard way that Freedoom doesn’t target something like my goal of being able to run this wad with the original DooM v1.1 release. The first problem is that Freedoom uses a different palette set, where it looks like it should be deeper? I’m not sure, but one thing was for sure everything looked like a rainbow sea of wrong and any vanilla or chocolate engines. And that is where I got a fun chance to play with ImageMagik. It really is quite powerful.
The first problem of course is the palette. Buried in the Python build scripts is a Perl fragment for generating a palette, and the all important playpal.lmp & colormap.lmp. I also got to spend a lot of time trying to extract that palette and do something useful with it to no avail. But googling led me to VGA_palette_with_black_borders.png, on Wikipedia of all things. So using this as a base I could convert, dither, and re-map the higher color Freedoom artwork into something that would play nice with Vanilla Doom. The downsite is that I didn’t try to find out exactly what assets a DooM version 1 wad needs, so I converted them all. On a good Xeon or i7 it takes about 10-20 minutes all the images. I can’t even think about how slow this would be using a 486, 68040 or MIPS.
Vanilla DooM v1.1 only plays audio at 11,000 Hz, 8bit deep. All the later ones needless to say use better sampling, and once more again Freedoom was at a higher level. I used sox to re-sample all the audio into the lower frequencies.
Later engines also are capable of directly playing MIDI files, and taking advantage of OPL3 chips, instead of v1.1’s OPL2 level. Thankfully Natt’s midi3mus is still online, and I was able to use this to convert Freedoom’s MIDI into the more restricted MUS format.
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:
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
#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)
#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))
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..
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.
It has cut down the video rendering obviously, but still has some of the C enemy AI logic, it’s a bit more like Wolf in that there is no height in the cut down levels, but wow it’s still amazing to see. The sound effects were re-cut from the PC speaker stuff, and yes, even reduced versions of the MIDI music make the cut!
Naturally this won’t run on a stock 20, rather you need to get the maximum 37kb of RAM, and it requires a floppy disk drive.
It’s really cool to check out, and yes it runs on VICE.
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.
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:
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.
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:
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.
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!
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.
For anyone who cares you can follow more of the porting adventure here:
If you choose to use the MIDI you’ll have to map them to a MIDI-OUT port, and I used the default Microsoft GS Wavetable. Of course you could use MUNT, or any other MIDI mapper or port. Also you may want to setup the serial port MIDI as a backup plan.
The sound effect settings work best for the PC-9801-86 audio board.
I’ll save installing MS-DOS, and installing DooM for another fun episode, but to configure DooM.
Run setup.exe to setup DooM!
The menu is simply:
2 Background Music
3 sound effects
4 not sure
The PC9821A driver works best from what I’ve done in my limited testing. I guess if you had a different emulator, or a real PC-98 you’ll get more out of this.
Next is the BGM or music
You really have 2 options here, #3 for the PC9801 driver which uses the YM2608 chip. Or the General MIDI either option 4 or 6. I didn’t notice any difference between the two of them, they both sound kinda slow, but workable.
Now for the audio board, select the PC-98
The PC-9801-86 is what you want here. Now with either a 100% PC-9801-86 config, or a 50/50 of the MIDI/PC-9801-86 we are ready to run DooM! Selection option 6 and away we go!
And all being well you’ll get the start of DooM!
Otherwise you’ll get this fun error:
In this case I had emm386.sys in my config.sys which conflicts with the dos extender DX386.
Personally I find it easier to boot off the #1 install diskette which will automatically start DooM!