Disassembly DIY

The following sections describe how to use SkoolKit to get started on your own Spectrum game disassembly.

Getting started

The first thing to do is select a Spectrum game to disassemble. For the purpose of this discussion, we’ll use Hungry Horace. To build a pristine snapshot of the game, run the following command in the directory where SkoolKit was unpacked:

$ tap2sna.py @examples/hungry_horace.t2s

(If that doesn’t work, or you prefer to make your own snapshot, just grab a copy of the game, load it in an emulator, and save a Z80 snapshot named hungry_horace.z80.)

The next thing to do is create a skool file from this snapshot. Run the following command from the SkoolKit directory:

$ sna2skool.py hungry_horace.z80 > hungry_horace.skool

Note that the ‘.skool’ file name suffix is merely a convention, not a requirement. In general, any suffix besides ‘.ref’ (which is used by skool2html.py to identify ref files) will do. If you are fond of the traditional three-letter suffix, then perhaps ‘.sks’ (for ‘SkoolKit source’) or ‘.kit’ would be more to your liking. However, for the purpose of this particular tutorial, it would be best to stick with ‘.skool’.

Now take a look at hungry_horace.skool. As you can see, by default, sna2skool.py disassembles everything from 16384 to 65535, treating it all as code. Needless to say, this is not particularly useful - unless you have no idea where the code and data blocks are yet, and want to use this disassembly to find out.

Once you have figured out where the code and data blocks are, it would be handy if you could supply sna2skool.py with this information, so that it can disassemble the blocks accordingly. That is where the control file comes in.

The control file

In its most basic form, a control file contains a list of start addresses of code and data blocks. Each address is marked with a ‘control directive’, which is a single letter that indicates what the block contains: c for a code block, or b for a data block (for example). A control file may contain annotations too, which will be interpreted as routine titles, descriptions, instruction-level comments or whatever else depending on the control directive they accompany.

A control file for Hungry Horace might start like this:

b 16384 Loading screen
i 23296
c 24576 The game has just loaded
c 25167
...

This control file declares that there is:

  • a data block at 16384 titled ‘Loading screen’
  • a block at 23296 that should be ignored
  • a code block (routine) at 24576 titled ‘The game has just loaded’
  • another code block at 25167

For more information on control file directives and their syntax, see Control files.

A skeleton disassembly

So if we had a control file for Hungry Horace, we could produce a much more useful skool file. As it happens, SkoolKit includes one: hungry_horace.ctl. You can use it with sna2skool.py thus:

$ sna2skool.py -c examples/hungry_horace.ctl hungry_horace.z80 > hungry_horace.skool

This time, hungry_horace.skool is split up into meaningful blocks, with code as code, data as data (DEFBs), and text as text (DEFMs). Much nicer.

By default, sna2skool.py produces a disassembly with addresses and instruction operands in decimal notation. If you prefer to work in hexadecimal, however, use the -H option:

$ sna2skool.py -H -c examples/hungry_horace.ctl hungry_horace.z80 > hungry_horace.skool

The next step is to create an HTML disassembly from this skool file:

$ skool2html.py hungry_horace.skool

Now open hungry_horace/index.html in a web browser. There’s not much there, but it’s a base from which you can start adding explanatory comments.

In order to replace ‘hungry_horace’ in the page titles and headers with something more appropriate, or add a game logo image, or otherwise customise the disassembly, we need to create a ref file. Again, as it happens, SkoolKit includes an example ref file for Hungry Horace: hungry_horace.ref. To use it with the skool file we’ve just created:

$ skool2html.py examples/hungry_horace.ref

Now the disassembly will sport a game logo image.

See Ref files for more information on how to use a ref file to configure and customise a disassembly.

Generating a control file

If you are planning to create a disassembly of some game other than Hungry Horace, you will need to create your own control file. To get started, you can use the -g option with sna2skool.py to perform a rudimentary static code analysis of the snapshot file and generate a corresponding control file:

$ sna2skool.py -g game.ctl game.z80 > game.skool

This will do a reasonable job of splitting the snapshot into blocks, but won’t be 100% accurate (except by accident); you will need to examine the resultant skool file (game.skool in this case) to see which blocks have been incorrectly marked as text, data or code, and then edit the generated control file (game.ctl) accordingly.

To generate a better control file, you could use a code execution map produced by an emulator to tell sna2skool.py where at least some of the code is in the snapshot. sna2skool.py will read a map (otherwise known as a profile or trace) produced by Fuse, SpecEmu, Spud, Zero or Z80 when specified by the -M option:

$ sna2skool.py -M game.map -g game.ctl game.z80 > game.skool

Needless to say, in general, the better the map, the more accurate the resulting control file will be. To create a good map file, you should ideally play the game from start to finish in the emulator, in an attempt to exercise as much code as possible. If that sounds like too much work, and your emulator supports playing back RZX files, you could grab a recording of your chosen game from the RZX Archive, and set the emulator’s profiler or tracer going while the recording plays back.

By default, sna2skool.py generates a control file and a skool file with addresses and instruction operands in decimal notation. If you prefer to work in hexadecimal, however, use the -h option to produce a hexadecimal control file, and the -H option to produce a hexadecimal skool file:

$ sna2skool.py -h -H -g game.ctl game.z80 > game.skool

Developing the skool file

When you’re happy that your control file does a decent job of distinguishing the code blocks from the data blocks in your memory snapshot, it’s time to start work on the skool file.

Figuring out what the code blocks do and what the data blocks contain can be a time-consuming job. It’s probably not a good idea to go through each block one by one, in order, and move to the next only when it’s fully documented - unless you’re looking for a nervous breakdown. Instead it’s better to approach the job like this:

  1. Skim the code blocks for any code whose purpose is familiar or obvious, such as drawing something on the screen, or producing a sound effect.
  2. Document that code (and any related data) as far as possible.
  3. Find another code block that calls the code block just documented, and figure out when, why and how it uses it.
  4. Document that code (and any related data) as far as possible.
  5. If there’s anything left to document, return to step 3.
  6. Done!

It also goes without saying that figuring out what a piece of code or data might be used for is easier if you’ve played the game to death already.

Annotating the code and data in a skool file is done by adding comments just as you would in a regular ASM file. For example, you might add a comment to the instruction at 26429 in hungry_horace.skool thus:

 26429 DEC A         ; Decrement the number of lives

See the skool file format reference for a full description of the kinds of annotations that are supported in skool files. Note also that SkoolKit supports many skool macros that can be used in comments and will be converted into hyperlinks and images (for example) in the HTML version of the disassembly.

As you become more familiar with the layout of the code and data blocks in the disassembly, you may find that some blocks need to be split up, joined, or otherwise reorganised. You could do this manually in the skool file itself, or you could regenerate the skool file from a new control file. To ensure that you don’t lose all the annotations you’ve already added to the skool file, though, you should use skool2ctl.py to preserve them.

First, create a control file that keeps your annotations intact:

$ skool2ctl.py game.skool > game-2.ctl

Now edit game-2.ctl to fit your better understanding of the layout of the code and data blocks. Then generate a new skool file:

$ sna2skool.py -c game-2.ctl game.z80 > game-2.skool

This new skool file, game-2.skool, will contain your reorganised code and data blocks, and all the annotations you carefully added to game.skool.

Adding pokes, bugs and trivia

Adding ‘Pokes’, ‘Bugs’, and ‘Trivia’ pages to a disassembly is done by adding [Poke:*], [Bug:*], and [Fact:*] sections to the ref file. For any such sections that are present, skool2html.py will add links to the disassembly index page.

For example, let’s add a poke. Add the following lines to hungry_horace.ref:

[Poke:infiniteLives:Infinite lives]
The following POKE gives Horace infinite lives:

POKE 26429,0

Now run skool2html.py again:

$ skool2html.py examples/hungry_horace.ref

Open hungry_horace/index.html and you will see a link to the ‘Pokes’ page in the ‘Reference’ section.

The format of a Bug or Fact section is the same, except that the section name prefix is Bug: or Fact: (instead of Poke:) as appropriate.

Add one Poke, Bug or Fact section for each poke, bug or trivia entry to be documented. Entries will appear on the ‘Pokes’, ‘Bugs’ or ‘Trivia’ page in the same order as the sections appear in the ref file.

See Ref files for more information on the format of the Poke, Bug, and Fact (and other) sections that may appear in a ref file.

Themes

In addition to the default theme (defined in skoolkit.css), SkoolKit includes some alternative themes:

  • dark (dark colours): skoolkit-dark.css
  • green (mostly green): skoolkit-green.css
  • plum (mostly purple): skoolkit-plum.css
  • wide (wide comment fields on the disassembly pages, and wide boxes on the Changelog, Glossary, Trivia, Bugs and Pokes pages): skoolkit-wide.css

In order to use a theme, run skool2html.py with the -T option; for example, to use the ‘dark’ theme:

$ skool2html.py -T dark game.skool

Themes may be combined; for example, to use both the ‘plum’ and ‘wide’ themes:

$ skool2html.py -T plum -T wide game.skool