36 KiB
Vendored
SFD700
Website: engineers@work | Repository: git.eaw.app/eaw/SFD700
Update February 2024 - The v1.2 hardware is fully functional and has been tested on my MZ-80A, MZ-700 and MZ-1500 using the EXT700 adapter and in the MZ-2000 expansion unit. Issues have been reported using the MZ-1U06 which needs to be investigated, seems a CPLD timing issue. The CPLD logic (VHDL) is complete and all ROM/RAM paging and host-mode logic works correctly. The Rom Filing System software ported to the SFD-700 is functional for basic FDC operations (floppy boot via 'F' command) but does not yet include the full suite of floppy disk monitor tools; this is under ongoing development. Client workload has slowed progress — please check the Gitea repository for the latest state. The board hasnt been tested in other MZ series machines, hopefully I will do this in due course.
One of the most needed accessories for the Sharp MZ series is the venerable Floppy Disk Controller. These are in relative short supply as not many people used them, mainly due to cost during the Sharp MZ era. Sharp designed and released multiple floppy disk expansion cards, some built into the base machine, such as the MZ-2500/2800/3500/5600/6500 series, others required a plug in card. They initially started with a custom controller within the MZ-80K series, then with the advent of the MZ-80B business machine, Sharp standardised on the Western Digital Floppy Disk Controller architecture and designed and produced their own controller IC, the MB8866. The MZ-80B design assumed all floppy disk control firmware would be stored in the machine's IPL (Initial Program Loader), which persisted into the MZ-800/MZ-1500/MZ-2000/MZ-2200 designs, maintaining controller compatibility with these newer machines. Unfortunately, for lesser models, such as the MZ-80A/MZ-700, floppy disks were not considered at the design stage and thus required newer controller expansion cards with onboard ROM to be developed in order to provide the necessary floppy disk bootstrap firmware. In addition, as the MZ-80A ran at 2MHz, it wasn't fast enough to read the DRQ flag and then read the available data in a steady stream, so Sharp had to make the DRQ line toggle a ROM address line in order to speed up processing to handle the data flow. Sharp floppy disk expansion cards were expensive. creating a window of opportunity for third parties to produce cheaper offerings. A company in Germany, K&P Partners GmbH was such a company and it offered two products, the SFD-800 for MZ-800 machines, which was also compatible with the MZ-80B/MZ-1500/MZ-2000/MZ-2200 hosts, and the SFD-700 which was targeted at the MZ-700. I initially, like the SFD-800, considered a replica design, but after studying the various circuits, observed a fatal flaw in the K&P SFD-700, memory paging. The card was designed to work in the MZ-1U06 expansion unit which had paging logic to disable access to expansion card memory according to the paging state registers of the MZ-700. If this card was used in a custom expansion unit, it wouldn't work. I also had MZ-80A's which needed a floppy controller so came to the conclusion a single card, which would work in all the MZ series from the MZ-80A onwards (excluding those with built in controllers) would be the way forward. Hence the concept of an SFD-700 mkII was born, same name as the K&P product but greater functionality. This document outlines the new schematic, the programmable logic and any issues discovered on each machine.Host Compatibility
| MODE | Host Machine |
|---|---|
| 0 | Sharp MZ-80A / MZ-1200 |
| 1 | Sharp MZ-700 |
| 2 | Sharp MZ-80B |
| 3 | Sharp MZ-800 |
| 4 | Sharp MZ-1500 |
| 5 | Sharp MZ-2000 |
| 6 | Sharp MZ-2200 |
Schematic
Programmable Logic
v1.0 / v1.1 — GAL-based design
The early revisions used two GAL devices: a Lattice GAL26CV12 as the primary I/O address decoder and MZ-700 memory management controller, and a Lattice GAL16V8 as the ROM address decoder and host-mode selector. The designs were written in CUPL (Compiler for Universal Programmable Logic) and compiled with the original Logical Devices CUPL v4.0 toolchain.The GAL26CV12 was chosen because it provided enough product terms and registered outputs to decode the wide I/O address range and manage the MZ-700 memory paging state, which required more macrocells than a standard 16V8 or 22V10 could offer. Unfortunately, the 26CV12 brought two practical problems. First, tool support: when Microchip Technology acquired Atmel (who had acquired Logical Devices and the CUPL toolchain), the successor product WinCUPL was updated to target only Atmel-compatible devices, dropping support for the Lattice 26CV12. Compilation for v1.0/v1.1 therefore requires the original DOS-era CUPL v4.0 or an equivalent toolchain rather than WinCUPL. Second, programmer support: no current off-the-shelf programmer such as the TL-866 II+ supports the 26CV12 without a PLCC-to-DIP adapter and a custom device configuration file for Minipro.
Despite these hurdles, v1.0 and v1.1 were functional on the MZ-700 for basic floppy operations. The GAL26CV12 register count was nevertheless a binding constraint: the device has only one registered output cluster and a limited expander pool, so it was not possible to simultaneously implement full MZ-700 memory management state tracking and the independent ROM/RAM page registers needed for the ROM Filing System — this limitation is the primary reason v1.2 moved to a CPLD.
v1.2 — CPLD (VHDL) Version 1.2 replaced both GAL devices with a single Altera MAX7000S EPM7128SLC84-15 CPLD (PLCC-84, 128 macrocells), implemented in VHDL and compiled with Quartus II 13.0.1 SP1. This resolved the register-count limitations of the GAL26CV12 and enabled full MZ-700/MZ-1500 memory mapping logic alongside independent ROM/RAM paging across two memory windows. The VHDL source files (sfd700.vhd, sfd700_Toplevel.vhd, sfd700_pkg.vhd) are in the CPLD/v1.2/ directory of the Gitea repository. The earlier CUPL files for v1.0/v1.1 remain in the CUPL/ directory for reference.
GAL (v1.0 / v1.1)
| Device | Package | Macrocells | Registered Outputs | Role |
|---|---|---|---|---|
| GAL26CV12 | 28-pin DIP | 12 | 12 | I/O decoder, FDC control, MZ-700 memory management |
| GAL16V8 | 20-pin DIP | 8 | 8 | ROM address decode, mode select, DRQ multiplexer |
GAL1 — GAL26CV12 (I/O Decoder)
SFD700_GAL1) is the primary logic device. It decodes the Z80 I/O address bus to generate all FDC control signals, manages the bidirectional data bus buffer, tracks MZ-700 memory paging state, and controls the interrupt enable flag.
I/O Address Decoding
Eight address lines (A0–A7) are combined with the IORQn, RDn, and WRn control inputs to identify each register access. Separate read and write selects are generated for the WD1773 FDC register block so that the bidirectional bus buffer can be switched in the correct direction: IOBUSDIRn goes low (Z80→FDC direction) only on FDC reads, and the FDCn chip select is asserted on both reads and writes.
FDC Peripheral Control
Writes to 0xDC, 0xDD, and 0xDE produce single-cycle strobe outputs (DRIVEn, SIDEn, DDENn) that clock the drive selection, head side, and data density latches on the PCB. The FDCRESETn output is tied directly to the Z80 RESET signal so the WD1773 is always reset on system power-up or hardware reset.
MZ-700 Memory Management
The MZ-700 uses I/O writes to ports 0xE1–0xE6 to bank its internal DRAM and CGROM in and out of the upper address space. The GAL tracks two independent state bits using its registered outputs, clocked by the decoded port strobes:
- DISROM — set by writes to 0xE3/0xE4, cleared by 0xE1 and by RESET. When set it signals that the host has mapped its DRAM over the card's ROM window.
- INHROM — set by writes to 0xE5, cleared by 0xE6 and by RESET. When set it inhibits the card's ROM entirely, regardless of DISROM state.
Interrupt Enable
The INTEN registered output is clocked by the INTCLK strobe generated from an access to port 0xE7. A write sets the enable (INTEN.D follows !WRn); a read clears it. INTEN is asynchronously reset by the system RESET input. The INTCLK output feeds the clock input of an external flip-flop on the PCB.
| Pin | Signal | Dir | Description |
|---|---|---|---|
| 1 | CLK | In | Registered output clock |
| 2–6, 8–11 | A0–A7 | In | Z80 I/O address bus |
| 11 | IORQn | In | Z80 I/O request (active low) |
| 12 | WRn | In | Z80 write strobe (active low) |
| 13 | RDn | In | Z80 read strobe (active low) |
| 28 | RESET | In | System reset (active high) |
| 15 | DISROMSET | Out | ROM-disable set strobe (active low) |
| 16 | DISROMCLR | Out | ROM-disable clear strobe (active low) |
| 17 | INTCLK | Out | Interrupt enable flip-flop clock |
| 18 | INROMHSET | Out | ROM-inhibit set strobe (active low) |
| 19 | INTEN | Out | Interrupt enable registered output (active low) |
| 20 | IOBUSDIRn | Out | Bus buffer direction — low = Z80→FDC |
| 22 | INHROMCLR | Out | ROM-inhibit clear strobe |
| 23 | SIDEn | Out | Head side select strobe (active low) |
| 24 | FDCRESETn | Out | WD1773 reset (active low, tied to RESET) |
| 25 | DDENn | Out | Double-density enable strobe (active low) |
| 26 | DRIVEn | Out | Drive select strobe (active low) |
| 27 | FDCn | Out | WD1773 chip select (active low) |
SFD700_GAL2) handles the memory-side address decoding: it generates the ROM chip select when the Z80 addresses the firmware window at 0xF000–0xFFFF, and multiplexes address lines onto the ROM to select the correct firmware page and handle the MZ-80A DRQ trick.
ROM Chip Select
MREQn and RDn are combined with the high address lines (A12–A15) to detect accesses to 0xF000–0xFFFF. The ROMCSn output is a registered value so that chip-select glitches caused by address bus settling are suppressed — the select only propagates on the clock edge.
ROM Address Multiplexing
Two additional outputs drive ROM address lines beyond A9:
- ROMA15 — driven from the MODESEL1 jumper input, it selects between two firmware images (MZ-700 page and MZ-80A page) stored in the upper and lower halves of the ROM address space.
- ROMA10 — this is the most complex output. On MZ-80A targets (MODESEL1 low) it is multiplexed with the WD1773 DRQ signal: when the ROM is selected and DRQ is asserted, ROMA10 selects one 1 KB mirror of the read routine; when DRQ is not asserted it selects the other mirror containing the wait/retry path. This allows the 2 MHz Z80 to service FDC data transfers via a simple linear jump through ROM rather than a polled software loop it cannot execute fast enough. On MZ-700 targets (MODESEL1 high), ROMA10 is driven directly from DRQ without the address qualification.
Two machine-specific variants exist in the CUPL source tree:
SFD700_2.PLD.MZ700— simplified ROMA10 logic: output follows DRQ directly.SFD700_2.PLD.MZ80A— full multiplexed ROMA10 with address qualification and commented-out output-enable controls used during development.
| Pin | Signal | Dir | Description |
|---|---|---|---|
| 1 | CLK | In | Registered output clock |
| 2–7 | A10–A15 | In | Z80 high address bus |
| 8 | MREQn | In | Z80 memory request (active low) |
| 9 | RDn | In | Z80 read strobe (active low) |
| 12 | MODESEL0 | In | Mode jumper bit 0 |
| 13 | MODESEL1 | In | Mode jumper bit 1 — selects ROM page / DRQ logic |
| 14 | ROMINH | In | ROM inhibit state from GAL1 |
| 15 | ROMDIS | In | ROM disable state from GAL1 |
| 16 | DRQ | In | WD1773 data request |
| 17 | ROMA15 | Out | ROM address bit 15 (firmware page select) |
| 18 | ROMA10 | Out | ROM address bit 10 (DRQ multiplexer on MZ-80A) |
| 19 | ROMCSn | Out | ROM chip select (active low, registered) |
CUPL/ directory can be used directly without recompilation.
To recompile from source, use the batch scripts included in the CUPL/ directory:
# Compile GAL1 (GAL26CV12) — run inside CUPL directory cupl -j -f -a g26cv12 SFD700_1 # Compile GAL2 (GAL16V8) cupl -j -f -a g16v8 SFD700_2
-j flag produces JEDEC output (.JED), -f produces the fuse plot (.DOC), and -a <device> specifies the target device. Compiled outputs are written to the same directory:
SFD700_1.JED— JEDEC fuse file for GAL1, ready for programming.SFD700_2.JED— JEDEC fuse file for GAL2, ready for programming.SFD700_1.DOC/SFD700_2.DOC— human-readable fuse plots and chip diagrams for verification.SFD700_1.ABS/SFD700_2.ABS— binary intermediate files used by some programmer utilities.
The GAL16V8 is supported natively by virtually all modern device programmers. Using a TL-866 II+ or similar with the open-source
minipro utility:
minipro -p GAL16V8 -w SFD700_2.JED
SFD700_G.JED) is also provided in the CUPL/ directory for direct use. Verify after programming with:
minipro -p GAL16V8 -v SFD700_2.JED
The GAL26CV12 is a 28-pin PLCC/DIP device that is not listed in the standard TL-866 II+ device database. Programming requires a PLCC-28 to DIP-28 adapter and a custom device entry in the Minipro
infoic.xml database — a pre-configured infoic.xml is included in the CUPL/ directory. With the adapter fitted and the custom database in place:
minipro -p GAL26CV12 -w SFD700_1.JED
.JED file directly — all compliant GAL programmers accept the JEDEC 3C format that CUPL produces.
Both GAL devices retain their programmed configuration in EEPROM and are ready immediately at power-on with no load delay. They can be erased and reprogrammed in-circuit if JTAG test points are provided, or removed from their sockets for bench programming.
CPLD
| Resource | Used | Available | Utilisation |
|---|---|---|---|
| Macrocells | 72 | 128 | 56% |
| Registers | 37 | 128 | 29% |
| I/O pins | 65 | 68 | 96% |
| Product terms | 179 | — | — |
| Global clocks | 2 | 2 | 100% |
CLK_16M (the primary clock) and Z80_RESETn (synchronous reset), minimising clock and reset skew across the device.
Clock Generation
The on-board 16 MHz crystal oscillator drives the CLK_16M global clock input. A single registered toggle macrocell divides this by two to produce CLK_FDC, the 8 MHz clock fed directly to the WD1773 FDC chip-clock input.
I/O Address Decoder
Purely combinatorial logic decodes Z80 I/O cycles (IORQn asserted with RDn or WRn) across three address blocks: the WD1773 FDC registers at 0xD8–0xDB, the FDC control registers at 0xDC–0xDF, and the paging and mode registers at 0x60–0x63. On MZ-700 and MZ-1500 targets (MODE 1 and 4) the decoder also captures writes to I/O ports 0xE0–0xE6 to track the host memory management state. The maximum fan-out node in the design originates from the address decode tree and drives 67 macrocell inputs.
Memory Address Decoder
Decodes Z80 memory cycles (MREQn with RDn or WRn) to generate active-low chip-select outputs for the on-board Flash ROM (ROM_CSn) and static RAM (RAM_CSn). Two independent 7-bit page registers — EXXX_PAGE (loaded via 0x60) and FXXX_PAGE (loaded via 0x61) — are driven onto address bits ROM_A10 and RAM_A10, bank-switching 4 KB windows within up to 512 KB of addressable storage.
Drive and Motor Control
A write to I/O port 0xDC loads an 8-bit registered value that drives the four active-low drive-select outputs (DRVSAn–DRVSDn) and the motor-enable line (MOTOR). Bits [2:0] encode the selected drive (values 4–7 select drives A–D; 0 deselects all); bit 7 controls the spindle motor. Head-side selection (0xDD) and double-density mode (0xDE) are managed by separate single-bit registers.
Data Bus Inversion and Multiplexing
The WD1773 requires bitwise-inverted data. The CPLD connects to a dedicated 8-bit inverted data bus (ID[7:0]) and handles the polarity inversion transparently in both read and write directions. On a Z80 read of an FDC register the inverted bus is re-inverted onto the Z80 data bus; on a write to an FDC register the Z80 data bus is inverted onto ID[7:0]. When a page register is read back by the host, the CPLD drives the stored page value directly onto the Z80 data bus instead.
On MZ-80A and MZ-1200 targets (MODE 0) the WD1773 DRQ signal is multiplexed onto Flash ROM address bit A10 (ROM_A10). Each 1 KB segment of the boot ROM contains a mirrored copy of the read routine; the DRQ state selects the correct copy directly, bypassing the software polling loop that the 2 MHz Z80 cannot execute fast enough to service the FDC data rate reliably.
Interrupt Control
The WD1773 INTRQ output is gated by a single registered enable bit. A write to I/O port 0xDF enables routing of INTRQ to the Z80 INT line; a read from 0xDF clears the enable. A secondary output, Z80_EXWAITn, is available to insert external wait states during FDC register access if required by host timing.
MZ-700 / MZ-1500 Memory Management
The MZ-700 and MZ-1500 use I/O writes to 0xE0–0xE6 to bank their internal DRAM and ROM in and out of the upper address space. The CPLD monitors these writes and maintains a two-bit state register: writing 0xE5 sets the inhibit state, suppressing ROM_CSn and RAM_CSn regardless of page register contents; writing 0xE3, 0xE4, or 0xE6 clears the inhibit and re-enables the expansion card windows.
Mode Register
Three mode jumper inputs (MODE[2:0]) are sampled and latched into a registered value on the rising edge of Z80_RESETn. Reading I/O port 0x63 returns this value, allowing boot firmware to auto-detect the host machine without DIP switches or manual configuration.
| Signal | Pin | Direction | Description |
|---|---|---|---|
| CLK_16M | 83 | In | 16 MHz crystal oscillator — global clock |
| CLK_FDC | 81 | Out | 8 MHz clock to WD1773 |
| CLK_BUS0 | 2 | In | Host Z80 bus clock |
| Z80_RESETn | — | In | Active-low reset — global resource, latches MODE |
| A[15:0] | 4–25 | In | Z80 address bus |
| D[7:0] | 27–35 | Bidir | Z80 data bus |
| ID[7:0] | 64–74 | Bidir | Inverted data bus (WD1773 side) |
| M1n | 36 | In | Z80 M1 machine-cycle indicator |
| RDn | 37 | In | Z80 read strobe |
| WRn | 39 | In | Z80 write strobe |
| IORQn | 40 | In | Z80 I/O request |
| MREQn | 41 | In | Z80 memory request |
| Z80_INT | 44 | Out | Interrupt output to Z80 (gated INTRQ) |
| Z80_EXWAITn | 45 | Out | External wait request to Z80 |
| FDCn | 63 | Out | WD1773 chip select (active low) |
| INTRQ | 61 | In | WD1773 interrupt request |
| DRQ | 60 | In | WD1773 data request |
| DDENn | 58 | Out | Double-density enable to WD1773 (active low) |
| SIDE1 | 57 | Out | Head side select |
| MOTOR | 56 | Out | Spindle motor enable |
| DRVSAn | 55 | Out | Drive A select (active low) |
| DRVSBn | 54 | Out | Drive B select (active low) |
| DRVSCn | 52 | Out | Drive C select (active low) |
| DRVSDn | 51 | Out | Drive D select (active low) |
| ROM_CSn | 77 | Out | Flash ROM chip select (active low) |
| RAM_CSn | 76 | Out | Static RAM chip select (active low) |
| ROM_A10 | 80 | Out | ROM page address bit / DRQ mux (MZ-80A MODE) |
| RAM_A10 | 79 | Out | RAM page address bit |
| MODE[2:0] | 49,48,50 | In | Host machine mode jumpers |
Clone the repository and open the project:
git clone https://git.eaw.app/eaw/SFD700 cd SFD700/CPLD/v1.2/build
quartus_map --read_settings_files=on sfd700 # Analysis & Synthesis quartus_fit --read_settings_files=on sfd700 # Fitter (Place & Route) quartus_asm --read_settings_files=on sfd700 # Assembler — generates sfd700.pof quartus_sta sfd700 # Timing analysis (optional)
CPLD/v1.2/build/sfd700.qpf in the Quartus II GUI and use Processing → Start Compilation. On a successful build the output programming file is written to:
CPLD/v1.2/build/output_files/sfd700.pof
EPM7128SLC84-15 (MAX7000S family) in the Quartus project settings.
To program from the command line:
quartus_pgm -c "USB-Blaster" -m JTAG \ -o "p;CPLD/v1.2/build/output_files/sfd700.pof"
- Open Tools → Programmer.
- Click Hardware Setup and select USB-Blaster.
- Click Add File and select
output_files/sfd700.pof. - Tick Program/Configure and optionally Verify.
- Click Start. Programming completes in a few seconds.
I/O Register Map
| Port | R/W | Description |
|---|---|---|
| 0xD8–0xDB | R/W | WD1773 FDC registers (Status, Command, Track, Sector, Data). |
| 0xDC | W | Drive & motor: bits [2:0] select drive (4=A, 5=B, 6=C, 7=D, 0=none); bit [7] controls motor. |
| 0xDD | W | Head side: D0=0 → side 1, D0=1 → side 0. |
| 0xDE | W | Data rate: D0=0 → double density, D0=1 → single density. |
| 0xDF | W/R | Interrupt: write → enable WD1773 INT to host; read → disable WD1773 INT. |
| 0x60 | R/W | EXXX page register: bits [6:0] select a 4 KB Flash ROM/RAM page mapped into E300:EFFF. |
| 0x61 | R/W | FXXX page register: bits [6:0] select a 4 KB Flash ROM/RAM page mapped into F000:FFFF. |
| 0x62 | R/W | Storage select: D0=0 → Flash ROM enabled; D0=1 → RAM enabled. |
| 0x63 | R | Mode register: reads back the MODE jumper value (0–6). |
| 0xE1 | W | MZ-700/MZ-1500 only: disable onboard ROM (host maps DRAM to D000:FFFF). |
| 0xE3, 0xE4 | W | MZ-700/MZ-1500 only: re-enable onboard ROM. |
| 0xE5 | W | MZ-700/MZ-1500 only: inhibit all onboard ROM/RAM access. |
| 0xE6 | W | MZ-700/MZ-1500 only: clear ROM inhibit, re-enable onboard ROM/RAM. |
Memory Map
| Window | Address Range | Page Register | Notes |
|---|---|---|---|
| EXXX | E300:EFFF | 0x60 | E000:E2FF is reserved for MZ-700/MZ-1500 memory-mapped I/O, so only 3.75 KB of the 4 KB page is usable by firmware (RFS). |
| FXXX | F000:FFFF | 0x61 | Full 4 KB window. Default page 0 holds the MZ-80A AFI ROM; default page 1 holds the MZ-700 AFI ROM. |
PCB
v1.1 PCB
The PCB is more complex than the SFD-800 as it requires a CPLD, ROM/RAM storage and additional support circuitry (earlier v1.0/v1.1 revisions used two GAL devices instead of the CPLD).
v1.2 PCB
Manuals
| Manual | Description |
|---|---|
| User Manual | Board overview, MODE jumper setup, drive installation, ROM Filing System usage, and troubleshooting |
| Technical Guide | Hardware architecture, CPLD design, I/O register map, memory map, and build/programming procedures |
| Developer's Guide | Full VHDL source code walkthrough with VHDL explained for non-VHDL programmers, process-by-process analysis, and CPLD modification guide |
Documentation
The above link downloads the original K&P SFD-800 User Manual which is relevant to this design. It is in German so for non German speakers, the best way to translate is to use your smart phone, load the Google translate app, set to realtime camera translate and set the language as German-><your language>.
Files
Please see Gitea for all project files.
The v1.2 PCB Gerbers are available in the releases/ directory of the Gitea repository. Six spare v1.2 boards are available — contact via the website if interested, postage cost only.
Credits
The SFD-700 mkII is a new design inspired by the original concept. The PCB layout, schematic and programmable logic (CUPL for v1.0/v1.1; VHDL for v1.2) were written from scratch. It is not a direct replica — the host-mode logic, ROM/RAM paging and MZ-80A DRQ-to-address-line adaptation are original additions not present in the K&P product.
Licenses
The Gnu Public License v3
The source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.






