Porting Meteor Mission II to Microbee

Part 1 - A Decent Disassembly

The first step in any porting project is to get a good listing of the program to work on. Since this is a reverse engineering exercise this involves acquiring a copy of the original program and disassemling it.

These are the tools I used. I'm doing this under Windows, not sure if all these or equivalent tools are availeble under other OSes.

  • trsread - reads TRS80 disk images
  • z80disasm - disassembler for TRS80 .CMD file
  • readcmd - dumps records from TRS80 .CMD files
  • YAZD - My Z80 disassembler
  • binhex - Tool to convert binary to hex and vice versa
  • bin2tap - Tool to generate Microbee .tap files from a .bin file
  • z80asm and Original Here - An open source Z80 cross-assembler
  • Cygwin - for make and gawk
  • Sublime Text - awesome text editor

Getting a Copy of the Original Program

So first of all I needed a copy of the program which I found on a TRS80 disk image here:

Next I created a directory for all the working files placed a copy the dsk image there. TRS80 disk based programs are stored as .CMD files, so I needed to extract that from the downloaded disk image. The easiest way to do that is with trsread. First I listed the disk's directory:

Z:\retro\meteor>trsread -v favourites1_80sssd_jv1.DSK
ATTACKFC/CMD    13,824
GAMMON/BAS       8,448
HISCORES/ATK       256
METEOR/CMD      12,057
PENETRAT/CMD    20,836
SCARFMAN/CMD     7,296
SEADRAG/CMD     14,720
STRTREK2/BAS    13,696
SWAMP/CMD        5,376
TAIPAN/BAS      13,440
    Free: 84,480 bytes

And then extracted it:

Z:\retro\meteor>trsread -e favourites1_80sssd_jv1.DSK meteor.cmd

Extracting the Raw Program from the CMD file

CMD files are not a raw binary image of the program - they have an internal format that splits the image up into pages defined by a set of records. I needed a way to extract the raw content of the image. There's probably a few ways to do this, but the easiest way I've found is with z80disasm which understands the CMD file format.

Z:\retro\meteor>z80disasm meteor.cmd > meteor.disasm

The other thing I needed was the entry point (ie: where it starts executing) which I found with readcmd:

Z:\retro\meteor>readcmd meteor.cmd

which reports the entry point as:

Reading 02 block length = 2.
Entry point is 36366 8e0e

8e0e is the hex address of the program's entry point. (I've since realized this is also available in the last line of meteor.disasm)

I now had a disassemabled listing of the program and knew the entry point. Unfortunately z80disasm isn't that great of a disassembler. YAZD does a much better job of creating cross references and following code paths to isolate code from data. Unforunately YAZD doesn't understand CMD files, so I needed to jump through a few hoops - namely extracting the hex column of the disasseambly, converting that back to a raw binary file and the re-disassemling with YAZD:

Here's what part of the disassbly from z80disasm looked like:

              00392 M5FEE  EQU	5FEEH          
              00393 M5FF5  EQU	5FF5H          
              00394 M5FFB  EQU	5FFBH          
              00395        ORG	6000H          
6000 F3       00396        DI                 s
6001 AF       00397        XOR  A             /
6002 D3FF     00398        OUT  0FFH,A        S.
6004 3E38     00399        LD   A,'8'         >8
6006 D3EC     00400        OUT  0ECH,A        Sl
6008 310080   00401        LD   SP,M8000      1..
600B AF       00402        XOR  A             /
600C 32F74C   00403        LD   (M4CF7),A     2wL
600F CD7C4B   00404        CALL M4B7C         M.K

What I needed was the second column of hex digits - the raw binary code of the program. I used a text editor to trim everything from the top/bottom of the file then ran it through gawk:

Z:\retro\meteor2>gawk '{print substr($0,6,8)}' meteor.disasm > meteor.hex

Then converted it back to a raw binary

Z:\retro\meteor2>binhex meteor.hex meteor.bin

Disassembly with YAZD

Finally we can run the raw binary through YAZD:

Z:\retro\meteor2>yazd meteor.bin --addr:0x6000 --entry:0x8e0e --xref --lst --mwr > meteor.yazd.disasm

To explain these options:

  • meteor.bin - the file we want to disassamble in raw binary form
  • --addr:0x6000 - the file is intended to be loaded at 0x6000 so YAZD needs to know this
  • --entry:0x8e0e - the entry point to the program. YAZD will follow all code paths from here to isolate code from data.
  • --xref - create cross references (useful for working things out)
  • --lst - create full listing including original raw binary data
  • --mwr - mark word references (handy for locating literal values that might be addresses and may need to be manually fixed up later)

At this point I should have had a complete, cross-referenced disassembly of the program but looking at the file showed almost all of it as raw data DB bytes. After a little investigation I noticed a tiny bit of code at the end of the file that was relocating the whole thing to a different memory address and jumping to a new entry point. I suspect this was the result of the TRS80 LMOFFSET program that's used to relocate cassette programs to make them work under LDOS. (There was other code in this stub at the end, but I'm assuming it's all related to relocating the program and I decided to ignore it for now)

                                        ; --- START PROC L8E00 ---
8E00: 21 00 60                   L8E00: LD      HL,6000h        ; address or value?
8E03: 11 00 45                          LD      DE,4500h        ; address or value?
8E06: 01 00 2E                          LD      BC,2E00h        ; address or value?
8E09: ED B0                             LDIR
8E0B: C3 00 45                          JP      4500h

Given that 0x6000h was getting shoved down to 0x4500, I just re-disassembled with the new memory location. Note the new entry point too - to match the jump above.

Z:\retro\meteor2>yazd meteor.bin --addr:0x4500 --entry:0x4500 --xref --lst --mwr > meteor.yazd.disasm

Finally, a decent disassembly and now the real work can begin.

Porting Meteor Mission II to Microbee continues with Part 2 - Basics and First Run.