# The Z80N extended instructions
What the thirty Z80N instructions do, as they behave in the T80/T80N FPGA core this one is derived
from.
**Every figure here is measured, not quoted.** Cycle counts come from a T-state-for-T-state
comparison against a simulation of that design. Flags and final register values come from running
each instruction on the simulation with seeded registers and reading the result off the bus.
Where this disagrees with published descriptions, the disagreement is deliberate. They're all
listed at the end.
All thirty are `ED`-prefixed. Turn the extended set off and they decode as the two-cycle
no-operation a Z80 gives an unassigned `ED` opcode.
## Notation
Flags are `SZYHXPNC` — sign, zero, undocumented bit 5, half-carry, undocumented bit 3, parity or
overflow, add/subtract, carry. In the flag column:
- **–** nothing is written to the flag register
- **block** the block-transfer rule. Half-carry and add/subtract are cleared. Parity is set while
the counter is non-zero. The two undocumented bits come from the accumulator plus the byte moved
— bit 3 and bit 1 of that sum. Sign, zero and carry are left alone.
## The instructions
| `ED 23` | `SWAPNIB` | 8 | `A` ← `A` rotated by four | – |
| `ED 24` | `MIRROR` | 8 | `A` ← `A` with its bits reversed | – |
| `ED 27 n` | `TEST n` | 11 | `A AND n`, result discarded | `SZ` from result, `H` set, `P` parity, `N` `C` cleared |
| `ED 28` | `BSLA DE,B` | 8 | `DE` ← `DE << (B AND 31)` | – |
| `ED 29` | `BSRA DE,B` | 8 | `DE` ← `DE >> (B AND 31)`, sign extended | – |
| `ED 2A` | `BSRL DE,B` | 8 | `DE` ← `DE >> (B AND 31)`, zero filled | – |
| `ED 2B` | `BSRF DE,B` | 8 | `DE` ← `DE >> (B AND 31)`, one filled | – |
| `ED 2C` | `BRLC DE,B` | 8 | `DE` ← `DE` rotated left by `B AND 15` | – |
| `ED 30` | `MUL D,E` | 8 | `DE` ← `D × E`, unsigned | – |
| `ED 31` | `ADD HL,A` | 8 | `HL` ← `HL + A`, zero extended | **carry cleared**, rest untouched |
| `ED 32` | `ADD DE,A` | 8 | `DE` ← `DE + A`, zero extended | **carry cleared**, rest untouched |
| `ED 33` | `ADD BC,A` | 8 | `BC` ← `BC + A`, zero extended | **carry cleared**, rest untouched |
| `ED 34 nn` | `ADD HL,nn` | 16 | `HL` ← `HL + nn` | – |
| `ED 35 nn` | `ADD DE,nn` | 16 | `DE` ← `DE + nn` | – |
| `ED 36 nn` | `ADD BC,nn` | 16 | `BC` ← `BC + nn` | – |
| `ED 8A hh ll` | `PUSH nn` | 23 | pushes the immediate, **encoded high byte first** | – |
| `ED 90` | `OUTINB` | 16 | `OUT (BC),(HL)`; `HL` ← `HL + 1`; `B` **is not counted down** | – |
| `ED 91 rr vv` | `NEXTREG rr,vv` | 20 | reports register `rr` ← `vv` to the machine | – |
| `ED 92 rr` | `NEXTREG rr,A` | 17 | reports register `rr` ← `A` to the machine | – |
| `ED 93` | `PIXELDN` | 8 | `HL` ← the display address one pixel row below | – |
| `ED 94` | `PIXELAD` | 8 | `HL` ← the display address of the pixel at column `E`, row `D` | – |
| `ED 95` | `SETAE` | 8 | `A` ← `0x80 >> (E AND 7)` | – |
| `ED 98` | `JP (C)` | 13 | reads port `BC`; `PC` ← `(PC AND C000) OR ((byte << 6) AND 3FC0)` | – |
| `ED A4` | `LDIX` | 16 | as `LDI`, but **the write is suppressed when the byte equals `A`** | block |
| `ED A5` | `LDWS` | 14 | `(DE)` ← `(HL)`; `L` ← `L + 1`; `D` ← `D + 1` | see below |
| `ED AC` | `LDDX` | 16 | as `LDIX`, skip included, but `HL` counts down while `DE` still counts up | block |
| `ED B4` | `LDIRX` | 21 / 16 | `LDIX`, repeating | block |
| `ED B6` | `LDIRSCALE` | 21 / 16 | **a plain repeating copy**; the scaling is not present | block |
| `ED B7` | `LDPIRX` | 21 / 16 | as `LDIRX`, source `(HL AND FFF8) OR (DE AND 7)`, `HL` unchanged | block |
| `ED BC` | `LDDRX` | 21 / 16 | `LDDX`, repeating | block |
The repeating forms take the longer count on every iteration that leaves `BC` non-zero, and the
shorter one on the last.
## The four with a catch
### `LDWS` — addition flags, not increment flags
`ED A5` copies a byte, increments the **low** half of the source pointer and the **high** half of
the destination pair, then writes the flags that second increment produces.
The catch is that they're the flags of `D + 1` as an **addition**, carry included. Not the flags of
`INC D`, which match in every other bit but leave the carry alone.
Measured, starting from all flags set:
| `05` | `06` | `00` |
| `7F` | `80` | `94` — sign, half-carry, overflow |
| `FF` | `00` | `51` — zero, half-carry, **carry** |
The first row is why this is easy to get wrong. Adding one to `05` sets no flag at all, so the
register looks like it's been wiped. It hasn't.
Neither the counter nor the source pointer's high half is touched, so this instruction won't
terminate on its own.
### `LDPIRX` — a fill, not a copy
The source address is `(HL AND FFF8) OR (DE AND 7)`. A byte comes from an eight-byte pattern at
`HL`, picked by the low three bits of the destination. `HL` doesn't advance — only `DE` and `BC`
move. That's what makes it a fill rather than a copy.
One warning if you're modelling the bus rather than the effect. The design drives the pattern
address for a single T-state, then the destination address for the rest of the machine cycle. So
what a read latches depends on the memory. One that follows the address bus continuously latches
the destination, and the instruction copies a byte onto itself. One that captures the address when
the cycle opens latches the pattern.
This core reads the pattern. The alternative turns a documented instruction into a no-op, which
can't be right.
### `PUSH nn` — the only big-endian operand
`ED 8A hh ll` carries its operand **high byte first**. No other Z80 instruction does.
It reaches the stack the normal way round, low byte at the lower address. So `ED 8A 12 34` pushes
`1234` and leaves `34` where the stack pointer ends up.
### `JP (C)` — the jump stays in the current 16K
The byte read from the port doesn't become the address. It's shifted into bits 13 to 6, and the top
two bits of `PC` are kept. So the jump can only reach a 64-byte-aligned target inside the 16K region
it's executing in.
## What reaches the machine
Most of these finish inside the processor. Three don't, and get reported to the host instead: the
two `NEXTREG` forms, where the report *is* the whole effect, and the port write in `OUTINB`.
The barrel shifts, additions, pixel helpers and block copies are reported too, for a machine
watching the extended bus. But their work is already done in the registers by then.
## Where published descriptions differ
Each was found by measuring. Follow the published description on any of them and you get a core
that looks right but doesn't match the part.
1. **`ADD HL,A`, `ADD DE,A` and `ADD BC,A` clear the carry.** They're widely documented as leaving
the flags alone. The design takes the carry from a bit above the truncated sum, so it's cleared
whether the addition overflows or not. The three immediate forms really do write no flags.
2. **The whole block-copy family writes flags.** Documented as leaving them alone. All six write
the block-transfer rule, and `LDWS` writes an addition's.
3. **`LDWS` computes the carry.** Neither preserved nor cleared. See above.
4. **All four `X` copies skip the write on a match**, the descending pair included. Easy to get
wrong, because the design writes the ascending and descending pairs as separate branches, so you
can implement the skip for one and miss the other.
5. **`OUTINB` leaves the flags alone.** It isn't the counted port output minus the counter. Those
forms get their flags from the counter's decrement, and this one has no counter, so nothing
writes the flag register at all.
6. **`PIXELAD` maps a coordinate to an address**, not the other way round.
7. **`JP (C)` stays inside the current 16K**, rather than jumping to the byte it read.
8. **`PIXELDN` uses a specific bit repacking.** The obvious-looking alternative overlaps fields and
gets it wrong.
9. **`LDIRSCALE` is a plain repeating copy.** The design decodes it, but the scaling it's named for
isn't in there.
10. **`NEXTREG rr,A` takes 17 T-states**, not the 14 some references give. The immediate form takes
20.