6

A long time ago, I've made some games for the Commodore Amiga. All done in 68000 assembly (So I still have the sources)

I want to port these games to modern platforms, and instead of hosting an emulator, I thought of converting the Assembly to C, and adding an SDL layer.

Any thoughts on how to tackle the 68000 -> C conversion part? (Not manually but automatically. As in a transpiler)

I was thinking of just creating a bunch of variables with similar names as the registers and then converting things like this:

 MOVE.l #23, d7

into

 MOVEL(23, d7);

The only thing I'm not sure how it would work is branches and subroutines. I think I could get it working with a very big switch statement, and having any label I could potentially jump to being a case statement.

Any thoughts? Any prior art I could draw inspiration from?

Toad
  • 15,593
  • 16
  • 82
  • 128
  • The code is way too big to do it manually. No just have it automatically converted would be fine. I don't mind if it becomes crappy C. As long as it becomes portable – Toad Jul 17 '18 at 05:49
  • Why don't you just write an emulator? – user202729 Jul 17 '18 at 05:51
  • 1
    Regarding subroutines; can't you create C functions for anything that's referenced by a `BSR`/`JSR` and translate the jumps into C function calls? For other types of branches it seems to me like `goto` would be easier to work with than switch-cases. – Michael Jul 17 '18 at 06:01
  • Then I need to find a binary somewhere. Find some 68000 emulator. Inherit all that code and have a huge dependency. And of course... It's less of a challenge ;^) – Toad Jul 17 '18 at 06:02
  • @michael tricky part is of course that goto's only jump in the current scope. The branches might actually jump over a function, or who knows, right into one (I hope I didn't do that back then). With my idea of having a huge switch statement I could even 'emulate' the stackpointer(a7), and implement RTS by popping the last switch value and going through the switch statement again. – Toad Jul 17 '18 at 06:05
  • I'd go with a 68000 emulator (google that). – Jabberwocky Jul 17 '18 at 06:14
  • 2
    there are open source 68k core emulators, but they may be only under GPL-like license (so it depends what's your plan with the final product)... if your code was not some black magic trickery, it may be easier to emulate the core, and put SDL layer on top of that, displaying memory state from emulator... i.e. you would create amiga emulator in the end.. hmmm... Anyway, generally disassembly asm into C usually turns to crap, especially if the assembly was optimized, but you may google if there is some 68k "decompiler" and see what the output would look, maybe would need only "weeks" of work.. – Ped7g Jul 17 '18 at 06:22
  • If you search for 68000 decompiler, you might find something that will help. – prl Jul 17 '18 at 06:29
  • 1
    I'm sure *most* of your jumps other than BSR/JSR are within functions so `goto` + C labels should be totally fine. A few manual fixes total for the whole program might be required for the occasional jump into another function, but that's fine, you're already planning to spend some time porting the graphics output. The decompiler you cobble together does *not* need to be 100% automatic, as long as problems turn into won't-compile errors in C, rather than subtle gotchas. Labels within functions and `if() goto` will make your C look very much like asm, unlike a giant `switch`. – Peter Cordes Jul 17 '18 at 06:31
  • Obviously the hard part of making actual separate C functions for each asm function is detecting which registers or memory locations hold args, and which are just stale. (And call-preserved vs. clobbered). If you used custom calling conventions on a per-function basis when it was convenient, this will be harder to decompile. – Peter Cordes Jul 17 '18 at 06:36
  • 2
    @PeterCordes I'd just make 20 or so global variables called a0-a7 and d0-d7, sr, etc and just do method calls without any arguments. The subroutine would then just continue with the global 'register' variables. It's true-er to the source. – Toad Jul 17 '18 at 07:03
  • @Toad That's not really a reason. If you choose to do so, it's because you decide not to write the emulator from scratch. – user202729 Jul 17 '18 at 07:13
  • After all, compilers (without optimizations) are basically interpreters specialized for the particular input. – user202729 Jul 17 '18 at 07:15
  • 2
    Your requirement is not far from writing a compiler: you have an input language (68k assembly), and you want programs written using that language to be executed on various plaforms. Assembly languages have normally a not too complex syntax, you could try to use the good old lex+yacc to parse it. After all, yacc name means Yet Another Compiler Compiler... But IMHO, it will be harder than directly using an emulator... – Serge Ballesta Jul 17 '18 at 07:41
  • 1
    I think it boils down to the using/writing emulator, because what your original proposal is, is exactly that, emulating 68k core. But then you need to emulate lot more, as that code was originally running inside Amiga computer, so you must emulate also memory and the peripherals chips like blitter/copper/disk-system/etc.. (depending what your games did use), and for any top quality Amiga game you would very soon end with complete Amiga emulator, probably even being picky about timing of the emulation... so maybe you should first check if there's something already done which can be reused? – Ped7g Jul 17 '18 at 09:25
  • Yeah global vars for registers should work, nice idea! You can manually clean up a few important function (important for performance or readability), or ones used in the code you're modifying anyway. Link-time / whole-program optimization by modern compilers might be able to do a decent job optimizing away useless spill/reload of the globals around every function call, and at the end of every function when compiling nasty source that assigns them. For regs you never use for arg passing / return, you could have your decompiler use local vars. – Peter Cordes Jul 17 '18 at 12:47
  • Hopefully you can map stack-allocated locals in your asm source to local vars with automatic storage in the C output. You'd really like `sp` to *not* be part of the C program's state, with all stack ops turned into local variable allocation, or alloca or C99 VLAs for variable-size subtractions. But C can't directly express the pattern of pushing items on the stack one at a time, then popping them off in reverse order. (i.e. using the call-stack as a stack data structure, which is easy in asm.) – Peter Cordes Jul 17 '18 at 12:50
  • At worst you can model a stack frame (within each function separately) as a char array that you memcpy to/from if you have unaligned or overlapping accesses. This assumes your asm is not totally evil and doesn't do stuff like modifying the parent stack frame directly, relative to SP without having the caller passed a pointer. – Peter Cordes Jul 17 '18 at 12:53
  • Here is a crazy idea. Make every opcode a function that modifies global variables. and uses continuation-passing-style. That makes it possible to implement BSR/JSR and RET in C. – Goswin von Brederlow Jul 17 '18 at 13:52
  • Seriously this comment thread shows why this stack needs to start enforcing the policy about answers in comments. No, your half-answer is not a comment. Either write it when it's done, or find a _discussion forum_. – pipe Jul 17 '18 at 20:45
  • How many lines of code are we talking about? – fuz Jul 17 '18 at 22:28
  • @pipe Generally, such cases indicates that something is wrong with the **question**. Indeed it is. To fix that is also quite easy -- post a (CW if you want) answer. – user202729 Jul 20 '18 at 16:17
  • @user202729 We already know something is wrong with the question - it's even put on hold. Still there's a lot of "helpful" people who just _can't_ stop themselves from filling up the comment section with their opinions. Some of them with an surprisingly high reputation, showing they should have been here long enough to know the policy. – pipe Jul 21 '18 at 13:52
  • I did something similar for a decompression code: http://jotd.pagesperso-orange.fr/misc/fimp_c.zip. Source code included (except for the awk conversion script) – Jean-François Fabre Aug 07 '18 at 21:04
  • I did something similar (SDL) but not the same processor (6502) to make old games that I didn't even write run: http://jotd.pagesperso-orange.fr/oric_remakes.html. Full source code of everything here. – Jean-François Fabre Aug 07 '18 at 21:05
  • Great! This is exactly how I envisioned it. Great that the original basic lines are in the comments so you can actually follow quite nicely even though the C is at times cryptic. – Toad Aug 09 '18 at 04:58

0 Answers0