tranZPUter SW-700 (v1) — Developer's Guide
tranZPUter SW-700 V1 Developer's Guide
This guide is a detailed walkthrough of the tranZPUter SW-700 V1 (hardware revision v1.2, Cyclone III FPGA) source code and development environment. It covers the VHDL design, CPLD logic, K64F firmware, TZFS Z80 software, and build toolchain specifically as they apply to the V1 hardware. Developers moving from V1 to the current release should pay particular attention to the V1 vs Current Firmware section, which documents every known incompatibility.
For hardware architecture and build system details see the tranZPUter SW-700 project page. For the current (v1.3, Cyclone IV) developer's guide see the Current Developer's Guide. For user-facing operation see the TZFS User Manual.
V1 HARDWARE NOTE
This guide specifically documents the v1.2 hardware (Cyclone III EP3C25E144C8 FPGA, 144-pin TQFP package). The FPGA source lives in
This guide specifically documents the v1.2 hardware (Cyclone III EP3C25E144C8 FPGA, 144-pin TQFP package). The FPGA source lives in
FPGA/SW700/v1.2/. Video controller registers are at I/O addresses 0xF8–0xFD. Code written against this guide will not run unmodified on current v1.3 hardware, which relocates those registers to 0xA8–0xAD and adds several new registers and service commands. See the V1 vs Current Firmware section for the complete migration checklist.
Introduction to VHDL for Non-VHDL Developers
The tranZPUter SW-700 FPGA logic is written in VHDL (VHSIC Hardware Description Language). Unlike software languages, VHDL describes hardware that executes in parallel — every
Entities and Architecture
process block runs simultaneously and continuously, not sequentially as functions do in C or assembly.
The fundamental building block in VHDL is the entity, which declares the external interface (ports), and the architecture, which defines the internal behaviour. In the tranZPUter VHDL:
Signals and Processes
entity VideoController700 isinVideoController700.vhd— the top-level video controller entity, describing all pins that connect to the FPGA package.architecture rtl of VideoController700 is— RTL (Register Transfer Level) description of the video controller logic.- Ports are declared as
in,out, orinout. Active-low signals conventionally end inn(e.g.VZ80_RDn= Z80 /RD, active low).
- Signals are internal wires or registers:
signal VIDEOMODE : std_logic_vector(7 downto 0);declares an 8-bit signal named VIDEOMODE. - Concurrent signal assignments (outside any
process) describe combinational logic that is always active:CS_FB_VMn <= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1000" else '1';— this chip-select is asserted whenever address bits select port 0xF8. - Process blocks describe synchronous (clocked) or asynchronous logic. A
process(rising_edge(CLK))block describes flip-flop behaviour — the assignments inside take effect on the rising clock edge. Aprocess(a, b, c)block with a sensitivity list describes combinational logic that re-evaluates whenever any listed signal changes. - std_logic is a nine-valued type ('0', '1', 'Z' for high-impedance, 'X' for unknown, etc.). std_logic_vector is an array of std_logic bits. Most port and signal declarations use one of these two types.
VHDL packages collect shared constants, types, and function declarations. The tranZPUter SW-700 V1 uses:
VideoController700_pkg.vhd— machine mode constants (MODE_MZ80KthroughMODE_MZ2000), CPLD version flags, and shared type definitions used by both the video controller and the toplevel.VideoController700_Toplevel.vhd— the FPGA top-level entity that connects the video controller to the physical device pins and instantiates PLLs and block RAMs.
use work.VideoController700_pkg.all;.
Source Tree
| Path | Contents |
|---|---|
CPLD/EPM7160/ |
CPLD VHDL — bus control, Z80 tri-state, memory management, clock selection. Shared between V1 and current. |
FPGA/SW700/v1.2/ |
V1.2 Cyclone III FPGA VHDL — video controller for the 144-pin TQFP device. |
FPGA/SW700/v1.2/VideoController700.vhd |
Main video controller RTL — all display logic, I/O register decoding, GRAM/VRAM control. |
FPGA/SW700/v1.2/VideoController700_pkg.vhd |
Shared constants and types package. |
FPGA/SW700/v1.2/VideoController700_Toplevel.vhd |
FPGA toplevel — pin assignments, PLL instantiation, BRAM wiring. |
FPGA/SW700/v1.2/functions.vhd |
Utility functions (log2, etc.) used by the toplevel. |
FPGA/SW700/v1.2/build/ |
Quartus project files and compiled output. SOF programming file is at build/output_files/. |
FPGA/SW700/v1.3/ |
Current Cyclone IV FPGA VHDL — for reference and migration. |
schematics/SW700/v1.2/ |
KiCad schematics for v1.2 hardware. PDF exports also present. |
pcb/SW700/v1.2a/ |
Gerber PCB fabrication files for v1.2a board revision. |
software/TZFS/asm/ |
Z80 assembly source for TZFS (shared between V1 and current). |
software/TZFS/asm/include/tzfs_definitions.asm |
All I/O port and configuration constants. |
software/TZFS/asm/include/tzfs_svcstruct.asm |
K64F service command and structure definitions. |
software/TZFS/build.sh |
Top-level build script for Z80 firmware. |
software/TZFS/tools/ |
Build tools including glass.jar (GLASS Z80 assembler). |
V1 PATH NOTE
All FPGA source references in this guide refer to
All FPGA source references in this guide refer to
FPGA/SW700/v1.2/. If you are reading the current Developer's Guide alongside this document, be aware that the current guide refers to FPGA/SW700/v1.3/. The files have the same names but different content — in particular, port address decoding, BRAM allocation, and the machine mode register map differ.
CPLD Design (EPM7160)
The CPLD (Altera EPM7160, 160 macrocells, PLCC84 package) handles bus arbitration and memory management — functions that require glue-logic response times faster than the FPGA can reliably achieve through its internal fabric routing. The CPLD design is identical between V1 and current hardware.
Source:
Bus Mastering and Z80 Tri-State
CPLD/EPM7160/tranZPUterSW_EPM7160.vhd (top-level RTL) and tranZPUterSW_pkg_EPM7160.vhd (package). Build in Quartus using the project file tranZPUterSW_EPM7160.qpf.
The CPLD implements Z80 bus mastering: asserting /BUSRQ to the Z80, waiting for /BUSAK, then driving the address and data bus directly for DMA-style transfers. This is used by the K64F to load monitor firmware into tranZPUter SRAM and to service SD card I/O requests on behalf of the Z80. The CPLD tri-states the Z80 by controlling the buffer direction and output-enable signals on the address and data bus transceivers.
Memory Management Configuration Register (MMCFG, port 0x60)
Writing a TZMM mode value to I/O port 0x60 selects which 64 KB block of tranZPUter SRAM (eight 64 KB blocks, 512 KB total) is visible in the Z80 address space. This is the core TZFS bank-switching mechanism. The CPLD decodes the 0x60 I/O write and latches the mode value. All TZFS bank switching is a single
Clock Selection
OUT (0x60), A instruction.
The CPLD routes one of two clock sources to the Z80: the original Sharp MZ-700 system clock (3.54 MHz) or the alternative high-speed clock (up to 24 MHz, generated by the K64F or a crystal oscillator). I/O ports:
CPLD Status Register (port 0x6B)
SETXMHZ EQU 062H— select the high-speed alternative clock.SET2MHZ EQU 064H— select the system 3.54 MHz clock.CLKSELRD EQU 066H— read current clock selection (0 = system speed, 1 = alternate).
V1 DIFFERENCE — The System Command Register at 0x6B (
CPLDSTATUS EQU 06BH in tzfs_definitions.asm) is a Version 2.1 CPLD feature. The V1 CPLD design does not implement this register. Code that reads 0x6B on V1 hardware will receive undefined data. Do not use 0x6B reads for hardware version detection on V1; instead, rely on the known register map differences (video registers at 0xF8 rather than 0xA8) to detect V1 hardware at runtime.
FPGA Design — V1.2 Cyclone III
The V1.2 FPGA is an Intel (Altera) Cyclone III EP3C25E144C8:
BRAM Limitation and the 640×200 Double-Buffer Constraint
- 25,000 Logic Elements (LEs)
- 76 KB embedded Block RAM (BRAM)
- 144-pin TQFP package — hand-solderable, unlike the 484-pin BGA of the v1.3 device
- Built with Quartus Prime 13.1 (the last version to support Cyclone III devices)
The 76 KB BRAM is the most significant hardware constraint of V1. The video controller uses BRAM for:
Video Controller I/O Registers (V1: 0xF0–0xFD)
- Character VRAM: 2 KB (text and attribute data)
- Character generator ROM (CGROM): 2 KB
- Graphics RAM (GRAM): three colour planes at 8 KB each = 24 KB for 640×200 resolution
- Scan-line frame buffer: additional BRAM for the VGA output scaler
The V1.2 FPGA decodes video controller registers in the I/O address range 0xF0–0xFF (the FXX block). The registers that the Z80 software uses are:
| Address | Name | Direction | Description |
|---|---|---|---|
| 0xF8 | VIDEO_MODE_REG | R/W | Video mode control. Bits [2:0] = machine emulation (000=MZ-80K, 001=MZ-80C, 010=MZ-1200, 011=MZ-80A, 100=MZ-700, 101=MZ-800, 110=MZ-80B). Bit [3] = column width (0=40, 1=80). Bit [4] = colour mode (0=mono, 1=colour). Bit [5] = PCGRAM enable. Bits [7:6] = VGA output mode. |
| 0xF9 | GRAM_MODE_REG | R/W | Graphics mode. Bits [7:6] = pixel operator (00=OR, 01=AND, 10=NAND, 11=XOR). Bit [5] = GRAM output enable. Bit [4] = VRAM output enable. Bits [3:2] = write page (00=Red, 01=Green, 10=Blue, 11=Indirect). Bits [1:0] = read page. |
| 0xFA | GRAM_R_FILTER | R/W | Red colour plane bit mask (1 bit per pixel, 8 pixels per byte). |
| 0xFB | GRAM_G_FILTER | R/W | Green colour plane bit mask. |
| 0xFC | GRAM_B_FILTER | R/W | Blue colour plane bit mask. |
| 0xFD | PAGE_MODE_REG | R/W | Graphics memory page. Bit [0] = GRAM page enable (maps 16 KB GRAM page to 0xC000–0xFFFF). Bit [7] = CGROM upload enable (maps CGROM to 0xD000–0xDFFF for reprogramming). Read: bit [7] = CGROM page, bit [6] = V-blank status, bit [5] = H-blank status. |
The I/O decoding in
VideoController700.vhd selects registers using the lower four address bits within the FXX block:
-- From VideoController700.vhd (v1.2): -- CS_IO_FXXn is asserted when VADDR[7:4] = "1111" (i.e., I/O address 0xF0–0xFF). CS_FB_VMn <= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1000" else '1'; -- 0xF8 CS_FB_CTLn <= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1001" else '1'; -- 0xF9 CS_FB_REDn <= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1010" else '1'; -- 0xFA CS_FB_GREENn<= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1011" else '1'; -- 0xFB CS_FB_BLUEn <= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1100" else '1'; -- 0xFC CS_FB_PAGEn <= '0' when CS_IO_FXXn = '0' and VADDR(3 downto 0) = "1101" else '1'; -- 0xFD
In the current v1.3 FPGA, all of these registers are relocated to the AXX block (0xA0–0xAF), decoded using
Machine Emulation Modes in V1
CS_IO_AXXn with VIDEO_ADDRi[7:4] = "1010". See V1 vs Current Firmware for the complete address mapping.
The V1.2 video controller supports hardware emulation of the following Sharp MZ machine video timings and character generators, selectable via bits [2:0] of the VIDEO_MODE_REG (0xF8):
VRAM and GRAM Organisation
- 000 = MZ-80K
- 001 = MZ-80C
- 010 = MZ-1200
- 011 = MZ-80A
- 100 = MZ-700 (default on power-on reset)
- 101 = MZ-800
- 110 = MZ-80B
V1 LIMITATION — Mode 111 (MZ-2000) is defined in the constants package (
MODE_MZ2000 = 7) but the MZ-2000 video timing parameters and graphics logic are not implemented in the V1.2 VHDL. Writing 0b111 to bits [2:0] of 0xF8 on V1 hardware produces undefined video output. MZ-2000 support was added in the v1.3 design alongside the larger FPGA. Porting MZ-2000 support back to V1 would require implementing the MZ-2000 CRTC timing, its graphics colour mode, and fitting the additional logic within the 25K LE budget — a non-trivial effort.
The V1 FPGA exposes two memory regions to the Z80:
- VRAM (0xD000–0xD7FF): 2 KB character video RAM, shared between the Z80 and the display scan logic. Even addresses hold character codes; odd addresses hold colour attributes (on machines with colour support). Write access by the Z80 is gated through the CPLD to the FPGA.
- GRAM (0xC000–0xFFFF when paged in): The 16 KB GRAM page is switched into the Z80 address space by setting bit [0] of the PAGE_MODE_REG (0xFD). Three separate 8 KB colour planes (Red, Green, Blue) exist in BRAM — the write page is selected by GRAM_MODE_REG (0xF9) bits [3:2]. On V1, all three planes together consume 24 KB of the 76 KB BRAM budget.
Building the V1.2 FPGA Bitstream
The V1.2 FPGA project requires Quartus Prime 13.1 (or Quartus II 13.1). Altera dropped Cyclone III device support in later Quartus versions. Version 13.1 is available from Intel's FPGA software download archive. The project file is
Command-Line Build
FPGA/SW700/v1.2/build/VideoController700.qpf.
cd /dvlp/Projects/tranZPUter/FPGA/SW700/v1.2/build quartus_sh --flow compile VideoController700
This runs the full Quartus compilation flow: Analysis and Synthesis → Fitter → Assembler → Timing Analyzer. A successful build produces the SRAM Object File (
Programming via JTAG
output_files/VideoController700.sof) and a POF programming file for flash-based programming.
quartus_pgm -m JTAG -o "P;output_files/VideoController700.sof@1"
This programs the compiled bitstream directly into the FPGA SRAM via the JTAG connector (USB Blaster or compatible). The
Resource Utilisation
@1 suffix selects device 1 in the JTAG chain. SRAM programming is volatile — the FPGA reverts to the flash-stored configuration on power cycle. Use the Quartus Programmer GUI to write the POF to the serial configuration device for permanent storage.
A typical V1.2 build occupies approximately 18,000–22,000 of the 25,000 available Logic Elements, leaving limited headroom for new features. Adding significant new logic risks exceeding the LE budget. The BRAM is more tightly constrained: the three GRAM colour planes, VRAM, and CGROM together account for most of the 76 KB. Any new feature requiring additional BRAM must first identify what can be compressed or removed.
If resource pressure becomes critical, consider porting the change to v1.3 (Cyclone IV, 75K LEs, 2.5 Mb BRAM) instead.
Build Environment (Docker)
The Z80 assembly firmware and K64F C/C++ firmware can be built inside a Docker container that provides a consistent toolchain version regardless of the host OS. The container image bundles:
Running the Build
- Java runtime (for the GLASS Z80 assembler,
tools/glass.jar) - ARM GCC cross-compiler (for K64F firmware)
- Python 3 and Perl (for ROM image generation scripts)
- Standard build utilities (make, bash, coreutils)
# Build Z80 firmware (TZFS) — runs inside the Docker container automatically: cd /dvlp/Projects/tranZPUter/software/TZFS ./build.sh # The build script assembles all TZFS banks, monitor patched images, and # produces binary ROM images in the roms/ output directory.
K64F Firmware
The Freescale Kinetis K64F (ARM Cortex-M4, 120 MHz, 256 KB SRAM, 1 MB flash) manages SD card access, monitor firmware loading, and bus mastering operations. It runs concurrently with the Z80 and FPGA, responding to service requests initiated by the Z80 through a shared memory API.
K64F Service API
The Z80 communicates with the K64F through a shared memory block at
TZSVCMEM (0xED80) and a single I/O port write to SVCREQ (0x68). The service API structure is defined in software/TZFS/asm/include/tzfs_svcstruct.asm. The call sequence from Z80 code is:
; Step 1 — Set the command byte in the service block.
LD A, TZSVC_CMD_LOADFILE
LD (TZSVCCMD), A ; Write command to shared memory
; Step 2 — Signal request to the K64F.
LD A, TZSVC_STATUS_REQUEST
LD (TZSVCRESULT), A ; Mark result field as "pending"
OUT (SVCREQ), A ; Trigger K64F interrupt
; Step 3 — Poll until the K64F completes.
WAIT:
LD A, (TZSVCRESULT)
CP TZSVC_STATUS_REQUEST
JR Z, WAIT
; Step 4 — Check result (0x00 = success, non-zero = error code).
LD A, (TZSVCRESULT)
OR A
JR NZ, ERROR
Key Service Commands
TZSVC_CMD_LOADFILE EQU 01H ; Load named file from SD card into Z80 RAM TZSVC_CMD_SAVEFILE EQU 02H ; Save Z80 RAM region to named file on SD card TZSVC_CMD_DIR EQU 03H ; Read SD card directory listing TZSVC_CMD_SD_RDPAGE EQU 04H ; Read raw SD sector TZSVC_CMD_SD_WRPAGE EQU 05H ; Write raw SD sector TZSVC_CMD_EMU_SETMZ80K EQU 10H ; Switch hardware emulation to MZ-80K mode TZSVC_CMD_EMU_SETMZ80A EQU 13H ; Switch hardware emulation to MZ-80A mode TZSVC_CMD_EMU_SETMZ700 EQU 14H ; Switch hardware emulation to MZ-700 mode TZSVC_CMD_EMU_SETMZ800 EQU 15H ; Switch hardware emulation to MZ-800 mode TZSVC_CMD_EMU_SETMZ80B EQU 16H ; Switch hardware emulation to MZ-80B mode TZSVC_CMD_CPU_SETZ80 EQU 20H ; Set active CPU to hardware Z80 TZSVC_CMD_CPU_SETT80 EQU 21H ; Activate T80 soft-core Z80 in FPGA TZSVC_CMD_CPU_SETZPUEVO EQU 22H ; Activate ZPU Evolution soft CPU in FPGA TZSVC_CMD_SET_VIDMODE EQU 23H ; Set video output mode TZSVC_CMD_SET_VGAMODE EQU 24H ; Set VGA output mode TZSVC_CMD_SET_VBORDER EQU 25H ; Set video border colour
V1 DIFFERENCE — Service command
TZSVC_CMD_LOAD2000IPL (0x26) requests the K64F to load the MZ-2000 IPL firmware. This command exists in the current firmware and tzfs_svcstruct.asm but is meaningless on V1 hardware because the V1 FPGA does not implement MZ-2000 video mode. Issuing 0x26 on V1 may succeed at the K64F level (the file is loaded) but the FPGA will not display MZ-2000 compatible video. Similarly, any K64F service command that configures MZ-2000 emulation mode will produce undefined FPGA behaviour on V1.
On cold start, TZFS issues a K64F service request to load the appropriate monitor ROM image into tranZPUter SRAM at 0x0000. The K64F uses bus mastering (via the CPLD) to DMA the firmware image from SD card into SRAM while the Z80 is held in /BUSRQ. Available monitor images include SA-1510 (MZ-80A), 1Z-013A (MZ-700), and patched 80-column variants of each. The monitor image is selected based on the machine emulation mode configured in TZFS.
TZFS Z80 Software
TZFS (tranZPUter Filing System) is the Z80 assembly language firmware that provides the user-facing command interface. It is shared between V1 and current hardware — the same source tree at
TZMM Bank Switching
software/TZFS/asm/ builds for both, with conditional assembly guards for hardware-specific features. On V1, features that depend on 0xA8-range registers or on V1-absent service commands are simply not exercised; the source compiles and runs identically on V1 hardware.
TZFS uses the Memory Management Configuration register (MMCFG, port 0x60) to switch between four 64 KB SRAM banks:
| TZMM Mode | Value | 0xE800–0xEFFF | 0xF000–0xFFFF | Purpose |
|---|---|---|---|---|
| TZMM_TZFS | 0x22 | TZFS core (bank 0) | TZFS core | Command dispatch, jump tables |
| TZMM_TZFS2 | 0x23 | TZFS core (bank 0) | tzfs_bank2 | Messages, help, print routines |
| TZMM_TZFS3 | 0x24 | TZFS core (bank 0) | tzfs_bank3 | Memory utils, I/O, emulation control |
| TZMM_TZFS4 | 0x25 | — | tzfs_bank4 | Full Z80 assembler/disassembler (52 KB) |
A single
Video Control Commands on V1
OUT (0x60), A instruction performs the bank switch. The TZFS core (bank 0) is always visible at 0xE800–0xEFFF in modes TZMM_TZFS, TZMM_TZFS2, and TZMM_TZFS3, ensuring the jump table and inter-bank stubs are always reachable. See the TZFS Developer's Guide for a full walkthrough of the TZFS source modules.
When the user types a video mode command (e.g.
VMODE 3 to switch to MZ-80A emulation), TZFS calls the K64F service API with the appropriate TZSVC_CMD_SET_VIDMODE or TZSVC_CMD_EMU_SET* command. The K64F in turn writes the new mode value to the V1 FPGA video register at 0xF8 via bus mastering, or signals the FPGA through its dedicated interface. From the Z80's perspective, the video command flow is identical on V1 and current hardware — the difference is only in what the K64F writes and to which register address.
If you are writing Z80 code that directly writes to the video registers (bypassing the K64F service API), you must write to 0xF8–0xFD on V1 hardware. The TZFS definitions file does not expose named constants for the V1 register addresses because the standard TZFS flow routes all video operations through the K64F service. For direct access, use literal port addresses and document the V1 dependency clearly.
; V1 ONLY — direct video mode register write. ; This code WILL NOT WORK on current (v1.3) hardware. ; On current hardware use TZSVC_CMD_SET_VIDMODE or write to 0xA8 instead. LD A, 04H ; MZ-700 mode (bits[2:0]=100), 40-col (bit3=0), colour (bit4=0) OUT (0F8H), A ; V1: video mode register at 0xF8
V1 vs Current Firmware — Migration Guide
This section documents every known incompatibility between the V1 (v1.2, Cyclone III) and current (v1.3, Cyclone IV) hardware and firmware. Developers migrating code from V1 to current, or writing new code intended to run on both, must account for all items listed here.
1. Video Register Address Block Relocation
This is the most critical incompatibility. All six video controller registers have moved from the FXX I/O block (0xF0–0xFF) to the AXX block (0xA0–0xAF) in the current firmware.
| Register | V1 Address | Current Address | Description |
|---|---|---|---|
| Video mode | 0xF8 | 0xA8 (VMCTRL) |
Machine emulation, column width, colour mode |
| Graphics mode | 0xF9 | 0xA9 (VMGRMODE) |
GRAM operator, page, output enables |
| Red mask | 0xFA | 0xAA (VMREDMASK) |
Red colour plane bit mask |
| Green mask | 0xFB | 0xAB (VMGREENMASK) |
Green colour plane bit mask |
| Blue mask | 0xFC | 0xAC (VMBLUEMASK) |
Blue colour plane bit mask |
| Page/CGROM | 0xFD | 0xAD (VMPAGE) |
GRAM page enable, CGROM upload |
Migration action: Any code that contains
2. No System Command Register (0x6B) in V1
OUT (0F8H), OUT (0F9H), OUT (0FAH), OUT (0FBH), OUT (0FCH), or OUT (0FDH) — or the corresponding IN instructions — must be updated to use the current addresses. In the TZFS definitions file, use the named constants (VMCTRL, VMGRMODE, VMREDMASK, VMGREENMASK, VMBLUEMASK, VMPAGE) rather than literal hex addresses so that a single change to the definitions file handles both targets via conditional assembly.
The CPLD System Command Register at I/O port 0x6B (
3. No MZ-2000 Emulation in V1
CPLDSTATUS EQU 06BH) is a Version 2.1 CPLD feature present only in current hardware. On V1, reads from 0x6B return indeterminate data from the bus (typically 0xFF with pull-ups asserted). Code that uses this register for hardware version detection, feature capability queries, or CPLD configuration on current hardware will not function correctly on V1.
Migration action: Do not use 0x6B reads on V1. To detect V1 hardware at runtime, write a known value to 0xF8 and read it back; if the value is not reflected (because 0xF8 is not decoded by current hardware's FPGA in its V1 position), the hardware is current. Alternatively, rely on a build-time flag rather than runtime detection.
The MZ-2000 video timing, graphics colour mode, and character generator are not implemented in the V1.2 FPGA. Writing machine mode value 7 (binary 111) to bits [2:0] of VIDEO_MODE_REG (0xF8) on V1 produces undefined video output.
Migration action: Do not use VMODE 7 / MZ-2000 mode on V1 hardware. If writing code that must support both V1 and current, guard all MZ-2000 code paths with a V1 detection check or a build-time flag.
4. No MZ-2000 K64F Service Commands in V1
The following K64F service commands are present in current firmware but are not meaningful on V1 hardware because V1 lacks MZ-2000 FPGA support:
5. No 640×200 Double-Buffer in V1
TZSVC_CMD_LOAD2000IPL (0x26)— load MZ-2000 Initial Program Loader from SD cardTZSVC_CMD_EMU_SETMZ2000— switch hardware emulation to MZ-2000 mode
The V1 Cyclone III FPGA lacks sufficient BRAM for double-buffering the 640×200 graphics mode. A WAIT state generator stalls the Z80 during display refresh instead. Effects:
6. FPGA Source Paths Differ
- Graphics-intensive code that fills large GRAM areas will execute slightly slower on V1 due to WAIT insertion — typically a few percent, but measurable with a cycle counter.
- In the worst case, a program that performs sustained back-to-back GRAM writes may experience visible snow on V1 if the WAIT generator fails to cover all refresh conflicts, particularly at the field boundary. This does not occur on current hardware.
All FPGA VHDL source references change between V1 and current:
| Item | V1 Path | Current Path |
|---|---|---|
| Video controller VHDL | FPGA/SW700/v1.2/VideoController700.vhd |
FPGA/SW700/v1.3/VideoController700.vhd |
| Package file | FPGA/SW700/v1.2/VideoController700_pkg.vhd |
FPGA/SW700/v1.3/VideoController700_pkg.vhd |
| Quartus project | FPGA/SW700/v1.2/build/VideoController700.qpf |
FPGA/SW700/v1.3/build/VideoController700.qpf |
| Quartus version | 13.1 (Cyclone III support) | 18.1 or later (Cyclone IV support) |
| FPGA device | EP3C25E144C8 (25K LE, 144 TQFP) | EP4CE75F484C8 / EP4CE115 (75K/115K LE, 484 BGA) |
Migration action: When applying VHDL patches or new features developed against the current source tree, verify that the logic fits within the V1 resource budget (25K LEs, 76 KB BRAM) before committing to V1. Features developed for V1 that require no changes to the register map or BRAM allocation can generally be back-ported to current without modification, since current is a superset of V1.
Migration Checklist Summary
| # | Difference | V1 | Current | Action Required |
|---|---|---|---|---|
| 1 | Video mode register | 0xF8 | 0xA8 (VMCTRL) | Update all OUT/IN addresses |
| 2 | Graphics mode register | 0xF9 | 0xA9 (VMGRMODE) | Update all OUT/IN addresses |
| 3 | Red mask register | 0xFA | 0xAA (VMREDMASK) | Update all OUT/IN addresses |
| 4 | Green mask register | 0xFB | 0xAB (VMGREENMASK) | Update all OUT/IN addresses |
| 5 | Blue mask register | 0xFC | 0xAC (VMBLUEMASK) | Update all OUT/IN addresses |
| 6 | Page/CGROM register | 0xFD | 0xAD (VMPAGE) | Update all OUT/IN addresses |
| 7 | CPLD status register | Not present | 0x6B (CPLDSTATUS) | Guard with V1 detection |
| 8 | MZ-2000 video mode | Not implemented | Implemented | Guard with V1 detection |
| 9 | TZSVC_CMD_LOAD2000IPL | Not functional | 0x26 | Guard with V1 detection |
| 10 | 640×200 double buffer | WAIT-state only | Double buffered | Handle snow on V1 if needed |
| 11 | FPGA source directory | v1.2/ | v1.3/ | Use correct path when patching |
| 12 | Quartus version | 13.1 | 18.1+ | Use correct toolchain version |
Adding Machine Emulation Support to V1
The video controller identifies new machine emulation modes by the value written to VIDEO_MODE_REG (0xF8) bits [2:0]. Adding a new mode to V1 requires changes in three places:
- Add constants to
VideoController700_pkg.vhd: Define a newMODE_*constant for the machine type if one does not already exist. The existing constants file already contains entries for all eight Sharp MZ variants including MZ-2000 (mode 7), but the MZ-2000 CRTC logic is absent from the v1.2 VideoController700.vhd. - Implement CRTC timing in
VideoController700.vhd: The CTRLREGISTERS process decodes writes to CS_FB_VMn (0xF8). Add a new branch to the case statement that sets the appropriate timing signals:MODE_VIDEO_*flags, horizontal and vertical sync parameters, character cell dimensions, and colour attribute format. For MZ-2000, this means implementing the 320×200 or 640×200 pixel-addressable colour mode and the associated GRAM banking. Reference the v1.3 source atFPGA/SW700/v1.3/for the completed implementation. - Verify BRAM budget: Any new machine mode that requires additional screen buffer RAM must fit within the remaining BRAM headroom. If the new mode needs a separate VRAM or additional GRAM plane, calculate the required BRAM blocks (M9K blocks in Cyclone III, each 9 Kbits = 1,152 bytes) before proceeding.
- Add a K64F service command: If the new machine requires the K64F to load a monitor ROM image before switching modes, add a new
TZSVC_CMD_EMU_SET*constant intzfs_svcstruct.asmand implement the handler on the ARM side. - Add a TZFS command: Add an entry to the CMDTABLE in
tzfs.asmthat maps the user-typed command to the appropriate service call. Add a handler intzfs_bank3.asmthat sets up the K64F service block and calls?SVCREQ. Add help text intzfs_bank2.asm.
Debugging Tips
Use RIO/WIO to verify register addresses: At the TZFS prompt, use
WIO F8,04 to write 0x04 (MZ-700 mode) directly to port 0xF8 on V1 hardware. If the display switches to MZ-700 timing, the V1 FPGA is present and responding correctly. On current hardware, write to 0xA8 instead — writing 0xF8 on current hardware hits a different register (if any is decoded there) and may produce unexpected results.
Read the page register for blanking status: RIO FD reads port 0xFD. On V1, bits [6] and [5] of the returned value reflect V-blank and H-blank status respectively. A returned value of 0xFF with bits [7:6] set typically indicates V-blank is active and CGROM page mode is off — this is normal during the vertical retrace period.
Verify FPGA is programmed: If video output is absent or shows random pixels after power-on, the FPGA configuration flash may have an issue. Reprogram via JTAG using a fresh SOF. If the SOF was built with the wrong Quartus device target (e.g. EP4CE75 instead of EP3C25), the bitstream will be rejected silently and the FPGA will not configure — verify the device setting in the Quartus project file before building.
Inspect the K64F service block: At the TZFS prompt, type D ED80 to hex-dump the K64F service communication area. The first byte is the command; the second is the result status. A result of 0x01 indicates the K64F is still processing a request; a non-zero non-0x01 result indicates an error. Cross-reference against TZSVC_STATUS_* constants in tzfs_svcstruct.asm.
Enable TZFS debug output: Set ENADEBUG EQU 1 in tzfs_definitions.asm and rebuild TZFS. This adds diagnostic output at cold-start, during bank switches, and during K64F service calls. On V1, the cold-start output will confirm that the TZMM mode register (0x60) is accepting writes and that the K64F service handshake completes within the expected poll timeout.
GRAM snow investigation: If 640×200 graphics operations produce snow artefacts on V1, add a polling loop that waits for H-blank before each burst of GRAM writes. Read port 0xFD in a tight loop and spin until bit [5] (H-blank) is set, then perform the write burst before the next active period begins.
Quartus timing analysis: After building a modified V1.2 bitstream, check the Quartus TimeQuest timing report at build/output_files/VideoController700.sta.rpt. Any negative setup slack (timing violation) on a critical path must be resolved before the bitstream is used in hardware — FPGA operation with timing violations is unpredictable. Common causes are long combinational paths through the VRAM mux or the GRAM page logic.
Use DASM to verify interactively-assembled code: After using the TZFS ASM command to enter a test routine at a scratch address, immediately type DASM addr,endaddr to disassemble the result. Verify that the instruction encodings are correct before executing the code, particularly for I/O instructions (IN A, (0F8H) vs OUT (0F8H), A) where an encoding mistake can produce a silent wrong-port access.
Reference Sites
| Resource | Link |
|---|---|
| tranZPUter SW-700 V1 project page | /sharpmz-700-upgrades-tranzputer-sw/ |
| tranZPUter SW-700 Current (v1.3) project page | /sharpmz-700-upgrades-tranzputer-sw-current/ |
| tranZPUter SW-700 Current Developer’s Guide | /tranzputer-sw-700-current-developersguide/ |
| TZFS Developer’s Guide | /sharpmz-upgrades-tzfs-developersguide/ |
| TZFS User Manual | /sharpmz-upgrades-tzfs-usermanual/ |
| RFS Developer’s Guide | /sharpmz-upgrades-rfs-developersguide/ |
| tranZPUter project page | /transzputer/ |
| GLASS Z80 Assembler | Bundled in software/TZFS/tools/glass.jar |
| Intel Quartus Prime 13.1 | Intel FPGA Software Download Centre (Cyclone III support) |
| Cyclone III Device Handbook | Intel FPGA documentation — LE architecture, BRAM M9K blocks, PLLs |
| Altera EPM7160 Datasheet | MAX 7000 family — macrocell architecture, pin assignments |
| Zilog Z80 CPU User Manual | Standard datasheet — bus timing, I/O cycle timing, instruction set |