Part 1 — Introduction & Target Audience
This guide is aimed at developers who want to understand, modify, or extend the Sharp MZ Series FPGA Emulator running on the tranZPUter SW-700 hardware platform. It covers the complete architecture — from the VHDL design synthesised into the Cyclone IV FPGA and the MAX7000AE CPLD bus manager, through the I/O Processor (K64F ARM Cortex-M4) interface protocol, to the emulation subsystems that faithfully reproduce up to eight Sharp MZ computers in a single FPGA. By the end of this guide, you should be able to add a new emulated machine model, extend an existing peripheral, integrate a new hardware subsystem, or debug timing and functional issues in the design.
Who is this guide for?
| Background |
What you will gain |
| FPGA / HDL developer |
Deep understanding of the VHDL architecture, clock domains, memory map, CONFIG bus, and how to add hardware modules |
| Embedded developer |
How the K64F ARM I/O Processor communicates with the FPGA via the IOP interface, chip select protocol, and interrupt servicing |
| tranZPUter hardware owner |
Complete picture of how the SW-700 board emulates multiple Sharp MZ computers and how to switch between modes |
| Student / hobbyist |
End-to-end view of a non-trivial multi-machine FPGA emulation project with real-world build, CI/CD, and debug workflows |
Repositories
Emulated machines
| Model |
Series |
Status |
Key differences |
| MZ-80K |
Personal |
Complete |
Original 1978 model, Z80 @ 2MHz, monochrome 40x25 |
| MZ-80C |
Personal |
Complete |
Cost-reduced MZ-80K |
| MZ-1200 |
Personal |
Complete |
Compact desktop, MZ-80A predecessor |
| MZ-80A |
Personal |
Complete |
Enhanced MZ-80K, most popular model |
| MZ-700 |
Personal |
Complete |
Colour display, different keyboard matrix, 3.58MHz |
| MZ-800 |
Personal |
Partial |
Extended MZ-700, enhanced graphics modes, QD drive |
| MZ-80B |
Business |
Complete |
Business series, 80-column display, GRAM, Z80 PIO |
| MZ-2000 |
Business |
Partial |
Enhanced MZ-80B, FDD support, APSS tape |
For hardware architecture and schematics see the tranZPUter SW-700 page. For user-facing operation and TZFS commands see the TZFS User Manual. For TZFS source walkthrough see the TZFS Developer’s Guide. For the MiSTer (Cyclone V) variant of this emulator see the Sharp MZ MiSTer Developer’s Guide.
The tranZPUter SW-700 v1.3 is a custom PCB that physically replaces the Z80 CPU in a Sharp MZ-700, MZ-80A, or MZ-2000. It sits in the Z80 socket on the host machine's mainboard and presents itself electrically as the original CPU, while internally hosting an FPGA, a CPLD, an ARM microcontroller, and 512KB of SRAM. The board can operate in several modes: as a transparent pass-through (hard Z80 on the mainboard still executes), as a video enhancement (FPGA provides upgraded display output), as a soft CPU host (T80 Z80 or ZPU Evolution running in the FPGA), or as a complete Sharp MZ series emulator (the emuMZ build).
FPGA: Cyclone IV E (CYC1000 module)
The FPGA is an Intel (Altera) Cyclone IV E device mounted on a CYC1000 carrier module. Two device variants are supported:
| Parameter |
EP4CE115F23I7 |
EP4CE75F23I7 |
| Logic elements |
114,480 |
75,408 |
| Embedded memory |
3,981 Kbits |
2,745 Kbits |
| Embedded multipliers |
266 (18x18) |
200 (18x18) |
| PLLs |
4 |
4 |
| Package |
FBGA-484 |
FBGA-484 |
| Speed grade |
I7 (industrial) |
I7 (industrial) |
The larger EP4CE115 is the primary target for the full emuMZ build, which requires substantial block RAM for ROM/RAM storage and logic for eight machine emulations. The EP4CE75 can accommodate the coreMZ (video-only) and coreMZ_SoftCPU builds but is tight for the full emuMZ variant.
CPLD: MAX7000AE (EPM7512AETC144-10)
The CPLD is an Altera MAX7000AE with 512 macro cells. It sits between the host mainboard's 5V Z80 bus and the 3.3V FPGA/SRAM, performing voltage translation, bus arbitration, memory mode decoding, and clock multiplexing. The CPLD is 5V-tolerant on all inputs, allowing it to interface directly with TTL-level mainboard signals without external level translators.
I/O Processor: ARM Cortex-M4 (K64F)
The K64F is a Freescale (NXP) Kinetis ARM Cortex-M4 microcontroller running at 120MHz. In the tranZPUter architecture it serves as the I/O Processor (IOP), providing services that the FPGA cannot efficiently handle in hardware: SD card file system access, tape image loading/saving, floppy disk image management, user interface menus, and host configuration. The K64F communicates with the FPGA through a parallel interface consisting of chip select lines, a 6-bit address bus, an 8-bit bidirectional data bus, and read/write strobes.
SRAM: 512KB Static RAM
A 512KB SRAM device provides the Z80 memory space, mapped in 64KB pages controlled by the CPLD's TZMM (tranZPUter Memory Mode) register. The SRAM is accessible by both the hard Z80 (via the CPLD) and the soft T80 (via the FPGA), with the CPLD controlling page selection and the FPGA providing additional address decoding for the emuMZ variant.
Host machine support
| Host |
Socket |
CPLD variant |
Notes |
| MZ-700 |
Z80 DIP-40 |
tranZPUterSW700 |
Primary development target |
| MZ-80A |
Z80 DIP-40 |
tzpuSW700_MZ80A |
Different mainboard I/O decode |
| MZ-2000 |
Z80 DIP-40 |
tzpuSW700_MZ2000 |
Business series bus timing |
Part 3 — Architecture Overview
The FPGA design is organised into three build variants, each implemented as a distinct top-level VHDL entity. All three share the VideoController module; they differ in whether they include soft CPU cores and/or the full Sharp MZ emulation subsystem.
Three build variants
| Variant |
Top-level entity |
Contents |
FPGA utilisation (EP4CE115) |
| coreMZ |
coreMZ.vhd |
VideoController only |
~15% LE, ~20% BRAM |
| coreMZ_SoftCPU |
coreMZ_SoftCPU.vhd |
VideoController + T80 + ZPU Evolution |
~35% LE, ~45% BRAM |
| coreMZ_emuMZ |
coreMZ_emuMZ.vhd |
VideoController + full Sharp MZ emulation |
~70% LE, ~85% BRAM |
Module hierarchy (coreMZ_emuMZ variant)
coreMZ (top-level entity, 1783 lines)
├── clkgen - 128MHz PLL, programmable clock dividers (571 lines)
│ CKMASTER 8MHz, CKENCPU variable 2-32MHz, CKENHOST, CKSOUND, CKRTC
├── VideoController - Multi-mode video rendering engine (5400 lines)
│ 40/80 col, mono/colour, VGA scaling, OSD overlays, palette
├── mctrl - Machine control: 91-bit CONFIG bus, register decode, reset (689 lines)
├── T80 - Z80-compatible soft CPU core (T80se wrapper)
├── arbiter - Round-robin bus arbitration with 1-second watchdog (653 lines)
├── keymatrix - PS/2 to Sharp MZ keyboard translation (1222 lines)
├── cmt - Cassette tape interface with APSS support (1806 lines)
├── fdd - Floppy disk controller, WD1793 emulation (355 lines)
├── iointr - 8-interrupt FIFO for I/O processor (325 lines)
├── snd - SN76489 sound + i8253 audio subsystem (369 lines)
├── mz80k_hw - Personal series hardware controller (1416 lines)
│ MZ-80K/C/1200/80A/700/800 memory map and I/O
│ ├── i8255 - Programmable Peripheral Interface
│ └── i8254 - Programmable Interval Timer
└── mz80b_hw - Business series hardware controller (676 lines)
MZ-80B/2000/2200/2500 memory map and I/O
├── i8255 - PPI (alternate configuration)
├── i8254 - PIT (cascade mode)
└── z8420 - Z80 PIO (Parallel I/O)
Data flow
The emuMZ variant has two independent data paths:
-
Emulation path — the T80 soft CPU executes Sharp MZ software, reading/writing ROM, RAM, video, peripherals, and cassette via address-decoded chip selects. This runs entirely within the FPGA clock domain using the CKMASTER clock with clock enables.
-
IOP path — the K64F ARM processor communicates with the FPGA via the parallel IOP interface, sending configuration registers, ROM images, tape data, floppy disk images, and keyboard maps. This is asynchronous to the emulation clock.
Both paths can access shared resources (CONFIG registers, CMT buffers, keyboard matrix) without contention because the arbiter module serialises competing requests using a round-robin scheme.
Part 4 — FPGA Top-Level Entity
The top-level entity coreMZ (defined in coreMZ_emuMZ.vhd) declares all physical FPGA pin connections and contains the instantiation of every sub-module. Its architecture (rtl) is primarily a wiring exercise — it connects sub-module ports via internal signals and contains the tri-state bus multiplexing logic that switches between hard Z80 bus signals and soft CPU bus signals.
Entity ports
The entity port list groups signals by function:
| Group |
Signals |
Direction |
Purpose |
| Clocks |
CLOCK_50, CTLCLK, SYSCLK, VZ80_CLK |
in |
50MHz base, external override, mainboard system, Z80 bus clock |
| Address bus |
VZ80_ADDR[15:0] |
inout |
Z80 address — active output when soft CPU drives, input when hard Z80 active |
| Data bus |
VZ80_DATA[7:0] |
inout |
Z80 data — active output on reads from FPGA resources, input on writes |
| Control |
VZ80_MREQn, IORQn, RDn, WRn, M1n |
inout |
Active output from soft CPU or input from hard Z80 |
| Video decoded |
VIDEO_RDn, VIDEO_WRn |
in |
CPLD-decoded video controller access strobes |
| VGA output |
VGA_R/G/B[3:0], HSYNC_OUTn, VSYNC_OUTn |
out |
4-bit per channel RGB + sync |
| Composite |
COLR_OUT, CSYNC_OUTn, CSYNC_OUT |
out |
Composite video signals |
| Mainboard video in |
V_CSYNC, V_HSYNCn, V_VSYNCn, V_R, V_G, V_B |
in |
Original mainboard video for pass-through or blending |
| Multiplexed pins |
VWAITn_A21_V_CSYNC, etc. |
inout |
Pins shared between address extension, CPU control, and video input |
Tri-state bus multiplexing
The address and data buses are shared between the hard Z80 on the mainboard and the soft T80 in the FPGA. The top-level entity contains tri-state drivers controlled by the CPU_CFG_DATA register and the MODE_EMU flag:
-- When emuMZ is active, the FPGA drives the address and data buses.
-- When the hard Z80 is active, these pins are high-impedance inputs.
VZ80_ADDR <= T80_ADDR when MODE_EMU = '1' and VZ80_BUSACKni = '0'
else (others => 'Z');
VZ80_DATA <= T80_DATA_OUT when MODE_EMU = '1' and CORE_WRn = '0'
else (others => 'Z');
The multiplexed pins (VWAITn_A21_V_CSYNC, VZ80_A20_RFSHn_V_HSYNCn, etc.) serve triple duty depending on the active mode. In emuMZ mode they carry the upper address bits (A16-A21) for accessing FPGA block RAM beyond the 64KB Z80 space. In video-only mode they carry the mainboard's video sync signals. In soft CPU mode they carry CPU status outputs (HALT, RFSH).
Key internal signals
| Signal |
Width |
Purpose |
| CPU_CFG_DATA |
8 bits |
CPU selection and control register (I/O 0x6C) |
| CPLD_CFG_DATA |
8 bits |
CPLD configuration register (I/O 0x6E) |
| MODE_EMU |
1 bit |
Flag: emuMZ module active |
| CORE_ADDR |
24 bits |
Extended address from active CPU (supports FPGA memory beyond 64KB) |
| CORE_DATA_OUT/IN |
32 bits |
Wide data path for ZPU and video controller word access |
| CONFIG |
91 bits |
Machine configuration bus from mctrl |
| CLKBUS |
7 bits |
Clock distribution bus from clkgen |
Part 5 — Clock Architecture
The clkgen module (571 lines) generates all clocks from a single 50MHz input using a PLL to produce a 128MHz master and programmable divider chains. A key design principle is that all variable-frequency clocks use clock enables on the master clock, not separate clock domains. This eliminates clock domain crossing issues and simplifies timing analysis.
Clock bus (CLKBUS)
A 7-bit CLKBUS vector distributes all clocks to every module:
| Index |
Name |
Function |
Typical frequency |
| 0 |
CKMASTER |
Master synchronous clock |
8MHz (from 128MHz PLL /16) |
| 1 |
CKENHOST |
Host machine clock enable |
~2MHz (original machine speed) |
| 2 |
CKSOUND |
Sound generation clock |
3.58MHz or 4MHz |
| 3 |
CKRTC |
Real-time clock |
~1Hz derived |
| 4 |
CKENCPU |
CPU clock enable (variable) |
2-32MHz (via TURBO config) |
| 5 |
CKENPERIPH |
Peripheral clock enable (i8254, i8255) |
Machine-dependent |
| 6 |
CKENFDC |
Floppy disk controller clock |
8MHz |
Clock enable technique
Rather than generating separate clock domains — which causes timing closure issues and requires explicit synchronisers — the design uses a single CKMASTER clock with pulsed clock enable signals. The T80 CPU, for example, is clocked at CKMASTER speed but only advances state when CKENCPU pulses high:
-- CPU executes only when CKENCPU pulses
T80se_inst : T80se
port map (
CLK_n => CLKBUS(CKMASTER),
CLKEN => CLKBUS(CKENCPU),
RESET_n => T80_RESETn,
...
);
This keeps the entire design in a single clock domain while supporting variable CPU speeds. All state machines, counters, and registers sample CKMASTER and qualify their updates with the appropriate clock enable.
PLL configuration
The PLL takes the 50MHz CLOCK_50 input and produces:
| PLL output |
Frequency |
Use |
| c0 |
128MHz |
Master PLL output, divided down for all enables |
| c1 |
75MHz |
Video pixel clock (optional high-res modes) |
The 128MHz output feeds a chain of binary dividers. Each divider produces a clock enable pulse at the target frequency by toggling a single-cycle pulse every N master cycles. For example, to generate a 2MHz CPU enable from 128MHz, the divider counts to 64 and emits a one-cycle pulse.
Configurable frequencies
The CONFIG bus from mctrl controls frequency selection via these bit fields:
| CONFIG bits |
Parameter |
Options |
| [61:59] |
TURBO |
CPU speed: 2MHz, 4MHz, 8MHz, 16MHz, 32MHz |
| [84:81] |
CPUSPEED |
Active CPU speed (derived from TURBO + machine type) |
| [86:85] |
PERSPEED |
Peripheral clock selection |
| [88:87] |
RTCSPEED |
RTC clock selection |
| [90:89] |
SNDSPEED |
Sound clock selection |
When the user or I/O processor changes TURBO via the CONFIG registers, clkgen recalculates the divider value and seamlessly transitions to the new frequency on the next divider cycle. There is no glitch because the enable pulse simply changes spacing — the underlying CKMASTER clock remains constant.
Part 6 — Machine Control & Configuration
The mctrl module (689 lines, plus the mctrl_pkg package at the top of the same file) is the central configuration authority for the emulation. It maintains the 91-bit CONFIG bus that controls every aspect of the emulated machine — which computer model is active, display mode, CPU speed, audio source, tape speed, floppy options, and more. It also manages reset distribution.
CONFIG bus bit assignments
The CONFIG bus is a wide vector that acts as a hardware configuration register file. Every module reads the bits relevant to its function. The complete map (from mctrl_pkg):
| Bits |
Constant |
Purpose |
| [10:0] |
CURRENTMACHINE |
Machine type — one-hot encoding (MZ80K=0, MZ80C=1, … MZ2500=10) |
| [11] |
MZ_KC |
Aggregate: machine is MZ-80K or MZ-80C series |
| [12] |
MZ_A |
Aggregate: machine is MZ-1200 or MZ-80A series |
| [13] |
MZ_B |
Aggregate: machine is MZ-2000/MZ-80B series |
| [15] |
MZ_K |
Aggregate: machine is any Personal series |
| [19:16] |
CURRENTDISPLAY |
Display mode: NORMAL(16), NORMAL80(17), COLOUR(18), COLOUR80(19) |
| [23:20] |
VGAMODE |
VGA output mode (640x400, 640x480, pixel doubling) |
| [24] |
USERROM |
User ROM (E800-EFFF) enable |
| [25] |
FDCROM |
FDC ROM (F000-FFFF) enable |
| [26] |
FDDENABLE |
Floppy Disk Controller enable |
| [27] |
FDDINTEN |
FDC interrupt enable |
| [31:28] |
FDDDISKREADY |
Per-drive disk loaded status (4 drives) |
| [35:32] |
FDDPOLARITY |
Per-drive data polarity |
| [39:36] |
FDDWRPROTECT |
Per-drive write protect |
| [42:40] |
RAMINSTALLED |
RAM installed configuration |
| [50:43] |
GRAPHICSOPTION |
GRAM options (GRAMI/II/III, PCG, MZ1R25) |
| [51] |
AUDIOSRC |
Audio source: 0=sound generator, 1=tape audio |
| [55:52] |
AUDIOVOL |
Volume (4-bit, 16 levels) |
| [57:56] |
AUDIOMIX |
Audio channel mixing |
| [58] |
AUDIOHW |
Audio hardware selection (host or FPGA) |
| [61:59] |
TURBO |
CPU speed selection |
| [64:62] |
FASTTAPE |
Tape read/write speed multiplier |
| [66:65] |
BUTTONS |
External button state (CMT play/record) |
| [67] |
PCGRAM |
PCG mode: ROM(0) or RAM(1) |
| [68] |
VRAMWAIT |
Insert video wait states on CPU access |
| [69] |
VRAMDISABLE |
Disable VRAM display output |
| [70] |
GRAMDISABLE |
Disable GRAM display output |
| [71] |
MENUENABLE |
Enable OSD menu overlay |
| [72] |
STATUSENABLE |
Enable OSD status overlay |
| [73] |
BOOT_RESET |
MZ-80B/2000 Boot IPL Reset enable |
| [74] |
CMTASCII_IN |
CMT Sharp ASCII to ASCII conversion (inbound) |
| [75] |
CMTASCII_OUT |
CMT ASCII to Sharp ASCII conversion (outbound) |
| [76] |
CMT_HWMODE |
Hardware CMT drive(1) or emulation(0) |
| [80:77] |
MZ800_SWITCH |
MZ-800 hardware selection switches |
| [84:81] |
CPUSPEED |
Active CPU speed (derived) |
| [86:85] |
PERSPEED |
Active peripheral speed |
| [88:87] |
RTCSPEED |
Active RTC speed |
| [90:89] |
SNDSPEED |
Active sound speed |
I/O Processor register interface
The mctrl module presents 16 addressable registers to the I/O Processor. The K64F writes to these registers (via the IOP bus with IOP_MCTRL_CSn asserted) to configure the emulation. Each register maps to a subset of CONFIG bits:
| IOP Address |
Register |
CONFIG bits affected |
| 0x00 |
Machine select |
[10:0] CURRENTMACHINE + aggregate flags |
| 0x01 |
Display mode |
[19:16] CURRENTDISPLAY, [23:20] VGAMODE |
| 0x02 |
CPU/tape speed |
[61:59] TURBO, [64:62] FASTTAPE |
| 0x03 |
Audio config |
[51] AUDIOSRC, [55:52] AUDIOVOL, [57:56] AUDIOMIX |
| 0x04 |
ROM enables |
[24] USERROM, [25] FDCROM |
| 0x05 |
FDD config |
[26] FDDENABLE, [27] FDDINTEN, [31:28] FDDDISKREADY |
| 0x06 |
RAM config |
[42:40] RAMINSTALLED, [50:43] GRAPHICSOPTION |
| 0x07 |
OSD/misc |
[71] MENUENABLE, [72] STATUSENABLE, [67] PCGRAM |
| 0x08 |
CMT config |
[74] CMTASCII_IN, [75] CMTASCII_OUT, [76] CMT_HWMODE |
| 0x0F |
Reset control |
System-wide reset generation |
Reset management
The mctrl module generates a unified MCTRL_RESETn signal from three sources:
- Cold reset — power-on reset counter (4-bit, ~16 CKMASTER cycles)
- Warm reset — I/O Processor writes to reset register (0x0F)
- CPU reset — CPU_CFG_DATA bit 7 set
All resets are synchronised to CKMASTER to prevent metastability. The reset output fans out to every sub-module.
Part 7 — CPU Switching Mechanism
One of the defining features of the tranZPUter SW-700 is its ability to switch between multiple CPUs at runtime. The mechanism is controlled through the CPU_CFG_DATA register at I/O address 0x6C and coordinated between the CPLD bus manager and the FPGA.
CPU Configuration Register (I/O 0x6C)
| Bit(s) |
Function |
Values |
| [5:0] |
CPU selection |
000000=Hard Z80, 000001=T80, 000010=ZPU, 000100=emuMZ |
| [6] |
Clock enable |
1=soft CPU clock running, 0=halted |
| [7] |
CPU Reset |
1=hold soft CPU in reset |
Available CPU modes
| Mode |
CPU_CFG_DATA[5:0] |
CPU |
Description |
| Hard Z80 |
000000 |
Mainboard Z80 |
Original CPU on the host machine, FPGA provides video only |
| Soft T80 |
000001 |
T80 in FPGA |
Z80-compatible soft core, runs TZFS and Sharp MZ software |
| ZPU Evolution |
000010 |
ZPU in FPGA |
32-bit stack processor, runs zOS |
| emuMZ |
000100 |
T80 + full emulation |
Complete Sharp MZ emulation, all peripherals in FPGA |
Switching sequence
The CPU switch is initiated by TZFS (running on the current CPU) writing to I/O port 0x6C. The sequence is:
- TZFS writes the new CPU_CFG_DATA value with bit 7 (reset) set — this holds the target CPU in reset.
- The CPLD detects the I/O write to 0x6C and updates its internal CPU mode register.
- If switching away from the hard Z80, the CPLD asserts BUSRQn to the mainboard Z80. When BUSACKn is received, the hard Z80 tri-states its bus and the FPGA takes control.
- If switching to the hard Z80, the FPGA tri-states its bus drivers and the CPLD releases BUSRQn.
- TZFS (or the I/O processor) clears bit 7 to release the target CPU from reset.
- The new CPU begins executing from its reset vector.
emuMZ mode entry
When emuMZ mode is selected (CPU_CFG_DATA[2]=1), additional initialisation occurs:
- The arbiter module activates, taking control of bus arbitration between the T80, keyboard scanner, CMT interface, interrupt generator, and sound modules.
- The mctrl module loads the default CONFIG for the selected machine model.
- The I/O processor loads the appropriate monitor ROM into the FPGA block RAM.
- The T80 is released from reset and begins executing the monitor ROM at address 0x0000.
Part 8 — Video Controller
The VideoController module (5400 lines in VideoController/VideoController.vhd) is the largest single module in the design. It implements the complete display system for all emulated machines, including character rendering, colour attribute overlay, graphics framebuffer compositing, VGA upscaling, palette management, and OSD (On-Screen Display) overlays for the menu and status systems.
Display modes
| Mode |
Resolution |
Colours |
Machines |
| Monochrome 40x25 |
320x200 |
Green/White |
MZ-80K/C/1200/80A |
| Colour 40x25 |
320x200 |
8 colours |
MZ-700/800 |
| Monochrome 80x25 |
640x200 |
Green/White |
MZ-80A (enhanced) |
| Colour 80x25 |
640x200 |
8 colours |
MZ-80B/2000 |
| Graphics 320x200 |
320x200 |
8 colours |
MZ-700/800 (GRAM) |
| Graphics 640x200 |
640x200 |
8 colours |
MZ-80B/2000 (GRAM I/II/III) |
Rendering pipeline
The video rendering pipeline processes each scanline in a pipelined sequence:
-
Timing generation: Horizontal and vertical counters produce sync, blanking, and active display windows. Each machine model has its own timing parameters selected by CONFIG[10:0].
-
Character fetch: During each character cell (8 pixels wide), the VRAM address is computed from the H/V position, the character code is read from VRAM, and the corresponding glyph row is fetched from CGROM (or CGRAM if PCG is enabled).
-
Attribute fetch: The same character cell address reads the colour attribute from ARAM. The attribute byte encodes foreground colour (3 bits), background colour (3 bits), and optional blink/underline flags.
-
Graphics overlay: For machines with GRAM (MZ-80B/2000 or MZ-700/800 with graphics extension), the corresponding graphics pixel row is read from the Red, Green, and Blue framebuffers. The blend mode (XOR, OR, AND, replace) is selected by the graphics control register.
-
Palette mapping: The 3-bit colour index is expanded to 12-bit RGB (4 bits per channel) through a programmable palette LUT. The palette supports 4096 colours.
-
VGA upscaling: The native resolution (320x200 or 640x200) is scaled to the configured VGA output mode (640x400, 640x480, or 800x600) using pixel doubling and line replication.
-
OSD compositing: If the menu or status overlay is enabled, the OSD framebuffer pixels are composited on top of the emulation display during the appropriate screen regions.
Video memory map (direct 24-bit addressing)
When the video controller is accessed via the extended 24-bit address bus (used by the ZPU or I/O processor), the following memory map applies:
| Address range |
Size |
Content |
| 0x200000-0x20FFFF |
64KB |
I/O registers (palette, GPU control, mode select) |
| 0x210000-0x21FFFF |
64KB |
Video RAM, attribute RAM, character generator RAM |
| 0x240000-0x243FFF |
16KB |
Red framebuffer plane |
| 0x250000-0x253FFF |
16KB |
Blue framebuffer plane |
| 0x260000-0x263FFF |
16KB |
Green framebuffer plane |
| 0x270000-0x2A1FFF |
~200KB |
OSD framebuffers (menu + status) |
| 0x320000 |
8KB |
Status frame buffer |
| 0x322000 |
8KB |
Menu overlay frame buffer |
| 0x324000 |
1KB |
Video parameter array (32x32 entries) |
| 0x324400 |
4B |
Current video mode register |
Z80 address space video access
From the Z80's perspective (16-bit addressing), video memory is mapped into the standard Sharp MZ locations:
| Machine |
VRAM |
ARAM |
CGROM/RAM |
| MZ-80K/C/1200/80A |
D000-D7FF (2KB) |
D800-DFFF (2KB) |
Read-only CG ROM |
| MZ-700 |
D000-D7FF (2KB) |
D800-DFFF (2KB) |
Colour attribute in ARAM |
| MZ-80B/2000 |
D000-DFFF (4KB) |
- |
E000-E7FF (GRAM access) |
Part 9 — Memory Architecture
The emuMZ build uses FPGA block RAM exclusively for all emulated machine memory. Unlike the coreMZ and coreMZ_SoftCPU builds (which use the external 512KB SRAM via the CPLD), the emuMZ variant is self-contained within the FPGA — it does not access the host mainboard's RAM at all.
Block RAM allocation
| Memory |
Size |
Type |
Init file |
Purpose |
| SYSROM |
128KB |
Dual-port ROM |
combined_mrom.mif |
Monitor ROMs for all machine models |
| SYSRAM |
64KB |
Dual-port RAM |
combined_mainmemory.mif |
Z80 main memory |
| VRAM |
4KB |
Dual-port RAM |
— |
Text display buffer |
| ARAM |
4KB |
Dual-port RAM |
— |
Colour attribute RAM |
| CGROM |
32KB |
Dual-port ROM |
— |
Character generator ROM (all models) |
| CGRAM |
32KB |
Dual-port RAM |
— |
Programmable character RAM (PCG) |
| GRAM (Red) |
16KB |
Dual-port RAM |
— |
Graphics framebuffer red plane |
| GRAM (Green) |
16KB |
Dual-port RAM |
— |
Graphics framebuffer green plane |
| GRAM (Blue) |
16KB |
Dual-port RAM |
— |
Graphics framebuffer blue plane |
| CMT HDR |
128B |
Dual-port RAM |
— |
Tape file header cache |
| CMT DATA |
64KB |
Dual-port RAM |
— |
Tape data cache |
| KEYMAP |
2KB |
Dual-port RAM |
— |
Keyboard mapping table |
ROM banking
The SYSROM stores monitor ROMs for all machine models in a single 128KB block. Bank selection is controlled by MROM_BANK[5:0], driven from the CONFIG bus machine selection bits. The upper address bits of the SYSROM select the bank:
| Machine |
Bank index |
ROM size |
Address range within SYSROM |
| MZ-80K |
0, 1 |
4KB + 2KB |
0x00000-0x00FFF |
| MZ-80C |
2, 3 |
4KB + 2KB |
0x02000-0x02FFF |
| MZ-1200 |
4, 5 |
4KB + 2KB |
0x04000-0x04FFF |
| MZ-80A |
6, 7 |
4KB + 2KB |
0x06000-0x06FFF |
| MZ-700 |
8, 9 |
4KB (1Z-013A) |
0x08000-0x08FFF |
| MZ-800 |
10, 11 |
8KB |
0x0A000-0x0BFFF |
| MZ-80B |
12, 13 |
4KB + IPL |
0x0C000-0x0CFFF |
| MZ-2000 |
14, 15 |
4KB + IPL |
0x0E000-0x0EFFF |
Switching machine models at runtime simply changes the bank select — no reloading required. The I/O processor can also write individual ROM banks via the IOP interface for custom ROM testing.
Z80 address decoding
The 64KB Z80 address space is decoded differently per machine family. The mz80k_hw and mz80b_hw modules generate chip selects based on the CONFIG machine type and the Z80 address.
MZ-80A (typical Personal series):
| Address range |
Component |
Chip select |
| 0x0000-0x0FFF |
Monitor ROM |
CS_ROM_n |
| 0x1000-0xCFFF |
User RAM (48KB) |
CS_RAM_n |
| 0xD000-0xD7FF |
VRAM (2KB) |
CS_VRAM_n |
| 0xD800-0xDFFF |
Colour attribute RAM |
CS_ARAM_n |
| 0xE000-0xE007 |
i8255 PPI |
CS_IO_PPI_n |
| 0xE008-0xE00B |
i8254 PIT |
CS_IO_PIT_n |
| 0xE800-0xEFFF |
User ROM (optional) |
CS_USERROM_n |
| 0xF000-0xFFFF |
FDC ROM (optional) |
CS_FDCROM_n |
MZ-700 (colour Personal series):
| Address range |
Component |
Chip select |
| 0x0000-0x0FFF |
Monitor ROM (banked out after boot) |
CS_ROM_n |
| 0x0000-0xFFFF |
64KB RAM (when ROM banked out) |
CS_RAM_n |
| 0xD000-0xD7FF |
VRAM |
CS_VRAM_n |
| 0xD800-0xDFFF |
Colour attribute RAM |
CS_ARAM_n |
| 0xE000-0xE003 |
i8255 PPI |
CS_IO_PPI_n |
| 0xE004-0xE007 |
i8254 PIT |
CS_IO_PIT_n |
| 0xE008 |
Memory bank control |
CS_BANKCTL_n |
MZ-80B/2000 (Business series):
| Address range |
Component |
Chip select |
| 0x0000-0x07FF |
IPL ROM (boot, then banked out) |
CS_IPL_n |
| 0x0000-0xFFFF |
64KB RAM |
CS_RAM_n |
| 0xD000-0xDFFF |
VRAM (4KB) |
CS_VRAM_n |
| 0xE000-0xFFFF |
GRAM access window |
CS_GRAM_n |
| I/O 0xD8-0xDB |
i8255 PPI |
CS_IO_PPI_n |
| I/O 0xD4-0xD7 |
i8254 PIT |
CS_IO_PIT_n |
| I/O 0xF4-0xF7 |
Z80 PIO |
CS_IO_PIO_n |
| I/O 0xF8-0xFD |
Graphics control |
CS_IO_GRAM_n |
CPU data bus multiplexing
The T80 data input is multiplexed from all memory and peripheral sources:
T80_DI <= SYSROM_DO when CS_ROM_n = '0' else
SYSRAM_DO when CS_RAM_n = '0' else
VIDEO_DO when CS_VRAM_n = '0' else
ARAM_DO when CS_ARAM_n = '0' else
PPI_DO when CS_IO_PPI_n = '0' else
PIT_DO when CS_IO_PIT_n = '0' else
FDD_DO when CS_FDD_n = '0' else
(others => '1'); -- Open-drain pullup simulation
The default '1' simulates the open-drain bus behaviour of real hardware, where unselected devices float high.
Part 10 — Cassette Tape Subsystem
The cmt module (1806 lines) emulates the cassette tape interface for all Sharp MZ models. It implements PWM bit encoding/decoding (matching the original hardware's Manchester-like encoding), tape motor control, the APSS (Automatic Program Search System) for MZ-2000, and a tape data queue managed by the I/O processor.
CMT bus signals
Output signals (CMT_BUS_OUT, 17 bits — FPGA to I/O processor):
| Bit |
Constant |
Function |
| 0 |
PLAY_READY |
Tape playback buffer loaded, ready for playback |
| 1 |
PLAYING |
Tape playback in progress |
| 2 |
RECORD_READY |
Record buffer full (data available for save) |
| 3 |
RECORDING |
Tape recording in progress |
| 4 |
ACTIVE |
Transfer active |
| 5 |
SENSE |
Tape state sense output to Z80 PPI |
| 6 |
WRITEBIT |
Bit value being sent to Z80 (playback) |
| 7 |
TAPEREADY |
Cassette loaded in virtual deck |
| 8 |
WRITEREADY |
Write permitted |
| 9 |
APSS_SEEK |
Start seeking next program (per APSS_DIR) |
| 10 |
APSS_DIR |
Seek direction: 0=Rewind, 1=Forward |
| 11 |
APSS_EJECT |
Eject cassette |
| 12 |
APSS_PLAY |
Play cassette |
| 13 |
APSS_STOP |
Stop play/rwd/ff |
| 14 |
APSS_AUTOREW |
Deck auto-rewind at tape end |
| 15 |
APSS_AUTOPLAY |
Auto-play after APSS action |
| 16 |
ENDOFTAPE |
End of tape detected |
Input signals (CMT_BUS_IN, 13 bits — Z80 machine to CMT):
| Bit |
Constant |
Function |
| 0 |
READBIT |
Bit value from Z80 (recording) |
| 1 |
REEL_MOTOR |
APSS reel motor on/off |
| 2 |
STOP |
Stop motor |
| 3 |
PLAY |
Play command |
| 4 |
SEEK |
Seek (FF/REW) |
| 5 |
DIRECTION |
Seek direction: L=Rewind, H=Fast Forward |
| 6 |
EJECT |
Eject cassette |
| 7 |
WRITEENABLE |
Enable recording |
| 8 |
AUTOPLAY |
Enable playback at end of rewind |
| 9 |
AUTOREW |
Enable auto-rewind |
| 10 |
CMTFF |
Fast forward |
| 11 |
CMTREW |
Rewind |
| 12 |
KINH |
Keyboard inhibit (blocks FF/REW/STOP/EJECT) |
Tape data flow
I/O Processor (K64F) FPGA (CMT module) Z80 CPU (T80)
Load .MZF file ─────────────────→ CMT DATA RAM (64KB) ─── PWM ──→ READBIT → i8255 PPI
│ CMT HDR RAM (128B) (Port C bit)
│ (IOP writes via IOP_CMT0_CSn)
│
│ CMT DATA RAM ←──── PWM ←─────── WRITEBIT → PPI
Save .MZF file ←────────────────── CMT HDR RAM (recording)
(IOP reads via IOP_CMT1_CSn)
The Sharp MZ tape format (.MZF) consists of a 128-byte header followed by the data body:
| Offset |
Size |
Content |
| 0x00 |
1 |
File type (01=binary, 02=MZ-80K BASIC, 03=data, 05=MZ-700 binary) |
| 0x01 |
17 |
Filename (Sharp ASCII, padded with 0x0D) |
| 0x12 |
2 |
File size (little-endian) |
| 0x14 |
2 |
Load address (little-endian) |
| 0x16 |
2 |
Execute address (little-endian) |
| 0x18 |
104 |
Comment/padding |
| 0x80+ |
N |
Data body (N = file size) |
Speed options (FASTTAPE config)
| CONFIG[64:62] |
Speed |
Baud equivalent |
| 000 |
1x (original) |
1200 baud (MZ-80K) or 2400 baud (MZ-700) |
| 001 |
2x |
Slightly faster loading |
| 010 |
4x |
Practical loading |
| 011 |
8x |
Quick testing |
| 100 |
16x |
Development |
| 101 |
32x |
Near-instant load |
APSS (MZ-2000)
The MZ-2000 supports APSS — Automatic Program Search System — which allows the tape deck to automatically fast-forward or rewind to the next program. The CMT module implements the APSS state machine using the APSS_SEEK, APSS_DIR, APSS_PLAY, and APSS_STOP signals. The I/O processor manages the tape queue (multiple MZF files concatenated on a virtual tape), advancing the file pointer when APSS_SEEK is asserted.
The keymatrix module (1222 lines) translates PS/2 keyboard input into the Sharp MZ keyboard matrix expected by the emulated machines. Each Sharp MZ model uses a different keyboard matrix layout, and the module maintains separate translation tables for each.
PS/2 to Sharp MZ translation
The translation process operates in two stages:
-
PS/2 decode: The PS/2 serial protocol is decoded into scan codes. Make codes (key press) and break codes (key release) are distinguished by the 0xF0 prefix byte.
-
Matrix mapping: Each PS/2 scan code is mapped to a (row, column) pair in the Sharp MZ keyboard matrix. The mapping is stored in a lookup table loaded by the I/O processor and can be customised per machine model.
Keyboard matrix sizes
| Machine |
Rows |
Columns |
Matrix size |
| MZ-80K/C/1200 |
10 |
8 |
80 keys |
| MZ-80A |
10 |
8 |
80 keys (different layout) |
| MZ-700 |
10 |
8 |
70 keys (reduced) |
| MZ-80B/2000 |
10 |
8 |
80 keys (business layout) |
Key scanning protocol
The Sharp MZ keyboard interface works through the i8255 PPI. The Z80 writes a scan row number to PPI Port A, then reads the column data from PPI Port B. The keymatrix module intercepts these PPI transactions:
-- When Z80 writes to PPI Port A, latch the scan row
MZ_KEYB_SCAN <= PPI_PORT_A(3 downto 0);
-- When Z80 reads PPI Port B, return the matrix column data for the active row
PPI_PORT_B <= KEYB_MATRIX(to_integer(unsigned(MZ_KEYB_SCAN)));
I/O processor keyboard interface
The I/O processor can also inject keystrokes by writing directly to the keyboard matrix via IOP_KEYB_CSn. This is used for automated testing and for the OSD menu navigation (the menu system runs on the K64F and sends synthetic key events to select menu items).
Break key detection
The MZ_KEYB_BREAKDETECT signal provides a direct indication when the Break key is pressed, bypassing the normal matrix scanning. This is used by the I/O processor to trigger an NMI to the emulated CPU for interactive debugging.
Arbiter interaction
The keyboard module requires bus access to perform its scanning — it must read PPI ports, which are on the emulated Z80 bus. The arbiter grants the keyboard a time slot in the round-robin schedule. The MZ_KEYB_GRANTn signal indicates when the keyboard has bus access; MZ_KEYB_BUSYn tells the arbiter the keyboard is still using the bus.
Part 12 — Sound Subsystem
The snd module (369 lines) implements the audio subsystem, combining the SN76489 sound generator (used by the MZ-700 and MZ-800) with the i8253/i8254 timer-based audio used by the MZ-80K/C/1200/80A families. Audio output is via a sigma-delta DAC or PWM DAC that drives an analogue output pin.
Sound sources
| Source |
Component |
Machines |
Capability |
| i8254 Counter 0 |
Programmable Interval Timer |
All Personal series |
Square wave tone generator |
| SN76489 |
Texas Instruments PSG |
MZ-700, MZ-800 |
3 tone channels + 1 noise |
| i8253 (business) |
Timer |
MZ-80B, MZ-2000 |
Square wave via PIT cascade |
SN76489 integration
The SN76489 PSG (Programmable Sound Generator) provides three independent tone generators and one noise generator. Each tone channel has a 10-bit frequency divider and a 4-bit volume attenuator. The noise channel supports white noise and periodic noise modes. The module uses an open-source SN76489 VHDL core.
Audio mixing and output
The CONFIG bus controls audio source selection and mixing:
| CONFIG bit(s) |
Function |
| [51] AUDIOSRC |
0=sound generator, 1=tape audio |
| [55:52] AUDIOVOL |
16-level volume control |
| [57:56] AUDIOMIX |
Left/right channel blend |
| [58] AUDIOHW |
Use host(0) or FPGA(1) audio hardware |
The final audio is output through a sigma-delta DAC (sigma_delta_dac module) that converts the digital audio samples to a 1-bit PWM stream. This is low-pass filtered on the PCB to produce the analogue audio signal.
Arbiter interaction
Like the keyboard, the sound module occasionally needs bus access (to process I/O register writes from the Z80). The arbiter grants it a slot via MZ_SND_GRANTn / MZ_SND_BUSYn.
Part 13 — Floppy Disk Controller
The fdd module (355 lines) emulates the Western Digital WD1793 floppy disk controller used by the MZ-80B, MZ-2000, and MZ-800 (with the optional floppy disk interface). The module implements the WD1793 register set and command state machine, with actual disk image data provided by the I/O processor from SD card.
WD1793 register map
| Address offset |
Read |
Write |
| 0 |
Status register |
Command register |
| 1 |
Track register |
Track register |
| 2 |
Sector register |
Sector register |
| 3 |
Data register |
Data register |
Drive configuration
Up to four virtual drives are supported, configured via the CONFIG bus:
| CONFIG bits |
Function |
| [26] FDDENABLE |
Master enable for FDD subsystem |
| [27] FDDINTEN |
Enable interrupt generation on FDD operations |
| [31:28] FDDDISKREADY |
Per-drive disk loaded status (4 bits, one per drive) |
| [35:32] FDDPOLARITY |
Per-drive data polarity (inverted vs. normal) |
| [39:36] FDDWRPROTECT |
Per-drive write protection |
Data flow
The I/O processor manages the disk images. When the WD1793 receives a read sector command:
- The FDD module generates an interrupt to the I/O processor via the
iointr module.
- The I/O processor reads the requested track/sector/side from the disk image file on SD card.
- The I/O processor writes the sector data into the FDD’s data buffer via
IOP_FDD_CSn.
- The FDD module presents the data byte-by-byte on the WD1793 data register with appropriate DRQ (Data Request) timing.
Write operations reverse the flow — the FDD module accepts data from the Z80, buffers it, and interrupts the I/O processor to write the sector back to the disk image.
FDC clock
The WD1793 requires a separate clock for its internal timing (step rate, head load, etc.). This is provided by CLKBUS[6] (CKENFDC), typically at 8MHz.
Part 14 — Bus Arbitration
The arbiter module (653 lines) provides a round-robin bus arbitration service for the emulated Z80 bus. In emuMZ mode, multiple agents need access to the emulated bus — the T80 CPU, the keyboard scanner, the CMT interface, the interrupt generator, and the sound module. The arbiter serialises these requests to prevent bus contention.
Arbitration scheme
The arbiter uses a round-robin priority scheme with four bus agents plus the T80 CPU as the default bus master:
| Agent |
Grant signal |
Busy signal |
Reset signal |
Priority slot |
| T80 CPU |
(default master) |
— |
— |
Always active unless preempted |
| Keyboard |
MZ_KEYB_GRANTn |
MZ_KEYB_BUSYn |
MZ_KEYB_RESETn |
0 |
| CMT |
MZ_CMT_GRANTn |
MZ_CMT_BUSYn |
MZ_CMT_RESETn |
1 |
| Interrupt |
MZ_INTR_GRANTn |
MZ_INTR_BUSYn |
MZ_INTR_RESETn |
2 |
| Sound |
MZ_SND_GRANTn |
MZ_SND_BUSYn |
MZ_SND_RESETn |
3 |
Protocol
Each agent that needs bus access asserts its BUSYn signal low (requesting the bus). The arbiter cycles through agents in round-robin order and asserts GRANTn low for the next requesting agent. While granted, the agent drives the emulated bus (address, data, control) and performs its transaction. When finished, the agent deasserts BUSYn, and the arbiter moves to the next slot.
T80 wait state injection
When an agent other than the T80 has the bus, the arbiter asserts MEMWAITn low, which freezes the T80 via its WAIT input. This ensures the T80 does not attempt a memory or I/O cycle while the bus is occupied. The wait state is transparent to the running Z80 software — it simply extends the current bus cycle.
Watchdog timer
The arbiter includes a 1-second watchdog. If any agent holds the bus for longer than ~1 second without deasserting BUSYn, the arbiter forcibly resets that agent (via its RESETn signal) and releases the bus. This prevents a hung peripheral from locking up the entire emulation.
I/O processor bus request
The I/O processor (K64F) can also request the bus via the BUSRQn input to the arbiter. This is a higher priority than the round-robin agents and is used when the I/O processor needs to perform operations like loading ROM images or reading/writing tape data buffers. When the I/O processor is granted the bus, the T80 receives a BUSRQ and must acknowledge with BUSACK before the I/O processor proceeds.
Initialisation
The ARB_INIT output signal pulses during the initial power-up sequence, allowing all agents to synchronise their state machines before the T80 begins execution.
Part 15 — I/O Processor Interface
The I/O Processor (IOP) interface is the communication path between the K64F ARM Cortex-M4 microcontroller and the FPGA. It uses a parallel bus with chip selects, address, data, and read/write control signals.
Physical signals
| Signal |
Width |
Direction |
Function |
| IOP_CSn (multiple) |
1 each |
K64F → FPGA |
Chip select for each module (active low) |
| IOP_ADDR[5:0] |
6 |
K64F → FPGA |
Register address within selected module |
| IOP_DIN[7:0] |
8 |
K64F → FPGA |
Write data |
| IOP_DOUT[7:0] |
8 |
FPGA → K64F |
Read data |
| IOP_WRn |
1 |
K64F → FPGA |
Write strobe (active low) |
| IOP_RDn |
1 |
K64F → FPGA |
Read strobe (active low) |
Chip select map
| Chip select |
Module |
Registers |
Purpose |
| IOP_MCTRL_CSn |
mctrl |
16 |
Machine configuration, reset |
| IOP_MZ80K_CSn |
mz80k_hw |
16 |
Personal series PPI/PIT config |
| IOP_MZ80B_CSn |
mz80b_hw |
16 |
Business series PPI/PIT/PIO config |
| IOP_KEYB_CSn |
keymatrix |
16 |
Keyboard matrix injection, mapping |
| IOP_FDD_CSn |
fdd |
16 |
FDD data transfer, status |
| IOP_CMT0_CSn |
cmt (write) |
64 |
CMT data write (tape loading) |
| IOP_CMT1_CSn |
cmt (read) |
64 |
CMT data read (tape saving) |
| IOP_INTR_CSn |
iointr |
16 |
Interrupt acknowledge, vector read |
| IOP_SND_CSn |
snd |
16 |
Sound configuration |
Transaction protocol
A typical IOP write transaction:
- K64F sets the target module’s CSn low.
- K64F drives IOP_ADDR with the register offset.
- K64F drives IOP_DIN with the data byte.
- K64F asserts IOP_WRn low for at least 2 CKMASTER cycles.
- K64F deasserts IOP_WRn.
- K64F releases CSn.
A typical IOP read transaction:
- K64F sets the target module’s CSn low.
- K64F drives IOP_ADDR with the register offset.
- K64F asserts IOP_RDn low.
- FPGA drives IOP_DOUT with the register value (one CKMASTER cycle latency).
- K64F reads IOP_DOUT.
- K64F deasserts IOP_RDn and CSn.
Data output multiplexing
Each module produces its own IOP_xxx_DOUT signal. The top-level entity multiplexes them based on which chip select is active:
IOP_DOUT <= IOP_MCTRL_DOUT when IOP_MCTRL_CSn = '0' else
IOP_MZ80K_DOUT when IOP_MZ80K_CSn = '0' else
IOP_MZ80B_DOUT when IOP_MZ80B_CSn = '0' else
IOP_KEYB_DOUT when IOP_KEYB_CSn = '0' else
IOP_FDD_DOUT when IOP_FDD_CSn = '0' else
IOP_CMT0_DOUT when IOP_CMT0_CSn = '0' else
IOP_CMT1_DOUT when IOP_CMT1_CSn = '0' else
IOP_INTR_DOUT when IOP_INTR_CSn = '0' else
IOP_SND_DOUT when IOP_SND_CSn = '0' else
(others => '1');
Part 16 — Interrupt System
The iointr module (325 lines) provides an interrupt aggregation and queuing service between the FPGA emulation modules and the I/O processor. It accepts up to 8 independent interrupt sources, queues them in a FIFO, and generates a single interrupt output to the K64F.
Interrupt sources
| Input |
Source |
Typical trigger |
| INTR0n |
CMT module |
Tape buffer empty (needs refill) or full (needs save) |
| INTR1n |
FDD module |
Sector read/write request |
| INTR2n |
Keyboard |
Break key detection |
| INTR3n |
mctrl |
Machine model change notification |
| INTR4n |
Sound |
Buffer underrun |
| INTR5n-7n |
Reserved |
Available for future expansion |
FIFO queue
Each interrupt source triggers a single-entry write to a FIFO. The FIFO stores the interrupt source number (3 bits) as a reason code. When the K64F reads the interrupt reason register (via IOP_INTR_CSn), it receives the oldest queued interrupt and the entry is dequeued. This allows multiple interrupts to be serviced in order even if the K64F cannot respond immediately.
Interrupt handling flow
- A peripheral (e.g., CMT) asserts its INTRn signal low.
- The iointr module latches the source number and pushes it to the FIFO.
- The iointr module asserts the aggregate interrupt output to the K64F.
- The K64F’s interrupt handler reads the reason register via IOP_INTR_CSn.
- Based on the reason code, the K64F performs the required service (e.g., load next tape block).
- The K64F writes an acknowledge to clear the interrupt.
- If more entries remain in the FIFO, the interrupt stays asserted.
Arbiter interaction
The iointr module itself requires bus access to write the interrupt vector to the Z80 bus during an interrupt acknowledge cycle (M1 + IORQ). This is arbitrated through the MZ_INTR_GRANTn / MZ_INTR_BUSYn mechanism.
Part 17 — CPLD Bus Manager
The CPLD (MAX7000AE EPM7512AETC144-10) sits between the Sharp MZ mainboard's 5V bus and the 3.3V FPGA and SRAM. It handles all timing-critical glue that cannot tolerate FPGA configuration latency and provides the first level of bus decode on every transaction.
CPLD source files
| File |
Purpose |
tranZPUterSW700.vhd (MZ-700) / tzpuSW700_MZ80A.vhd (MZ-80A) |
Main architecture |
tranZPUterSW700_Toplevel.vhd |
Top-level entity, I/O pin assignments |
tranZPUterSW700_pkg.vhd |
Package (constants, type definitions) |
CPLD Configuration Register (I/O 0x6E)
| Bit(s) |
Function |
| [2:0] |
Video mode: 000=MZ-80K, 001=MZ-80C, 010=MZ-1200, 011=MZ-80A, 100=MZ-700, 101=MZ-800, 110=MZ-80B, 111=MZ-2000 |
| [3] |
Mainboard video enable (1=mainboard video active) |
| [4] |
WAIT state enable |
| [7] |
Preserve config (prevent reset from clearing mode register) |
Key CPLD functions
Level translation and bus interface: The CPLD drives the VZ80_* signals (3.3V, FPGA-side) from the Z80_* signals (5V, mainboard-side). All mainboard-facing pins operate at 5V tolerance; all FPGA-facing pins drive 3.3V.
BUSRQ/BUSACK handshake: When the FPGA (or K64F) needs to take control of the mainboard bus, the CPLD manages the Z80 BUSRQ/BUSACK protocol. S-R latches ensure glitch-free transitions between bus master states.
Clock frequency switching: Two D flip-flops implement a glitch-free clock multiplexer. The Z80 can run on either the mainboard SYSCLK (original speed) or CTLCLK (programmable frequency from K64F). The changeover waits for both clocks to be idle.
TZMM mode register (MEM_MODE_LATCH): The 8-bit memory mode latch (I/O port 0x60) selects which 64KB page of the 512KB SRAM is mapped into the Z80 address space. Bits [4:0] are forwarded on Z80_MEM[4:0] to the FPGA. Bit 5 enables the I/O wait state generator.
I/O address decode: The CPLD decodes writes to the tranZPUter I/O range 0x60-0x6F into individual chip-select signals for the FPGA's CPU configuration, CPLD configuration, memory mode, and video control registers.
Video access decode: The CPLD generates the VIDEO_RDn and VIDEO_WRn signals by decoding memory access to the video RAM address range (typically D000-DFFF), forwarding these as dedicated strobes to the FPGA video controller.
Build variants
| CPLD project |
Host machine |
Differences |
| tranZPUterSW700 |
MZ-700 |
Default I/O decode, colour video access |
| tzpuSW700_MZ80A |
MZ-80A |
Modified I/O decode for MZ-80A memory map |
| tzpuSW700_MZ2000 |
MZ-2000 |
Business series bus timing, GRAM access decode |
The CPLD is built with Quartus Prime 13.0 SP1 (the last version supporting MAX7000AE) using the CPLDfit fitter. Programming uses a standard USB-Blaster cable in JTAG mode.
Part 18 — Personal Series Hardware
The mz80k_hw module (1416 lines) implements the hardware for the Personal series Sharp MZ computers: MZ-80K, MZ-80C, MZ-1200, MZ-80A, MZ-700, and MZ-800. It contains the Z80 address decoder, I/O address decoder, and instantiates the machine-specific peripherals.
Peripherals
| Component |
Instance |
Function |
| i8255 |
PPI |
Keyboard scanning (Port A), keyboard data (Port B), cassette/sound control (Port C) |
| i8254 |
PIT |
Counter 0 = sound tone, Counter 1 = cascaded, Counter 2 = RTC |
I/O address map (Personal series)
| Address |
Read |
Write |
Machine |
| 0xE000 |
PPI Port A (key scan) |
PPI Port A |
All |
| 0xE001 |
PPI Port B (key data) |
PPI Port B |
All |
| 0xE002 |
PPI Port C (status) |
PPI Port C (control) |
All |
| 0xE003 |
— |
PPI control word |
All |
| 0xE004-E007 |
PIT Counter 0-2 + control |
PIT Counter 0-2 + control |
All |
| 0xE008 |
— |
Memory bank control |
MZ-700 only |
| 0xE9 |
— |
Graphics bank switch reset |
MZ-700/800 (with GRAM) |
| 0xEA |
Graphics control |
Graphics control |
MZ-700/800 (with GRAM) |
Memory banking (MZ-700)
The MZ-700 uses a unique memory banking scheme controlled by writes to address 0xE008. At boot, the monitor ROM occupies 0x0000-0x0FFF; after loading a program, the ROM is banked out and the full 64KB RAM is accessible. Additionally, the MZ-700 can bank in/out the VRAM/ARAM at 0xD000-0xDFFF and I/O at 0xE000-0xFFFF:
| Bank control write |
Effect |
| 0xE0 to 0xE000 |
Bank out ROM, bank in RAM at 0x0000 |
| 0xE1 to 0xE000 |
Bank in ROM at 0x0000 |
| 0xE2 to 0xE000 |
Bank out VRAM/IO, bank in RAM at 0xD000-0xFFFF |
| 0xE3 to 0xE000 |
Bank in VRAM/IO at 0xD000-0xFFFF |
Machine-specific differences
The CONFIG[10:0] CURRENTMACHINE bits select which machine model is emulated. The mz80k_hw module uses these bits to:
- Select the correct ROM bank from SYSROM
- Enable or disable colour attribute RAM (mono machines have no ARAM)
- Configure the PPI Port C bit assignments (which differ between MZ-80K and MZ-700)
- Enable/disable the SN76489 sound (MZ-700/800 only)
- Configure PCG support (MZ-700 with PCG option)
Part 19 — Business Series Hardware
The mz80b_hw module (676 lines) implements the hardware for the Business series: MZ-80B, MZ-2000, MZ-2200, and MZ-2500. These machines have a fundamentally different architecture from the Personal series, with IPL boot ROM, a Z80 PIO, 80-column display, three-plane graphics RAM, and an APSS-capable cassette interface.
Additional peripherals
| Component |
Instance |
Function |
| i8255 |
PPI |
Similar to Personal series but different port assignments |
| i8254 |
PIT |
Counter cascade mode for timing |
| z8420 |
PIO |
Z80 Parallel I/O — interrupt-driven input/output |
I/O address map (Business series)
| Address |
Function |
Notes |
| 0xD4-0xD7 |
i8254 PIT |
Different base address from Personal series |
| 0xD8-0xDB |
i8255 PPI |
Business series configuration |
| 0xDC-0xDD |
Memory control |
RAM/ROM banking |
| 0xE0-0xE3 |
CRTC / video control |
Display timing registers |
| 0xE4-0xE7 |
Reserved |
— |
| 0xE8-0xED |
Graphics control |
Frame buffer bank/colour select |
| 0xF4-0xF7 |
Z80 PIO Port A/B |
Data and control registers |
| 0xFE-0xFF |
IPL / Boot control |
IPL ROM enable/disable |
Graphics Frame Buffer
The MZ-80B/2000 graphics subsystem provides three independent frame buffer planes (Red, Green, Blue), each 16KB, mapped into the Z80 address space at 0xC000-0xFFFF via bank switching:
| Register |
Address |
Function |
| 0xE8 |
Graphics bank switch set |
Select R/W bank (R/G/B) for C000-FFFF window |
| 0xE9 |
Graphics bank switch reset |
Deselect bank |
| 0xEA |
Control register |
Read bank select, write bank select, VRAM/GRAM enable, blend operator |
| 0xEB |
Red colour writer |
Write byte to red plane |
| 0xEC |
Green colour writer |
Write byte to green plane |
| 0xED |
Blue colour writer |
Write byte to blue plane |
The colour writer registers allow simultaneous writes to one or more planes with a single I/O instruction, enabling fast screen fills and colour setting operations.
IPL Boot sequence
The MZ-80B and MZ-2000 use an IPL (Initial Program Load) ROM that is active only during boot. When CONFIG[73] BOOT_RESET is set, the IPL ROM appears at address 0x0000. After the IPL loads the monitor from cassette (or FDD), it banks out the IPL ROM and jumps to the loaded code. The BOOT_RESET configuration allows the I/O processor to trigger a clean boot cycle.
Part 20 — Graphics Frame Buffer
The graphics frame buffer is a shared subsystem used by both the Personal series (MZ-700/800 with GRAM option) and the Business series (MZ-80B/2000 native). It provides three 16KB frame buffer planes that can be independently addressed and composited with the character display.
Memory layout
| Plane |
FPGA address |
Size |
Z80 access |
| Red |
0x240000-0x243FFF |
16KB |
Via bank switch register (0xE8/0xE9) |
| Blue |
0x250000-0x253FFF |
16KB |
Via bank switch register |
| Green |
0x260000-0x263FFF |
16KB |
Via bank switch register |
Blend modes (Control register 0xEA)
| Mode bits |
Operation |
Description |
| 00 |
Replace |
Graphics pixels replace character display |
| 01 |
OR |
Graphics OR’d with character display |
| 10 |
AND |
Graphics AND’d with character display |
| 11 |
XOR |
Graphics XOR’d with character display |
Colour writer operation
The colour writer registers (0xEB-0xED) provide a hardware-accelerated method for setting pixel colours across multiple planes simultaneously. Writing a byte to the Red colour writer (0xEB) sets 8 horizontal pixels in the Red plane. Writing to Green (0xEC) and Blue (0xED) does the same for their respective planes. The address within each plane is set by the Z80's current address in the 0xC000-0xFFFF window:
-- Colour writer: when Z80 writes to colour register, the value is
-- written to the corresponding plane at the current GRAM address.
if CS_GRAM_WR = '1' then
case GRAM_BANK is
when "001" => GRAM_RED(GRAM_ADDR) <= Z80_DATA;
when "010" => GRAM_GREEN(GRAM_ADDR) <= Z80_DATA;
when "100" => GRAM_BLUE(GRAM_ADDR) <= Z80_DATA;
when others => null;
end case;
end if;
GRAM options (CONFIG bits)
| CONFIG bit |
Constant |
Function |
| 43 |
OPT_GRAMI |
MZ-80B GRAM I / MZ-2000 Blue installed |
| 44 |
OPT_GRAMII |
MZ-80B GRAM II / MZ-2000 Red installed |
| 45 |
OPT_GRAMIII |
MZ-2000 Green installed |
| 46 |
OPT_PCG |
PCG (Programmable Character Generator) installed |
| 47 |
OPT_MZ1R25 |
16KB Video RAM expansion installed |
The VideoController provides two OSD (On-Screen Display) overlays: a status bar and a configuration menu. Both are rendered into dedicated frame buffers and composited on top of the emulation display.
Status overlay
The status bar occupies the bottom portion of the screen and displays real-time information: current machine model, CPU speed, tape status, and drive activity. It is enabled by CONFIG[72] STATUSENABLE. The I/O processor writes status text into the status frame buffer at address 0x320000.
The configuration menu allows the user to change machine model, display mode, CPU speed, audio settings, and other options without a host computer. It is enabled by CONFIG[71] MENUENABLE. The I/O processor manages the menu state machine and writes the rendered menu into the menu frame buffer at address 0x322000.
Video parameter table
A 32x32 parameter table at address 0x324000 stores per-mode display timing parameters. Each entry contains horizontal/vertical total, active, sync start/end values. The VideoController reads the active entry to configure its timing generators when the display mode changes. The current video mode index is stored at 0x324400.
OSD compositing
During the active display period, the VideoController checks whether the current pixel position falls within the OSD region. If it does and the corresponding OSD pixel is non-transparent, the OSD colour replaces the emulation output. The OSD uses a semi-transparent background to remain readable over any emulation display mode.
Part 22 — Adding a New Emulated Machine
This section provides a step-by-step guide for adding support for a new Sharp MZ model (or a closely related Z80 machine) to the emuMZ emulator.
Step 1: Define the machine constant
Add a new machine constant in mctrl_pkg (at the top of mctrl.vhd):
constant MZ_NEW_MODEL : integer := 11; -- Next available index after MZ2500
Extend the CURRENTMACHINE subtype range if necessary.
Step 2: Add ROM bank
Allocate a bank pair in the SYSROM for the new machine's monitor ROM. Update the ROM initialisation file (combined_mrom.mif) to include the binary image at the correct offset.
Step 3: Choose controller branch
Decide whether the new machine belongs to the Personal series (extend mz80k_hw.vhd) or Business series (extend mz80b_hw.vhd). Add the new CONFIG machine bit to the relevant controller's decode logic.
Step 4: Define memory map
Add address decode logic in the chosen controller for the new machine's memory map. Use the CONFIG[10:0] machine bit to gate the new decode:
if CONFIG(MZ_NEW_MODEL) = '1' then
-- New machine's memory map
CS_ROM_n <= '0' when Z80_ADDR(15 downto 12) = "0000" else '1';
CS_RAM_n <= '0' when Z80_ADDR(15 downto 12) /= "0000" else '1';
-- ... etc
end if;
Step 5: Add machine-specific peripherals
If the new machine has peripherals not already in the design, create new VHDL modules and instantiate them in the controller. Register them with the arbiter if they need bus access.
Step 6: Update keyboard mapping
If the keyboard layout differs, add a new mapping table in keymatrix.vhd selected by the CONFIG machine bits.
Step 7: Update video timing
If the display timing differs, add a new timing parameter set in the VideoController. Add the new mode constant to VideoController_pkg.vhd.
Step 8: Update I/O processor
Update the K64F firmware to recognise the new machine model: add the ROM filename, display name, and default configuration values. Update the OSD menu to include the new model in the machine selection list.
Step 9: Test
Build the FPGA project, program the device, select the new machine via the OSD menu, and verify that the monitor ROM executes correctly. Use Signal Tap or slow clocks for debugging if needed.
Part 23 — Building from Source
Prerequisites
| Tool |
Version |
Purpose |
| Intel Quartus Prime |
17.1.1 (Lite or Standard) |
FPGA synthesis, place & route |
| Intel Quartus II |
13.0 SP1 (Web Edition) |
CPLD synthesis (MAX7000AE) |
| USB-Blaster |
— |
JTAG programming cable |
| Docker |
Latest |
Containerised build environment for CI/CD |
FPGA build
The FPGA project files are under FPGA/SW700/v1.3/MZ700/build/. Each build variant has its own Quartus project file:
| Project file |
Build variant |
Top entity |
coreMZ.qpf / coreMZ.qsf |
Video-only |
coreMZ |
coreMZ_SoftCPU.qpf / coreMZ_SoftCPU.qsf |
Video + soft CPUs |
coreMZ |
coreMZ_emuMZ.qpf / coreMZ_emuMZ.qsf |
Full emulation |
coreMZ |
To build manually:
cd FPGA/SW700/v1.3/MZ700/build/
quartus_sh --flow compile coreMZ_emuMZ
The build produces:
| Output file |
Purpose |
coreMZ_emuMZ.sof |
SRAM Object File — volatile JTAG programming |
coreMZ_emuMZ.pof |
Programmer Object File — non-volatile EPCS programming |
coreMZ_emuMZ.rbf |
Raw Binary File — for loading via K64F |
CPLD build
The CPLD project files are under CPLD/, one directory per target machine:
cd CPLD/SW700/MZ700/build/
quartus_sh --flow compile tranZPUterSW700
Build matrix
FPGA builds (Quartus 17.1.1):
| Target |
FPGA |
Variant |
Total |
| SW700 v1.3 |
EP4CE115 |
coreMZ, coreMZ_SoftCPU, coreMZ_emuMZ |
3 |
| SW700 v1.3 |
EP4CE75 |
coreMZ, coreMZ_SoftCPU |
2 |
| Fusion v1.0 |
EP4CE115 |
coreMZ, coreMZ_SoftCPU, coreMZ_emuMZ |
3 |
| Fusion v1.0 |
EP4CE75 |
coreMZ, coreMZ_SoftCPU |
2 |
With three host machines (MZ-700, MZ-80A, MZ-2000) per FPGA variant, the complete SW700 FPGA build matrix is 3 machines x 2 FPGAs x 3 modes = 18 builds.
CPLD builds (Quartus 13.0 SP1):
| Target |
Host |
CPLD project |
| SW700 v1.3 |
MZ-700 |
tranZPUterSW700 |
| SW700 v1.3 |
MZ-80A |
tzpuSW700_MZ80A |
| SW700 v1.3 |
MZ-2000 |
tzpuSW700_MZ2000 |
| FusionX v1.0 |
MZ-700 |
tzpuFusionX (MZ700) |
| FusionX v1.0 |
MZ-80A |
tzpuFusionX (MZ80A) |
| FusionX v1.0 |
MZ-2000 |
tzpuFusionX (MZ2000) |
Part 24 — Jenkins CI/CD Pipeline
Build overview
The tranZPUter-Build Jenkins pipeline automates the entire FPGA and CPLD build matrix, producing versioned release packages. The pipeline is triggered by Gitea push webhooks on the master branch.
| Stage |
Tool |
Output |
| Checkout |
Git (Gitea) |
tranZPUter source tree |
| Version |
Gitea API |
Auto-incremented version number |
| FPGA Build (×N) |
Quartus 17.1.1 (Docker) |
.sof, .pof, .rbf per variant |
| CPLD Build (×N) |
Quartus 13.0.1 (Docker) |
.pof per target |
| Package |
tar/gz |
Versioned release archives |
| Release |
Gitea API |
Tagged release with downloadable assets |
Docker build environments
| Image |
Version |
Purpose |
quartus-prime-17.1.1 |
Intel Quartus Prime 17.1.1 Lite |
FPGA synthesis for Cyclone IV |
quartus-ii-13.0.1 |
Intel Quartus II 13.0 SP1 |
CPLD synthesis for MAX7000AE |
Triggering builds
- Automatic: Gitea push webhook on
master branch
- Manual: Jenkins “Build Now” at
https://jenkins.eaw.app/job/tranZPUter-Build/
Build artifacts
Each build produces programming files for all variants in the matrix. The release package includes:
- FPGA .sof/.pof/.rbf files for each machine/FPGA/variant combination
- CPLD .pof files for each machine target
- ROM initialisation files (combined_mrom.mif)
- Release notes
Part 25 — Development Workflow
Edit-compile-test cycle
The typical development workflow is:
- Edit VHDL — Modify the relevant source file(s) in a text editor or Quartus.
- Compile — Run
quartus_sh --flow compile coreMZ_emuMZ (or use Quartus GUI “Start Compilation”). A full emuMZ build takes approximately 15-25 minutes on a modern workstation.
- Program — Connect USB-Blaster to the JTAG header. Use
quartus_pgm or Quartus Programmer to load the .sof file. JTAG programming takes ~10 seconds and is volatile (lost on power-off).
- Test — Power on the host machine. The FPGA loads from the JTAG image and the emulation starts. Use the OSD menu (if compiled in) to select machine model and verify operation.
- Iterate — If issues are found, return to step 1. Use Signal Tap for debugging if the issue is internal to the FPGA.
Debug techniques
| Technique |
Tool |
Use case |
| Signal Tap |
Quartus (JTAG) |
Capture internal FPGA signals at full speed, view waveforms |
| Slow clocks |
CONFIG debug register |
Set CPU to 0.1-100Hz for human-observable execution |
| LED indicators |
Board LEDs |
Quick status indication (bus state, mode, errors) |
| IOP register dump |
K64F serial console |
Read back CONFIG, CMT status, arbiter state |
| VRAM inspection |
IOP VRAM read |
Verify video memory contents match expected state |
| Logic analyser |
External probe |
Capture external bus signals (VZ80_ADDR, VZ80_DATA, etc.) |
Signal Tap setup
Signal Tap II is Quartus's built-in logic analyser. To add it to the emuMZ build:
- Open the Quartus project (
coreMZ_emuMZ.qpf).
- Go to Tools → Signal Tap II Logic Analyzer.
- Add signals of interest (e.g., T80_ADDR, T80_DATA_OUT, CORE_MREQn, CLKBUS).
- Set the sample clock to CLKBUS(CKMASTER) and the sample depth (limited by available block RAM).
- Define trigger conditions (e.g., T80_ADDR = 0x0000 to capture the first instruction fetch after reset).
- Recompile — Signal Tap adds instrumentation logic and uses block RAM for the capture buffer.
- Program the FPGA and run the capture from the Signal Tap GUI.
Note: Signal Tap consumes block RAM. On the EP4CE75, this may cause the emuMZ build to exceed memory limits. Use the EP4CE115 for Signal Tap sessions.
Timing analysis
After compilation, always check the Quartus Timing Analyzer report. The SDC constraints file (coreMZ_emuMZ_constraints.sdc) defines all clock relationships. Key items to verify:
- All setup/hold requirements met (no negative slack)
- CKMASTER-to-register paths meet timing at 128MHz
- Cross-domain paths (CLOCK_50 to PLL output) properly constrained
Part 26 — Extending the Design
Adding a new peripheral
To add a new peripheral to the emulation:
-
Create the VHDL module — Follow the existing module pattern: entity with CLKBUS, CONFIG, IOP, and bus signals; architecture with clocked processes on CKMASTER.
-
Add IOP chip select — If the peripheral needs I/O processor access, add a new IOP_xxx_CSn signal in the top-level entity and connect it to the K64F’s chip select decoder.
-
Register with arbiter — If the peripheral needs emulated bus access, add a new agent slot to the arbiter. Extend the round-robin with a new GRANT/BUSY/RESET signal triplet.
-
Connect to top-level — Instantiate the new module in coreMZ_emuMZ.vhd and wire its ports to the appropriate internal signals.
-
Add to QIP — Add the new VHDL file to the coreMZ_emuMZ.qip file list so Quartus includes it in compilation.
-
Update CONFIG — If the peripheral needs configuration bits, extend the CONFIG bus in mctrl_pkg and add the corresponding IOP register in mctrl.vhd.
Memory expansion
The emuMZ variant uses FPGA block RAM exclusively. To add more memory:
- Block RAM: Instantiate additional
dpram modules. Check FPGA utilisation — the EP4CE115 has 3,981 Kbits total.
- External SRAM: Route through the CPLD. This requires changes to the CPLD decode logic and FPGA top-level entity to add SRAM address/data/control signals.
- SDRAM controller: The
devices/sysbus/SDRAM/ directory contains SDRAM controller IP for W9864G6 and 48LC16M16 devices. These can be instantiated for large memory applications (e.g., ZPU Evolution with megabytes of RAM).
Porting to a new FPGA
The VHDL is largely portable. Platform-specific items that require modification:
| Item |
File(s) |
What to change |
| PLL |
PLL/ directory |
Replace Altera PLL megafunction with target vendor equivalent |
| Block RAM |
dpram.vhd, BRAM templates |
Replace Altera RAM megafunctions |
| SFL |
SFL/ directory |
Serial Flash Loader — remove or replace |
| Pin assignments |
.qsf file |
Map to new FPGA package pins |
| SDC constraints |
coreMZ_emuMZ_constraints.sdc |
Update clock and timing constraints |
The T80 Z80 core, all peripheral controllers (i8254, i8255, z8420, WD1793, SN76489), and the VideoController are pure VHDL and synthesise on any FPGA vendor's tools.
Part 27 — Source File Reference
FPGA/SW700/v1.3/MZ700/ (main source tree)
| File |
Lines |
Purpose |
coreMZ.vhd |
~800 |
Top-level entity — video-only build |
coreMZ_SoftCPU.vhd |
~1200 |
Top-level — video + soft CPUs (T80 + ZPU) |
coreMZ_emuMZ.vhd |
1783 |
Top-level — full Sharp MZ emulation |
coreMZ_pkg.vhd |
187 |
Package: host model constants, utility functions |
functions.vhd |
~200 |
Shared utility functions |
FPGA/SW700/v1.3/MZ700/VideoController/
| File |
Lines |
Purpose |
VideoController.vhd |
5400 |
Complete video pipeline (character, graphics, OSD, palette) |
VideoController_pkg.vhd |
201 |
Video mode constants, host hardware mode definitions |
ChrGenRAM_DP_3208.vhd |
— |
Character generator dual-port BRAM template |
VideoRAM_DP_3216.vhd |
— |
Video RAM dual-port BRAM template |
FPGA/SW700/v1.3/MZ700/emuMZ/ (emulation core)
| File |
Lines |
Purpose |
mctrl.vhd |
689 |
Machine control: CONFIG bus, register decode, reset management |
clkgen.vhd |
571 |
Clock generation: PLL, dividers, clock enables |
arbiter.vhd |
653 |
Round-robin bus arbitration with watchdog |
cmt.vhd |
1806 |
Cassette tape: PWM encode/decode, APSS, data cache |
keymatrix.vhd |
1222 |
PS/2 to Sharp MZ keyboard translation |
mz80k_hw.vhd |
1416 |
Personal series hardware (MZ-80K/C/1200/80A/700/800) |
mz80b_hw.vhd |
676 |
Business series hardware (MZ-80B/2000/2200/2500) |
fdd.vhd |
355 |
Floppy disk controller (WD1793 emulation) |
iointr.vhd |
325 |
I/O processor interrupt aggregation FIFO |
snd.vhd |
369 |
Sound: SN76489 + i8253 audio |
FPGA/SW700/v1.3/MZ700/emuMZ/ (sub-directories)
| Directory |
Contents |
i8254/ |
Intel 8254 Programmable Interval Timer VHDL |
i8255/ |
Intel 8255 Programmable Peripheral Interface VHDL |
wd1793/ |
WD1793 Floppy Disk Controller VHDL |
z8420/ |
Zilog Z80 PIO VHDL |
common/T80/ |
T80 Z80 CPU core (T80.vhd, T80_ALU.vhd, T80_MCode.vhd, T80_Reg.vhd, T80_Pack.vhd) |
mz80c/, mz80b/ |
Machine-specific sub-modules |
mif/ |
Memory initialisation files (.mif) |
FPGA/SW700/v1.3/MZ700/softT80/
| File |
Purpose |
softT80.vhd |
T80 soft Z80 wrapper module |
softT80_pkg.vhd |
T80 configuration package |
T80/ |
T80 Z80 IP core source (shared with emuMZ) |
FPGA/SW700/v1.3/MZ700/softZPU/
| File |
Purpose |
softZPU.vhd |
ZPU Evolution soft CPU wrapper |
softZPU_pkg.vhd |
ZPU configuration package |
ZPU/ |
ZPU Evolution core VHDL |
Other directories
| Path |
Contents |
FPGA/SW700/v1.3/MZ700/PLL/ |
Altera PLL megafunction instances |
FPGA/SW700/v1.3/MZ700/SFL/ |
Serial Flash Loader megafunction (EPCS boot ROM programming) |
FPGA/SW700/v1.3/MZ700/devices/ |
Peripheral IP: BRAM, SDRAM, UART, timer, interrupt, SD/MMC, RAM |
FPGA/SW700/v1.3/MZ700/build/ |
Quartus project files (.qpf, .qsf, .sdc per variant) |
CPLD/ |
CPLD VHDL source per target machine |
schematics/SW700/ |
KiCad schematics per board revision (v1.0-v1.4) |
pcb/SW700/ |
Gerber PCB files (v1.2a, v1.3, v1.3a) |
tools/ |
Build utilities: build_meminitfiles.sh, Python BRAM init scripts |
Part 28 — Resources & Links
Project links
Reference documentation
| Document |
Content |
| T80 CPU core (opencores.org) |
Z80 instruction set implementation, bus timing |
| Intel i8255A datasheet |
Programmable Peripheral Interface specification |
| Intel i8254 datasheet |
Programmable Interval Timer specification |
| Zilog Z8420 datasheet |
Z80 PIO specification |
| WD1793 datasheet |
Floppy Disk Controller command set and timing |
| SN76489 datasheet |
Programmable Sound Generator specification |
| Intel Quartus Prime Handbook |
FPGA synthesis, timing analysis, Signal Tap |
| Quartus II 13.0 CPLD Handbook |
MAX7000AE fitting, programming |
Sharp MZ technical references
| Machine |
Key specifications |
| MZ-80K/C/1200 |
Z80 @ 2MHz, 48KB RAM, 4KB ROM, 40x25 mono, cassette 1200 baud |
| MZ-80A |
Z80 @ 2MHz, 48KB RAM, 4KB ROM, 40x25 mono, improved keyboard |
| MZ-700 |
Z80 @ 3.58MHz, 64KB RAM, colour display, PCG option, built-in plotter |
| MZ-800 |
Z80 @ 3.58MHz, 64KB RAM, QD drive, enhanced graphics |
| MZ-80B |
Z80 @ 4MHz, 64KB RAM, 80-column display, GRAM I/II, IPL boot |
| MZ-2000 |
Z80 @ 4MHz, 64KB RAM, GRAM I/II/III, FDD, APSS cassette |
Acronym reference
| Acronym |
Meaning |
| APSS |
Automatic Program Search System |
| ARAM |
Attribute RAM (colour attributes per character cell) |
| BRAM |
Block RAM (FPGA embedded memory) |
| CGRAM |
Character Generator RAM (programmable characters) |
| CGROM |
Character Generator ROM (fixed font) |
| CMT |
Cassette Magnetic Tape |
| CONFIG |
91-bit machine configuration bus |
| CPLD |
Complex Programmable Logic Device |
| DRQ |
Data Request (WD1793 handshake) |
| emuMZ |
Sharp MZ Series FPGA Emulation build variant |
| FDC |
Floppy Disk Controller |
| FDD |
Floppy Disk Drive |
| FPGA |
Field-Programmable Gate Array |
| GRAM |
Graphics RAM (frame buffer memory) |
| IOP |
I/O Processor (K64F ARM Cortex-M4) |
| IPL |
Initial Program Load (boot ROM) |
| JTAG |
Joint Test Action Group (debug/programming interface) |
| MZF |
Sharp MZ tape File format |
| OSD |
On-Screen Display |
| PCG |
Programmable Character Generator |
| PIO |
Parallel Input/Output (Z80 PIO Z8420) |
| PIT |
Programmable Interval Timer (i8254) |
| PLL |
Phase-Locked Loop |
| PPI |
Programmable Peripheral Interface (i8255) |
| PSG |
Programmable Sound Generator (SN76489) |
| SDC |
Synopsys Design Constraints (timing constraints file) |
| SFL |
Serial Flash Loader |
| SOF |
SRAM Object File (volatile JTAG programming) |
| T80 |
Open-source Z80 CPU core (VHDL) |
| TZMM |
tranZPUter Memory Mode |
| TZFS |
tranZPUter Filing System |
| VRAM |
Video RAM (character display memory) |
| ZPU |
Zylin Processing Unit (32-bit stack CPU) |