0
Feb 17, 2006 at 15:00

Hi Guys,

My first post here so why not start of with a nice Code of the day.
This code of the day is by no means finished, but is a work in progress…
I’d love to hear feedback on this, especially from people with heavy template metaprogramming experience.

Anyway, let’s start with explaining first the goal of this code.

I have been programming games for a long time and it all started with the Amiga.
Of course, everyone who was anyone on the Amiga programmed 68000, and C coders were considered Lamers. Yes a lot has changed….

anyhow, I still have a lot of games I’d like to see ported to other platforms, like PocketPC, Windows, Symbian etc. But you guessed, porting 68000 code to C is quite a cumbersome thing to do.

The most common solution is to forget about it completely. But I really like to have all these old games with me on my PocketPC (for sentiment reasons). Another solution is to make an emulator, but this takes quite some time.
Using existing emulators is also an option but making small changes to the program is quite hard/impossible. Also I just don’t like the fact to start an emulator first.

So then I came with the next solution:

Why not convert the Asm mnemonics to matching C code?
A bit like this:

// 68000 equivalent:
// moveq #0,d0

int d0,d1,d2,d3,d4,d5,d6,d7;

d0 = 0;
d0 += d1;


etc…

Still an amazing amount of work actually to convert it like this, and even more work to get it right (making mental notes about the status register and stuff).

Some 7 iterations further I’m at my current implementation. Let me show you a bit of code which actually compiles straight in MSVC 6, but resembles 68000 a lot ;\^D

#include "68000asm.h"
#include "studie7.h"

START68000

EQU(offset,1)

DATA(tabel1)
DCW (0x1234)
DCB (0x56)
DCB (0x78)
DCL (0x87654321)
DCL (0x11335577)
ENDDATA(tabel1)

LABEL(main)
LEA   (tabel1, a0)  //tabel indexing
MOVEL (#offset, d0)
MOVEL (1(a0,d0),d1)

ADDW  (#$7000,d1) // word operations on long registers ADDW (#$7000,d1)
SUBW  (#$7000,d1) SUBW (#$7000,d1)

MOVEW (#4,d1)
BNE (skipover)   // Branches
LABEL(skipover)     // mid routine labels

JSR (subtract)  // sub routines

MOVEL (#4,d0)
JSR (stop)
MOVEL (#2,d0)
RTS

// simple example subroutine
LABEL(subtract)
SUBL (d0,d1)
RTS

// advanced subroutine where we push a new return adress on the stack. The rts will then go there instead of returning
LABEL(stop)
PEA (stop2)
RTS

LABEL(stop2)
ADDL (#4,a7)    // Popping one return address of the stack... the next rts will now actually return to the caller of main (e.g. exit the program) rather then returning.
RTS

LABEL(looptest)
MOVEL (#4,d4)
MOVEL (#0,d5)
LABEL(loop)
SUBL (#1,d4)
BNE (loop)
RTS

END68000


As you can see, stuff like advanced adressing modes is tackled, jumping/branching and subroutines work, labels can be interspersed throughout the code, data definitions work, and stack manipulation (altering return adresses) works.

I’m still not happy though how it’s set up. The underlying code actively parses the adressing modes at runtime which would be much better if it could be done at compile time.
This is why I hoped some of you template boys could point me to how the compiler can better actively parse the mnemonics.

the whole poject can be downloaded from my site:

http://www.klaar.com/codeoftheday.rar

Reinier v Vliet

#### 10 Replies

0
101 Feb 18, 2006 at 04:22

This could prove to be useful in conjunction with the Mattathias Basic project since all of the old Amos Basic extensions will have been written in 68000 Assembly. Of course we’ll still have to emulate bitplanes and the like but this may be helpful for porting lots of old Amiga source codes to the newer PowerPC-based Amigas.

0
101 Feb 18, 2006 at 16:42

Interesting idea.. Guess this is pretty much the same work you have to do as a programmer as when you write an emulator the standard way, but with meta-programming like this you give the compiler a chance to optimize the code across emulated instructions – you’d never get this with regular emulator design. Did you take a look at the (intel) code the compiler generated for the above example? Would be interesting to see if you got some optimized stuff.

Edit: Ahh guess you check some stuff at runtime.. I read your whole post now ;-) But if you improve the adressing mode issue you’d probably get very optimized code.

0
101 Feb 18, 2006 at 17:27

samuraicrow: the need to emulate bitplanes, coppers etc will still be there, but the most part of the logic and stuff would have been tackled. And what is easy is that you can just put a bit of C code in between to do some of your own stuff and then continue with the legacy 68000 code :lol:

z80: Yes, the parsing of the operands is the thing which bugs me the most. It would be really nice if somehow with fancy template stuff we could get rid of that whole part and the compiler would do that work. Any pointers from anyone would be appreciated :happy:

0
101 Mar 04, 2006 at 14:37

There’s this thing on the new macs..don’t remember the name..it start’s with an “R”..Rosetta or so…whate ever..basically it converts powerpc opcodes/apps into x86 opcodes/apps. It should be a lot more performant than an emulation in most cases. It’d be great to have something the like for 68000 or the snes…
Having to rewrite all the asm using macros/templates seams a bit ..over the top..

0
101 Mar 07, 2006 at 18:31

Alex: Rosetta is correct, see http://www.apple.com/rosetta/

0
101 Mar 09, 2006 at 11:08

What about detecting things like arithmetic overflow/carry? How does that work?

0
101 Mar 23, 2006 at 08:53

dave: in the code example I gave above, I detect overflows and carry manually and set the corresponding processor flags. Of course this is again a task which is mundane and would be perfect if the compiler throws all the flag set code out if the flags are in fact not checked.

0
101 Aug 21, 2008 at 16:04

That was an interesting way of handling 68000 legacy code, I had to write a 68000 to C converter for Sonic 3D (from the Genesis to the Saturn & PC). I didn’t want to have to maintain all the carry flags, zero flags, negative flags etc as that would ruin performance, so I wrote a converter that kept track of each flag (lea doesn’t affect flags for example so it knew that the last instruction that did set the flags might still be needed). I used unions to handle registers, so you had union (byte b; short w; int l;} and could you could use d0.w. It also handled addq #4,sp (popping return address) by marking the routine as can pop, and then when called it would be if (func()) return;

I’ve done something similar for the company I am working for (Javaground), it converts Java bytecode into C++. This allows me to handle differences in the way Java and Brew work. One early program we tested was faster after being converted from Java than another companies manual conversion of the Java code to Brew (there was about 10% code size overhead though, due to reference counting garbage collection to emulate Java).

Neil Harding

0
101 Jul 09, 2009 at 15:32

Hi all

Do not want to make a new topic becouse it the same about i want to ask. So, i just trying to port some assembler routines to the C, and a bit stuck with that. The lines of asm code not so big (400-500), but rewriting everythink by the hands anyway looks hard.

As i can see in this thread someone already to do some automatic convertor from assembler to C for the 68k cpus, so maybe it possible to found somethere ? (the link from 2006 years are not works anymore :) ). Or maybe any other freeware toolz are present ?

0
101 Aug 14, 2009 at 00:42

Hi all,
I know this is an old post, but I have just joined AND found this info and I am also interested in how it works :)

Does anyone have the code (from original post)

http://www.klaar.com/codeoftheday.rar

as it isn’t available any more?

cheers,
Paul