Really, all the hard work was by neko68k, I just mashed enough old GCC to get something to do something.
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:
Source & binaries are here:
And my cross compiler toolchain is here:
Undefined symbol(s) in SRAND.O
Undefined symbol(s) in ECVT.O
Undefined symbol(s) in FCVT.O
I finally figured out what these are from.. The Sharp/Hudson floating point libraries. Link with FLOATEML.L, and the problem is solved.
DOH! Now to build libgcc.a without GCC ….
Yes, I probably need a better hobby.
D:\proj\142\gcc-1.42_x68000>gccnew.exe -v -c x.c
gcc version 1.30 Tool#2(X680x0)
hcpp.exe -v -undef -D__GNUC__ -Dmc68000 -Dhuman68k -DHUMAN68K -DMARIKO_CC -Dmariko_cc -D__mc68000__ -D__human68k__ -D__HUMAN68K__ -D__MARIKO_CC__ -D__mariko_cc__ x.c C:\Users\jason\AppData\Local\Temp\x.cpp
GNU CPP version 1.30 Tool#2(X680x0)
hcc1.exe C:\Users\jason\AppData\Local\Temp\x.cpp -quiet -dumpbase x.c -fhuman -version -o C:\Users\jason\AppData\Local\Temp\x.s
GNU C version 1.30 Tool#2(X680x0) (HAS Ver 3.XX syntax)
compiled by GNU C version 5.1.0.
default target switches:
x.c: 5: Message:ì┼ôKë╗é═ìséφéΩé─éóé▄é╣é±
run68 has.x -e -w -u -i . C:\Users\jason\AppData\Local\Temp\x.s -o x.o
D:\proj\142\gcc-1.42_x68000>run68 ..\hlkb\hlk301.x x.o CLIB.L
Hello x68000 from GCC 1.30 Tool#2(X680x0)!
Microsoft Windows [Version 10.0.10586]
I’ve gotten the compiler to build natively as a win32, however the assembler & linker are x68000 programs that I run via run68. libgcc.a is missing so there is no floating point support at all. I have to figure out how to generate it. Right now it’s using the SHARP/Hudson libraries on the C Compiler PRO-68K ver2.1 disks.
I don’t think this will be of value to anyone, but for the hell of it, you can download my incredibly rough port here.
Linking doesn’t work by default, so you have to manually link, as what I did above.
I guess the bad power supplies really are quite bad.
So now I have a project instead of something to do something. I guess it doesn’t matter, I don’t have a keyboard, video cable, diskettes or anything.
Sigh so much I wanted to do with this….
It’s a x68000 emulator. What made me jump was looking was the license on github:
* Copyright (c) 2003 NONAKA Kimihiro
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgment:
* This product includes software developed by NONAKA Kimihiro.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Which is the normal BSD license… But the other v0.65 source code makes no mention. Oh well, I guess it’s really not BSD licensed then? I need to keep banging on system16 anyways…
But in this case the graphics are for GTK of all things, and are hard coded to only run on 15/16bit displays. SO by removing the requirement I got it to display something. Also the IPL roms need to be in $HOME/.keropi . It plays R-Type well enough, but at the same time so does MAME.
Ok, I know… why? But it’s more of a why not!
So I figured since I’ve had major issues trying to get DOOM to run, I’d try something bigger, like NetHack. I figured its a good fit, it’s all ASCII based anyways, so how complicated can it be?
Actually it turned out to not be that complicated. Thankfully having both run68’s source and NetHack source I was able to adapt enough of the system stuff to get it running. I decided to use this build of NetHack 1.3d that has been updated to compile with modern compilers, since the cross tools use GCC 4.6.2. NetHack 1.3d synchronized PC hack, and UNIX based NetHack enough that I could start to build under MS-DOS, and then re-target it, as Human68k and MS-DOS share a lot of features (although Human68k has support for tasks, and shared memory. It’s more like OS/2 although no memory protection… ).
I’ve gotten it to the point where you can save, load and quit. Oddly enough the ANSI support in Human68k isn’t as good as ansicon so it actually runs better on run68.
So my next step will be to figure out more of the console controls on Human68k, and remove the ANSI support.
Ideally I’d love to figure out how to talk to the sound drivers on the x68000. Add some music. Maybe sound effects, and graphics?
So for anyone who cares, my source directory, binaries and a xm6 disk image is all here. I’ve seen in the cvs tree on sourceforge that run68 has some support for BSD. That’d be another interesting thing to add, common exe’s between windows/linux. But console access first!
So like all zork obsessed people (I really should get help or something), I was trying to build a z-machine interpreter for the x68000, using Lydux’s cross GCC compiler. And it was honestly looking like a LOT of work in the IO department. Thinking that the older versions were more simpler, I went looking for the oldest open Z-machine, called the “The InfoTaskForce Infocom interpreter”, released by the InfoTaskForce. Unfortunately I can only find version 4.01 searching for the source code. Which still looks too complicated. But looking the history file, the project started back in 1987. So with that to go on a new google search got me this:
From an TRS-80 dump of all things. I don’t know what version this is other than the brief copyright mention:
/* (C)opyright 1987 InfoTaskforce. */
All of the files are dated 4/12/2001 so they obviously aren’t original. And the version string is:
echo ( “Interpreter: C Version 1.0\n” ) ;
So assuming this is correct, from the 4.01 history file:
REV_E – June 25, 1987.
REV_E is the first major overhaul to the interpreter.
* The source is now significantly lint free.
* TERMCAP support has now been added [#define TERMCAP option].
* Screen paging and word wrap has been added, along with a new
command line option which disables screen paging (-p).
* Random number generator seeding using time () added [#define
* Attributes in the object list are listed as bits.
* A debuging version can now be produced as an inbuilt options
[#define DEBUG option].
* The coded requirement that 25k is always free in the system can
now be removed [#define ALLOCALL option].
* A new command line option was added to print the object/room list
as a tree (-r).
* interp.c has been re-written to improve efficiency [large
switches have been replaced with arrays of pointers to funcions].
There are now 14 machines on the porting list:
Machine C Compiler Operational Porting details
Macintosh Aztec C Version 1.06F 18/05/87
Macintosh Lightspeed C 2.01 29/05/87 Use “rb” & “wb” in all fopen()s
IBM PC/AT Microsoft C 4 30/05/87 Link with binmode.obj
DEC VAX 11/780 UNIX V7 cc 01/06/87
HP-9000 HP-UX cc 02/06/87
gould cc 03/06/87
Amiga Aztec C 04/06/87
Pyramid 9810 cc 04/06/87
Pyramid 90x cc 04/06/87
Osiris cc 05/06/87
DEC PDP-11/? UNIX V? cc 07/06/87 EXTENSIVE
mods to fix problems with signed chars.
VAX VMS cc 16/06/87 Add #define
times ttmes to fix multiply defined symbol problem. [infocom.h]
Version 1.00 – August 17, 1987.
The REV_C interpreter of June 2, 1987 was officially archived as
Version 1.00 on August 17, 1987.
So this means it’s very 16bit & 32bit friendly, especially on BIG endian machines like the 68000 processor.
Luckily this older version is pretty trivial to compile, and get running. But I was over thinking the build process and decided to strip the executable as GCC would kick out a 500kb file, which objcopy would extract a 81kb executable. Stripping it brought the size down to a 50kb executable but it wouldn’t run in either xm6 or run68. I ended up going in circles for a while trying to find fault in what is broken where until I manually compiled the interpreter, and omitted the strip step and suddenly had a working interpreter.
Now there is one issue, saving doesn’t work. Something in the libc is having issues using fopen with a file to write. Reading works perfectly fine though. So to fix it, I went ahead and redid the save feature to use the HumanOS native _open/_write/_close functions and I’m able to now save & restore a game.
D:\proj\run68\test>run68.exe infocom.X minizork.z3
MINI-ZORK I: The Great Underground Empire
Copyright (c) 1988 Infocom, Inc. All rights reserved.
ZORK is a registered trademark of Infocom, Inc.
Release 34 / Serial number 871124
West of House
You are standing in an open field west of a white house, with a boarded front
door. You could circle the house to the north or south.
There is a small mailbox here.
West of House Score: 0/0
Living Room Score: 10/19
A nasty knife
A brass lantern (providing light)
A brown sack
A glass bottle
The glass bottle contains:
A quantity of water
Living Room Score: 10/20
In this process I’ve also managed to build run68, and verified that it’s operating correctly, as both run68 and XM6 both failed to write to a file with fopen, and both work using the native calls.
I’m sure most people won’t care but I think it’s great having the ability to run a GCC generated C program in a relatively small interpreter.
If anyone cares, here is my updated cross compiler + run68 source along with tweaked Info Task Force 1.0 source. Or a disk image that XM6 can boot up, and run some demo programs from Infocom of ages ago.
I found this one by accident, but it’s more like DOSBox in that it runs 68000 executables with an emulated processor and emulated OS. No SHARP ROMs or HumanOS diskettes needed. It’s strictly text mode, but it’s enough to run executables produced by GCC.
The project is over on sourceforge, and unlike any other x68000 project this one is GPL’d. The source code is remarkably tiny so I’d say for anyone looking for a way to sneak some C into something this may be an interesting ‘door’..
So I downloaded the Windows version, set it up according to this guide, and set on trying to build a simple EXE. I did install CodeBlocks, but I ran into a problem while trying to build a running executable. For some reason objcopy doesn’t work correctly unless it is in verbose mode. I found that by accident, but much to my surprise it does work!
In the script for CodeBlocks, changing
oc_x = _T(“human68k-objcopy -O xfile $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).X”);
oc_x = _T(“human68k-objcopy -v -O xfile $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).X”);
did the trick, and now it’ll generate working executables.
I’ve found the emulator XM6 TypeG version 3.13 L21 the easiest to deal with as it has English translated menu’s and lets you mount a folder on your PC as a virtual drive. This makes loading cross compiled stuff much easier.
Since finding this stuff is getting harder and harder, and that most of the xm6 forked emulators are closed source, I thought I’d at least upload what I’ve been able to find. It’s a shame the 68030 stuff is closed off, but there isn’t anything I can do about that. Apparently there was some feud between some dev groups. I’m not really sure as it seems.
Be sure to set the shared directory under Tools -> Options to be able to map a shared directory. In the disks sub directory there is a HUMAN302 disk image which contains the needed device driver to map into the directory. You can run either the 68000 or 68030 model depending on what you like more. If you have no emulated SCSI or SASI disk, the shared directory will appear as your ‘c’ drive. And as always the keyboard will be mapped to a Japanese keyboard, so that is why the : * = keys seem in the wrong place.
On the OS X front I went ahead and built a cross compiler. I ran into this fun error building GCC on OS X:
Makefile:142: ../.././gcc/libgcc.mvars: No such file or directory
So yeah it turns out you really should configure/compile gcc in a separate directory from the source. Bad old habits die hard. Anyways my tool chain is here. I’m running 10.10 so I’m not sure about older versions of OS X.