For my own knowledge I’m trying to port the original Pac Man arcade game to run on my old Color Computer 3. This will probably be a more general description of the Z80 to 6809 conversion, so it should be useful to others if they want to do the same thing for other old games. This could also be used to convert the TRS-80 Model 1 which also has a Z80 processor to work on a CoCo 3. I don’t know how far I’m going to get with future blogs, but I might as well start somewhere…
So far what I have done is found all the information I could for the hardware I’m trying to convert. This means finding disassemblies of the ROM code on the internet. If you’re lucky you’ll find some awesome commented disassembly code like the ones on the Computer Archeology website. With Pac Man I wasn’t so lucky, but I did find some disassembly code that has some comments on them. I found that Namco has also had some take downs of some disassembly posts. 😦 So what I ended up with was a couple of disassemblies, one with some comments and one that has the actual bytes in the disassembly.
For example code 1 with some comments:
0272 CoinDebounce: 0272 LD A,(InterruptEnable) 0275 LD B,A 0276 RLC B 0278 LD A,(CoinState) ; Coin state shifted left 1 027B RLA 027C AND 0Fh 027E LD (CoinState),A ; Coin state shifted left 1 0281 SUB 0Ch
For example code 2 with data bytes:
0272 3A0050 LD A,(#5000) 0275 47 LD B,A 0276 CB00 RLC B 0278 3A664E LD A,(#4E66) 027B 17 RLA 027C E60F AND #0F 027E 32664E LD (#4E66),A 0281 D60C SUB #0C
Out of the above it would be best to combine the two disassemblies to use to transcode, since having the actual bytes can sometimes help to figure out how the code works. So first I wrote up a program to merge the two files which gives me this.
CoinDebounce: 0272: 3A 00 50 LD A,(InterruptEnable) 0275: 47 LD B,A 0276: CB 00 RLC B 0278: 3A 66 4E LD A,(CoinState) ; Coin state shifted left 1 027B: 17 RLA 027C: E6 0F AND 0Fh 027E: 32 66 4E LD (CoinState),A ; Coin state shifted left 1 0281: D6 0C SUB 0Ch
From here I use another program that will transcode the Z80 codes to the 6809 equivalent code (or at least a close version). For this I wrote another program that basically looks up the Z80 instruction and inserts the 6809 instruction in it’s place and keeps the Z80 code as comments beside the 6809 code. This will look like this:
CoinDebounce: LDA InterruptEnable ;0272 3A 00 50 LD A,(InterruptEn TFR A,B ;0275 47 LD B,A ROLB * ROL is 9bit check code ;0276 CB 00 RLC B LDA CoinState ;0278 3A 66 4E LD A,(CoinState) Coin state shifted left 1 ROLA ;027B 17 RLA ANDA #$0F ;027C E6 0F AND 0Fh STA CoinState ;027E 32 66 4E LD (CoinState),A Coin state shifted left 1 SUBA #$0C ;0281 D6 0C SUB 0Ch
With the code side by side it will be easier to see if things don’t look right and compare the 6809 with Z80 code.
There are still some bugs in my translating program and it needs to be hand tweaked quite a bit depending on the Z80 source code.
Once I get the code all transcoded to a 6809 version I will then split the Z80 source code into two parts one is the Z80 data section, and the other with just the Z80 instructions. The reason to split them is so that I can make sure to have the data in the exact same RAM/ROM locations that the original Pac Man hardware would look for it. So I’ll take all the sections of the source code that has DB, DW & DL statements and turn these sections into FCB statements in a 6809 compatible version at the proper points in memory. Another thing to deal with here is that Z80 disassemblers swap the bytes around when you have DW & DL instructions.
For example :
03D0: DW 05E5h
will be stored in memory at 03D0 as E5 and memory address 03D1 will be 05 (backwards to what you would think looking at the code).
With the 6809 you would convert this as:
03D0: FCB $E5,$05 or 03D0: FDB $E505
It is the same with the DL instruction but it’s the entire 4 bytes that need to be swapped, so the following Z80 instruction needs to converted from:
33BB: DL B5AD5AD6h
To this in the 6809 assembly version:
33BB: FCB $D6,$5A,$AD,$B5
We want to make sure all the data that the 6809 converted code will read is in the same location and read the same way the original Z80 program did. So once the data sections have been pulled out into a separate file and ORG statements put in place so that the data gets assembled into the correct location we can then work on the actual Z80 translated code. This is what I did (mostly) when I was doing this type of translation from the Intel 8080 to 6809 conversion for Space Invaders.
A little more information about the big endian and little endian differences between 6809 vs the Z80. Of course the 6809 is the processor that I first learned to program assembly language on and all the number orders made sense to me and still do today. As far as I’m concerned when you load a register from a word in memory it should always be MSB & LSB just as when you are counting bits. A byte is made up of bits 7,6,5,4,3,2,1,0 and two bytes (one word) is bits 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 or MSB,LSB and this is exactly how these values are stored and loaded on the 6809 CPU it all makes sense and you never have to think twice about it. But Intel messed it all up and this is going to make the life of a transcoder a pain in the ass. Intel CPUs and the Zilog Z80 store one byte as bit 7,6,5,4,3,2,1,0 which is perfect. But when you are storing a word in memory it get’s stored as bits 7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8 or LSB,MSB. When the Z80 loads the 16 bit word into a register it’s value is correctly ordered as MSB,LSB so you can deal with the values as normal 16 bit numbers. I’m not sure at this time what I should do about this type of data. For the most part on my Space Invaders transcode I loaded the data with the LDD command and did an EXG A,B then TFR D,X to use in the X register. This way I didn’t have to think about what the program was doing just let the computer swap the bytes and carry on. Now the 8080 was and older CPU and the 6809 code do this switch and it didn’t seem to effect the speed. But with Pac Man and a Z80 CPU I might need to figure out what data locations will be accessed as words and swap the original data in those locations. This will speed up the program but it will mean a lot more decoding on my part. I still don’t know what I’m going to do.
I’ll have to look closer at the code and see if there are any ambiguous sections of code. If I see a bunch of LDX $2000 bytes then that will be simple enough to swap out in the original data.
See you in the next post…