Hello!
Little bit of introduction...At first I should admit, that I'm not a Pascal expert of any kind. I fiddled around with TP7 when I was 8-10, only had access to very "academic" books about it and - at that age - considered it boring and moved forward.
Now, two decades later, I'm rediscovering FreePascal and I feel it's underrated and overlooked a little too much, considering it's clarity and features compared to C or C++, on the same level of native code generation.
However, there's someone who succeeded in Pascal a little more, and this is the major reason of this post.
Mike Wiering made a homebrew game called
Mario & Luigi in 1994 and published it officially in 2001
with complete source code.
UPDATE: I made a GitHub repo with the
unmodified source code unpacked for easy access. Additionally, there's a very simple build script there and files got put into separate subdirs for sources and sprite data.
Many of you (especially in Europe) probably played it, even before 2001. There was a leaked beta version which was spreading around on a floppies, but the game wasn't complete and you couldn't get past on some level. I also played that version back in the game, and the "official" 2001 release too.
The game runs in 16-bit real-mode under MS-DOS, the binary is ~57KB UPX'd and ~170KB uncompressed. It also ran properly on 9x/Me and NTVDM under 2000/XP. It stopped working for me on machines past Pentium 4 era even under the same NTVDM, still unsure if it was about the CPU or later GPUs not handling direct VGA access properly.
...but straight to the point...After my latest encounter of FreePascal (I was looking for non-C environments which were able to generate native code on m68k/Amiga) the game got back on my mind and I recalled the website has original source code archives.
So I've got an idea:
Could I try building the game with latest FPC version, then port it on other platforms?And then, the whole journey started... It's not as flashy as it could be, and most likely I won't be able to progress forward without your help. But I'd like to post my present experiences.
What I did and where I am?Okay, so I grabbed the "stable" native FPC 3.2 and built the i8086/msdos target from source. It was easier than expected, the internal build system isn't that well documented and a little messy, but still works better than bootstrapping cross GCC, for example.
Initially, I thought that binary isn't packed in any way so assumed I should target -WmTiny memory model, and straight crashed to the issues with "NearPointer" vs "FarPointer". Took me a bit to realize that TP7 defaulted to what FPC calls "-WmLarge" memory model.
However, the FPC 3.2 failed to build it even then.
One of the initial set of issues resulted from sources having ASCII >127 characters present as options in
case statements, as well as other expressions. It's related to level data stored in raw format and using these characters for blocks, enemies, etc. Setting codepage directives to CP437 did not change anything, sadly.
I made a simple Python script to replace all occurrences of extra ASCII chars with direct
#nnn statemens. It made the related errors go away, but then the final boss arrived:
ENEMIES.PAS(354,3) Fatal: Internal error 200309041
Fatal: Compilation aborted
The procedure
StopEnemies looked quite normal and didn't show any suspicious behavior. I tried commenting it out and other lines calling it, but the problem persisted.
Someone told me to use latest 3.3.1-trunk compiler from snapshots instead. It changed mostly everything and made the application compile without any changes in source code.So I started pulling these from snapshots (cross-ompilers for x86_64/linux, there are also win32 ones):
https://downloads.freepascal.org/fpc/snapshot/trunk/i8086-msdos/I am using the following command to build it:
$FPC_LARGE/bin/x86_64-linux/ppcross8086 \
-XX \
-Tmsdos \
-Mtp \
-WmLarge \
-Fu'$FPC_LARGE/units/i8086-msdos/*' \
-Fu'$FPC_LARGE/units/msdos/*' \
MARIO.PAS
It compiles nicely to ~190KB executable and ~70KB UPX'd. Great success.
However,
it doesn't run.
Trying in DOSBox-X, it just shows blinking cursor, and the DOSBox throws this on standard output in a loop:
ERROR CPU:Illegal Unhandled Interrupt Called 6
Sometimes, when I flip the various build flags (like
-Xs,
-O-,
-Cp8086, etc.)
or just move the order of these flags around it also throws the
Invalid opcode XXXX in a loop (interleaved with the previous error). Changing randomly every time I rebuild the code with different params.
Same happens on QEMU with FreeDOS 1.4 (boot floppy). But this time the FreeDOS just stops the application and prints "Invalid Opcode NNNN NNNN NNNN NNNN..." every time.
NOTE: The original binary from official website runs just fine without any issues on both of these platforms.
The README.TXT suggests that the application should work on at least 80486, so I tried
-Cp80486 with no effect. What was I thinking, since TP7 doesn't perform such optimizations, I don't know

The game also uses FPU due to some divisions and
Round()] calls here and there. Currently, i8086 target does not allow for soft-floats so I made sure that both DOSBox and QEMU had FPUs enabled and tested them, still no changes.
Someone even suggested
LOADFIX -a MARIO.EXE which should fix memory access for 16-bit realmode code, even in DOSBox. Guess what, nothing changed

I found that the game does
InitKeyboard on very beginning which is registering a custom keyboard interrupt handles. Makes sense, but the
GetKey procedure is hardcoded assembly. Actually,
the whole game has lots of hardcoded x86 asm in random places. Initially I thought there's some bug in how FPC handles such procedures or references in these, so commented it out. At least the game should run without keyboard, right? Not really, nothing changed.
The DOSBox-X has internal debugger, grandfathered from upstream DOSBox. However, it's atrocious and lacking many features. For example, you can't step through the code with commands, you need to use F<x> keys only (and these conflict with my terminal emulator and system hotkeys). You can't also load symbols or show backtrace stack respectively, like GDB.
Speaking of GDB, I tried to plug
i386-elf-gdb to QEMU which supports it. But GDB generally doesn't work really well with real mode and segmented memory, mostly showing trash or unreliable data.
Sadly, I'm kinda out of options in regards to how to debug this properly. I see there's a big issue with debugging real-mode DOS stuff in general. The most respectable 86box/PCem emulators don't seem to provide any means of debugging, too.
I also tried various ways of commenting or flipping around some code blocks to make it at least go "somewhere", but unfortunately I can't really find any way to progress forward, as I'm definitely not an expert in low-level PC/DOS architecture. Mostly an Amiga guy in general, which is definitely simpler in basic stuff like this, plus has linear memory addressing without segmentation or XMS/EMS/UMB/whatever
The PlanThe ultimate objective is to make this game running on modern (and maybe some legacy) platforms without changing the gameplay and make it a faithful port. Similar to how
Apotris has been done (but it's in C++).
But the current plan is:
- Make the current dump of original TP7.x sources compile under FPC-trunk (i8086/msdos) with only necessary changes to execute the game properly: We are here.
- Refactor the code a little and abstract out hardware access to separate unit, still making it work on DOS all the time forward.
- Drop -Mtp and fix issues resulting from that.
- Try adding at least one simple target which allows to open a framebuffer in indexed color mode (Lazarus canvas? BGRABitmap? SDL2? Any suggestions?)
- Write down the current experiences, refine the project and decide if we should go forward with FPC or move to any other environment
- If decided with Pascal, move to Modern Pascal / ObjFPC completely
- Add proper desktop (Windows, MacOS, Linux) support
- If the code is reliable and abstracted enough, add all platforms supported by FPC which are capable of running this game in separate platform units (Amiga, GBA, NDS, PSX, WebAssembly, etc...)
- Finally start adding improvements over the original feature set: save/restore (currently it just stores the last level and restarts from there), custom levels (maybe with editor), speedrun timer, and so on
- Refine and optimize with gained experience from previous steps
My questions- How to progress forward with making current source code build properly? I am aware that FPC might not be able to replicate all of the TP7 quirks and some changes should be made, but I can't really find anything that should be patched here for now.
- Do you know any reliable ways to debug real-mode code under DOS, which are not a Turbo Debugger?

Sorry to be a little too broad and lacking specifics in some places, but as I said at the beginning, I am not a Pascal expert and probably might be overlooking something very obvious. Additionally, if I succeed with the initial issues I'd plan to keep this thread updated in the future with more information as I go forward.
Thank you in advance for any bits of information and suggestions.