1K DISASSEMBLER
by H.M. Tucker
from ZX Computing Jun/Jul.1984

Disassemble your ZX81 ROM in just 1K - sounds impossible?
Well, have a go with this program written for us by HM
Tucker of Luton.


This program is designed to decode any area of ROM or RAM
into instructions comprising op-code and data if any, and to
print them out with their addresses, one to a line, until
the screen is full (approximately one second in Fast mode)
and groups all Z80 instructions.

It fits easily into an unexpanded ZX81, and will also run in
Slow mode, which is essential if you wish to change the
program to scroll so that you may sit back and watch the
entire ROM unfold before you (about six instructions per
second in Slow mode).

It accepts up to four digits of Hex address, but if decimal
addressing is preferred, simply change lines 10 and 20 and
omit lines 30 to 60. Options are available for copying to
printer, continuing disassembly or of selecting new start
address.

Apart from being very interesting to write and to run, it
will allow you to find the misprints in some published
versions of what is in the ROM.


How it does it

The BASIC program asks for the start address in Hex; this is
converted to decimal by lines 30 to 60 and POKEd into spare
locations in the system variables area by lines 70 and 80.

The machine code now takes over and Part 1 prints out the
address as four digit Hex. The program doesn't seem to have
achieved much so far does it? But these few bytes can be
tucked away above RAMtop or in the printer buffer as a handy
decimal to hex converter.

Part 2 moves four bytes of data from the start address to
the four reserved bytes at the start of the REM ready for
Part 3 to look at, and for Part 4 to print as necessary.

Part 3 is the longest and most complicated of the whole
program and comprises all the decision blocks in the flow
chart [see 1KDISASS.GIF], and all the tables. Briefly, it
searches the tables guided by a pointer in HL and a length
in BC, looking for a match for a particular byte of the
op-code. The accumulator is loaded with the first byte and
table 1 is searched; if a match is not found in table 1 all
we can be sure of, is that we do not have a four byte
instruction, but more about this later.

Tables two and three are then searched for two and three
byte instructions respectively; any code escaping these
searches must of necessity be a one byte instruction. All
these instructions have one byte op-codes and in all cases C
is loaded with the appropriate value and control passed to
Part 4 to print code.

If a match was found in table 1 we may have an instruction
two, three or four bytes long, it depends on the value in
byte two, so the accumulator is loaded with the second byte
and table 4 searches for four byte instructions, then table
2A for two byte instructions beginning with DD or FD. Again
C is loaded with the appropriate value and control passed to
Part 4 to print code.

I told you it was complicated didn't I? Don't worry though,
the worst is yet to come. We are now left with 50 two byte
instructions which began with ED, and 48 three byte
instructions which began with DD or FD. Nobody wants 98
bytes of tables, so the accumulator is re-loaded with the
first byte and the main program rejoined at table 2 where
the 50 two byters are picked out by ED. And so to table 3
where the 48 three byters are picked out by DD and FD. Again
C is loaded and control passed to Part 4.

Part 4 prints out the appropriate number of bytes and is
virtually the same as Part 1, but this time prints a space
before each byte to make the display easier to read. Since
we don't care about corrupting the data, this time we can
leave out the rotate left digit necessary in Part 1. On
return to BASIC at line 100, the decimal address is updated
by the number of bytes used and the screen examined to see
if it is full. If not then back to line 70, and off we go
again until it is full.


Loading the REM

This is without doubt the worst part of all, but the
following hints may help. Use Fast mode to load the REM with
208 characters; eg. a sequence of nine full stops and a zero
repeated makes counting quite easy, but as a check when you
have finished, a direct command of PRINT PEEK 16511 should
give a value of 210.

Use any loader program you may have that loads Hex or use
the following which although rather long and with limited
protection on the input, is easy to use. When RUN, it will
display the current contents of the first byte of the REM as
"1 is 1B?" and wait for you to either accept it by pressing
Newline, or to change it by entering the desired code
followed by Newline.

In either case the code will be POKEd in and displayed to
the right of the old code. The next byte is then displayed
below the first, so carry on and enter all 208 bytes, and
good luck, remember to start with four 'no ops'.

If you make an error leave it for corrections later, the
byte numbers will help you keep in step with the program
which will stop after 208 bytes and display a simple
checksum which should be 22880; if it isn't you have made an
error. Run the loader again and step through till you find
it. Note that a simple checksum is not an absolute guarantee
of accuracy but you may proceed with fair hope of success.
Save it onto tape just in case. Delete all the loader except
the REM in line 1 starting with the last line and working
back to line 10.


Basically ...

Enter the BASIC program, select Fast mode, enter RUN Newline
and you should see: 'START? IN HEX'.

Type in a start address, say 0, and with your fingers
crossed press Newline; all being well you should have no
more than one second of suspense followed by a display of
Hex addresses and groups of code, which are the first 22
instructions in ROM. The program will stop with error code
9/120.

You may now COPY to printer if required, continue
disassembly by CONT Newline or use RUN Newline to select a
new start address.

Assuming all has gone according to plan, it is now play
time; why not look at our own program using 4086, then use
4082 and note that even though not starting at the beginning
of an instruction, that the program is self aligning.
Instead of the boring old THEN STOP in line 120, try THEN
CLS or THEN SCROLL; but do select Slow mode before running
these last two.


Notes

There are seven possible routes through the flow chart [see
1KDISASS.GIF] corresponding to the following table:

     number of bytes
opcode    data  instruction
  1        0        1
  1        1        2
  1        2        3
  2        0        2
  2        1        3
  2        2        4
  3        1        4

For our purpose it has been sufficient to look no further
than the second byte of the op-code, since all 62 three byte
op-codes form four byte instructions which are detected by
their second byte.

In the interests of easy programming and description, no
great attempt has been made to save memory, since even at
the most crowded part of the ROM around 0650 there is plenty
of room on the screen for all the code.

My thanks to Dr Ian Logan's book "Understanding your ZX81
ROM" for the inspiration to write this program. Should you
require more information on the techniques used in my
program, I suggest you look no further than this excellent
book.


--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--
