2026-04-30 03:24:02 +07:00
|
|
|
# test_z80 — Zilog Z80 as a velxio custom chip
|
|
|
|
|
|
|
|
|
|
See [../autosearch/02_intel_chips_overview.md](../autosearch/02_intel_chips_overview.md#zilog-z80-1976)
|
|
|
|
|
for the spec.
|
|
|
|
|
|
|
|
|
|
## Status
|
|
|
|
|
|
|
|
|
|
✅ **Implemented (core).** 6/13 active tests pass; 7 are `it.todo`
|
|
|
|
|
deferred milestones. ~550 LOC clean-room C in `z80.c` compiled to
|
|
|
|
|
`fixtures/z80.wasm`.
|
|
|
|
|
|
|
|
|
|
Validated against:
|
|
|
|
|
- Zilog Z80 Family CPU User Manual UM008003-1202 (2002 reprint of the
|
|
|
|
|
canonical doc; PDF at `autosearch/pdfs/z80_user_manual.pdf`)
|
|
|
|
|
- Sean Young, "The Undocumented Z80 Documented" v0.91 (PDF at
|
|
|
|
|
`autosearch/pdfs/z80_undocumented.pdf`)
|
|
|
|
|
- Cross-checked against `floooh/chips/z80.h` (zlib),
|
|
|
|
|
`superzazu/z80` (MIT, passes ZEXALL), `kosarev/z80` (MIT)
|
|
|
|
|
|
|
|
|
|
What works:
|
|
|
|
|
- 40-pin contract, M1 cycle (M1̅+MREQ̅+RD̅ asserted simultaneously),
|
|
|
|
|
RFSH̅ pulse with R counter and I driving the address bus.
|
|
|
|
|
- 8080-superset ISA: LD r,r' / LD r,n / LD rr,nn / LD (nn),A / LD A,(nn) /
|
|
|
|
|
ALU / INC / DEC / 16-bit ADD HL / rotates / control flow / stack.
|
|
|
|
|
- Z80-only: EX DE,HL / EX AF,AF' / EXX / DJNZ / JR / LDIR / LDDR / NEG
|
|
|
|
|
(8 aliases) / IM 0/1/2 / EI / DI / IN / OUT.
|
|
|
|
|
- DD/FD prefix → IX/IY substitution for HL-using opcodes (incl. (IX+d)
|
|
|
|
|
with displacement byte).
|
|
|
|
|
- ED prefix → block ops, IM, NEG, RETN/RETI, LD (nn),rr / LD rr,(nn).
|
|
|
|
|
- NMI̅ falling-edge → push PC, vector to 0x0066 (without IFF1→IFF2
|
|
|
|
|
copy, per Sean Young's hardware tests, contradicting Zilog's manual).
|
|
|
|
|
|
|
|
|
|
Deferred until ZEXDOC/ZEXALL integration phase:
|
|
|
|
|
- X (bit 3) and Y (bit 5) "undocumented" flag bits — required by ZEXALL
|
|
|
|
|
but no current test exercises them.
|
|
|
|
|
- MEMPTR (WZ) register — only observable through `BIT n,(HL)`.
|
|
|
|
|
- CB-prefix bit ops (BIT/SET/RES/RL*/RR*/SLA/SRA/SLL/SRL).
|
|
|
|
|
- Block I/O instruction flags (full deterministic rules per Sean Young
|
|
|
|
|
§4.3 — currently approximate).
|
|
|
|
|
- DAA's full Z80-specific table (currently uses an 8080-equivalent
|
|
|
|
|
approximation — will diverge for N=1 cases).
|
|
|
|
|
- Cycle-accurate WAIT̅ and contention timing.
|
|
|
|
|
|
|
|
|
|
## Pin contract (40-pin DIP)
|
|
|
|
|
|
|
|
|
|
| Group | Pins | Dir |
|
|
|
|
|
| ------------ | ------------------------------------------------------------- | --- |
|
|
|
|
|
| Address bus | `A0..A15` | out |
|
|
|
|
|
| Data bus | `D0..D7` | I/O |
|
|
|
|
|
| Memory ctrl | `MREQ̅`, `RD̅`, `WR̅`, `RFSH̅` | out |
|
|
|
|
|
| I/O ctrl | `IORQ̅` | out |
|
|
|
|
|
| Cycle marker | `M1̅` | out |
|
|
|
|
|
| CPU state | `HALT̅` | out |
|
|
|
|
|
| Wait/sync | `WAIT̅` | in |
|
|
|
|
|
| Interrupts | `INT̅`, `NMI̅` | in |
|
|
|
|
|
| Bus arb | `BUSREQ̅`, `BUSACK̅` | I/O |
|
|
|
|
|
| System | `CLK`, `RESET̅` | in |
|
|
|
|
|
| Power | `VCC`, `GND` | power |
|
|
|
|
|
|
|
|
|
|
Total: 16 + 8 + 4 + 1 + 1 + 1 + 1 + 2 + 2 + 2 + 2 = **40 pins** —
|
|
|
|
|
all 40 of the real DIP. No power simplification needed (single 5 V rail).
|
|
|
|
|
|
|
|
|
|
## Bus cycle reference
|
|
|
|
|
|
|
|
|
|
The Z80's bus is closer to "what you'd design today" than the 8080's:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
M1 (opcode fetch):
|
|
|
|
|
T1: drive A0..A15, assert M1̅, MREQ̅ then RD̅
|
|
|
|
|
T2: sample D0..D7
|
|
|
|
|
T3: deassert RD̅, MREQ̅; assert RFSH̅; drive A0..A6 with R register
|
|
|
|
|
T4: deassert RFSH̅
|
|
|
|
|
|
|
|
|
|
Memory read (non-M1):
|
|
|
|
|
T1: drive A0..A15, assert MREQ̅
|
|
|
|
|
T2: assert RD̅, sample D0..D7
|
|
|
|
|
T3: deassert RD̅, MREQ̅
|
|
|
|
|
|
|
|
|
|
Memory write:
|
|
|
|
|
T1: drive A0..A15, MREQ̅
|
|
|
|
|
T2: drive D0..D7, assert WR̅
|
|
|
|
|
T3: deassert WR̅, MREQ̅
|
|
|
|
|
|
|
|
|
|
I/O read/write:
|
|
|
|
|
Like memory but with IORQ̅ instead of MREQ̅.
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
We faithfully drive `M1̅` and `RFSH̅` so dynamic-RAM-style wiring works
|
|
|
|
|
in user demos.
|
|
|
|
|
|
|
|
|
|
## Why the Z80 is the high-value target
|
|
|
|
|
|
|
|
|
|
- **Recognisable.** ZX Spectrum, MSX, GameBoy CPU (modified Z80),
|
|
|
|
|
CP/M machines, MAME arcade boards. Users *will* try to wire one.
|
|
|
|
|
- **Best documented.** The full instruction set, including undocumented
|
|
|
|
|
flags, has been reverse-engineered.
|
|
|
|
|
- **Best reference emulator.** `floooh/chips/z80.h` is single-header,
|
|
|
|
|
cycle-accurate, MIT-licensed.
|
|
|
|
|
|
|
|
|
|
## Implementation plan
|
|
|
|
|
|
|
|
|
|
1. Spike: `LD A, n`, `OUT (n), A`, `JR n`, `HALT` only. Drive an LED
|
|
|
|
|
from a memory-mapped port. Confirms the bus state machine works.
|
|
|
|
|
2. Port `floooh/chips/z80.h` into `z80.c` as the decoder core. Adapt
|
|
|
|
|
the bus interface from "callback function" style to "drive velxio
|
|
|
|
|
pins" style.
|
|
|
|
|
3. Run ZEXDOC / ZEXALL — the canonical Z80 documented/all-flags self
|
|
|
|
|
tests. These boot CP/M-style and print results to a UART.
|
|
|
|
|
4. Add `INT`/`NMI` handling. Implement IM 0 / IM 1 / IM 2.
|
|
|
|
|
5. Stretch: hook a ZX Spectrum ROM and a 16K RAM chip; see if the
|
|
|
|
|
Spectrum boot screen renders. (Display would be a separate chip.)
|
|
|
|
|
|
|
|
|
|
## Target demo sketch
|
|
|
|
|
|
|
|
|
|
Same as 8080 (UART hello world) so we can compare the two chips
|
|
|
|
|
side-by-side on the canvas. Then a Z80-only second demo using the
|
|
|
|
|
shadow registers (`EXX`) — something the 8080 cannot do — to show
|
|
|
|
|
the Z80's expanded ISA.
|
|
|
|
|
|
|
|
|
|
## Files to create later
|
|
|
|
|
|
|
|
|
|
- `z80.chip.json`
|
|
|
|
|
- `z80.c` (likely split into `z80_core.c` + `z80_decode.c` if the
|
|
|
|
|
ported decoder is large)
|
|
|
|
|
- `vendor/` for any vendored MIT-licensed reference code (or move
|
refactor: rename wokwi-libs/ → third-party/
The directory grew well beyond Wokwi-only contents: it now hosts
lcgamboa's QEMU fork (qemu-lcgamboa), Espressif's esp32-camera, the
ngspice WASM build, fritzing-parts, picowi, an alternative QEMU
(qemu-esp32), the 100_Days_100_IoT_Projects examples repo, and
Wokwi's own avr8js/rp2040js/wokwi-elements/wokwi-features/wokwi-boards.
"wokwi-libs" was misleading — half the contents have nothing to do
with Wokwi. "third-party/" is the standard convention for vendored
external dependencies.
Mechanical changes:
Path rename:
wokwi-libs/ → third-party/
update-wokwi-libs.bat → update-third-party.bat
docs/WOKWI_LIBS.md → docs/THIRD_PARTY.md
Submodule reconfiguration:
.gitmodules — 4 path= and section names updated
.git/modules/wokwi-libs/ → .git/modules/third-party/
each submodule's .git file rewired to ../../.git/modules/third-party/<name>
Reference updates (~80 files): vite.config.ts aliases, Dockerfile
COPY paths, GH Actions workflow steps, build_qemu_*.sh, all
docs/* and test/*/autosearch/* entries that mention the path,
package-lock.json file: dependencies, .gitignore patterns,
sitemap.xml + index.html SEO blurbs, scripts/generate-component-*,
.dockerignore, .idea/vcs.xml. Bulk replaced both `wokwi-libs/`
(path) and bare `wokwi-libs` (textual mentions in docs/comments).
Verified:
- npx tsc -b --noEmit produces no new errors related to these paths
- vite.config.ts aliases now point at ../third-party/avr8js etc.
- All 4 git submodules (avr8js, rp2040js, wokwi-elements,
wokwi-features) are linked under third-party/ with their
worktrees re-populated and config files referencing the new path
- `grep -r wokwi-libs` returns zero hits outside node_modules,
.vite, frontend/dist, third-party/ (upstream submodule contents),
*.pyc caches, and *.dll.pre-camera rollback binaries
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 10:58:57 +07:00
|
|
|
to `third-party/cpu-cores/` per the open question in
|
2026-04-30 03:24:02 +07:00
|
|
|
[../autosearch/05_open_questions.md](../autosearch/05_open_questions.md#q2-where-exactly-should-vendor-emulator-cores-live))
|
|
|
|
|
- `roms/zexdoc.bin`, `roms/hello.bin`
|
|
|
|
|
- `z80.test.ts`
|