From litech!mat@nusun.jinr.dubna.su Sat Jul 08 19:41:39 1995
Received: by iap.franko.lviv.ua (UUPC/@ v6.14d, 30Mar95) with UUCP;
          id AA01620 Sat,  8 Jul 1995 19:41:39 +0300
Received: from Sigma.ICMP.Lviv.UA (Sigma.ICMP.Lviv.UA [193.124.228.32]) by Big.LITech.Lviv.UA (8.6.9/8.6.9) with ESMTP id TAA04738 for <alex@iap.franko.Lviv.UA>; Fri, 7 Jul 1995 19:55:20 GMT
Received: from nusun.jinr.dubna.su (mat@nusun.jinr.dubna.su [159.93.19.200]) by Sigma.ICMP.Lviv.UA (8.6.8/8.3) with ESMTP id RAA23027; Fri, 7 Jul 1995 17:25:24 +0300
Received: (from mat@localhost) by nusun.jinr.dubna.su (8.6.12/8.6.9) id SAA24963; Fri, 7 Jul 1995 18:14:19 +0400
Message-Id: <199507071414.SAA24963@nusun.jinr.dubna.su>
Date: Fri, 07 Jul 1995 18:08:45 
From: "Matafonov V N" <mat@nusun.jinr.dubna.su>
Organization: JINR
To: alex@iap.franko.lviv.ua
X-Mailer: MAIL2 ( Ver. 2.11.0 from TECHNO )
X-Protocol: TCP
Subject: Z80 undocumented
Lines: 235
MIME-Version: 1.0
Content-Type: text/plain; charset=x-cp866-u
Content-Transfer-Encoding: 8bit
Content-Length: 11905
Status: RO


: Z80.DOC

Sinclair ZX Spectrum Emulator 'Z80' v3.03  -  29/12/94  -  by G.A. Lunter

[skipped]

5.4  The Z80 microprocessor


    The Z80 processor is quite straightforward, and contains to my
    knowledge no interesting bugs or quirks.  However, it has some
    undocumented features.  Some of these are quite useful, and some are
    not, but since many programs use the useful ones, and a few programs
    use the weird ones, I tried to figure them out and emulate them as best
    as I could.  There is a Z80 emulator around, intended as a CP/M
    emulator, which halts the program if an undocumented opcode is
    encountered.  I don't think this makes sense.  ZiLOG doesn't dictate
    the law, the programs which use the processor's features do!

    In section 5.1 there is some information on Z80 interrupt timings in
    different modes.

    Most Z80 opcodes are one byte long, not counting a possible byte or
    word operand.  The four opcodes CB, DD, ED and FD are 'shift' opcodes:
    they change the meaning of the opcode following them.

    There are 248 different CB opcodes.  The block CB 30 to CB 37 is
    missing from the official list.  These instructions, usually denoted by
    the mnemonic SLL, Shift Left Logical, shift left the operand and make
    bit 0 always one.  Bounder and Enduro Racer use them, to name just two.
    The SamRam monitor can disassemble these and uses the mnemonic SLL.
    These instructions are quite commonly used.

    The DD and FD opcodes precede instructions using the IX and IY
    registers.  If you look at the instructions carefully, you see how they
    work:

        2A nn           LD HL,(nn)
        DD 2A nn        LD IX,(nn)
        7E              LD A,(HL)
        DD 7E d         LD A,(IX+d)

    A DD opcode simply changes the meaning of HL in the next instruction.
    If a memory byte is addressed indirectly via HL, as in the second
    example, a displacement byte is added.  Otherwise the instruction
    simply acts on IX instead of HL.  (A notational awkwardness, that will
    only bother assembler and disassembler writers: JP (HL) is not
    indirect; it should have been denoted by JP HL)  If a DD opcode
    precedes an instruction that doesn't use the HL register pair at all,
    the instruction is executed as usual.  However, if the instruction uses
    the H or L register, it will now use the high or low halves of the IX
    register! Example:

        44              LD B,H
        FD 44           LD B,IYh

    These types of inofficial instructions are used in many programs. By
    the way, many DD or FD opcodes after each other will effectively be
    NOPs, doing nothing except repeatedly setting the flag 'treat HL as IX'
    (or IY) and taking up 4 T states.  (But try to let MONS disassemble
    such a block.)

    The doubly-shifted opcodes that start with DD CB and DD ED behave
    differently.  If a DD or FD precedes an ED instruction, the DD or FD is
    ignored.  ED instructions never operate on the IX or IY register, and
    are executed normally instead.  With CB instructions, the situation is
    more interesting.  Within an 8-instruction block, every DD CB
    instruction works as the official one, but also copies the result to
    the specified register (except when it is (HL)).  For example,

        CB CE           SET 0,(HL)
        CB C0           SET 0,B
        DD CB nn CE     SET 0,(IX+nn)
        DD CB nn C0     SET 0,(IX+nn) ; copy result to B

    (The information about the inofficial CB instructions was given to me
    by Arnt Gulbrandsen, and originated from David Librik.)

    There are a number of inofficial ED instructions, but none of them are
    very useful.  The ED opcodes in the range 00-3F and 80-FF (except for
    the block instructions of course) do nothing at all but taking up 8 T
    states and incrementing the R register by 2.  Most of the unlisted
    opcodes in the range 40-7F do have an effect, however.  The complete
    list: (* = not official)

        ED40   IN B,(C)                 ED60   IN H,(C)
        ED41   OUT (C),B                ED61   OUT (C),H
        ED42   SBC HL,BC                ED62   SBC HL,HL
        ED43   LD (nn),BC               ED63 * LD (nn),HL
        ED44   NEG                      ED64 * NEG
        ED45   RETN                     ED65 * RET
        ED46   IM 0                     ED66 * IM 0
        ED47   LD I,A                   ED67   RRD
        ED48   IN C,(C)                 ED68   IN L,(C)
        ED49   OUT (C),C                ED69   OUT (C),L
        ED4A   ADC HL,BC                ED6A   ADC HL,HL
        ED4B   LD BC,(nn)               ED6B * LD HL,(nn)
        ED4C * NEG                      ED6C * NEG
        ED4D   RETI                     ED6D * RET
        ED4E * IM 0                     ED6E * IM 0
        ED4F   LD R,A                   ED6F   RLD
        ED50   IN D,(C)                 ED70 * IN (C)
        ED51   OUT (C),D                ED71 * OUT (C),0
        ED52   SBC HL,DE                ED72   SBC HL,SP
        ED53   LD (nn),DE               ED73   LD (nn),SP
        ED54 * NEG                      ED74 * NEG
        ED55 * RET                      ED75 * RET
        ED56   IM 1                     ED76 * IM 1
        ED57   LD A,I                   ED77 * NOP
        ED58   IN E,(C)                 ED78   IN A,(C)
        ED59   OUT (C),E                ED79   OUT (C),A
        ED5A   ADC HL,DE                ED7A   ADC HL,SP
        ED5B   LD DE,(nn)               ED7B   LD SP,(nn)
        ED5C * NEG                      ED7C * NEG
        ED5D * RET                      ED7D * RET
        ED5E   IM 2                     ED7E * IM 2
        ED5F   LD A,R                   ED7F * NOP

    The ED70 instruction reads from port (C), just like the other
    instructions, but throws away the result.  It does change the flags in
    the same way as the other IN instructions, however.  The ED71
    instruction OUTs a byte zero to port (C), interestingly.  These
    instructions 'should', by regularity of the instruction set, use (HL)
    as operand, but since from the processor's point of view accessing
    memory or accessing I/O devices is almost the same thing, and since the
    Z80 cannot access memory twice in one instruction (disregarding
    instruction fetch of course) it can't fetch or store the data byte.  (A
    hint in this direction is that, even though the NOP-synonyms LD B,B, LD
    C,C etcetera do exist, LD (HL),(HL) is absent and replaced by the HALT
    instruction.)

    The instructions ED 4E and ED 6E are IM 0 equivalents: when FF was put
    on the bus at interrupt time, the Spectrum continued to execute
    normally, whereas when an EF (RST #28) was put on the bus it crashed,
    just as it does in that case when the Z80 is in the official interrupt
    mode 0.  In IM 1 the Z80 just executes a RST #38 (opcode FF) no matter
    what is on the bus.

    The RETI instruction is functionally exactly equivalent to the RET
    instruction.  It is used only to signify the end of an interrupt
    routine to an external hardware device (read: the Z80 PIO).  The RETN
    however is different from RET in that it resets IFF1 to the current
    value of IFF2.  Now IFF1 and IFF2 are usually equal (and become equal
    after DI and EI and after a maskable interrupt has been accepted).
    They're different only if an NMI occurs when interrupts are enabled;
    then IFF1 is off, and IFF2, holding the previous state of the interrupt
    flip flop, is on, signifying that interrupts were enabled before the
    non-maskable interrupt.  Since the state of IFF2 can be read by using
    LD A,R and LD A,I, the RETN instruction is not used much in Spectrum
    ROM software, and it is utterly useless in normal software.  In other
    words, I have not tried to figure out whether the unofficial RET's are
    RETI's or RETN's.

    About the R register.  This is not really an undocumented feature,
    although I have never seen any thorough description of it anywhere.
    The R register is a counter that is updated every instruction, where
    DD, FD, ED and CB are to be regarded as separate instructions.  So
    shifted instructions will increase R by two.  There's an interesting
    exception: doubly-shifted opcodes, the DDCB and FDCB ones, increase R
    by two too. LDI increases R by two, LDIR increases it by 2 times BC, as
    does LDDR etcetera.  The sequence LD R,A / LD A,R increases A by two.
    The highest bit of the R register is never changed (except possibly by
    LD R,A of course).  This is because in the old days everyone used 16
    Kbit chips.  Inside the chip the bits where grouped in a 128x128
    matrix, needing a 7 bit refresh cycle.  Therefore ZiLOG decided to
    count only the lowest 7 bits.  If the R register emulation is switched
    on the R register will behave as is does on a real Spectrum; if it is
    off it will (except for the upper bit) act as a random generator.

    You can easily check that the R register is really crucial to memory
    refresh.  Assemble this program:

        ORG 32768
        DI
        LD B,0
    L1  XOR A
        LD R,A
        DEC HL
        LD A,H
        OR L
        JR NZ,L1
        DJNZ L1
        EI
        RET

    It will take about three minutes to run.  Look at the upper 32K of
    memory, for instance the UDG graphics.  It will have faded.  Only the
    first few bytes of each 256 byte block will still contain zeros,
    because they were refreshed during the execution of the loop.  The ULA
    took care of the refreshing of the lower 16K.  (This example won't work
    on the emulator of course!)

    Then there's one other dark corner of the Z80 which has its effect on
    programs like Sabre Wulf, Ghosts'n Goblins and Speedlock.  The Mystery
    of the Undocumented Flags!

    Bit 3 and 5 of the F register are not used.  They can contain
    information, as you can readily figure out by using PUSH AF and POP AF.
    Furthermore, sometimes their values change.  I found the following
    empirical rule:

        The values of bit 7, 5 and 3 follow the values of the
        corresponding bits of the last 8 bit result of an instruction
        that changed the usual flags.

    For instance, after an ADD A,B those bits will be identical to the bits
    of the A register.  (Bit 7 of F is the sign flag, and fits the rule
    exactly).  An exception is the CP x instruction (x=register, (HL) or
    direct argument).  In that case the bits are copied from the argument.

    If the instruction is one that operates on a 16 bit word, the 8 bits of
    the rule are the highest 8 bits of the 16 bit result - that was to be
    expected since the S flag is extracted from bit 15.

    Ghosts'n Goblins use the undocumented flag due to a programming error.
    The rhino in Sabre Wulf walks backward or keeps running in little
    circles in a corner, if the (in this case undocumented) behaviour of
    the sign flag in the BIT instruction isn't right.  I quote:

        AD86    DD CB 06 7E        BIT 7,(IX+6)
        AD8A    F2 8F AD           JP P,#AD8F

    An amazing piece of code!  Speedlock does so many weird things that
    everything must be exactly right for it to run.  Finally, the '128 rom
    uses the AF register to hold the return address of a subroutine for a
    while.  To keep all programs happy, and still have a fast emulator, I
    had to make a compromise.  The undocumented flags are not always
    emulated right, but they are most of the time.  Not telling you when
    not.

[skipped]

ᥣ 襣,
                   ਩.


