Sharp MZ-80A Video Module — Technical Guide
Sharp MZ-80A Video Module Technical Guide
This guide documents the internal architecture, memory map, programmable register set, GPU command interface, video timing modes, and build system for the Sharp MZ-80A Video Module. It covers all three hardware versions: the v1.0 prototype, the v1.1 recommended discrete design, and the v2.0 FPGA-based design. It is intended for hardware developers, firmware authors, and anyone who needs to understand or program the Video Module at a system level.
For day-to-day usage and installation instructions see the Video Module project page.
Hardware Versions
Three hardware versions of the Video Module exist. They share the same core objective — restoring the 80-column capability that Sharp disabled in the MZ-80A and adding colour output — but differ substantially in implementation. v1.0 is a prototype with known issues and is not recommended for new builds. v1.1 corrects all v1.0 issues with discrete logic and is the recommended choice when a tranZPUter board is not available. v2.0 uses CPLD and FPGA technology and requires a pre-installed tranZPUter board; it delivers the full video capabilities of the Sharp MZ Emulator on real hardware.
v1.0 — Prototype
The v1.0 board was the initial prototype. Five issues were discovered during production and use:
v1.1 — Current Discrete Design (Recommended)
- Gate array footprints swapped in KiCad. The MB14298 and MB14299 footprints were transposed. Correction required fine soldering and rewiring on the assembled board.
- Oscillator signal quality. The oscillator did not produce a clean signal. Adding a 100 pF ceramic capacitor between U14B pin 4 and GND resolved this; the problem was compounded by the rewiring required for issue 1.
- Gate array G signal PCB break. The G signal between the two gate arrays was unconnected on the PCB despite being correctly shown in the schematic. A manual jumper wire was required.
- Attribute RAM and control latch address clash at 0xDFFF. A write to the control latch also updated the top location of the attribute RAM mirror, which could corrupt the last visible attribute if the Character RAM was hardware-scrolled to the bottom of the display.
- Physical alignment issues. The gate array raiser pin positions were not accurately measured, causing difficulty during installation and stress on the raiser pins.
v1.1 resolves all five v1.0 issues in a redesigned PCB:
v2.0 — FPGA Design
- Issues 1, 2, and 5 were resolved by correcting the KiCad footprints, switching from discrete oscillator components to an oscillator module, and using precise measurements (pencil trace of the MZ-80A motherboard with micrometer verification) for the gate array raiser pin positions.
- Issue 3 was resolved in the corrected schematic and PCB routing.
- Issue 4 was resolved by adding a 74HCT123 monostable multivibrator circuit. When a read occurs at 0xDFFF the monostable is triggered, opening a window of approximately one Z80 instruction cycle in which a subsequent write to 0xDFFF is directed to the control latch (IC U11) rather than the attribute RAM. This allows the sequence
LD A,(HL); LD (HL),Bwith HL=0xDFFF to safely update the latch. Any write to 0xDFFF that is not immediately preceded by a read goes to the attribute RAM as normal.
v2.0 replaces all discrete logic with an Altera MAX 7000A CPLD for bus interfacing and level translation, and an Altera Cyclone III FPGA (EP3C25E144C8) for a full software-defined video controller. The FPGA carries all video RAM, attribute RAM, character generator RAM, and graphics frame buffers internally as block RAM, eliminating all external video memory chips. A tranZPUter board must be installed before fitting v2.0, as the Video Module requires signals forwarded from the tranZPUter that are not available on the MZ-80A motherboard expansion connector alone.
v2.0 provides:
- Full emulation of all Sharp MZ series video modes: MZ-80K, MZ-80C, MZ-1200, MZ-80A, MZ-700, MZ-80B (including GRAM I and II), MZ-800, MZ-2000.
- VGA output at 640×480, 800×600, and 1024×768 at 60 Hz, in addition to the native 15.62 kHz horizontal scan rate.
- 8-colour pixel graphics frame buffer at 640×200 (80-column mode) or 320×200 (40-column mode).
- A programmable character generator RAM (CGRAM) uploadable by the CPU.
- A GPU with VRAM and GRAM clear/fill commands.
- A programmable palette system with 256 entries.
- Double-buffered display in all modes except 640×200 (insufficient block RAM for two full buffers at that resolution).
v1.x Hardware Architecture
The v1.x design implements the colour and 40/80 column circuits using discrete 74HCT-series logic, a 2 KB SRAM for the attribute RAM, and a 32 KB Flash RAM for the character generator. The gate arrays IC20 and IC31 (MB14298 and MB14299) are lifted from the MZ-80A motherboard and re-seated on the daughter card where their signal connections can be rerouted. No signals on the MZ-80A motherboard are cut; the modification is fully reversible.
Memory Map
The v1.x board adds two new memory-mapped regions to the standard MZ-80A address space. The Character RAM at 0xD000–0xD7FF is unchanged from the original machine. The Attribute RAM and control latch occupy 0xD800–0xDFFF:
Address Size Contents
───────────────────────────────────────────────────────────────────
0xD000–0xD7FF 2 KB Character RAM — display characters, unchanged from original MZ-80A.
CPU read/write. Scanned by video hardware each frame.
0xD800–0xDFFF 2 KB Attribute RAM (IC U6, 2 KB SRAM) — colour and CG-ROM selection.
Each byte pairs with the corresponding Character RAM location.
CPU read/write for 0xD800–0xDFFE.
0xDFFF Control latch (74HCT373, IC U9 v1.0 / IC U11 v1.1) — write-only.
Address shared with top byte of Attribute RAM.
In v1.1: a read of 0xDFFF must immediately precede any write
intended for the latch (see monostable circuit description).
───────────────────────────────────────────────────────────────────
Attribute RAM
The 2 KB SRAM at IC U6 is mapped to 0xD800–0xDFFF. Each byte in the attribute RAM corresponds to the character at the same offset in the Character RAM (0xD000–0xD7FF). The video scanning circuit reads both RAMs in parallel; as each character byte is serialised for display the corresponding attribute byte is latched by IC U7 and used to generate colour and CG-ROM selection signals.
The attribute byte layout is:
| Bits | Field | Description |
|---|---|---|
| 0 | Background Blue | Background colour blue channel (1=on). |
| 1 | Background Red | Background colour red channel (1=on). |
| 2 | Background Green | Background colour green channel (1=on). |
| 3 | CG-ROM sub-select bit 0 | Selects one of 4 CG-ROM slots within the active group (combined with bit 7). |
| 4 | Foreground Blue | Foreground colour blue channel (1=on). |
| 5 | Foreground Red | Foreground colour red channel (1=on). |
| 6 | Foreground Green | Foreground colour green channel (1=on). |
| 7 | CG-ROM sub-select bit 1 | Selects one of 4 CG-ROM slots within the active group (combined with bit 3). |
Example: to display the character 'A' (0x41) in blue foreground on a black background at screen position (0,0), write 0x41 to 0xD000 and 0x10 to 0xD800. Bit 4 of the attribute byte sets the blue foreground channel; bits 2:0 are clear giving black background. CG-ROM sub-select bits 7 and 3 are both zero, selecting slot 0 of the active group.
Colour Generation
The original Sharp MZ-80A was intended by Sharp to have a colour output board, as documented in the 1982 user manual (a very rare edition). Nibbles Lab discovered and published a working circuit design based on this documentation. The v1.x Video Module implements this circuit with modifications for composite video output.
Colour is generated digitally — each RGB channel is either fully on or fully off, giving 8 possible foreground colours and 8 possible background colours. Foreground RGB is driven by attribute bits 6 (G), 5 (R), and 4 (B); background RGB is driven by bits 2 (G), 1 (R), and 0 (B). The resulting digital signals are fed to separate resistor networks for foreground and background, producing analogue voltage levels appropriate for an RGB monitor. Transistor Q1 blends the RGB outputs with the composite sync signal for composite monitor output.
The available colours are:
| Bits 6,5,4 (FG) or 2,1,0 (BG) | Colour |
|---|---|
| 0,0,0 | Black |
| 0,0,1 | Blue |
| 0,1,0 | Red |
| 0,1,1 | Magenta |
| 1,0,0 | Green |
| 1,0,1 | Cyan |
| 1,1,0 | Yellow |
| 1,1,1 | White |
The control latch is a 74HCT373 octal transparent latch (IC U9 in v1.0, IC U11 in v1.1) mapped write-only to address 0xDFFF. It controls the 40/80 column mode and the CG-ROM group selection. The latch address is shared with the top byte of the attribute RAM. In v1.0 this sharing could cause corruption; in v1.1 the 74HCT123 monostable circuit ensures that a write immediately following a read of 0xDFFF targets the latch, while any other write to 0xDFFF targets the attribute RAM.
Control latch bit map:
| Bit | Function | Description |
|---|---|---|
| 0 | CG-ROM group select bit 0 | Together with bit 1, selects one of 4 groups of 4 CG-ROM slots in the 32 KB Flash. |
| 1 | CG-ROM group select bit 1 | |
| 2–6 | Unused | Reserved, should be written as 0. |
| 7 | 40/80 column select | 0 = 40 column (default). 1 = 80 column. |
To switch to 80-column mode in v1.1 software, use the read-modify-write sequence:
LD HL, 0xDFFF ; target address
LD B, 0x80 ; value to latch (bit 7 = 80-column enable)
LD A, (HL) ; read 0xDFFF — triggers monostable, opens latch window
LD (HL), B ; write within window — goes to control latch, not attribute RAM
The monostable pulse is sized to expire in just over one Z80 instruction cycle. The read (LD A,(HL)) and the immediately following write (LD (HL),B) fall within the window. A NOP or any other instruction between the read and write will cause the window to close, and the write will fall through to the attribute RAM instead.
40/80 Column Circuit
The Sharp MZ-80A contains the same video chipset as the MZ-80B business machine but was wired differently by Sharp to disable 80-column output, presumably for marketing differentiation. The v1.x design restores the MZ-80B circuit by lifting gate arrays IC20 and IC31 (MB14298 and MB14299) from the MZ-80A motherboard and re-seating them on the daughter card, where their interconnections can be rerouted to match the MZ-80B configuration.
80-column mode requires a doubled pixel clock. A dedicated oscillator module on the daughter card provides this clock. Bit 7 of the control latch at 0xDFFF selects between the standard 40-column clock and the doubled 80-column clock. The 40/80 switch takes effect immediately; software must reinitialise the display after switching modes.
IC8 (74LS165) on the MZ-80A motherboard must be removed and a socket installed in its place before fitting the daughter card, since the Video Module needs to inject new load and clock signals into the serialiser. This is the only permanent modification to the motherboard; reinstalling the original 74LS165 restores the machine to factory condition.
Character Generator ROM System
The original 2 KB Character Generator ROM (IC15 on the MZ-80A motherboard) is removed and replaced by IC U10, a 32 KB 28C256 Flash RAM on the daughter card. This Flash stores up to 16 CG-ROM images of 2 KB each, or up to 8 images of 4 KB each (occupying two consecutive 2 KB slots).
The 32 KB Flash address space is divided into 4 groups of 4 slots. The active group is selected by control latch bits 1:0. Within the active group, attribute bits 7 and 3 for each character select which of the 4 slots is used for that character's glyph data. This means every character on screen can independently draw its glyph from any of the 4 slots in the active group.
Flash address = (latch bits 1:0) × 8 KB + (attr bits 7,3) × 2 KB + char_offset Latch bits 1:0 → group (A14:A13): selects one of four 8 KB regions Attr bits 7,3 → slot (A12:A11): selects one of four 2 KB slots within the group Char + row → A10:A0: glyph byte address within the 2 KB slot
The current slot allocation shipped in the COLOURBOARD_CG.rom image:
| Slot | Attr bits 7,3 | Latch bits 1:0 | Size | ROM File | Description |
|---|---|---|---|---|---|
| 0 | 0,0 | 0,0 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 1 | 0,1 | 0,0 | 2 KB | MZ80K_cgrom.rom | MZ-80K European CG-ROM |
| 2 | 1,0 | 0,0 | 2 KB | MZ80K2E_Jap_cgrom.rom | MZ-80K Japanese CG-ROM |
| 3 | 1,1 | 0,0 | 2 KB | MZFONT.rom | Unknown-origin CG-ROM |
| 4–5 | 0,0–0,1 | 0,1 | 4 KB | MZ700_cgrom.rom | MZ-700 European CG-ROM (two slots) |
| 6–7 | 1,0–1,1 | 0,1 | 4 KB | MZ700_cgrom_jp.rom | MZ-700 Japanese CG-ROM (two slots) |
| 8 | 0,0 | 1,0 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 9 | 0,1 | 1,0 | 2 KB | MZ80B.rom | MZ-80B European CG-ROM |
| 10 | 1,0 | 1,0 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 11 | 1,1 | 1,0 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 12 | 0,0 | 1,1 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 13 | 0,1 | 1,1 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 14 | 1,0 | 1,1 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
| 15 | 1,1 | 1,1 | 2 KB | mz-80acg.rom | MZ-80A European CG-ROM |
v2.0 Hardware Architecture
The v2.0 board uses two programmable logic devices in place of all the discrete logic, relocated gate arrays, SRAM, and Flash RAM of the v1.x design. The CPLD handles the 5V/3.3V boundary and bus control; the FPGA implements the complete video system in internal block RAM and logic elements.
CPLD — Altera MAX 7000A (EPM7128S)
The CPLD (Complex Programmable Logic Device) is an Altera MAX 7000A device, part number EPM7128S, in an 84-pin PLCC package. MAX 7000A devices are 5V tolerant on all I/O pins, which is the principal reason for their selection: the Sharp MZ-80A Z80 bus operates at 5V while the FPGA I/O is 3.3V, and direct connection of 5V signals to a standard 3.3V FPGA input would damage the device.
The CPLD performs the following functions:
FPGA — Altera Cyclone III (EP3C25E144C8)
- Voltage level translation — buffers and translates all signals between the 5V MZ-80A bus and the 3.3V FPGA I/O.
- Clock generation and conditioning — derives the system and video clocks required by the FPGA (8 MHz, 4 MHz, 3.54 MHz, 2 MHz, 1 MHz, 31.5 kHz) from the source oscillator.
- Address decode and bus control — decodes I/O and memory addresses, generates chip-select signals, and controls bus direction for bidirectional data lines.
- Replacement gate array logic — provides the functions originally performed by the MB14298 and MB14299 gate arrays that are removed from the motherboard for v2.0.
- tranZPUter serialiser interface — receives signals forwarded from the tranZPUter board (A15–A11, video RDn/WRn, IORQn) that are not accessible via the motherboard video expansion connector.
CPLD/VideoInterface.vhd. Built with Quartus Prime 13.0.1.
The FPGA is an Altera Cyclone III EP3C25E144C8 in a 144-pin LQFP package. It provides all video controller logic and internal memory. Key specifications:
| Parameter | Value |
|---|---|
| Device | EP3C25E144C8 |
| Package | 144-pin LQFP |
| Logic Elements | 25,000 |
| Block RAM | 76 KB |
| I/O voltage | 3.3 V (all banks) |
| VHDL sources | FPGA/VideoController.vhd, VideoController_Toplevel.vhd, VideoController_pkg.vhd, functions.vhd |
| Build tool | Quartus Prime 13.1 |
The FPGA bitstream is stored in an EPCS16 serial Flash device connected to the FPGA's dedicated serial boot pins. On power-up the FPGA automatically loads its configuration from the EPCS16. Direct FPGA programming via JTAG is volatile and lost on power-off; the EPCS16 must be programmed separately to make the configuration persistent.
FPGA Internal Memory Usage
The 76 KB of block RAM inside the Cyclone III is the critical limiting resource. It is allocated as follows:
| Block | Size | Description |
|---|---|---|
| Video RAM (VRAM) | 2 KB | Character display — equivalent to 0xD000–0xD7FF on the original machine. CPU read/write via normal memory bus. |
| Attribute RAM | 2 KB | Colour and CG-ROM selection per character — equivalent to 0xD800–0xDFFF on v1.x. CPU read/write. |
| Character Generator RAM (CGRAM) | Variable | Programmable CG-ROM image. Can be written by the CPU when enabled via the Memory Page register (0xFD bit 7). |
| Graphics frame buffer — Red bank | 16 KB | One bit per pixel for the red channel. Covers 640×200 pixels (80-column) or 320×200 (40-column). |
| Graphics frame buffer — Green bank | 16 KB | One bit per pixel for the green channel. |
| Graphics frame buffer — Blue bank | 16 KB | One bit per pixel for the blue channel. |
| Key maps, palette tables | Remainder | Keyboard mapping tables and the 256-entry palette RAM. |
Total graphics frame buffer RAM: 3 × 16 KB = 48 KB. This is the dominant consumer of block RAM. In 640×200 mode the full 48 KB is required for a single frame buffer, leaving insufficient RAM for a second buffer; double buffering is therefore not available in that mode. All other modes use the remaining capacity for a second (hidden) frame buffer, enabling tear-free display updates.
Graphics Frame Buffer
The graphics frame buffer consists of three independent 16 KB banks — Red, Green, and Blue — each holding one bit per pixel. Pixels are stored left-to-right within each row, top-to-bottom across rows, with 8 pixels per byte (MSB = leftmost pixel). For 80-column mode the resolution is 640×200 pixels; for 40-column mode it is 320×200 pixels.
CPU access: Any one of the three banks can be mapped into Z80 address space 0xC000–0xFFFF by setting bit 0 of the Memory Page register (0xFD). The bank to map is selected by bits 1:0 of the Graphics Mode register (0xF9) for reads, and bits 3:2 for writes. Setting write mode to 11 (Indirect) causes a write to update all three banks simultaneously, with each bank write masked by its corresponding Colour Writer register (0xFA for Red, 0xFB for Green, 0xFC for Blue).
Indirect write example: With Red filter = 0x80, Green filter = 0x40, Blue filter = 0x20, writing any non-zero value to 0xC000 will set pixel (0,0) to red, pixel (1,0) to green, and pixel (2,0) to blue. The written data byte itself is masked by each filter register before being stored.
Double buffering: Active for all modes except 640×200. The active display reads from the front buffer while the CPU writes to the back buffer. Buffers are swapped under GPU or CPU control. In 640×200 mode a WAIT state generator can be enabled to avoid display tearing.
Register Map
All v2.0 Video Module registers are accessed via Z80 I/O instructions (
IN / OUT). Unless noted otherwise every register is read/write; a read returns the last value written. Registers in the 0xD0–0xD7 range control video mode parameters and the palette. Registers in the 0xF3–0xFD range control the video mode, graphics, GPU, memory paging, and colour writing.
| I/O Port | Name | R/W | Description |
|---|---|---|---|
| 0xD0 | Video Mode Parameter Selector | W | Selects which timing parameter (0–18) to update via ports 0xD1/0xD2. |
| 0xD1 | Video Mode Parameter Low | W | Lower byte of the parameter selected by 0xD0. |
| 0xD2 | Video Mode Parameter High | W | Upper byte of the parameter selected by 0xD0. |
| 0xD3 | Palette Off Pointer | W | Palette entry number (0–255) for the pixel-off colour configuration. |
| 0xD4 | Palette On Pointer | W | Palette entry number (0–255) for the pixel-on colour configuration. |
| 0xD5 | Palette Red Value | W | 5-bit Red value for the palette entry currently selected by 0xD3 or 0xD4. |
| 0xD6 | Palette Green Value | W | 5-bit Green value for the palette entry currently selected by 0xD3 or 0xD4. |
| 0xD7 | Palette Blue Value | W | 5-bit Blue value for the palette entry currently selected by 0xD3 or 0xD4. |
| 0xF3 | VGA Border Colour | R/W | Bits 2:0 = border colour R/G/B in VGA output modes. |
| 0xF5 | Active Palette | R/W | Selects the active palette. 0 = default system palette. 1–255 = fixed palettes. |
| 0xF6 | GPU Parameters | R/W | 128-bit push/pop FIFO for GPU command parameters. Write pushes, read pops. |
| 0xF7 | GPU Command / Status | R/W | Write: GPU command byte. Read: bit 0 = BUSY flag (1 = GPU busy). |
| 0xF8 | Control Register | R/W | Machine model, column width, colour enable, PCG enable, VGA mode select. |
| 0xF9 | Graphics Mode Register | R/W | GRAM bank select, VRAM/GRAM output enable, blend operator. |
| 0xFA | Colour Writer Red | R/W | 8-pixel red channel mask applied to indirect GRAM writes. |
| 0xFB | Colour Writer Green | R/W | 8-pixel green channel mask applied to indirect GRAM writes. |
| 0xFC | Colour Writer Blue | R/W | 8-pixel blue channel mask applied to indirect GRAM writes. |
| 0xFD | Memory Page / Status | R/W | Write bit 0: map GRAM bank into 0xC000–0xFFFF. Write bit 7: map CGROM into 0xD000–0xDFFF. Read bits 5,6: horizontal/vertical blanking status. |
The Control Register is the primary mode register. It selects which Sharp MZ machine the Video Module emulates, the column width, whether colour is enabled, whether the programmable character generator is active, and the VGA output resolution.
| Bits | Function | Description |
|---|---|---|
| 2:0 | Machine model | 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 | Column width | 0 = 40 column. 1 = 80 column. |
| 4 | Colour enable | 0 = Monochrome output. 1 = Colour output. |
| 5 | PCG RAM enable | 0 = PCG disabled (hardware CG-ROM used). 1 = Programmable CG RAM enabled. |
| 7:6 | VGA mode | 00 = Native 15.62 kHz horizontal scan. 01 = VGA 640×480 @ 60 Hz. 10 = VGA 1024×768 @ 60 Hz. 11 = VGA 800×600 @ 60 Hz. |
The Graphics Mode Register controls which GRAM bank the CPU reads from and writes to, whether the character display (VRAM) and graphics display (GRAM) contribute to the output, and how the two layers are blended.
| Bits | Function | Description |
|---|---|---|
| 1:0 | Read bank | 00 = Red, 01 = Green, 10 = Blue. Selects which GRAM bank is visible at 0xC000–0xFFFF for CPU reads. |
| 3:2 | Write bank | 00 = Red, 01 = Green, 10 = Blue, 11 = Indirect (write to all three banks simultaneously, masked by Colour Writer registers). |
| 4 | VRAM output | 0 = Enable character display. 1 = Disable character display. |
| 5 | GRAM output | 0 = Enable graphics display. 1 = Disable graphics display. |
| 7:6 | Blend operator | 00 = OR, 01 = AND, 10 = NAND, 11 = XOR. Applied when both VRAM and GRAM outputs are enabled. |
The three Colour Writer registers provide an 8-pixel-wide bit mask that is applied to GRAM writes when the write bank is set to Indirect mode (Graphics Mode register bits 3:2 = 11). Each register controls one colour channel. When a byte is written to the GRAM address range 0xC000–0xFFFF in indirect mode, the byte is ANDed with the Red filter and stored in the Red bank, ANDed with the Green filter and stored in the Green bank, and ANDed with the Blue filter and stored in the Blue bank. This allows a single write to set different colours on individual pixels within the byte.
Example: Red filter (0xFA) = 0xFF, Green filter (0xFB) = 0x00, Blue filter (0xFC) = 0x00. An indirect write of 0xFF to 0xC000 sets all 8 pixels in row 0 to red with no green or blue component.
| Register | Colour | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|---|---|---|
| 0xFA | Red | Pixel 0 | Pixel 1 | Pixel 2 | Pixel 3 | Pixel 4 | Pixel 5 | Pixel 6 | Pixel 7 |
| 0xFB | Green | Pixel 0 | Pixel 1 | Pixel 2 | Pixel 3 | Pixel 4 | Pixel 5 | Pixel 6 | Pixel 7 |
| 0xFC | Blue | Pixel 0 | Pixel 1 | Pixel 2 | Pixel 3 | Pixel 4 | Pixel 5 | Pixel 6 | Pixel 7 |
Bit 7 is the leftmost pixel (pixel 0) in each byte; bit 0 is the rightmost (pixel 7).
Memory Page / Status Register (0xFD)
This register controls CPU access to Video Module internal memory and reports display blanking status. Memory mappings set by this register override all other memory page settings, including any MZ-700 or MZ-80B specific page registers.
| Bits | Dir | Function | Description |
|---|---|---|---|
| 0 | R/W | GRAM enable | 1 = Map the selected 16 KB GRAM bank into 0xC000–0xFFFF. 0 = Normal Z80 memory. |
| 5 | R | H-blank status | 1 = Horizontal blanking interval active. |
| 6 | R | V-blank status | 1 = Vertical blanking interval active. |
| 7 | R/W | CGROM enable | 1 = Map CGROM into 0xD000–0xDFFF for CPU upload. 0 = Normal memory. |
GPU — Graphics Processing Unit
The FPGA implements a basic GPU that can execute bulk VRAM and GRAM operations without tying up the Z80 CPU. To use the GPU:
GPU Commands
- Push all required parameters into the GPU Parameters register (0xF6) in order. Each write shifts the existing 128-bit FIFO left by 8 bits and inserts the new byte at bits 7:0. Parameters are therefore pushed MSB-first (highest-numbered parameter bits first).
- Write the command byte to 0xF7.
- Poll 0xF7. Bit 0 (BUSY) will be 1 while the GPU is executing. Wait until bit 0 is 0 before issuing the next command.
| Command | Parameters (pushed MSB-first to 0xF6) | Description |
|---|---|---|
| 0x00 | None | No-op. Idle state. Issuing this command has no effect. |
| 0x01 | None | Clear entire VRAM to space character (0x00) with white foreground on blue background attribute. |
| 0x02 | [15:8] = character byte, [7:0] = attribute byte | Clear entire VRAM with the specified character and attribute values. |
| 0x03 | [47:40] = StartX, [39:32] = StartY, [31:24] = EndX, [23:16] = EndY, [15:8] = character, [7:0] = attribute | Fill a rectangular region of VRAM (character coordinates) with the specified character and attribute. |
| 0x81 | None | Clear all GRAM — sets every pixel in all three (Red, Green, Blue) 16 KB frame buffers to zero. |
| 0x82 | [87:72] = StartX, [71:56] = StartY, [55:40] = EndX, [39:24] = EndY, [23:16] = Red filter, [15:8] = Green filter, [7:0] = Blue filter | Fill a rectangular region of GRAM (pixel coordinates) according to the filter masks. Each filter is 8 bits wide (bit 7 = leftmost pixel). A 1 bit sets the pixel; a 0 bit clears it. |
| 0xFF | None | Reset GPU. Cancels any running operation and returns immediately to idle state. |
Parameter push order for command 0x82 example: to clear GRAM pixels (0,0)–(639,199) with all pixels set red and all pixels clear green and blue, push bytes in this order to 0xF6: StartX high (0x00), StartX low (0x00), StartY high (0x00), StartY low (0x00), EndX high (0x02), EndX low (0x7F), EndY high (0x00), EndY low (0xC7), Red filter (0xFF), Green filter (0x00), Blue filter (0x00). Then write 0x82 to 0xF7.
Video Timing Modes
The active video timing mode is determined by bits 7:6 (VGA mode) and bit 3 (column width) and bits 2:0 (machine model) of the Control Register (0xF8). Individual timing parameters within a mode can be overridden at runtime using the Video Mode Parameter registers (0xD0–0xD2). The parameter selector (0xD0) takes a parameter number 0–18; the value is written as a 16-bit quantity split across the Low (0xD1) and High (0xD2) byte registers.
Parameter key:
H_DSP_START Param 0 Horizontal display area start (physical). H_DSP_END Param 1 Horizontal display area end. H_DSP_WND_START Param 2 Horizontal display window start (data output area). H_DSP_WND_END Param 3 Horizontal display window end. V_DSP_START Param 4 Vertical display area start. V_DSP_END Param 5 Vertical display area end. V_DSP_WND_START Param 6 Vertical display window start. V_DSP_WND_END Param 7 Vertical display window end. H_LINE_END Param 8 Last horizontal pixel (total line length − 1). V_LINE_END Param 9 Last vertical line (total frame height − 1). MAX_COLUMNS Param 10 Maximum character columns (40 or 80). H_SYNC_START Param 11 Horizontal sync pulse start (= H_DSP_END + front porch). H_SYNC_END Param 12 Horizontal sync pulse end. V_SYNC_START Param 13 Vertical sync pulse start. V_SYNC_END Param 14 Vertical sync pulse end. H_POLARITY Param 15 Horizontal sync polarity: 0 = negative, 1 = positive. V_POLARITY Param 16 Vertical sync polarity: 0 = negative, 1 = positive. H_PX Param 17 Horizontal pixel doubling factor (0=1×, 1=2×, 2=4×). V_PX Param 18 Vertical pixel doubling factor (0=1×, 1=2×, 2=4×).
The sixteen predefined modes cover native MZ scan rates and three VGA output rates, each in 40-column and 80-column, monochrome and colour variants:
| Mode | Description | H_DSP | V_DSP | H_LINE | V_LINE | MAX_COL | H_SYNC | V_SYNC | H_POL | V_POL | H_PX | V_PX |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Native 40-col mono (512×260, 320×200 viewable) | 0–320 | 0–200 | 511 | 259 | 40 | 363–408 | 219–223 | 0 | 0 | 0 | 0 |
| 1 | Native 80-col mono (1024×260, 640×200 viewable) | 0–640 | 0–200 | 1023 | 259 | 80 | 746–836 | 219–223 | 0 | 0 | 0 | 0 |
| 2 | Native 40-col colour (512×260, 320×200 viewable) | 0–320 | 0–200 | 511 | 259 | 40 | 363–408 | 219–223 | 0 | 0 | 0 | 0 |
| 3 | Native 80-col colour (1024×260, 640×200 viewable) | 0–640 | 0–200 | 1023 | 259 | 80 | 746–836 | 219–223 | 0 | 0 | 0 | 0 |
| 4 | VGA 640×480 40-col mono | 0–640 | 0–480 | 799 | 524 | 40 | 656–752 | 490–492 | 0 | 0 | 1 | 1 |
| 5 | VGA 640×480 80-col mono | 0–640 | 0–480 | 799 | 524 | 80 | 656–752 | 490–492 | 0 | 0 | 0 | 1 |
| 6 | VGA 640×480 40-col colour | 0–640 | 0–480 | 799 | 524 | 40 | 656–752 | 490–492 | 0 | 0 | 1 | 1 |
| 7 | VGA 640×480 80-col colour | 0–640 | 0–480 | 799 | 524 | 80 | 656–752 | 490–492 | 0 | 0 | 0 | 1 |
| 8 | VGA 1024×768 40-col mono | 0–1024 | 0–768 | 1343 | 805 | 40 | 1048–1184 | 771–777 | 0 | 0 | 2 | 2 |
| 9 | VGA 1024×768 80-col mono | 0–1024 | 0–768 | 1343 | 805 | 80 | 1048–1184 | 771–777 | 0 | 0 | 0 | 2 |
| 10 | VGA 1024×768 40-col colour | 0–1024 | 0–768 | 1343 | 805 | 40 | 1048–1184 | 771–777 | 0 | 0 | 2 | 2 |
| 11 | VGA 1024×768 80-col colour | 0–1024 | 0–768 | 1343 | 805 | 80 | 1048–1184 | 771–777 | 0 | 0 | 0 | 2 |
| 12 | VGA 800×600 40-col mono | 0–800 | 0–600 | 1055 | 627 | 40 | 840–968 | 601–605 | 1 | 1 | 1 | 2 |
| 13 | VGA 800×600 80-col mono | 0–800 | 0–600 | 1055 | 627 | 80 | 840–968 | 601–605 | 1 | 1 | 0 | 2 |
| 14 | VGA 800×600 40-col colour | 0–800 | 0–600 | 1055 | 627 | 40 | 840–968 | 601–605 | 1 | 1 | 1 | 2 |
| 15 | VGA 800×600 80-col colour | 0–800 | 0–600 | 1055 | 627 | 80 | 840–968 | 601–605 | 1 | 1 | 0 | 2 |
Build System
The v2.0 Video Module has two distinct hardware build targets — the CPLD and the FPGA — each requiring a different version of Quartus Prime. A Docker image is provided that bundles both versions and is the recommended approach, eliminating the need to manage complex native Altera toolchain installations.
CPLD Build (Quartus Prime 13.0.1)
The CPLD VideoInterface is compiled with Quartus Prime 13.0.1, which is the last version to support the Altera MAX 7000A family. The target device is EPM7128S.
| File | Description |
|---|---|
CPLD/VideoInterface.vhd |
Main VHDL design file — all gate and interconnect logic. |
CPLD/VideoInterface_pkg.vhd |
Package file — constants, types, and function declarations shared across all modules. |
CPLD/VideoInterface_TopLevel.vhd |
Top-level wrapper — pin I/O declarations and component instantiation. |
CPLD/build/VideoInterface.qpf |
Quartus Prime project file. Open this to load the project. |
CPLD/build/VideoInterface.qsf |
Project settings file — pin assignments, device selection, compilation parameters. |
CPLD/build/VideoInterface_constraints.sdc |
Timing constraints for TimeQuest analyser and place-and-route guidance. |
CPLD/build/VideoInterface.csv |
Pin assignment CSV — can be imported into Quartus Prime Pin Planner. |
Compilation: 1. Start Quartus Prime v13.0.1. 2. File → Open Project → select CPLD/build/VideoInterface.qpf. 3. Processing → Start Compilation. Warning messages can be ignored. 4. Output bitstream: CPLD/build/output_files/VideoInterface.sof Programming: 1. Connect Altera USB Blaster to the 10-pin JTAG IDC connector on the Video Module. 2. Tools → Programmer → Hardware Setup → select USB Blaster → Close. 3. Click Auto Detect. Three devices should appear: EPM7128S, EP3C25E144, EPCS16. 4. Right-click EPM7128S → Add File → select VideoInterface.sof. 5. Enable 'Program/Configure' and 'Verify' for EPM7128S. 6. Click Start.FPGA Build (Quartus Prime 13.1)
The FPGA VideoController is compiled with Quartus Prime 13.1, which supports the Cyclone III EP3C25 device. The FPGA bitstream is volatile — it must be stored in the companion EPCS16 serial Flash to persist across power cycles.
| File | Description |
|---|---|
FPGA/VideoController.vhd |
Main VHDL design file — full video controller logic. |
FPGA/VideoController_pkg.vhd |
Package file — constants, types, and shared declarations. |
FPGA/VideoController_Toplevel.vhd |
Top-level wrapper — FPGA pin I/O and component instantiation. |
FPGA/functions.vhd |
Shared utility functions. |
FPGA/build/VideoController.qpf |
Quartus Prime project file. |
FPGA/build/VideoController.qsf |
Project settings — pin assignments, device, compilation options. |
FPGA/build/VideoController_constraints.sdc |
Timing constraints. |
FPGA/build/VideoController.csv |
Pin assignment CSV. |
Compilation: 1. Start Quartus Prime v13.1. 2. File → Open Project → select FPGA/build/VideoController.qpf. 3. Processing → Start Compilation. Warning messages can be ignored. 4. Output bitstream: FPGA/build/output_files/VideoController.sof Programming FPGA (volatile — lost on power-off): 1. Connect USB Blaster to the 10-pin JTAG connector. 2. Tools → Programmer → Hardware Setup → select USB Blaster → Close. 3. Auto Detect — three devices should appear. 4. Right-click EP3C25E144 → Add File → select VideoController.sof. 5. Enable 'Program/Configure' for EP3C25E144. 6. Click Start. Programming EPCS16 (persistent — survives power cycles): 1. File → Convert Programming Files. 2. Programming File Type: JTAG Indirect Configuration File (.jic). 3. Configuration Device: EPCS16. 4. Flash Loader → Add Device → Cyclone III → EP3C25 → OK. 5. SOF Data → Add File → select VideoController.sof → OK. 6. File Name: set output path for VideoController.jic. 7. Click Generate → Close. 8. Tools → Programmer → Auto Detect. 9. Add VideoController.sof to EP3C25E144 (Program/Configure). 10. Add VideoController.jic to EPCS16 (Program/Configure + Verify). 11. Click Start. FPGA and EPCS16 are now both programmed.Docker Build Environment
Installing Quartus Prime natively on Linux can be unreliable due to missing or conflicting package dependencies. A Docker image is provided that bundles Ubuntu, all required packages, Quartus Prime 13.0.1 (for the CPLD), and Quartus Prime 13.1 (for the FPGA). X11 forwarding allows the Quartus GUI to display on the host machine. The USB Blaster is passed through from the host to the container via udev rules installed in the image.
# Clone the Docker build repository:
cd ~
git clone https://git.eaw.app/eaw/zpu.git
cd zpu/docker/QuartusPrime
# (Optional) Switch from Lite to Standard edition before building:
# Edit Dockerfile.13.0.1:
# Uncomment: ARG QUARTUS=QuartusSetup-13.0.1.232.run
# Comment: ARG QUARTUS=QuartusSetupWeb-13.0.1.232.run
# (Optional) Install a license file:
# cp <your license> files/license.dat
# Edit run.sh and set MAC_ADDR to match your license MAC address.
# Build the Docker image for Quartus 13.0.1 (CPLD):
docker build -f Dockerfile.13.0.1 -t quartus-ii-13.0.1 \
--build-arg user_uid=`id -u` \
--build-arg user_gid=`id -g` \
--build-arg user_name=`whoami` .
# For Quartus 13.1 (FPGA), repeat with Dockerfile.13.1.
# Configure X11 forwarding on host:
export DISPLAY=<x-server-ip>:0
xhost + # or xhost <docker-host-ip> for security on shared networks
# Configure project directory mapping:
# Edit run_quartus.sh:
# PROJECT_DIR_HOST=<host path to project>
# PROJECT_DIR_IMAGE=<container path to project>
# Start Quartus in the container:
./run_quartus.sh
# Stop the container:
docker stop quartus
On first launch, Quartus Prime will prompt for a license. Select "Run the Quartus Prime software" and click OK. The USB Blaster will appear in the Programmer tool automatically if plugged in after the container has started, provided the udev rules are active on the host.
CG-ROM Image Build
The 32 KB Character Generator Flash RAM image (COLOURBOARD_CG.rom) is assembled by concatenating the 16 individual 2 KB CG-ROM slot images in order. The shell script
software/tools/make_cgrom.sh performs this concatenation automatically. The output file can be flashed directly into a 28C256 Flash RAM for use on a v1.x board, or loaded as a memory initialisation file into the FPGA for v2.0.
cd <repository root>/software ./tools/make_cgrom.sh # Output: ../../MZ80A_80COLOUR/software/roms/COLOURBOARD_CG.rom (32 KB)
Reference Sites
| Resource | Link |
|---|---|
| Video Module project page | /sharpmz-upgrades-videomodule/ |
| tranZPUter project page | /sharpmz-upgrades-tranzputer/ |
| Sharp MZ Emulator | /sharpmz-emulator/ |
| RFS Technical Guide | /sharpmz-upgrades-rfs-technicalguide/ |
| Nibbles Lab Sharp MZ museum | http://retropc.net/ohishi/museum/mz1200.htm |
| Altera Quartus Prime (legacy) | https://www.intel.com/content/www/us/en/collections/products/fpga/software/downloads.html |
| Docker build repository | https://git.eaw.app/eaw/zpu |