
This is an extract from the comp.sys.sinclair Sinclair ZX Spectrum FAQ v.2.0
(July 3 1994), which is maintained by Marat Fayzullin (fms@freeflight.com).
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 very 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.).
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/1 ED6E * IM 0/1
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
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 IM 0/1 instruction puts the processor in either IM 0 or 1, I couldn't
figure out which on my own Spectrum.
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!).
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 all 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.