eZX Spectrum — Hardware Specification

Overview

The eZX Spectrum is a Spectrum-lineage home computer built on a constrained variant of the Ant64 platform. It holds three FPGA images, selectable at boot:

  • An eZX primary image — a clean-slate reimagining with its own CPU, chipset, and display stack
  • A faithful ZX Spectrum Next compatible image, derived from the official Next core
  • A Classic Spectrum image — cycle-accurate emulation of the pre-Next Spectrum range (16K, 48K, 128K, +2, +2A, +3, plus the major non-UK clones) running entirely from on-chip BSRAM for deterministic ULA timing

All three images run on the same hardware. Platform services — supervisor OS, control processor, peripherals — are shared with Ant64.


Hardware Summary

FPGA GoWin GW5AST-LV138 — 138K LUT4, 340 BSRAM blocks (~765 KB), 298 DSPs, 12 PLLs, hard RISC-V core; same FPGA component as Ant64's FireStorm
Main RAM 16 MB HyperRAM (Infineon S70KL1282) sharing the FPGA boot bus with config flash — serves both as system RAM (in the base configuration) and as ROM tier across all configurations (OS images, cartridge ROMs, system ROMs), plus snapshot loading and tape/disk image buffering. Optional DDR3 SODIMM72-bit ECC SODIMM, x8 chip width; 1R x8 (9-chip) modules give full capacity, 2R x8 (18-chip) modules also fit but half the capacity is unreachable (FPGA controller IP drives only one CS). All 72 bits used as RAM rather than 64+ECC parity and organised as 8 data bytes + 8 metadata bits per 72-bit word. Supported capacities: 1 / 2 / 4 GB user-addressable data (theoretical max 8 GB; address space reserves 8 GB, only 4 GB software-supported). The 8 metadata bits per word do double duty — debugger watch bits (1 per data byte) for data accesses, or wide-mode extension nibbles (2 × 4-bit per pair of instruction slots) for code fetches. Not required to run the eZX primary image — required only for "expanded" eZX primary titles that use genuine wide-mode instructions; see Compatibility-mode and expanded software
Supervisor DeMon — RPi CM4 lite (user-upgradeable to CM5 lite for more RAM / faster compute) + ESP32-C5 for wireless — running AntOS. Connects to the FPGA over 2× HDMI (physically 2× LVDS sets of 4 channels each — display overlay + layer/data stream) + PCIe 1x to the FPGA's serdes interface (also carries hardware debug), plus JTAG and a vsync/VBLANK GPIO input. DeMon's own MIPI output feeds its local 4″ touchscreen, not the FPGA
Control Pulse — ESP32-P4 + 32MB PSRAM — MIPI feed to FPGA carries composer descriptions (highest priority) plus controller/peripheral state; register-window / data-request access to the chipset over an 8-bit OPI bus
Keyboard 8×7 matrix scanned by Clicky — dedicated AVR with on-chip UTF-8 decoding, UART to DeMon. Physical interface uses the standard Sinclair Spectrum column + row ribbon connectors (accepts an original 40-key Sinclair keyboard directly) plus a Spectrum Next keyboard extender for the additional 2 rows (modern 56-key keyboards). Clicky also drives a unified WS2812 chain — DeMon's 8 system status LEDs at the head, followed by the NeoPixel string under the keys — and owns the passive buzzer for system-level audio feedback (boot chime, error beep, optional key click). DeMon sends intent, Clicky handles the bit-bang timing
Joysticks / paddles 4 × DE-9 ports via full Ant64-spec Sticky — supports digital Atari pads, Sega 3-button and 6-button pads, Genesis controllers, and analog paddle pairs via the per-port ADC pins. Far beyond what any real Spectrum offered (max 2 ports on the +2/+3). Port A configurable as I2C; per-port serial TX/RX available. SPI + INT-OUT to Pulse, identical to Ant64 — same chip, same firmware, same controller library across both products. The Ant64's dedicated jog-dial controller (Crank) is not present on the eZX; the keyboard handles menu navigation
Storage MicroSD via DeMon + USB mass storage host
Network WiFi 2.4 + 5GHz via ESP32-C5
Card reader NFC reader
Expansion Three optional expansion mechanisms — see Expansion: SRAM expansion (connector for an optional 36-bit parallel SRAM daughter-board, exposing the FPGA's freed LVDS lanes), DDR3 expansion (204-pin SODIMM slot for the eZX primary showcase image), MIDI/audio expansion (connector for an Ant64-compatible MIDI/audio daughter-board). No separate accelerator expansion — DeMon's CM4/CM5 compute module is the Linux-class compute, user-upgradeable by swapping the module
Display Main HDMI + retro VGA / audio output
FPGA images Three — eZX primary image (eZX mode) at cold boot from the FPGA's own flash; Classic Spectrum and Next-compatible modes loaded by DeMon over JTAG from DeMon's flash on demand

Three FPGA Images

The eZX primary image (eZX mode) is the default — it loads automatically at power-on directly from the FPGA's own QSPI flash chip (the flash that shares the MSPI boot bus with HyperRAM). The Next-compatible and Classic Spectrum images are loaded on demand by DeMon over JTAG (see Image selection); those two bitstreams live in DeMon's flash. The eZX mode bitstream also lives in DeMon's flash as a backup, so DeMon can re-flash the FPGA's own flash if the on-board copy is ever corrupted, and DeMon can reload the FPGA to eZX mode at runtime without a power cycle.

eZX primary image

A clean-slate reimagining of what a Spectrum-lineage machine could be — a few years after the last Spectrum. Not Next-compatible. Its own CPU, chipset, display stack, and audio engine — all eZX-original. See cpu and ezx.

Next-compatible image

Z80N-compatible Spectrum-Next runtime, derived from the official NextNano ZX Spectrum Next FPGA core for the display, audio, sprite, layer, paging, and peripheral subsystems. The CPU is the Z80NG — a clean-room Z80N-compatible CPU with instruction prefetch buffer, μop cache, and unlocked turbo mode. The Z80NG is not derived from any existing Z80N RTL; full ISA compatibility is achieved through independent implementation. The 72-bit DDR3 memory path provides ample bandwidth for full Next compatibility including all sprite, layer, and audio features.

Display capabilities inherited from the upstream Next core: standard ULA, ULANext (256-colour attribute mapping), ULA+ (via NextReg $68 bit 3), Layer 2 (256-colour pixel mode), tilemap mode, hardware sprites, and the Next's hi-res / hi-colour modes — all using the Next's 9-bit RGB palette space (512 colours total, with 256 simultaneous on-screen via the 256-entry palette table).

See Nextgen for the catalogue of eZX-specific improvements to the Next-compatible image that maintain full software compatibility — BSRAM replication for sprite-per-line headroom, 1080p output with integer scaling and optional CRT simulation, HyperRAM-resident ROM/cartridge/disk-image library for instant-access workflows, and hardware debug.

This image is open source. Its microarchitectural improvements are contributed back to the upstream Next project for the team to absorb if they wish.

Hardware debug. The Next-compatible image includes proper hardware debug — breakpoints, watchpoints, single-step, and register access surfaced over the DeMon JTAG path. This makes the eZX a more capable development target for Next-compatible software than a real ZX Spectrum Next, where developers depend on the NMI-driven dezogif workaround. Some developers may prefer to do Z80N work on the eZX for this reason alone.

Classic Spectrum image

Cycle-accurate emulation of the pre-Next Spectrum range. Where the Next-compatible image is a working Next that happens to live on FPGA, the Classic image is a precise replica of the original Sinclair / Amstrad / clone hardware — ULA timing exact to the cycle, contention pattern accurate to the half-T-state, floating bus correct, snow effect reproducible, multicolour and 8×1 attribute tricks pixel-faithful.

What's covered:

  • ZX Spectrum 16K (1982)
  • ZX Spectrum 48K (1982) and Spectrum + (1984)
  • ZX Spectrum 128K (1985)
  • ZX Spectrum +2 (Amstrad, 1986)
  • ZX Spectrum +2A (Amstrad, 1987)
  • ZX Spectrum +3 (Amstrad, 1987 — with emulated 3" floppy via SD-backed .dsk images)
  • Pentagon 128 (the most common Russian clone)
  • Timex Sinclair 2068 / TC2048 (US and Portuguese variants)
  • Didaktik (Czech clone)
  • Scorpion ZS-256 / ZS Turbo+ (Russian extended)

Model selection is a boot-time argument to the AntOS spectrum-mode classic command (see Image selection). Switching between models within the Classic image is a quick FPGA-internal reconfiguration — no full image reload needed — because the difference between, say, 48K and 128K mode is paging logic and ROM contents, not a complete fabric remap.

System RAM in BSRAM, ROM in HyperRAM. The pre-Next Spectrum's ULA-CPU contention pattern is the defining timing behaviour for compatibility with games and demos. Every snow-effect demo, multicolour bar, precise tape loader, and floating-bus trick depends on it being exact, and that exactness applies to system RAM specifically — the area the CPU writes to and the ULA reads from. BSRAM gives synchronous-read deterministic latency with no refresh, no row activation, no burst structure — the same timing model the original SRAM offered. The GW5AST-LV138's 340-block BSRAM tier provides approximately 765 KB of dedicated on-chip RAM, comfortably covering every Spectrum model up to Scorpion ZS-256 (256 KB) with room to spare for line buffers and ULA logic.

ROM has different characteristics: read-only, accessed less frequently than RAM (mostly during system calls and ROM-resident routines), and timing-uncritical at cycle-accurate Z80 clocks (HyperRAM's ~70 ns effective first-byte latency fits comfortably inside a 3.5 MHz Z80 T-state's 285 ns budget). The Classic image therefore puts system RAM in BSRAM for cycle-exact CPU-ULA contention, and ROM in HyperRAM as part of the eZX-wide ROM tier (see HyperRAM (Infineon S70KL1282)) — keeping BSRAM available for chipset state and freeing the ROM data into a bus that doesn't compete with the time-critical RAM and display paths.

CPU: Z80NG in Z80 strict mode. The Classic image reuses the same Z80NG CPU core as the Next-compatible image, configured for Z80 strict mode (Z80N extensions disabled) and BSRAM-backed memory. The Z80NG runs cycle-accurate at the per-model nominal clock (3.5 MHz for 16K/48K/128/+2/+2A/+3/Pentagon/Didaktik, 7 MHz for Scorpion Turbo+, 3.58 MHz for Timex TS2068) — with the same CPU design serving both images and the Spectrum Next compatibility lineage.

See Classic for the full architectural treatment of the Classic Spectrum image — per-model emulation specifics, ULA implementation, ULAplus / Timex hires / Pentagon multicolour, peripheral emulation, storage, and snapshot format support.

Tape and disk. Tape .tap / .tzx / .pzx images and .dsk floppies for the +3 are mounted from SD storage via DeMon and presented to the Classic image as tape and disk peripherals. The tape loader hardware is cycle-accurate too — turbo and protection loaders that depend on edge-precise timing work as on real hardware.

Peripheral emulation. Interface 1 (Microdrive, RS-232, ZX Net), Interface 2 (joystick ports, ROM cartridges), Kempston joystick interface, DivIDE / DivMMC mass storage, ZX Printer, and Currah Microspeech are emulated peripherals in the Classic image — selectable on or off per session via AntOS command-line arguments. Interface 2 cartridge ROM images and Interface 1 ROM live in HyperRAM alongside the system ROM (see HyperRAM (Infineon S70KL1282)) — switching between cartridges is a memory-controller remap, not a data copy, because the HyperRAM holds the entire cartridge library. Physical joysticks plug into the eZX's DE-9 ports via Sticky as usual; the Kempston / Sinclair / Cursor protocol routing is configured at session start.

Enhanced ULA support. The Classic image supports ULAplus, the universal post-2010 enhanced-ULA standard — 64-colour palette mode addressable via I/O ports $BF3B (register select) and $FF3B (data), giving 64 simultaneous on-screen colours from a 256-colour 8-bit RGB (3R + 3G + 2B) palette in place of the original 15. ULAplus is fully backward-compatible: any program that ignores it sees standard Spectrum colours; programs that opt in get a substantial colour upgrade. The mode is toggleable per session — games and demos that depend on the exact original palette can disable it.

ULAplus is also supported in the Next-compatible image (where it's a native Next feature, enabled via NextReg $68 bit 3, with the top 64 entries of the Next's 256-entry palette holding the ULAplus colours). The Classic image brings the same capability to the pre-Next models that never had ULA+ in real hardware — 16K, 48K, 128K, +2, +2A, +3, Pentagon, Didaktik — giving these classic platforms the same enhanced-palette story the Next has.

ULAplus applies on the 48K, 128K, +2, +2A, +3, Pentagon, and Didaktik model entries. The Timex TS2068 and TC2048 entries get the Timex high-resolution modes (mono 512×192 and 8×1 attribute mode) inherent to those machines instead, since those models predate ULAplus and have their own enhanced video paths. The Pentagon entries also get the Pentagon-specific 8×1 multicolour attribute mode (per-scanline attribute changes) supported by various Russian demos. The eZX Classic image is the first hardware platform to combine all three of these enhanced-video flavours — ULAplus, Timex hires, Pentagon multicolour — selectable from one image with cycle-accurate per-model timing.

Image selection

The eZX primary image (eZX Spectrum mode) is the boot default. To switch images, the user runs an AntOS command from the command line, naming the target image. The command instructs DeMon to load the chosen bitstream into the FPGA via JTAG. The change can be applied for the current session, or stored as a persistent default so the next power-on starts in the configured image. Returning between images follows the same path.

> spectrum-mode               # default: eZX primary image
> spectrum-mode next          # switch to Next-compatible image
> spectrum-mode classic 48k   # switch to Classic image, 48K Spectrum model
> spectrum-mode default next  # set Next-compatible as the persistent default

The Classic image takes additional arguments for the emulated model (16K / 48K / 128K / +2 / +2A / +3 / Pentagon / Timex / Didaktik / Scorpion) and optionally per-session peripheral toggles (Interface 1, Interface 2, DivMMC, Kempston, ZX Printer, Microspeech). Defaults are stored in AntOS configuration and applied if not specified.

A graphical / menu-driven launcher is planned for a future AntOS release, where image and model selection happens visually rather than via command line. The underlying mechanism (DeMon JTAG bitstream load) is the same — the menu is a UX layer over the existing command. Command-line access will remain for power users and scripting.


FPGA

The eZX uses a GoWin GW5AST-LV138 — the same FPGA component the Ant64 uses for FireStorm. Same die, same package, same pin count, same 138K LUT4, same 340 BSRAM blocks (~765 KB), same DSPs, PLLs, and hardcells. The eZX deliberately omits the 36-bit parallel SRAM bank from its main board — not because of any pin constraint (there are enough pins; the Ant64's main board fits the SRAM bank into the same component), but as a design choice to keep the eZX architecturally distinct from the Ant64 as a Spectrum-focused machine. The freed pins route instead to the SRAM expansion connector, which can accept an optional 36-bit parallel SRAM daughter-board if a user wants Ant64-class wide-SRAM capability. See Why no parallel SRAM for the full rationale. Everything else is unchanged from FireStorm — same fabric capacity, same memory tier capability, same hardcell roster.

The internal capacity Anthony Ball confirmed for the part:

Resource Capacity
LUT4 138,240
REG (flip-flops) 138,240
Block BSRAM 6,120 Kbit (≈ 765 KB across 340 BSRAM blocks)
Shadow SRAM (SSRAM) up to 1,080 Kbit (≈ 135 KB) — consumes LUT4 budget when used
DSP blocks 298
PLLs 12

The GW5AST-LV138 has two on-chip RAM tiers with different characteristics, and they are not additive in the way a simple "765 KB + 135 KB = 900 KB" reading would suggest:

  • Block BSRAM — the primary tier. Dedicated silicon in columnar blocks throughout the fabric; each block is 18 Kbit. Independent ports A and B with their own clock, address, data, and control signals. Synchronous read and synchronous write (with optional pipeline register for additional read latency). 340 blocks total. This is where line buffers, sprite tables, the prefetch buffer, μop caches, the composer texture cache, and the Classic image's system RAM live.
  • Shadow SRAM (SSRAM) — the secondary tier. LUT-distributed RAM built from the same LUT4 cells the fabric uses for logic; the small RAM primitives (e.g. 16-deep × 2-bit) compose into wider/deeper structures as the design requires. Synchronous write, asynchronous read — reads come out combinationally with no clock latency. Spread throughout the fabric, close to whichever logic needs small storage. Best for things like CPU register files, small FIFOs, pipeline state buffers, per-channel audio state, and small lookup tables that don't justify a full BSRAM block.

The SSRAM ceiling is a trade-off, not free capacity. Every bit of SSRAM in use consumes LUT cells that would otherwise be available for logic. The 1,080 Kbit figure is the maximum achievable if a significant fraction of the LUT4 budget is committed to RAM mode; realistic SSRAM use is much smaller, sized to the immediate needs of the consuming logic and balanced against how much LUT4 capacity the rest of the design needs. The 138K LUT4 headline number and the 1,080 Kbit SSRAM headline number both describe what the silicon could do — they're not both achievable at once.

138K LUT4 is comfortable headroom for everything the eZX Spectrum's images do. The upstream NextNano project demonstrates that a complete ZX Spectrum Next core (Z80N CPU, sprites, layered display, audio, paging, peripherals) fits in a Gowin GW2AR-18 at ~20K LUT4; the Z80NG-based eZX Next-compatible image takes well under that on a 138K part. The eZX primary image's clean-slate CPU and chipset, the Classic Spectrum image's per-model emulation matrix, the composer-receiving block on the eZX primary, the BSRAM-replication scheme for contention-free sprites, the 1080p display pipeline, the debug subsystem — all fit with substantial fabric headroom. The eZX-specific design choices (HyperRAM + optional DDR3 SODIMM, the three-image scope, no Ant64 cartridge port) are scope decisions, not gate-budget pressure.

The hard RISC-V core included in the GW5AST-LV138 SoC variant is available for the same kinds of uses FireStorm makes of it on the Ant64: internal hardware-debug overlay, low-level supervisor tasks that benefit from being inside the FPGA, and any control function where running on a soft core would consume fabric better spent on the rest of the design. The hard core frees the eZX from having to instantiate a soft control CPU just to coordinate the chipset.

The 298 DSP blocks comfortably cover hardware multipliers across all the image scopes (eZX primary's chipset, Z80NG's MUL D,E, the audio mixer's per-voice volume and panning, the BSRAM-replication-multiplied sprite blender, etc.) with room left over. The 12 PLLs support independent clock domains for the DDR3 controller, the FPGA fabric, each display output, each MIPI receiver, the audio subsystem, and the JTAG / debug subsystem without contention.

The target core clock for the FPGA fabric on the eZX images is 380 MHz, set by the GW5AST-LV138's BSRAM fmax (rated to 400+ MHz; 380 MHz delivers ~5% timing-closure margin). This is the architectural ceiling for all images and both image-defined CPUs: anything that uses BSRAM (line buffers, sprite tables, the prefetch buffer, the Z80NG μop cache, the eZX's Xctx context-save, the Classic image's system RAM, the composer texture cache) is bounded by the same clock. The DSP blocks comfortably exceed 400 MHz and standard ALU combinational paths fmax at 380 MHz with reasonable pipelining, so neither logic nor multiplication is the bottleneck. The DDR3 controller runs on its own clock domain at 400 MHz, giving DDR3-800 (800 Mbps per pin) — this is the GW5AST-LV138's maximum supported DDR3 data rate. Clock-domain crossing into the user logic happens through boundary FIFOs.

On-chip BSRAM

The 340-block Block BSRAM tier — 6,120 Kbit (≈ 765 KB) of dedicated, columnar, synchronous-read-and-write on-chip RAM — is where the latency-critical inner-loop storage lives.

Use varies per image. The eZX primary image and Next-compatible image use BSRAM for sprite registers, line buffers, palette storage, character buffers, tile maps, small lookup tables, the per-CPU instruction prefetch buffer, μop cache (Z80NG), debug trace ring (Next-compat only), the composer texture cache (eZX primary), and the eZX's Xctx context-save storage — main system RAM lives in HyperRAM (base configuration) or DDR3 (equipped configuration) and is fed to the CPUs via the prefetch buffer plus speculative memory mechanisms. The Classic Spectrum image goes the other way: it puts the entire system RAM in BSRAM for every supported model up to and including Scorpion ZS-256 (256 KB), which fits comfortably with substantial headroom. The only model that still exceeds the BSRAM tier is Pentagon 1024 (1 MB system RAM), which uses HyperRAM with prefetch. System ROMs live in HyperRAM (see HyperRAM (Infineon S70KL1282)) rather than being copied into BSRAM, which keeps the BSRAM budget focused on the latency-critical RAM working set, line buffers, and ULA logic. DDR3, when fitted, sees minimal use in the Classic image — only supervisor mailboxes and DMA scratch. Exact allocation is image-dependent; no image uses BSRAM for a DDR3 cache.

Per-block width configuration up to 72 bits. Each GoWin BSRAM block is configurable at 1, 2, 4, 8, 9, 16, 18, 32, 36, or 72 bits per word. The bit budget is fixed (18 Kbit per block) but the addressable shape varies: at 8-bit width a block is 2.25 KB byte-addressable; at 72-bit width it is 256 words × 72 bits each. The FPGA image author picks per-block. Blocks configured at 72-bit width carry 8 metadata bits per word alongside the 64 data bits. On the eZX primary image these wider blocks are used for chipset state that benefits from wider word access (sprite tables, audio mixer voice records, blitter source/destination indirection metadata) and for CPU data buffers where per-byte debugger watch-bit visibility is wanted — the same watch-bit semantics that apply to DDR3 (see Watch bits). BSRAM does not host CPU code on the eZX primary image: ~765 KB total budget is fully claimed by prefetch buffers, sprite/line/palette state, audio mixer voices, Xctx context-save storage, debug trace ring, and the other latency-critical inner state; there isn't enough residue to host application code. Wide-mode CPU code therefore lives in the DDR3 SODIMM when fitted (the practical wide-mode tier on the eZX). The Classic and Next-compatible images use BSRAM differently — they put simulated Z80 system RAM in BSRAM, configured at the widths that match the simulated system's natural byte addressing.

SSRAM use is more scattered and image-author-determined: CPU architectural register files (the EE's 32-GPR/32-FPR register file, extended to 64/64 in wide mode — see EE; Z80NG's main+shadow Z80 register set widened to 32-bit), pipeline state buffers in the composer's display-list resolver, small per-channel state in the audio subsystem (AY register shadows, ADSR phase counters, mixer per-voice state), per-stage FIFOs in the chipset's scanline pipeline, and small colour-conversion / palette-index translation lookup tables. The cost is paid out of the LUT4 budget each time, so SSRAM lands where the storage is too small to justify a BSRAM block and where the design can afford the LUT consumption.

Watch bits

72-bit memory (DDR3 SODIMM and 72-bit-configured BSRAM blocks) carries 1 watch bit per data byte in the upper 8 bits of each 72-bit word. The watch bits are an architectural debug primitive accessible to the M-mode debug subsystem and to the FPGA-image hardware debug logic.

Scope: watch bits are a CPU-data-path concept. The EE's data load/store unit routes the upper 8 bits of every 72-bit-memory word to the debug subsystem as watch bits, with the lower 64 bits going to the register file as data. The FPGA chipset hardware (audio mixer, blitter, composer engine, display scanout, DMA channels) is different — those subsystems read the same 72-bit memory as flat 72-bit data, treating all 72 bits as a single wide data word. No watch-bit interpretation, no extension-nibble interpretation; the chipset's view of DDR3 is just "9 bytes per word" or "72-bit-wide texture / sample / framebuffer storage." This is why the chipset can drive 7.2 GB/s peak DDR3 bandwidth (full 72 bits as data) while the CPU's user-data view sees 6.4 GB/s peak (the 8 metadata bits are the watch bits, not user data).

The practical consequence: memory regions used exclusively by the chipset (composer texture pool, audio sample banks, framebuffer storage, blitter source/destination indirection) use the full 72-bit width with no metadata overhead — they're storing more data per word, not paying any cost for the metadata bits. Memory regions accessed by both the CPU (with watch-bit visibility) and the chipset (as flat data) — typically CPU-prepared content that the chipset later consumes — work without conflict: the FPGA image author allocates such regions with the upper 8 bits cleared by CPU writes (the typical case), and the chipset reads them as data with the upper 8 bits being zero. If the debugger sets watch bits on a region that the chipset later reads, those bits appear in the chipset's data word — but typical workflows partition regions cleanly between debug-watched CPU data and chipset-fed data, avoiding this case.

Semantics for CPU data accesses:

  • Every byte of 72-bit memory has its own watch bit. When the watch bit is 0, the byte is unwatched and accesses to it behave as ordinary memory operations. When the watch bit is 1, the byte is watched and any CPU access (load, store, or instruction fetch of any byte within the same 72-bit word) raises a debug trap that hands control to the debugger
  • Watch bits are set and cleared by the debug subsystem, not by user code. The standard load and store instructions cannot read or write watch bits; CSR-level debug instructions and external-debug-port access do
  • A single 72-bit word's 8 watch bits can be set/cleared independently — a single byte can be watched without affecting its 7 neighbours. The granularity is genuinely 1 byte
  • The watch state is preserved across reads — reading a byte does not clear its watch bit. The bit is a sticky marker, not a one-shot flag

Capacity: every byte of every 72-bit memory region can be watched simultaneously. On a fully-DDR3-equipped 4 GB eZX, the debugger has 4 G watch bits available, each independently settable. This is dramatically more granular than the typical hardware-debug architecture's 4–8 dedicated watchpoint registers; with watch bits, the question "watch this 1 KB region" becomes a 1 KB bitmap write, not "I need 1024 watchpoint registers."

Use cases:

  • Persistent variable watching. Mark a struct field watched once; the debugger gets notified on every subsequent read or write without re-arming
  • Region tripwires. Mark an entire memory region as forbidden (e.g., guard pages, stack-overflow detection, sentinel canaries) — any access trips the debugger
  • Coverage / hot-spot profiling. Set all bits in a region; track which bytes get touched over a run by the debugger reading the cleared bits afterwards (debugger clears as it goes)
  • Read-only enforcement. Set watch bits on a region; configure the debug handler to treat watched-byte writes as a fault while letting watched-byte reads through silently
  • Self-tracing JIT. Set watch on the JIT output buffer; the debugger logs the first execution of each freshly-emitted instruction for verification

The watch-bit mechanism is hardware-only — neither the user-mode program nor M-mode supervisor code can intentionally read the watch bits as data. Reads of the user-data portion of a watched byte raise the debug trap before the data is returned to the CPU.

See the eZX debug subsystem documentation (currently in the eZX primary image's debug system section) for the full debug-handler protocol, the watch-bit access CSRs, and the interaction with the external JTAG debug port.


Memory

The eZX has a three-tier memory hierarchy with a configurable top tier:

Tier Capacity Location Always present?
BSRAM ~765 KB (340 blocks) On-chip, inside the GW5AST-LV138 Yes
HyperRAM 16 MB (Infineon S70KL1282) Soldered to the board Yes
DDR3 SODIMM 1 / 2 / 4 GB user-addressable data supported (theoretical max 8 GB; 8 GB address-space reserved). 8 metadata bits per 72-bit word for debugger watch bits and wide-mode extension nibbles User-installable SODIMM slot Optional

The base eZX configuration ships without DDR3 — the SODIMM slot is empty. HyperRAM is the primary system-memory tier in this configuration, with BSRAM holding everything that needs single-cycle access (video memory, sprite tables, line buffers, system RAM on the Classic image, the CPU prefetch buffers). The base configuration supports the entire Spectrum-lineage software corpus including every Classic Spectrum model and the Next-compatible image at every clock from cycle-accurate 28 MHz through unlocked turbo — plus the eZX primary image itself, running compatibility-mode titles that share code, graphics, and sound across HyperRAM (see Compatibility-mode and expanded software). For users who want expanded eZX primary titles, or want compatibility-mode titles to get more asset room and faster code automatically, a DDR3 SODIMM upgrade plugs into the slot and unlocks both.

Memory part. The eZX is committed to the Infineon S70KL1282 — a 128 Mb (16 MB) HyperRAM in the 3.0V grade, dual-die stacked, 24-ball FBGA, with HyperBus interface running at 200 MHz DDR for 400 MB/s sustained bandwidth. The silicon's intrinsic first-byte access time is 35 ns (tACC max), but because the part is dual-die stacked, it is forced into fixed 2× latency mode — the chip can't predict which die might be refreshing at any given moment, so the host conservatively allows a refresh window on every access. The effective first-byte access time is therefore 70 ns (14 clocks × 5 ns at 200 MHz, the default latency setting), not the 35 ns of a single-die part.

The two configurations

Configuration What's installed What runs
Base BSRAM + 16 MB HyperRAM, no DDR3 SODIMM Classic Spectrum (every model including Pentagon 1024), Next-compatible at every clock (cycle-accurate 28 MHz, all turbo modes including unlocked turbo), and the eZX primary image running compatibility-mode titles (code, graphics, and sound sharing HyperRAM)
DDR3-equipped BSRAM + 16 MB HyperRAM + DDR3 SODIMM (72-bit ECC module, 1 / 2 / 4 GB user data plus 8 metadata bits per word for watch-bits and wide-mode extension nibbles) The above, with compatibility-mode titles automatically getting more asset room and faster code, plus expanded eZX primary titles that require genuine wide-mode CPU features

The hardware doesn't care which configuration is present — the chipset's memory controller detects whether DDR3 is installed at boot. The base configuration is fully usable as a complete Spectrum-lineage machine with every Classic model, the Next at every speed, and eZX primary compatibility-mode titles; the DDR3-equipped configuration adds expanded eZX primary titles and gives compatibility-mode titles more room and speed.

Why HyperRAM works for every Z80N mode

The Z80NG's prefetch buffer combined with HyperRAM's 70 ns effective first-byte latency (35 ns intrinsic × 2 from the dual-die fixed-latency mode — see HyperRAM (Infineon S70KL1282)) means all Next-compatible clocks from 3.5 MHz through 380 MHz unlocked turbo run from HyperRAM in the base configuration. The arithmetic:

Clock T-state 3-T mem cycle First-byte penalty on prefetch miss
3.5–14 MHz (Classic models) 286–71 ns 857–214 ns 0 (fits in cycle)
28 MHz (Next cycle-accurate) 35.7 ns 107 ns 0 (70 ns fits in 107 ns cycle)
56 MHz turbo 17.9 ns 53.6 ns ~1 T-state
112 MHz turbo 8.9 ns 26.8 ns ~5 T-states
224 MHz turbo 4.5 ns 13.4 ns ~13 T-states
380 MHz unlocked turbo 2.6 ns 7.9 ns ~24 T-states

The penalty figures are per prefetch-window miss, not per memory cycle. The Z80NG's instruction prefetch buffer (~2 KB window with PC in the middle) combined with the μop cache means most fetches are window-hits or μop-cache-hits with zero HyperRAM access. Typical sequential code paths see 30–50 cycles between misses, so even at 380 MHz unlocked turbo the amortised penalty is small. The μop cache filters hot loops entirely out of the HyperRAM access path. After a miss, the first byte arrives at 70 ns and subsequent bytes stream at 2.5 ns/byte (400 MB/s), so the prefetch window refills rapidly. Turbo modes never promised cycle-accurate timing; what they promise is "as fast as the FPGA can run the Z80NG", and that's exactly what HyperRAM delivers.

Empirical confirmation: the Tang Nano 20K runs the upstream NextNano core at full 28 MHz from 32-bit SDRAM at 166 MHz SDR with neither cache nor prefetch buffer. HyperRAM at 70 ns first-byte with the Z80NG's prefetch + μop cache is comfortably more capable.

Pentagon 1024 fits trivially. Pentagon 1024's 1 MB system RAM is well inside the 16 MB HyperRAM tier, and its native 3.5 MHz Z80 clock has 286 ns per T-state — HyperRAM's 70 ns first byte is invisible at this speed (less than a quarter of a single T-state). Pentagon 1024 runs in the base configuration without DDR3.

Why BSRAM holds video memory in the base configuration

The eZX's 765 KB BSRAM tier easily holds the entire Next video subsystem master copy without help from external memory:

Region Size
ULA pixel data 6 KB
ULA attribute data 768 B
Layer 2 framebuffer (256×192×8bpp) 48 KB
Layer 2 hi-res (320×256×4bpp) 40 KB
Layer 2 hi-color (640×256×4bpp) 80 KB
Sprite pattern memory 16 KB
Sprite attribute table 1 KB
Tilemap index + attribute 3 KB
Palette RAM (all banks) 2 KB
Subtotal — master copies ~197 KB
BSRAM replication (4× on contention-prone blocks) ~110 KB
Total video subsystem BSRAM ~307 KB

That's about 40% of the 765 KB BSRAM tier for the entire video subsystem, master copies and replicas together. The remaining ~460 KB BSRAM covers Z80NG (μop cache, prefetch buffer, register file), line buffers, debug trace, audio FIFOs, AY register state, and the rest of the chipset state — with comfortable headroom remaining.

A concrete win this gives over a real Spectrum Next: on the Next, video memory and system RAM come from the same 2 MB SRAM pool, so software using Layer 2 hi-res (80 KB) loses 80 KB from its system RAM budget. On the eZX in either configuration, video memory is in BSRAM and system RAM is in HyperRAM (base) or DDR3 (equipped) — they don't share a pool, and software has the full system RAM budget regardless of which Layer 2 mode is active. All Layer 2 modes can be simultaneously resident in BSRAM; mode switches just change which BSRAM region the display engine reads from.

DDR3 SODIMM details

The DDR3 SODIMM slot is the eZX's DDR3 expansion — one of the four optional user-installable expansion mechanisms. When installed, the SODIMM is a standard 204-pin DDR3 ECC SODIMM running at DDR3-800 (400 MHz controller clock, 800 Mbps per pin) — DDR3-800 is the GW5AST-LV138's maximum supported DDR3 data rate, not a hedged working figure.

The eZX prefers a 72-bit DDR3 ECC SODIMM in the 1R x8 / 9-chip organisationsingle-rank (full module capacity reachable), x8 chip width (each DRAM chip exposes 8 data bits), 9 chips total (8 data chips × 8 bits + 1 chip carrying the extra 8 bits, also at x8 width = 72 bits combined). This is the standard ECC SODIMM layout — typical workstation / refurbished-server DDR3 ECC SODIMMs use exactly this organisation.

2R x8 / 18-chip dual-rank SODIMMs also fit and work — both chip-select lines are wired on the board, but the FPGA's DDR3 controller IP drives only one CS, so only the first rank is reachable. Users who install a 2R x8 module will see half the labelled capacity as usable: a 4 GB dual-rank module presents as 2 GB usable, a 2 GB as 1 GB. AntOS reads the JEDEC SPD at boot and warns the user if a dual-rank module is detected, naming the actual usable capacity.

The eZX is incompatible with non-ECC 64-bit SODIMMs (no 9th chip, no 72-bit bus) and x4 chip organisations (rare in SODIMMs, more common in registered DIMMs — the controller is configured for x8 chip width).

All 72 bits are used as RAM, not as 64-bit data plus 8-bit parity. The 9th chip on a standard ECC SODIMM carries 8 bits per word that the typical workstation memory controller computes and verifies as Hamming-code ECC syndromes. The eZX's controller does no such ECC calculation — it treats the 9th chip's 8 bits per word as straight RAM storage, identical in nature to the bits stored in the other 8 chips. The 8 extra bits per word are physically stored, transferred, read, and written the same as the 64 data bits; they are repurposed at the logical level for eZX-specific roles (per-byte debugger watch bits on CPU data accesses, wide-mode extension nibbles on CPU instruction fetches; flat 72-bit data for the FPGA chipset hardware) but are full RAM storage at the electrical level.

Usable data capacity matches the labelled module capacity (1 GB labelled → 1 GB user-addressable data; 2 GB → 2 GB; 4 GB → 4 GB). The metadata bits are not user-addressable data through the standard load/store path — they are dedicated to the eZX's debug and CPU subsystems (see below). Users buy the SODIMM separately and install it themselves; the connector and routing layout follow JEDEC's DDR3 SODIMM standard so any compliant 1R x8 72-bit ECC module works.

Supported capacities: 1 / 2 / 4 GB. Address space reservation: 8 GB. The theoretical ceiling for a single-rank DDR3 ECC SODIMM at JEDEC's DDR3 chip-density maximum (8 Gbit per chip × 9 chips for 64-bit data + 8-bit metadata) is 8 GB labelled. The eZX reserves 8 GB of address space for the DDR3 region in its memory map; only 1 / 2 / 4 GB capacities are software-supported. SPD detection at boot determines the actual installed capacity and configures the controller and runtime memory map accordingly; capacities outside the supported set (8 GB modules, the rare 16 Gbit-chip 16 GB modules) probe as the supported subset their address decoder can reach, with the unused upper portion left dark.

The 8 metadata bits per 72-bit word do double duty depending on how the CPU accesses the word:

  • Data load / store treats the word as 8 data bytes + 8 watch bits, 1 watch bit per byte. The watch bits are a per-byte hardware debug primitive: when the CPU touches a byte whose watch bit is set, the debug subsystem is notified — see Watch bits for the full semantics. Every byte of DDR3 (and 72-bit BSRAM, §On-chip BSRAM) can be individually watched without consuming a separate watchpoint-register slot
  • Instruction fetch treats the word as 2 × 36-bit instruction slots, each carrying one standard 32-bit RV64 instruction plus a 4-bit extension nibble. The nibble extends the register file (32→64 GPRs), widens immediates (12→14 bit and 20→23 bit), and reserves one bit as the per-instruction predication-enable that gates the Xcond extension. This is the same wide-mode mechanism the Ant64's FireStorm uses — see EE § Memory Architecture and Mode Selection and EE § 32-bit Instructions in Wide Mode for the full architecture

Same physical bits, two software interpretations. The hardware doesn't switch state between them — every access type sees the same word, just routed differently in the CPU pipeline.

The 72-bit organisation versus a hypothetical 64-bit non-ECC SODIMM costs ~0.5–1× the unit price (ECC SODIMMs are more niche), and gives: (a) per-byte memory watching for the entire DDR3 capacity without dedicated watchpoint hardware, and (b) wide-mode CPU access to extended registers, wider immediates, and Xcond predication for any code placed in DDR3. The data capacity and data bandwidth are the same 8/9 = ~89% of the 72-bit raw memory throughput. Net effect: the same data-tier story as DDR3-800 ×64, plus two architectural features that depend on the metadata bits.

Rank constraint: first rank only. Both chip-select lines (CS0#, CS1#) are wired on the eZX board to the SODIMM slot, so dual-rank modules will physically fit and electrically pass detection. The FPGA controller IP drives only CS0#, so only the first rank is reachable; the second rank's address space is invisible — half the labelled capacity is unusable on a dual-rank module. A 4 GB rank-2 module presents as 2 GB usable; a 2 GB rank-2 module presents as 1 GB usable. Users buying SODIMMs should choose single-rank ECC modules to get the full labelled capacity. The standard JEDEC SPD (Serial Presence Detect) data on every SODIMM reports rank count, so AntOS reads this at boot and warns the user if a dual-rank module is installed, naming the actual usable capacity.

Sourcing. DDR3 ECC SODIMMs are less common than non-ECC SODIMMs in the consumer market, but they remain widely available in the workstation, refurbished-server, and prosumer-laptop channels. DDR3-1600 ECC SODIMMs (and faster) are typical and work perfectly when run at the eZX's DDR3-800 — the same underclocking-for-better-timing story applies as for any DDR3 module. A standard DDR3-1600 ECC module typically has 11-11-11 timing at native speed (CL / tRCD / tRP each 11 × 1.25 ns = 13.75 ns absolute). At the eZX's 400 MHz controller clock (2.5 ns per cycle), the same module's 13.75 ns absolute timing requires only 6 cycles worth of controller state-machine setup — a tractable low cycle count that simplifies the controller logic. Absolute access latency on a fast underclocked module is at-worst equivalent to native DDR3-800 silicon (5-5-5 = 12.5 ns) and is often better than budget DDR3-800 modules (6-6-6 = 15 ns). The "buy any cheap DDR3-1600 ECC SODIMM" story therefore strikes the right balance for the eZX: the wider 72-bit bus carries the eZX-specific watch-bit and wide-mode metadata at no cost to data capacity or bandwidth versus a 64-bit non-ECC equivalent, at the price of slightly higher unit cost and slightly less plentiful retail availability. Single-rank is the constraint to watch — laptop SODIMMs are typically available in both rank configurations, with rank-1 modules dominating at 1 GB and 2 GB capacities and being the safer default at 4 GB too.

A real Spectrum Next has 1–2 MB of SRAM. A 4 GB SODIMM gives 4 GB user-addressable data — 2,000–4,000× more memory than a real Next has, and even a 1 GB SODIMM at 1 GB usable is 500–1,000× more. For the eZX primary showcase image's workloads (game-class assets, large compiled-content, multi-MB save states, asset preload caches), this is the right tier — the chipset's composer texture pool, blitter source/destination indirection, and 1080p scanout bandwidth all benefit from DDR3's GB/s-class sustained throughput.

Prototype hardware note. Early prototype eZX boards have run with 16-bit or 32-bit DDR3 during board bring-up before the final 72-bit SODIMM-equipped configuration is characterized. This is a hardware-revision detail, not an architectural change: the FPGA images, CPU pipelines, prefetch buffers, write FIFOs, and software interfaces work identically on narrower buses — only the available memory bandwidth scales with width, and the metadata bits (watch bits / wide-mode nibbles) require the 72-bit production bus. A 16-bit prototype delivers ~1.6 GB/s peak data; a 32-bit prototype delivers ~3.2 GB/s peak; the final 72-bit production bus delivers ~6.4 GB/s peak data plus ~0.8 GB/s of metadata traffic (7.2 GB/s combined). Watch-bit and wide-mode operation are unavailable on narrower prototypes — they require the metadata bits the 72-bit production bus carries.

Bandwidth

Base configuration (no DDR3 SODIMM): the working set lives in BSRAM and HyperRAM.

  • BSRAM: at 380 MHz × 64-bit per port × many ports = multi-GB/s per port, single-cycle deterministic. Carries video memory reads, sprite pattern fetches, palette lookups, line buffer writes — the high-frequency inner-loop traffic
  • HyperRAM: 400 MB/s sustained at 200 MHz DDR, 70 ns effective first-byte (35 ns intrinsic × 2 from dual-die fixed-latency). Carries Z80N system RAM access (~5–10 MB/s typical at 28 MHz, up to ~75 MB/s peak at 224 MHz turbo), ROM reads, tape/disk image streaming, asset preload — sequential or near-sequential bulk traffic
  • Combined, the base configuration has comfortable headroom for every Spectrum-lineage workload at every clock

DDR3-equipped configuration: the above tiers stay in place, plus DDR3 SODIMM adds wide-bus bandwidth for the eZX primary image at DDR3-800 (the GW5AST-LV138's maximum supported DDR3 data rate):

  • FPGA chipset hardware (audio mixer, blitter, composer, display scanout, DMA channels) sees DDR3 as flat 72-bit data, with no metadata interpretation: 7.2 GB/s peak, ~4.5–5.6 GB/s sustained after refresh and command overhead. This is the data bandwidth available to the composer texture pool, audio sample streaming, framebuffer scanout, and blitter source/destination indirection
  • CPU data accesses route the upper 8 bits per word to the watch-bit logic and see 6.4 GB/s peak user-data, ~4–5 GB/s sustained — the same 8/9 fraction of the raw bandwidth
  • CPU instruction fetches in wide mode route the upper bits as extension nibbles, delivering 16 instructions per BL8 burst in either narrow or wide mode (the wide-mode instruction is denser in encoding but the same instruction-count-per-burst)

The chipset bandwidth headroom is the key win: 7.2 GB/s sustained against the chipset's typical demand (composer texture fills at 1080p60, audio mixer at 128+ voices, framebuffer scanout) leaves comfortable margin for the CPU's lower-rate DDR3 access without contention.

This is far in excess of what the eZX primary image needs at the CPU level, leaving headroom for display scanout, blitter and copper traffic, audio DMA, and the composer texture cache fills.

DDR3 carries the eZX primary image's composer texture pool reads, blitter traffic, audio mixer state, the chipset's bitmap layers at 1080p, and the EE's prefetch refills.

Per-image memory architecture

Classic Spectrum image — every model runs in the base configuration.

System RAM lives in BSRAM (single-cycle, ULA-contention-accurate) for every model up to and including Scorpion ZS-256 (256 KB). For Pentagon 1024 (1 MB), system RAM lives in HyperRAM with the Z80NG's prefetch buffer hiding the 70 ns effective first-byte latency — Pentagon 1024's native 3.5 MHz Z80 clock is comfortable on HyperRAM. System ROM lives in HyperRAM for every model. DDR3 is not needed and not used for any Classic Spectrum model.

Next-compatible image — full Next compatibility plus every turbo mode in the base configuration.

Video memory subsystem lives in BSRAM (master copies plus contention-free replicas — see Why BSRAM holds video memory in the base configuration above). System RAM lives in HyperRAM, with the Z80NG prefetch buffer hiding the 70 ns effective first-byte latency. At cycle-accurate 28 MHz mode, software is timing-identical to a real Spectrum Next; turbo modes (56 MHz through unlocked 380 MHz) run with the prefetch buffer absorbing most miss penalties — typical code paths see negligible turbo-mode slowdown vs an ideal-memory machine.

eZX primary image — runs in the base configuration; DDR3 is what separates compatibility-mode titles from expanded titles, not what gates the image itself.

The eZX primary image boots and runs on the base configuration exactly as the Classic and Next-compatible images do — it does not probe for DDR3 at boot and does not refuse to launch without it. What DDR3 gates is individual software titles, not the image as a whole, via the compatibility-mode/expanded split below.

DDR3's chipset-level performance case still holds regardless of title category: the composer texture pool, blitter, audio mixer per-voice state, and bitmap layer scanout at 1080p all benefit from DDR3's GB/s-class bandwidth, well beyond HyperRAM's ~400 MB/s sustained. What's not yet pinned down is whether the chipset's own native rendering (independent of any title's code/asset split) also degrades gracefully on the base configuration — for example, whether 1080p scanout or the full sprite/layer count is available without DDR3, or whether the base configuration runs the chipset at a reduced resolution or feature set. That's a question about the chipset's own scaling, separate from the compatibility-mode/expanded split described below, which is specifically about how a title's code and assets scale.

Compatibility-mode and expanded software

eZX primary titles fall into two categories, distinguished by whether their compiled code ever uses a genuine (non-zero) wide-mode extension nibble:

  • Compatibility-mode titles — code, graphics, and sound all share HyperRAM. These run on the base configuration with no DDR3 required, and automatically get faster and roomier if the user later fits a DDR3 SODIMM — same binary, no recompilation, no separate build.
  • Expanded titles — use genuine wide-mode instructions (extended register file, wider immediates, predication). These require DDR3 and will not run on the base configuration at all — there's no way to fake real wide-mode encoding on HyperRAM.

How compatibility mode works. HyperRAM is 16 MB. On the base configuration, it's split into two address-mapped halves:

  • First half (8 MB) — code, mapped at the low end of the wide-tier address range (where DDR3 would normally sit). The memory controller serves this address range from HyperRAM instead, decoding it via the wide-mode fetch path: each 32-bit instruction is assembled from two 16-bit HyperRAM reads, with the extension nibble bits — which would come from a wide memory's extra per-byte bit — hardwired to zero, since HyperRAM has no such bits to provide. A zero nibble is architecturally defined as functionally identical to standard narrow encoding (no register extension, no immediate widening, predication disabled), so code placed here runs correctly regardless of whether the backing memory is real wide-tier hardware or this HyperRAM emulation
  • Second half (8 MB) — audio/graphics, mapped in the normal narrow HyperRAM address range, available for asset data

A compatibility-mode title is therefore compiled once, with its code always emitting zero-nibble (narrow-equivalent) instructions, placed at the fixed wide-tier code address. The same binary, at the same address, runs unmodified whether or not DDR3 is fitted:

  • Without DDR3: code executes from the HyperRAM-backed first half (8 MB available for code); assets get the second half (8 MB)
  • With DDR3 fitted: code moves transparently to real DDR3 — still zero-nibble, still narrow-equivalent, just backed by faster and larger genuine wide-tier memory instead of the HyperRAM emulation. Because code no longer needs any of HyperRAM, the entire 16 MB of HyperRAM becomes available for audio/graphics — double the asset room, with no code changes

This is a pure capacity-and-speed upgrade, not a mode switch the title has to implement — the memory controller does the work of re-routing the wide-tier code address from HyperRAM to DDR3 when a SODIMM is detected at boot. A compatibility-mode title that wants to take advantage of the extra asset room when it's available can probe for DDR3 presence (via the same detection the EE's mxwide/mxfeatures CSRs expose — see ee_cpu) and choose to load more assets; a title that doesn't bother still runs correctly either way, just without using the extra headroom.

Expanded titles don't have this graceful-degradation path. Any code that emits a genuine non-zero-nibble wide-mode instruction — to name an extended register, use a widened immediate, or predicate an operation — requires the instruction to actually be fetched from real wide-tier memory with real nibble bits available. HyperRAM's emulated wide-tier region can only ever supply zero, so an expanded title simply won't decode correctly there. These titles are unavailable on the base configuration; DDR3 is a hard prerequisite for running them at all, not a performance upgrade.

The unifying point: the eZX's three-tier memory architecture lets each image use the right tier for its workload. The Classic and Next-compatible images live in BSRAM + HyperRAM (no DDR3 needed at any clock); the eZX primary image lives across all three tiers with the heaviest reliance on DDR3. The base configuration ships ready for the open-source Spectrum-lineage corpus in its entirety; the SODIMM upgrade unlocks the closed-source showcase.

What runs on the eZX CPU

AntOS does not run on the EE. AntOS is the supervisor operating system on DeMon's CM4/CM5 Compute Module — it runs the Luau interpreter, executes user scripts on DeMon, drives USB / SD / WiFi / NFC, hosts the file system, services telnet/FTP, and brokers the FPGA image change-over via JTAG. The EE running inside the eZX FPGA is a separate processor with its own role and its own software stack. See cpu for the full CPU-integration picture; the EE itself is the same core Ant64's FireStorm runs — see EE.

What runs on the EE:

  • User code — the primary workload. Applications, libraries, language runtimes, games, demos. Compiled for RV64GC plus whichever EE extensions the toolchain targets (Xcrisp, Xmath, Xstack, Xlate, Xctx, Xez always available; Xwide/Xcond wherever wide-tier memory — DDR3, or the SRAM expansion when fitted — is available)
  • A small debugger / mini-OS living in the FPGA's flash chip mapped into the EE's address space. The flash chip is the same physical device that holds the FPGA bitstreams (it shares the MSPI boot bus with HyperRAM — see Bus topology — 12 signals shared with flash); the EE sees it as a memory-mapped read-only region from which the mini-OS executes. The mini-OS provides:
    • Boot-time setup — clearing memory, initialising CSRs, setting trap vectors, transferring control to the user's _start
    • Trap and debug handling — breakpoints, watchpoints (driven by the watch bits on wide-tier memory), single-step, register inspection, memory inspection, mode switching between wide and narrow code
    • A syscall / mailbox interface to AntOS — when user code needs file I/O, network access, or any service AntOS provides, it traps into the mini-OS, which forwards the request to AntOS over the supervisor channel (the FPGA's mailbox/FIFO regions, reached from DeMon over its HDMI and PCIe/serdes links — see Supervisor ↔ FPGA interconnect). Replies come back via the same path. From the user-code side, file I/O looks like a normal syscall; the path under the hood is "user → mini-OS → mailbox → DeMon → AntOS → SD / network / etc → back through the same chain"
    • Configuration of the EE's image-specific facilities — Xctx pool initialisation, Xstack base address, default Xlate slot mapping, default xcarry state

The mini-OS is small (a few KB), executable directly from flash without copying to RAM, and provides the minimum that user code needs to exist as a portable RISC-V program on the eZX. It does not provide a full OS — there is no process model, no shell, no file system in the mini-OS itself; those live in AntOS on DeMon and are accessed via mailbox. The split keeps the EE's software stack thin and focused on user computation, with the heavyweight services centralised on the supervisor side where their power is already paid for.

When this document or any of the per-image documentation says "code runs on the eZX CPU" or "on the EE", it means user code plus the mini-OS — both narrow-mode (RV64GC plus the base extension set) and optionally wide-mode (in wide-tier memory). When it says "AntOS does X", that's the supervisor side, on DeMon, not on the EE.

DDR3 access strategy

No image uses a DDR3 cache. The eZX in the eZX primary image hides DDR3 latency in three ways: a windowed instruction prefetch buffer on the fetch side, speculative load run-ahead on the data read side, and a small write FIFO on the store side. BSRAM stays free for sprite registers, line buffers, palette storage, character buffers, the Classic image's system RAM, the Next-compat image's video memory, context-save storage, debug trace, and the prefetch buffers themselves — never tied up as cache storage.

The 72-bit DDR3 bus with BL8 burst (8 × 72 bits = 72 bytes per burst, of which 64 bytes are data and 8 bytes are metadata) is well-matched to this strategy: one DDR3 burst fills 16 instructions in a single transaction — equivalently, 16 wide-mode 36-bit slots, since each 72-bit word contains 2 × 36-bit slots = 2 × 32-bit instructions in narrow mode or 2 wide-mode instructions in wide mode. The write FIFO coalesces sequential stores into the same burst structure on the way back out, amortising address/setup overhead across the full transaction.

eZX primary image — EE prefetch buffer plus speculative load run-ahead plus write FIFO. The EE at 380 MHz uses a windowed byte buffer occupying one full BSRAM block (~2 KB) with PC positioned in the middle, pre-fetching forward from DDR3 in 64-byte BL8 bursts while retaining recently-fetched bytes behind the current PC. Sequential execution sees no DDR3 latency. A typical function fits entirely within the window — every backward branch within it (loops, retries, error paths) and short forward branch (conditional skips) is free — the read pointer just moves within the existing valid byte range. Only branches that land outside the window's address range trigger a refetch, costing one DDR3 round-trip (~50 ns). Data-side reads use speculative load run-ahead from the decode stage; data-side writes go through a 16–32-entry write FIFO that coalesces into BL8 bursts on the way to DDR3 and is snoopable from the read path for read-after-write hazards. Combined with Xcrisp's auto-increment loads/stores and block-memory ops, this absorbs almost all DDR3 latency from the CPU's pipeline without the cost of a full cache. See EE § Instruction Fetch and Prefetch Buffers for the shared EE mechanism.

Code and data on different buses

The eZX's memory tiers are physically independent buses — BSRAM is on-chip with per-block ports (multiple ports per block, dual-port BRAMs), HyperRAM rides the HyperBus, and DDR3 (when fitted) rides its own dedicated 72-bit controller. Each bus can be in use simultaneously without arbitration between them. The performance-relevant consequence: code fetches and data accesses on different buses see zero contention. A CPU running its inner loop from one tier while reading data from another has both ports/buses fully available; both transactions complete in parallel.

The realistic placement story on the eZX, given BSRAM's ~765 KB total budget across all its uses:

  • Most code lives in HyperRAM. HyperRAM has 16 MB always present, comfortably covering user-program code, user libraries, language runtimes, and any non-tight-inner-loop workload. The prefetch buffer hides the 70 ns first-byte latency on sequential paths; window-resident branches are free
  • Most data also lives in HyperRAM in the base configuration (no DDR3). User-program working sets, file-system buffers (data landed from AntOS over the supervisor channel), network buffers, asset caches — anything that doesn't need DDR3's bandwidth fits comfortably in HyperRAM's 16 MB. Speculative load run-ahead and the write FIFO hide the per-access latency
  • BSRAM holds the latency-critical inner state: prefetch buffers, line buffers, sprite tables, palette storage, the Classic image's system RAM, audio mixer per-voice state, Xctx context-save storage, debug trace ring, and the μop cache (Z80NG). On the eZX primary image, BSRAM is not used for CPU code — the budget is fully claimed by chipset and CPU inner state, and there isn't enough residue to host application code
  • DDR3 (when fitted) extends both code and data into the GB-class application tier: bulk asset stores, composer texture pool, large working sets, wide-mode CPU code (the practical wide-mode tier on the eZX), audio sample banks at full quality

The performance contract: code in HyperRAM + data in BSRAM = no contention (HyperBus and BSRAM ports are independent). Code in HyperRAM + data in DDR3 = no contention (HyperBus and DDR3 controller are independent). Wide-mode code in DDR3 + data in HyperRAM or BSRAM = no contention either, and the kernel benefits from extended registers, wider immediates, and Xcond predication. The pathological case is code and data both in the same off-chip tier — code and data both in HyperRAM, or code and data both in DDR3 — where the prefetch buffer + write FIFO + speculative load run-ahead combination still hides most of the contention, but the bus is shared bandwidth.

For wide-mode kernels that benefit from the register-pressure relief or predication (audio DSP at full sample-rate, real-time blitter feeders, high-rate parser inner loops), placing wide-mode code in DDR3 and bulk data in DDR3 is the typical pattern, with smaller working data in BSRAM or HyperRAM keeping the buses separated where possible.

This is the same lesson Ant64's FireStorm carries: code and data on different buses gives the highest sustained throughput. The eZX delivers the equivalent benefit through HyperRAM and DDR3 as the two off-chip code-or-data buses; BSRAM serves the inner-state role separately, and the chipset hardware's concurrent flows (composer texture pool in DDR3, audio mixer voices in 72-bit BSRAM, blitter source in DDR3, line buffers in BSRAM) ride independent paths.

The same contention-free principle applies to chipset hardware. The composer texture pool in DDR3, the audio mixer's per-voice state in BSRAM, the blitter source buffer in DDR3, the audio sample streams in HyperRAM, and the line buffers in BSRAM — these are concurrent flows on independent buses. The 7.2 GB/s of chipset-visible DDR3 bandwidth, the 400 MB/s of HyperRAM bandwidth, and the BSRAM tier's multi-GB/s per-port bandwidth combined comfortably saturate the chipset's worst-case demand.

HyperRAM access strategy

HyperRAM is the realistic main code-and-data tier on the eZX. BSRAM is finite (~765 KB total across all uses — sprite registers, line buffers, palette storage, prefetch buffers, context-save storage, the Classic image's system RAM, audio mixer state — typical residue for general code or data is small), so most application code lives in HyperRAM, and most application data lives in HyperRAM in the base configuration. DDR3 (when fitted) extends both, but HyperRAM remains the always-present tier that every image relies on.

Z80NG fetch path. The Z80NG's HyperRAM access path uses the windowed prefetch buffer mechanism: one full BSRAM block (~2 KB) holding bytes around PC, with PC in the middle. Most Z80 function bodies fit entirely within the window, so backward branches (the DJNZ / JR NZ loop idiom) and short forward branches are both free of HyperRAM access cost. Sequential execution streams from HyperRAM at 400 MB/s into the prefetch window; branches that miss the window pay one HyperRAM first-byte (~70 ns effective on the dual-die part) then the same streaming rate. The μop cache further filters memory accesses on hot loops — many tight loops execute entirely from BSRAM, with HyperRAM untouched.

EE fetch path. The EE uses the same windowed prefetch buffer mechanism for HyperRAM-resident code. Functions in HyperRAM benefit identically: the ~2 KB window holds ~512 instructions, a typical compiled C function fits entirely, and backward / short-forward branches within it are free of memory access cost. Sequential execution streams from HyperRAM at 400 MB/s; the prefetch buffer hides the 70 ns first-byte latency for window misses. For most application-class code, HyperRAM is the natural fetch tier — comfortable bandwidth, 16 MB of capacity, no DDR3 SODIMM dependency. The EE at 380 MHz does outrun HyperRAM's per-byte streaming rate on a pathological worst-case tight loop straddling window edges, but the prefetch buffer + speculative load run-ahead combination keeps amortised throughput comfortably high for realistic code paths.

EE data path. Data loads and stores to HyperRAM use the same speculative load run-ahead and write FIFO that serve DDR3 data accesses. The write FIFO coalesces sequential stores into HyperBus bursts on the way out; the speculative load issues reads as soon as the address is known, hiding the 70 ns first-byte for cases where the result isn't immediately needed. HyperRAM data accesses don't contend with HyperRAM code fetches in the typical case because the prefetch buffer absorbs sequential code reads — most cycles execute code from the buffer's BSRAM port without touching HyperBus, leaving HyperBus available for data transactions. When code and data both miss the prefetch window simultaneously, HyperBus arbitrates between them — but this is rare in realistic workloads. HyperRAM is narrow-mode-only for code (HyperBus has no metadata bits, so wide-mode encoding can't live there), but data loads and stores work exactly the same as in any other tier.

At cycle-accurate 28 MHz on the Next-compatible image, the rendezvous mechanism enforces Z80-visible timing while the underlying HyperRAM access path runs at full FPGA speed — software is bit-identical and timing-identical to a real Spectrum Next. At turbo modes, the rendezvous is dropped and the CPU runs at the full FPGA clock; HyperRAM stalls on prefetch-window misses (per the table earlier in this section) are typically tiny in amortised terms due to the prefetch + μop cache combination.

HyperRAM (Infineon S70KL1282)

The eZX board carries an Infineon S70KL1282 — 16 MB HyperRAM in the 3.0V grade. Concretely: 128 Mb total capacity (two stacked 64 Mb dice), HyperBus interface, 200 MHz DDR clock for 400 MB/s sustained bandwidth, 35 ns maximum first-byte access time (tACC), 24-ball FBGA package at 6 × 8 × 1.0 mm, 38-nm DRAM process technology, industrial temperature grade (-40°C to +85°C). The 3.0V grade is chosen specifically because it operates at the same voltage as the bitstream flash and the FPGA's MSPI bank — no LDO and no separate voltage rail. The 1.8V grade (S70KS1282) is an alternative if the FPGA's MSPI bank moves to 1.8V; both grades support the same 200 MHz / 400 MB/s figure.

Bus topology — 12 signals shared with flash. HyperBus is a low-pin-count interface: clock + chip select + 8-bit data bus + bidirectional read-write data strobe + hardware reset. Combined with the flash on the same MSPI bus (sharing the clock and lower 4 data pins), the total FPGA pin count for the boot bus is:

Pin Owner Role
CK Shared Bus clock — 200 MHz DDR for HyperRAM transactions, lower rate for QSPI flash
DQ0DQ3 Shared Data lines used by flash in 4-bit QSPI mode, and by HyperRAM as the lower half of its 8-bit DDR bus
DQ4DQ7 HyperRAM only Upper half of the HyperRAM 8-bit DDR data bus (unused by flash)
RWDS HyperRAM only Bidirectional read-write data strobe — read data strobe on reads, write data mask on writes, refresh-pending indicator during CA phase
HyperRAM_CS# HyperRAM only Asserted when accessing HyperRAM
flash_CS# Flash only Asserted when accessing flash
RESET# HyperRAM only Hardware reset for HyperRAM

That's 12 pins total. The S70KL1282 also offers an optional differential clock (CK + CK#) variant and a DCARS variant with phase-shifted read strobe (PSC/PSC#) for higher-speed signal integrity, but the eZX uses the standard single-ended clock variant — at 200 MHz on a short PCB trace, single-ended signalling has comfortable timing margin. The simpler bus topology saves an FPGA pin.

Self-refresh — transparent to the host. HyperRAM has internal DRAM cells that need periodic refresh, but the refresh logic is on-chip and the host (FPGA) never has to issue refresh commands. The chip indicates a refresh-in-progress condition by asserting RWDS HIGH at the start of a transaction, which the host honours by inserting an additional initial latency. The FPGA's HyperRAM controller handles this automatically. The array refresh interval is 64 ms at 85°C (the eZX's industrial-grade operating ceiling), with the chip distributing refresh operations transparently across that interval.

Burst length constraint. Because individual DRAM rows can't refresh during an active transaction, the host must end each burst within the chip select LOW maximum time (tCSM = 4 µs at 85°C, 1 µs at 105°C) — the chip's internal refresh scheduler needs this gap to insert distributed refreshes. At 400 MB/s, 4 µs translates to ~1600 bytes per burst (worst-case at industrial temperature). The FPGA HyperRAM controller breaks longer transfers into chained bursts with brief CS# pauses between them; software is unaware of this. For the Z80NG prefetch buffer (~2 KB window) and most CPU access patterns, this limit is essentially never reached in practice — bursts naturally end at branch points well inside the 1600-byte budget.

Power. 60 mA active read/write at 200 MHz; 750 µA standby (full array refresh, 105°C, 3.0V); 250 µA deep power down (data lost) or 480 µA hybrid sleep (data retained). Far lower power than DDR3. The chip supports two software-selectable low-power modes that AntOS can use during idle periods (e.g., paused game state, deep idle) without losing the working memory contents — Hybrid Sleep retains the full 16 MB at the cost of ~480 µA.

Performance characteristics. At 200 MHz DDR on the 8-bit bus, the device delivers 400 MB/s sustained bandwidth with 70 ns effective first-byte access time on the dual-die part (silicon tACC max = 35 ns per die, doubled because the dual-die stack runs in fixed 2× latency mode). A 64-byte transfer takes ~228 ns (70 ns first-byte + 63 × 2.5 ns), a 1 KB sequential read takes ~2.6 µs, a maximum-burst 1600-byte transfer takes ~4 µs. The chip supports linear burst (default), wrapped burst (16/32/64/128 byte groups for critical-word-first cache line fills), and hybrid burst (wrap once then continue linear) — the FPGA HyperRAM controller uses linear bursts for sequential CPU/asset traffic and wrapped bursts for branch-target fills into the Z80NG prefetch buffer.

Flash and HyperRAM are mutually exclusive at any instant — only one chip select is asserted at a time, and the other chip's pads sit in tri-state. Flash drives only DQ0DQ3 in QSPI mode; HyperRAM drives DQ0DQ7 plus RWDS in HyperBus mode. The shared CK + DQ0DQ3 lines see whichever protocol is active. The DQ2 / DQ3 lines double as the flash's WP# / HOLD# pins in 1-bit SPI mode; both chips are operated in their higher-bus-width modes where those pins are pure data lines.

At power-on, the HyperRAM CS# is held high by a pull-up resistor, so the FPGA's hard configuration block sees only the flash and loads its bitstream deterministically — the HyperRAM cannot interfere with cold boot. Once the FPGA is configured, those MSPI pins become user-controllable GPIO, and the running design owns the bus. In normal operation of the Classic, Next-compatible, and eZX primary images, the design holds the bus in HyperBus mode continuouslyflash_CS# is deasserted, HyperRAM_CS# is asserted as needed, the bus drives the 8-bit HyperBus DDR protocol with RWDS. Flash is never accessed from inside a running image; the only consumer of flash data is the FPGA's hard configuration block at boot time, and image-switching (which loads a different bitstream from flash) is initiated externally by DeMon over JTAG, not by the running image.

This simplifies the FPGA-side bus controller substantially: no flash↔HyperRAM mode switching during normal operation, no protocol arbitration. The design only ever issues HyperBus DDR transactions while running; the QSPI flash protocol is dormant. The design just needs to be aware of the bus (control both CS# lines, drive the lines correctly when issuing HyperRAM transactions) — it doesn't need to multiplex between two active protocols.

Capacity is fixed by the part. The S70KL1282 is the largest 3V HyperRAM in Infineon's current catalogue at 16 MB. 16 MB is generous headroom for the ROM tier and bulk staging uses described below.

Performance vs other memory tiers. Compared to DDR3 (~50 ns first-byte latency at DDR3-800, 4–5 GB/s sustained) and SD (50–100 µs random, 5–20 MB/s sequential), HyperRAM's 70 ns first-byte and 400 MB/s sustained put it genuinely between the two tiers — close to DDR3's latency class (slightly slower but the same order of magnitude), making it a credible ROM-execution surface, not just a staging buffer.

HyperRAM is uncached. The use cases are sequential bulk transfers (asset preload, snapshot save/restore, ROM execution, tape buffering) where the 400 MB/s burst speed is already comfortably above any workload's demand. A BSRAM cache in front of HyperRAM would mostly miss on first access and pay duplicate storage cost on bulk data — net negative. The BSRAM budget is better spent on line buffers, sprite tables, the Classic image's system RAM, the eZX's instruction prefetch buffer, debug trace, and context-save storage. Random HyperRAM access patterns (DivMMC sector cache) are served by software-level caching in DDR3 on equipped systems, or directly from HyperRAM on base systems where the latency is still well inside Z80 access budgets.

Bus independence. The HyperBus is completely independent of the DDR3 path. Display scanout, blitter traffic, audio DMA, and CPU fetch on DDR3 see zero contention from HyperRAM access. The eZX has three architecturally-independent memory tiers, each on its own bus: BSRAM (single-cycle on-die, ≤ 5 ns latency, used for line buffers, sprite tables, the Classic image's system RAM, the eZX and Z80NG instruction prefetch buffers, context-save storage, and debug trace), HyperRAM (400 MB/s burst, 70 ns first-byte, used for ROM tier, base-configuration system RAM, bulk staging, and SD-cache duty), and DDR3 on equipped systems (high-bandwidth wide bus, 4–5 GB/s sustained at ~50 ns latency — fed to the CPUs via the per-image latency-hiding mechanisms documented in DDR3 access strategy). Workloads partition across all three without arbitration tax.

Primary use: ROM tier for the simulated systems. The eZX uses HyperRAM as the ROM storage tier for every simulated system — OS ROMs, system ROMs, game cartridge images, NextZXOS, +3DOS, DivMMC firmware, esxDOS, the lot. Each image's memory controller maps the relevant ROM-range addresses to HyperRAM offsets; from the simulated CPU's perspective the ROM is just there at the addresses it expects. This is the right tier for ROMs for four reasons:

  1. Bus parallelism. ROM reads happen on the HyperBus and do not consume DDR3 bandwidth (on equipped systems) or contend with anything else. The Z80NG can be fetching code from a ROM bank while the chipset is streaming a frame buffer from DDR3 and the blitter is operating on BSRAM. Three independent buses, no arbitration tax
  2. Latency fit for the workload. HyperRAM's 70 ns effective first-byte latency comfortably fits within a 3.5 MHz Z80 T-state (285 ns) and is hidden by the prefetch buffer at higher CPU clocks. ROM is read sequentially most of the time (boot code, interrupt handlers, system routines), and sequential HyperRAM reads run at 400 MB/s = 2.5 ns per byte — well under any T-state budget
  3. Frees BSRAM. The Classic Spectrum image's BSRAM budget now serves only the simulated system's RAM, not RAM + ROM. The largest covered model (Scorpion ZS-256 with 256 KB RAM) fits in ~128 BRAM blocks instead of the ~144 blocks RAM+ROM would have needed — meaningful headroom for line buffers, sprite tables, and other latency-critical chipset state
  4. Frees DDR3 bandwidth on equipped systems. On the Next-compatible image with DDR3 installed, DDR3 holds only RAM banks; ROM banks redirect to HyperRAM. NextZXOS, the Spectrum 48K ROM, the +2 grey ROM, the +3 ROM with disk, and any user-loaded alternative ROM are all in HyperRAM, leaving DDR3 to serve the RAM banks at full bandwidth

16 MB of HyperRAM is generous headroom for ROM duty: every published Spectrum-lineage ROM ever shipped (across all models, regions, and revisions) plus a curated cartridge library plus the Next's full alternative-ROM collection fits in a few hundred KB, leaving roughly 15 MB free. That margin is what makes ambitious secondary uses (full-instruction debug trace ring spanning seconds of execution, dozens of snapshot slots, multi-MB tape and disk image preloads, real-time asset streaming for the eZX primary image) viable simultaneously without contention or eviction. The 400 MB/s bandwidth gives equally substantial headroom for those uses on the bus side.

Secondary uses:

  • Tape and disk image buffering. .tap / .tzx / .pzx tape images and .dsk floppies are loaded from SD into HyperRAM at session start and presented to the Classic / Next-compat images as virtual cassette / disk hardware. Far quicker than streaming from SD — allows seamless multi-load tape sequences, instant disk-side flips, and game-loader compatibility with edge-precise timing
  • SD-asset preload cache. NextZXOS file I/O is fast by Z80 standards but slow by modern standards; multi-megabyte games can take seconds to load. AntOS stages anticipated game data into HyperRAM at image-launch time (when the user runs the AntOS command to start the Next-compatible image), and the Next-compat image presents it to NextZXOS at HyperRAM-fast access speeds rather than SD-slow. Multi-level games and assets-heavy demos load near-instantly
  • DivMMC / SD-card image working set. Frequently-accessed sectors of the mounted SD image are cached in HyperRAM, accelerating mass-storage workloads (NextZXOS dot commands, esxDOS volume operations) without changing the cycle-accurate memory model of the simulated system
  • Hardware debug trace ring. The Next-compatible image's cycle-accurate hardware debug subsystem (breakpoints, watchpoints, single-step, register inspection over DeMon JTAG) writes a continuous trace into HyperRAM. With 400 MB/s available, full-instruction tracing is now feasible (Next CPU at ~5 MIPS × ~10 bytes per record = ~50 MB/s, comfortably within the 400 MB/s budget) — every retired Z80 instruction can be timestamped and logged, not just branches. On breakpoint hit or crash, the host debugger reads back the last several seconds of execution from HyperRAM via DeMon for full post-mortem reconstruction
  • Snapshot / quick-save ring. A hotkey freezes the running image, dumps the entire simulated-system state (RAM + sprites + Layer 2 + palette + ULA mode + Z80NG register file + AY state) into a HyperRAM slot, and resumes. Another hotkey restores. Multiple snapshot slots support save-before-tricky-section gameplay. Modern emulators have this; the eZX brings it to hardware. At 400 MB/s, even a 1 MB snapshot save/restore completes in under 4 ms
  • eZX primary image asset cache. Cache for the chipset's audio sample banks, tile data, font ROM lookups, and other bulk read-mostly content. At 400 MB/s the cache is fast enough to be on the active rendering path, not just a staging buffer
  • Alternate boot source. DeMon can stage an alternative bitstream into HyperRAM via the running design and re-trigger FPGA configuration with the HyperRAM as the boot source. Useful for development and field updates where you want to test a new bitstream without overwriting the known-good copy in flash. Cold boot still always uses flash by default

The use-case mix is bandwidth-friendly: ROM reads are mostly sequential (covered by prefetch); tape / disk / asset caches are bulk transfers; snapshot save/restore is single-shot. Random access from a single source (e.g., DivMMC sector lookup) is rare enough that the 70 ns first-byte latency is acceptable. The HyperRAM never sees the pathological "random access at full CPU rate" pattern that would saturate the bus, and the 400 MB/s ceiling means even adding new bandwidth-hungry uses (full-instruction debug trace, real-time asset streaming) doesn't require a redesign.

Why no parallel SRAM

The Ant64 includes a wide-mode 36-bit parallel SRAM bank for latency-sensitive workloads. The eZX deliberately doesn't carry this over to the base machine — a design choice rather than a constraint. The FPGA component is the same as Ant64's FireStorm (same die, same package, same pin count); the pins for a 36-bit parallel SRAM bank are available on the eZX board just as they are on the Ant64 board. But adding the SRAM on the eZX's main board would make the eZX architecturally almost identical to the Ant64, undermining the distinct identity of the two machines — Ant64 is the general-purpose home computer with the full multi-tier memory hierarchy including the latency-critical wide SRAM; the eZX is a Spectrum-focused machine with its own scope and price point. Keeping the SRAM off the main board preserves the architectural separation.

Instead, those pins are routed to a SRAM expansion connector on the eZX board, designed to accept an optional 36-bit-wide parallel SRAM daughter-board. Users who want Ant64-class wide-SRAM capability can install the daughter-board; the stock eZX runs without one. The expansion connector ships on the board; the daughter-board is currently parked for future official or community design. The pin map, signal voltages, address-range mapping, and FPGA-side controller are intended to match Ant64's SRAM tier so that wide-SRAM-aware software ports without changes once the board is installed.

The FPGA images released for the base machine are therefore designed around HyperRAM (base) plus optional DDR3 plus on-chip BSRAM for the latency-critical inner loops — image authors trade absolute access latency for a simpler memory hierarchy than the Ant64's. The HyperRAM fills the "fast and plentiful" tier where DDR3 would be overkill and BSRAM would be too small. The 340-block BSRAM tier (~765 KB) gives substantial low-latency capacity for the inner loops, supplemented by LUT-distributed SSRAM for small per-stage state (see On-chip BSRAM for the tier distinction); the 72-bit DDR3 covers everything else when fitted.


CPUs

The eZX hosts two soft CPUs across its FPGA images.

Image CPU Notes
Next-compatible Z80NG Clean-room Z80N-compatible CPU; cycle-accurate at 28 MHz or unlocked turbo
eZX primary eZX 32-bit RISC-V base + custom instructions for Z80 ergonomics
Classic Spectrum Z80NG Same Z80NG core in Z80 strict mode with BSRAM-backed memory; cycle-accurate at per-model nominal clock

The eZX CPU is specified in cpu. The Z80NG is specified in z80ng — it is a clean-room reimplementation of the Z80 / Z80N CPU specifically, not derived from the NextNano Z80 / Z80N CPU implementation. The rest of the Next FPGA core (display, audio, sprites, layers, paging, peripherals) is used as-is in the Next-compatible image under its existing licence.


Display

All three images drive the same physical display outputs:

  • Main HDMI output
  • Retro VGA / audio output for CRT-compatible displays

The display mode set and layer model differ between images. The Next-compatible image presents the Next display stack faithfully. The eZX primary image presents its own display stack — see ezx.


Audio

Audio mixing is performed in FPGA fabric and routed to a WM8960 stereo codec driving the HDMI audio path and the retro analogue audio output. Each FPGA image presents its own audio model:

  • The Next-compatible image presents the Next audio model — beeper, AY/YM via TurboSound, and SpecDrum.
  • The eZX primary image presents its own audio engine — see ezx.

MIDI

USB MIDI is supported by the eZX primary and Next-compatible images via DeMon's USB stack — not by the Classic Spectrum image, which has no native MIDI hardware to expose. Hardware DIN MIDI (In, Out, Thru) is provided through the MIDI/audio expansion daughter-board — see MIDI/audio expansion below and Expansion for the unified expansion overview.


Connectivity

USB

USB host via DeMon. Supports keyboards, mice, gamepads, mass storage, and USB MIDI devices.

NFC card reader

An NFC reader is fitted to the board, supporting MIFARE Classic and NTAG216 cards. Cards carry game data, save states, and user identity. Card behaviour is image-defined.

WiFi

WiFi 2.4 + 5GHz via the ESP32-C5 inside DeMon. Used by AntOS for network services and by the running FPGA image for any network-aware software.

MIDI/audio expansion

The MIDI/audio expansion connector is mechanically and electrically identical to the Ant64 MIDI/audio expansion connector. MIDI/audio expansion daughter-boards — including the Ant64C-style DIN MIDI In/Out/Thru board, and any analogue-audio variants — are physically interchangeable between eZX and Ant64. See Expansion § MIDI/audio expansion for the unified expansion overview.


Supervisor and control

The eZX uses the same DeMon and Pulse processors as the Ant64:

  • DeMon — CM4 lite (user-upgradeable to CM5 lite) + ESP32-C5, runs AntOS, handles FPGA configuration via JTAG, USB host, SD card, WiFi, NFC reader, OSD, and host debugging. AntOS includes a Luau scripting layer for user code, command-line tools, telnet/FTP services, and a DBFS-backed filesystem. DeMon is a busy general-purpose supervisor — multi-tasked, branchy, executing user scripts alongside AntOS internal tasks
  • Pulse — ESP32-P4 + 32MB PSRAM, handles MIDI events, the music sequencer, control surfaces, and any task DeMon delegates. Pulse runs an RTOS with a fixed set of dedicated tasks — no user scripts, no general-purpose execution model — and specialises in sustained, high-throughput streaming to the FPGA

These subsystems carry over from Ant64 with the following constraints on the eZX:

  • The eZX CPU is the same FireStorm EE, not a separate soft core — earlier eZX documentation specified a standalone RV32 core with its own parallel extension set; that's retired. The eZX primary image now runs the identical RV64GC EE that Ant64's FireStorm runs, including the full Xcrisp / Xstack / Xcond / Xlate / Xctx / Xmath / Xez extension stack and wide mode. See cpu for the eZX-board-specific integration and EE for the shared CPU architecture. What differs from FireStorm is the chipset around that CPU (the eZX's own Spectrum-lineage display/audio/sprite engine, not FireStorm's Amiga-derived one) and the memory configuration (no on-board 36-bit SRAM by default), not the CPU itself
  • No wide-mode 36-bit SRAM bank on the base machine — Ant64 has a wide parallel SRAM bank on its main board; the eZX deliberately doesn't, even though the FPGA pin count is identical (same FPGA component as Ant64's). Keeping the SRAM off the base board preserves the eZX's distinct identity as a Spectrum-focused machine. The pins instead route to the SRAM expansion connector — an optional daughter-board can plug in to add the wide-SRAM tier (currently parked / not shipping). DDR3 (when fitted) is the only wide-bus memory on the base machine; HyperRAM is the only other off-chip RAM. See Why no parallel SRAM
  • No cartridge port — FPGA images are fixed in flash and selected at boot

The eZX Spectrum uses the same FPGA component as the Ant64 — identical die, package, pin count, fabric, BSRAM, DSP, PLL, and hardcell capacity (138K LUT4, 340 BSRAM blocks / ~765 KB, plus 1080 Kbit SSRAM, 298 DSPs, 12 PLLs, hard RISC-V core, MIPI / USB HS / QSPI / JTAG hardcells). There is no structural difference at the FPGA level. The eZX primary image's chipset is therefore not constrained by silicon budget relative to FireStorm — it differs from FireStorm in scope (Spectrum-lineage focus) and in deliberate design choices about which external buses to build in versus expose via connector (no on-board 36-bit SRAM bank — see SRAM expansion — and no cartridge port), not in fabric availability. The constraints above are deliberate architectural choices for a Spectrum-focused machine, not pin or gate-budget pressure.

With those constraints in mind, see ant64.com for the shared subsystem detail.

Supervisor ↔ FPGA interconnect

DeMon and Pulse connect to the eZX FPGA very differently from each other — the two supervisors are no longer symmetric in how they reach the chipset. Pulse's connectivity matches how it reaches FireStorm on the Ant64 (same physical link, same protocol). DeMon's does not: DeMon moved from an ESP32-P4 to a Raspberry Pi Compute Module, and its FPGA connectivity moved with it.

Link DeMon Pulse Direction Role
HDMI ×2 Two HDMI outputs to the FPGA DeMon → FPGA Physically 2× LVDS sets of 4 channels each (the standard TMDS-pair physical layer HDMI uses — 3 data pairs + 1 clock pair per link). One HDMI carries display overlay content, the other carries a layer/data stream — video-encoded composer and supervisor data rather than a finished framebuffer. Replaces DeMon's earlier MIPI DSI uplink entirely
PCIe 1x PCIe 1x to the FPGA's serdes interface Bidirectional Hardware debug access across the FPGA design, and the general-purpose high-bandwidth link between DeMon and the chipset. The exact split of which traffic classes ride HDMI versus PCIe is still settling
MIPI uplink MIPI DSI TX, all lanes (2 data lanes + clock) Pulse → FPGA Pulse connects every MIPI TX lane it has to the FPGA's MIPI RX hardcell — the full native lane count, unreduced. (DeMon no longer occupies a MIPI RX hardcell at all, since its link moved to HDMI + PCIe, so there's no lane-budget pressure on Pulse's side either.) Carries composer descriptions (text cell grids, tilemap index maps, sprite display lists; highest priority) and audio buffers (AMY-synthesized voices, tracker engines, classic synth emulators), plus controller/peripheral state at lower priority
OPI bus 8-bit-wide SPI2, register window + interrupt-driven data request Bidirectional Pulse's register-window and control-plane path to the chipset, parallel to MIPI — small packets, register accesses, audio parameter writes. Also the mechanism Pulse uses to request data back from Tempest (the chipset's audio engine): an interrupt line lets either side signal the other when it has something to request, rather than a dedicated always-on return link
JTAG Master DeMon → FPGA FPGA bitstream programming. Only DeMon has JTAG to the FPGA; separate from the PCIe/serdes debug link
System vsync Input (VBLANK GPIO) Input FPGA → Supervisors Frame sync broadcast — both supervisors pace their description/audio streams to this signal. The FPGA is the genlock master; the supervisors follow

DeMon no longer has a return-path bus of its own in the old sense — no MIPI, no dedicated USB-HS link, no QSPI-with-interrupt. Its connectivity is HDMI (outbound, display/layer data) and PCIe/serdes (bidirectional, debug plus general chipset traffic), with JTAG and vsync as before. DeMon's HS USB OTG is fully committed to its internal storage hub (D:, D!:, E:, B:) and its FS USB OTG to its HID hub — neither carries any FPGA traffic.

Pulse's return path is the OPI bus, not USB. Pulse's two USB OTG controllers are both committed to MIDI 2.0 roles — HS as MIDI 2.0 host (external instruments/controllers), FS as MIDI 2.0 device (the machine presenting as a MIDI device to a computer) — so neither is available for FPGA traffic. Pulse pulls data back from Tempest over the same SPI2 OPI bus it uses for register writes, using the interrupt line to signal requests in either direction rather than a dedicated streaming return link.

Why the asymmetry? DeMon's role changed fundamentally with the CM4/CM5 move — it's now a full Linux host with a GPU, and the natural way for a Linux host with HDMI/PCIe capability to feed a display compositor is exactly that: HDMI for pixels/layers, PCIe for everything else. Pulse's role hasn't changed — it's still a dedicated RTOS-based streamer with no general-purpose OS, and MIPI + a control-plane SPI bus remains the right fit for a fixed, real-time task set. The two supervisors were never required to use identical interconnects; they were symmetric before mostly by coincidence (both being ESP32-P4-based), and that coincidence no longer holds now that DeMon is a different class of device.

The composer contract is unchanged despite the plumbing change underneath: DeMon still maintains scene state and emits per-frame layer descriptions rather than finished pixels — those descriptions now ride inside the HDMI layer/data stream instead of MIPI, but the compositor-side contract (descriptions in, chipset renders at scanout) is the same. See Composer integration below.

Composer integration

DeMon and Pulse use the same composer contract with the eZX FPGA that they use with the Ant64's FireStorm — descriptions in, chipset renders at scanout, never a finished framebuffer from either supervisor. The physical path differs now (DeMon's descriptions ride the HDMI layer/data stream; Pulse's still ride MIPI), but neither supervisor cares which FPGA or which physical link is downstream — they maintain scene state in their own memory and emit per-frame display list descriptions (text cell grids, tilemap index maps, sprite display lists), frame-locked to the FPGA's system vsync. Both supervisors can emit the full set of description types; differentiation between text-only and full composer support is at the FPGA-image side, not at the supervisor side. The eZX FPGA is the genlock master for the eZX Spectrum, in the same role FireStorm plays for the Ant64.

Differentiated support across the three images. The composer-receiving interface is implemented in full only on the eZX primary image, with the Next-compatible and Classic Spectrum images implementing a text-cell subset. The primary reason is licensing: the Next-compatible and Classic Spectrum images are open source (NextNano upstream + Z80NG; see Open source where it makes sense on the home page), and the full composer-receiving RTL — sprite display-list resolver, tilemap engine, the 4bpp 16×16 texture pool, the genlock master function — is closed-source IP that travels with the eZX primary chipset. The text-cell receiver is small and simple enough to ship openly with the open-source images; the rest stays inside the closed eZX primary image. Architecturally the subset is also a happy fit for the two open-source images — neither needs more than text to do what it does — but the licensing split is the driver:

  • eZX primaryfull composer-receiving interface (closed source). Accepts all three description types (text cell grid, tilemap index map, sprite display list) and composites them as overlay layers on top of the eZX chipset's native content. Uses the shared 4bpp 16×16 texture pool with 16 palette banks × 16 entries (index 0 = colour key), the display-list resolver, and the composite-at-scanout pipeline. This is the same contract FireStorm implements on the Ant64 — sprites and tiles authored for the Ant64 work unchanged on the eZX primary image, and vice versa
  • Next-compatibletext-only subset (open source). Accepts the text cell grid description only, sufficient for AntOS UI overlays. The text-cell receiver is a small open-source block; the Next-compatible image's sprite, tilemap, layer, and pixel rendering are NextNano-upstream territory anyway, so the subset isn't an architectural compromise — adding parallel composer-driven sprites/tilemaps would duplicate functionality that already exists in NextNano and consume BSRAM that's needed for the contention-free sprite engine (see nextgen § Sprites per line, contention-free)
  • Classic Spectrumtext-only subset (open source). Same scope as Next-compatible. The Classic image is bit-exact pre-Next Spectrum emulation; the original Spectrum hardware had no sprite or tilemap engines, so there is no native compositing context to merge composer-driven sprites into. The text-only subset gives AntOS the same overlay capability the other images get without intruding on the cycle-accurate ULA path or consuming BSRAM that's needed for the largest emulated model's system RAM (up to ~114 blocks for Scorpion ZS-256)

What runs on the text-only channel. The text cell grid is the platform's standard sys_text_cell_t × cols × rows format (4 bytes/cell). A full 64×30 grid is ~7.5 KB; dirty-cell streaming drops most frames to a few hundred bytes; FireStorm-style on-FPGA glyph rendering pulls characters from a small font ROM at scanout, with cell size, glyph tiling, and the font all FPGA-side concerns rather than supervisor-side concerns. See the Ant64's AntOS Text Architecture for the shared specification — same document for the eZX Spectrum implementation.

Practical implications:

  • AntOS UI works consistently across all three images — same DeMon-driven text channel, same overlay behaviour, same font and styling. The user's experience switching between images is uniform from the AntOS UI side
  • Cross-platform asset portability for sprites and tiles applies only to the eZX primary image. Spectrum-Next-compatible software that uses NextNano sprite memory observes the Next's own sprite format; Classic Spectrum software doesn't have hardware sprites at all. Composer-driven sprite assets that ride the shared 4bpp 16×16 contract are an eZX-primary-image story
  • Pulse's role on the eZX Spectrum is therefore concentrated on the eZX primary image — that's where Pulse's display lists for music sequencer UI, secondary debug HUDs, and control-surface visualisation actually composite. On Next-compatible and Classic images, Pulse can still contribute a text cell grid to RX #1 alongside DeMon's RX #0 feed, but the richer description types (tilemap, sprite display list) aren't accepted
  • BSRAM budget on the smaller images is preserved. The Next-compatible image's BSRAM-replication scheme for contention-free sprites stays inside its allocation (~45 blocks); the Classic image's system-RAM-in-BSRAM allocation for Scorpion ZS-256 stays inside its allocation (~114 blocks). The text-only composer subset is small enough to fit alongside both

The architectural payoff: every eZX Spectrum FPGA image inherits AntOS UI compositing through the same DeMon-driven text-cell channel, while only the showcase image (eZX primary) commits BSRAM and FPGA-side logic to the full sprite-and-tilemap composer pipeline that the Ant64's FireStorm runs.


Boot

The boot sequence is straightforward:

  1. Power-on. The FPGA's hard configuration block reads the bitstream from the QSPI flash (HyperRAM CS# pulled high so flash wins the shared bus) and loads the eZX primary image by default. This is the FPGA's standard cold-boot path; no external supervisor is involved.
  2. DeMon boots AntOS on its CM4/CM5 Compute Module. AntOS comes up on DeMon's own processor, separate from the eZX FPGA core.
  3. The user interacts with AntOS via the eZX-board keyboard, with display output rendered through the running FPGA image (the eZX primary image by default). The keyboard input path goes through Clicky over UART2 to DeMon, which surfaces it to AntOS; joystick / paddle input goes through Sticky to Pulse and onward to AntOS or the running image. The display output path renders through the active FPGA image to the HDMI / RGB outputs.
  4. From AntOS the user can switch images with the spectrum-mode command (see Image selection). The command triggers DeMon to load a different bitstream over JTAG, replacing the running image. The currently-active image is replaced, the new image is loaded, and the user's session continues with the new chipset and CPU configuration.

The eZX primary image is the boot default for three reasons:

  • It's the showcase machine — what the eZX is for
  • It supports the AntOS interaction layer natively without compatibility constraints
  • The other two images (Next-compatible, Classic Spectrum) are explicitly switched into for specific tasks (running Next software, running pre-Next Spectrum software) rather than being the default day-to-day environment

A graphical / menu-driven launcher is planned for a future AntOS release — image and model selection will happen visually rather than via command line. The underlying mechanism (DeMon JTAG bitstream load) stays the same.

Cold-boot bus topology

The FPGA's MSPI configuration bus is shared between two chips — the QSPI NOR flash holding the bitstream, and the HyperRAM. At power-on the HyperRAM's CS# is held high by a pull-up, so the FPGA's hard configuration block sees only flash and loads its bitstream deterministically in 4-bit QSPI mode. The HyperRAM is invisible to the boot process and cannot interfere with cold boot — a bricked-HyperRAM scenario can never prevent the FPGA from configuring. Once the bitstream loads and the configured design starts running, the bus is held in HyperBus mode continuously — flash is dormant during normal operation, with flash_CS# deasserted; the only consumer of flash data is the FPGA's hard configuration block at boot, and image-switching (loading a different bitstream from flash) is initiated externally by DeMon over JTAG, not by the running image. See Memory § HyperRAM (Infineon S70KL1282) for the use cases and the full pin breakdown.


Hardware debug

The three FPGA images have different debug stories at this stage of the project.

The Next-compatible image includes a full hardware debug subsystem — breakpoints, watchpoints, single-step, and register inspection — surfaced over the DeMon JTAG path with a host protocol intended to integrate with existing Z80 toolchains. Detail is documented separately with the Next-compat image release.

The eZX primary image debug system is being designed around the EE and the HyperRAM + BSRAM + optional DDR3 memory architecture. The previous SRAM-based tag bit approach does not carry over. Detail is not in this revision of the specification.

The Classic Spectrum image carries the same hardware debug subsystem as the Next-compatible image, scaled to the simpler vintage Z80 — breakpoints, watchpoints, single-step, and register inspection over the DeMon JTAG path. This makes the eZX the most debugger-friendly classic-Spectrum platform in existence; debugging on real hardware historically required external pods or ROM-resident monitors with their own compatibility costs.

DeMon retains full JTAG access to the FPGA in all three cases and is the canonical entry point for host-side debugging. Host protocol detail will be documented separately.


Compatibility Summary

Classic ZX Spectrum software (16K / 48K / 128K / +2 / +2A / +3)

Runs on the Classic Spectrum FPGA image with cycle-accurate ULA timing. Snow effects, multicolour bars, floating bus, turbo loaders, attribute tricks, and demo effects all work as on real hardware. Model is selected before image start; all major hardware peripherals (Interface 1 / 2, Microdrive, DivIDE/DivMMC, Kempston interface, ZX Printer) are available as configurable emulated peripherals. Modern enhanced-ULA software — ULAplus-aware games and demos, Timex high-resolution programs, Pentagon 8×1 multicolour productions — runs with full colour and resolution support.

ZX Spectrum Next software

Runs on the Next-compatible FPGA image. Compatibility is as faithful as the upstream Next core — the Z80NG's microarchitectural enhancements are internal and software-invisible. Next-specific software that requires the Next's exact memory architecture and extended hardware uses this image rather than the Classic one.

eZX-native software

Runs on the eZX primary FPGA image. Not compatible with Spectrum or Spectrum Next hardware; eZX-native software is targeted specifically at the eZX chipset and CPU.

eZX image on Ant64

The eZX primary FPGA image is also distributed as an Ant64 personality cartridge. An Ant64 owner can load the cartridge and run eZX-native software directly. The eZX is the canonical reference for that personality.


Comparison with ZX Spectrum Next

Feature ZX Spectrum Next eZX — Next-compat eZX — primary eZX — Classic
CPU Z80N Z80NG (clean-room Z80N + prefetch + μop cache, turbo capable) eZX Z80NG (Z80 strict mode, BSRAM-backed, cycle-accurate per model)
Main RAM 1 MB / 2 MB SRAM 16 MB HyperRAM + optional DDR3 SODIMM (1 / 2 / 4 GB user data + watch bits) 16 MB HyperRAM + optional DDR3 SODIMM (1 / 2 / 4 GB user data + watch bits) On-chip BSRAM (single-cycle)
ROM / cartridge storage Internal SD-loaded into RAM 16 MB HyperRAM (400 MB/s, on bus shared with flash) 16 MB HyperRAM (400 MB/s, on bus shared with flash) 16 MB HyperRAM (400 MB/s, on bus shared with flash)
Display Next layers Next layers (faithful) New display stack Original ULA per model
Audio Beeper + AY + SpecDrum Same as Next New audio engine Beeper + AY (128K and up)
Supervisor n/a DeMon (CM4/CM5 + ESP32-C5) DeMon (CM4/CM5 + ESP32-C5) DeMon (CM4/CM5 + ESP32-C5)
Network Optional add-on Built-in WiFi 2.4 + 5 GHz Built-in WiFi 2.4 + 5 GHz n/a in image (file I/O via DeMon)
MIDI Optional add-on USB MIDI + DIN via expansion USB MIDI + DIN via expansion n/a in image
Storage SD via Next SD via DeMon + USB mass storage SD via DeMon + USB mass storage Tape/disk images on SD via DeMon
Cartridge n/a None None Interface 2 ROM cartridge image support
Compute upgrade n/a CM4 → CM5 swap (more RAM, faster compute) CM4 → CM5 swap (more RAM, faster compute) n/a in image
Cycle-accurate No No (faithful Next) No Yes — exact ULA contention, floating bus, turbo loaders
Enhanced ULA n/a (Next-native palette) Inherits Next palette (256 on-screen from 512-colour 9-bit RGB) + Next-native ULA+ support New chipset palette ULAplus (64-of-256 8-bit RGB), Timex hires, Pentagon 8×1 multicolour

Important: The eZX Spectrum board is at early design/prototype stage, everything you see here is subject to change.