README - readme file for Z80/Z280 disassembler package
------------------------------------------------------

Overview
--------

This package comprises a universal Z80/Z280 (compile-time selectable)
disassembler module, together with three front-ends using it: a simple
disassembler for CP/M .COM files, an opcode table producing program and
an opcode list producing program.

The package was originally written in TurboC 2.0. It has been cleaned up
to the point that it *should* be portable C now. Prototypes are included and
used if the preprocessor symbol PROTO is defined (see the Makefile). The
Z80 version works with SunOs 4.0.3 cc; both Z280 and Z80 work with gcc.

Portability
-----------

Only #ifdef and #ifndef are used, and no use is made of any ANSI-ness
except the following:

- In the file dis.c ANSI string concatenation is used in the form "LD"W where
  W is a preprocessor macro. It is defined to be "W" if Z280 is defined, and
  empty otherwise. This is done to modify certain mnemonics when compiling a
  Z280 disassembler. If needed, it can be gotten rid of with

	mv dis.c dis.old
	sed 's/"W/W"/g' dis.old >dis.c

  since it is only used in this form.

- The file <stdlib.h> is included in disas.c, optab.c and oplist.c. Non-ANSI
  compilers and even gcc don't usually have it, so I've included a dummy
  stdlib.h that is used automatically (with gcc at least) if the standard one
  is not available (by -I. in the Makefile).

- The functions memset, strchr and various other SysV/ANSI functions are used,
  that might not be on a BSD system (they *are* on SunOs).

- In disas.c, the file to be disassembled is opened with mode "rb",
  meaning binary mode.  On some systems, this may be different from the
  default text mode.

- If you don't have a compiler that accepts void, enable the VOID macro
  in the Makefile.

Byte order is not (should not) be a problem, since I've tried to insure
that it isn't exploited anywhere now (in the original version, it was).

The types word and byte (declared in dis.h) really *must* be unsigned. It
would be most convenient if you could do ``typedef unsigned short word'' and
``typedef unsigned char byte'', but this gives problems if you use function
prototypes, since all function *definitions* are still old-style and hence
suffer argument promotion. This would give a mismatch between the promoted
type (``unsigned int'' in both cases) and the type used in the function
prototypes (TurboC 2.0 seems to allow this however; maybe this is a bug?)
However, the type byte not being a char flavor is a bit inconvenient; see
for example the function get() in disas.c.

The code passes lint; all messages generated are spurious or arise from
omitting declarationof things like sprintf, memset etc.

Structure
---------

The disassembler module itself consists of the files dis.c and dis.h.
It contains a function dis() that takes an array of sufficient ``byte''s
as argument and produces (via the functions outs() and outval()) it's
disassembled form, returning the length of the instruction. Opcode and
operands are separated by a tab. This module compiles a Z280 assembler if
the preprocessor constant Z280 is defined, otherwise as Z80. It's flexibility
is due to the use of the function outval() that is called for any value to
be output. Example's of such a function can be found in outsym.c, outdebug.c
and outhex.c. The outval() function should direct all it's output via outs()
in order to interoperate properly with the disassembler.

The Z280 instruction set is almost a superset of the (legal) Z80 instruction
set, even LD IXH,A is now legal. The only instruction changed is IN F,(C)
which is now spelled TSTI (C) (probably more clearly). Also, a considerable
syntax weakening has been done: one may now write AND A,B and NEG A also.
Lots of opcodes now have multiple mnemonics, usually one with and one without
a trailing "W" (e.g. LD HL,0 == LDW HL,0 == LDA HL,(0)). Since a disassembler
can only produce one form, I've chose for the most elaborate one (that is,
include the "W" and the optional "A" or "A," if allowed), e.g. write NEG A and
not NEG (there's now also a NEG HL), write AND A,B not AND B and LDW HL,0 not
LD HL,0. Note that there is one nasty case: ADD HL,BC != ADDW HL,BC (the
latter sets *all* flags, while the former only sets the carry flag). In the
Z280 version I also chose NV and V instead of PO and PE as condition codes.
Finally, the illegal Z80 instruction SLIA (shift left filling with 1-bits)
that fills the gap in the Z80 CB opcodes is now called TSET (test and set) and
works totally different. In fact, it's the instruction Zilog recommends using
to differentiate the two chips.

The disassembler consists mainly of several large switch statements. Despite
its apparent chaos, there *is* a method (or maybe several methods :-) to the
Z80 instruction set, and even more so to the Z280 instruction set. This can
be seen most clearly by the opcode tables produced by optab, and also in the
structure of the disassembler itself.

Three front-end programs using the module are included:

- The program disas is a simple disassembler for CP/M .COM files. It is
  included merely as a demonstration of the function outhex(). It's
  stucture reflects the fact that it was actually cut from a larger program
  that was too messy to include here. More elaborate versions, including a
  symbolic one, are easily written. Use it on the file beep.com (included
  as beep.com.uue) to see a sample of it's use.

- The program optab produces opcode tables of 160 characters wide (this is
  the maximum width my PC printer can support). The tables are organized as
  8 columns by 32 rows. The program takes a few bytes as arguments, and
  produces a table of all 256 extensions of these bytes. The following
  invocations are useful:

	optab [-] [dd|fd]
	optab [-] [dd|fd] cb
	optab [-] [dd|fd] ed

  (opcodes dd ed and fd ed are meaningful for the Z280 only).

  If the minus is included, the outdebug() function is used instead of the
  outsym() function, producing things like "JP jp" and "IN A,(in)" to show
  what values the "out" parameter of the outval() function gets for the
  different instructions. See the files dis.c, dis.h and the discussion above.

  For the Z280 EPU ("extended processing unit", read "floating point unit")
  instructions, the four byte operands are printed as "epu,epu,epu,epu", but
  this can easily be changed inside the outval() function, see for example
  outval() in optab.c.

- The program oplist works just like optab, except that it produces a list
  of instructions instead of a table. Instruction bytes containing operands
  are displayed **, e.g. ``21****  LD  HL,nn''.

Installation
------------

Installation should be as simple as typing ``make''. This will build the
Z80 version of the package. If you want the Z280 version, you must edit
the Makefile and use a C compiler that supports ANSI string concatenation,
or use the sed script given above.

Comments
--------

Although I believe that the disassembler is correct and complete, I might
have overlooked some things. If you find any bugs or omissions, please
report them to me, Luc Rooijakkers <lwj@cs.kun.nl>. Note that I am *not*
interested in mnemonic changes, except to correct mistakes.

Have Fun !


