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 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 process block runs simultaneously and continuously, not sequentially as functions do in C or assembly.

Entities and Architecture
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:
  • entity VideoController700 is in VideoController700.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, or inout. Active-low signals conventionally end in n (e.g. VZ80_RDn = Z80 /RD, active low).

Signals and Processes
  • 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. A process(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.

Package Files
VHDL packages collect shared constants, types, and function declarations. The tranZPUter SW-700 V1 uses:
  • VideoController700_pkg.vhd — machine mode constants (MODE_MZ80K through MODE_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.
In the source, every file that uses shared constants begins with 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 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: CPLD/EPM7160/tranZPUterSW_EPM7160.vhd (top-level RTL) and tranZPUterSW_pkg_EPM7160.vhd (package). Build in Quartus using the project file tranZPUterSW_EPM7160.qpf.

Bus Mastering and Z80 Tri-State
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 OUT (0x60), A instruction.

Clock Selection
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:
  • 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).
When the Z80 accesses Sharp MZ-700 mainboard peripherals (memory-mapped I/O in the 0xE000–0xFFFF range), the CPLD automatically inserts WAIT states to maintain the original timing — the Z80 sees correct peripheral timing regardless of which clock speed is active.

CPLD Status Register (port 0x6B)
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:
  • 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 FPGA implements the entire video controller subsystem: it accepts the Z80 bus signals from the CPLD, decodes video register I/O, manages character RAM (VRAM), graphics RAM (GRAM), the character generator ROM (CGROM), and drives the VGA output.

BRAM Limitation and the 640×200 Double-Buffer Constraint
The 76 KB BRAM is the most significant hardware constraint of V1. The video controller uses BRAM for:
  • 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
In the current v1.3 design, the larger Cyclone IV BRAM budget allows the 640×200 GRAM to be double-buffered — one buffer is displayed while the Z80 writes to the other, preventing screen tearing and snow. The V1.2 Cyclone III does not have enough BRAM for double buffering at 640×200. A WAIT state generator is used instead: the FPGA asserts /WAIT on the Z80 during the horizontal blanking interval when the display is being refreshed from GRAM, preventing simultaneous read and write access that would produce snow. This means 640×200 graphics operations on V1 are slightly slower than on current hardware — the Z80 is stalled for a fraction of each scan line. This is not normally noticeable in practice but should be considered when writing timing-sensitive graphics code.

Video Controller I/O Registers (V1: 0xF0–0xFD)
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 CS_IO_AXXn with VIDEO_ADDRi[7:4] = "1010". See V1 vs Current Firmware for the complete address mapping.

Machine Emulation Modes in V1
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):
  • 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.

VRAM and GRAM Organisation
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 FPGA/SW700/v1.2/build/VideoController700.qpf.

Command-Line Build
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 (output_files/VideoController700.sof) and a POF programming file for flash-based programming.

Programming via JTAG
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 @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.

Resource Utilisation
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:
  • 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)
The FPGA compilation (Quartus 13.1) is not containerised — Quartus must be installed natively because it requires direct access to the JTAG USB hardware for programming.

Running the Build
# 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.

Monitor Firmware Loading
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 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.

TZMM Bank Switching
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 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.

Video Control Commands on V1
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 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.

2. No System Command Register (0x6B) in V1
The CPLD System Command Register at I/O port 0x6B (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.

3. No MZ-2000 Emulation in V1
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:
  • TZSVC_CMD_LOAD2000IPL (0x26) — load MZ-2000 Initial Program Loader from SD card
  • TZSVC_CMD_EMU_SETMZ2000 — switch hardware emulation to MZ-2000 mode
Issuing these commands on V1 may not cause a K64F error (the K64F may successfully load the file) but the FPGA will not display MZ-2000 compatible output.
Migration action: Guard all MZ-2000 service calls with V1 detection.

5. No 640×200 Double-Buffer in V1
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:
  • 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.
Migration action: If snow artefacts appear when porting graphics demos from current to V1, add horizontal blanking checks before large GRAM fills. Reading the H-blank status from PAGE_MODE_REG (0xFD) bits [5] and [6] allows software to avoid writing during the vulnerable interval.

6. FPGA Source Paths Differ
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:
  1. Add constants to VideoController700_pkg.vhd: Define a new MODE_* 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.
  2. 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 at FPGA/SW700/v1.3/ for the completed implementation.
  3. 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.
  4. 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 in tzfs_svcstruct.asm and implement the handler on the ARM side.
  5. Add a TZFS command: Add an entry to the CMDTABLE in tzfs.asm that maps the user-typed command to the appropriate service call. Add a handler in tzfs_bank3.asm that sets up the K64F service block and calls ?SVCREQ. Add help text in tzfs_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