Added RFS versions of BASIC MZ-5Z008 and 2Z009E

This commit is contained in:
Philip Smart
2026-04-01 17:16:00 +01:00
parent dbfa22baa4
commit dfb82db143
25 changed files with 6250 additions and 40952 deletions

File diff suppressed because it is too large Load Diff

12
asm/mz2z009e_orig.asm Normal file
View File

@@ -0,0 +1,12 @@
; ===========================================================================
; Build configuration — set these flags to select the build variant:
;
; BUILD_RFS=0, BUILD_TAPE=0 : Original BASIC (QD boot, no RFS)
; BUILD_RFS=0, BUILD_TAPE=1 : Original BASIC (Tape/CMT/RFS ROM boot)
; BUILD_RFS=1, BUILD_TAPE=0 : RFS Enhanced BASIC (QD boot)
; BUILD_RFS=1, BUILD_TAPE=1 : RFS Enhanced BASIC (Tape/CMT/RFS ROM boot)
; ===========================================================================
BUILD_RFS EQU 0 ; 0 = original BASIC, 1 = RFS enhancements
BUILD_TAPE EQU 1 ; 0 = QD boot, 1 = Tape/CMT/RFS ROM boot
INCLUDE "mz2z009e.asm"

12
asm/mz2z009e_rfs.asm Normal file
View File

@@ -0,0 +1,12 @@
; ===========================================================================
; Build configuration — set these flags to select the build variant:
;
; BUILD_RFS=0, BUILD_TAPE=0 : Original BASIC (QD boot, no RFS)
; BUILD_RFS=0, BUILD_TAPE=1 : Original BASIC (Tape/CMT/RFS ROM boot)
; BUILD_RFS=1, BUILD_TAPE=0 : RFS Enhanced BASIC (QD boot)
; BUILD_RFS=1, BUILD_TAPE=1 : RFS Enhanced BASIC (Tape/CMT/RFS ROM boot)
; ===========================================================================
BUILD_RFS EQU 1 ; 0 = original BASIC, 1 = RFS enhancements
BUILD_TAPE EQU 1 ; 0 = QD boot, 1 = Tape/CMT/RFS ROM boot
INCLUDE "mz2z009e.asm"

File diff suppressed because it is too large Load Diff

12
asm/mz5z008_orig.asm Normal file
View File

@@ -0,0 +1,12 @@
; ===========================================================================
; Build configuration — set these flags to select the build variant:
;
; BUILD_RFS=0, BUILD_TAPE=0 : Original BASIC (QD boot, no RFS)
; BUILD_RFS=0, BUILD_TAPE=1 : Original BASIC (Tape/CMT/RFS ROM boot)
; BUILD_RFS=1, BUILD_TAPE=0 : RFS Enhanced BASIC (QD boot)
; BUILD_RFS=1, BUILD_TAPE=1 : RFS Enhanced BASIC (Tape/CMT/RFS ROM boot)
; ===========================================================================
BUILD_RFS EQU 0 ; 0 = original BASIC, 1 = RFS enhancements
BUILD_TAPE EQU 1 ; 0 = QD boot, 1 = Tape/CMT/RFS ROM boot
INCLUDE "mz5z008.asm"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
tools/MZQD/MZQDTool vendored Executable file

Binary file not shown.

366
tools/MZQD/MZQDTool.c Executable file
View File

@@ -0,0 +1,366 @@
/* =========================================================================
* MZQDTool — Sharp MZ-700 Quick Disk (QD) image tool
*
* Creates and manages QD disk images for the MZ-700 Quick Disk system.
* Supports format, directory listing, and adding MZF files to QD images.
*
* Original V0.30 (c) 2002 by BKK
* Updated V1.00 (c) 2026 Philip Smart — rewritten with configurable disk
* name, fixed file ordering, correct CMT→QD header conversion,
* and robust error handling.
*
* QD disk image format (61455 bytes):
*
* Disk header:
* [00] [16 16] [A5] [block_count] [CRC: 43 52 43]
*
* Per file (2 blocks each: header + data):
*
* Header block:
* [00] [16 16] [A5] [00] [size_lo=40] [size_hi=00]
* [64 bytes: QDHeaderStr]
* [CRC: 43 52 43]
*
* Data block:
* [00] [16 16] [A5] [05] [size_lo] [size_hi]
* [file data]
* [CRC: 43 52 43]
*
* Usage:
* MZQDTool format [-o disk.qd]
* MZQDTool dir [-o disk.qd]
* MZQDTool add <file.mzf> [-o disk.qd]
* ========================================================================= */
#define VERSION "1.00"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define QDSIZE 61455
#define MAXQDFILETYPES 12
#define DEFAULTQDFILE "MZ700.qd"
#define CMTHDRSIZE 128 /* MZF/CMT file header size */
#define QDHDRSIZE 64 /* QD file header size */
/* MZF/CMT tape file header (128 bytes) */
struct CMTHeaderStr {
uint8_t Attribute; /* File type: 01=OBJ, 02=BTX, etc. */
char Name[17]; /* Filename (CR-terminated, null-padded) */
uint16_t Size; /* Data size (0 = use actual file size) */
uint16_t LoadAddress; /* Load address (DTADR) */
uint16_t ExecAddress; /* Execution address (EXADR) */
char Comment[104]; /* Comment area */
};
/* QD file header (64 bytes, stored in header block) */
struct QDHeaderStr {
uint8_t Attribute; /* File type: 01=OBJ, 02=BTX, etc. */
char Name[17]; /* Filename (CR-terminated, null-padded) */
uint16_t Unknown; /* Reserved (usually 0) */
uint16_t Size; /* Data size in bytes */
uint16_t LoadAddress; /* Load address */
uint16_t ExecAddress; /* Execution address */
char Comment[38]; /* Comment (truncated from CMT's 104) */
};
static const char *QDFileTypes[MAXQDFILETYPES] = {
"???", "OBJ", "BTX", "BSD", "BRD", "RB ",
"???", "LIB", "???", "???", "SYS", "GR "
};
static uint8_t QDArray[QDSIZE];
static char qdFileName[256] = DEFAULTQDFILE;
/* ------- Low-level QD block I/O helpers ------- */
static void write_sync(uint16_t *ptr)
{
QDArray[(*ptr)++] = 0x00; /* BREAK */
QDArray[(*ptr)++] = 0x16; /* SYNC */
QDArray[(*ptr)++] = 0x16; /* SYNC */
QDArray[(*ptr)++] = 0xA5; /* SHARP SYNC */
}
static void write_crc(uint16_t *ptr)
{
QDArray[(*ptr)++] = 'C';
QDArray[(*ptr)++] = 'R';
QDArray[(*ptr)++] = 'C';
}
static int save_qd(void)
{
FILE *f = fopen(qdFileName, "wb");
if (!f) {
fprintf(stderr, "ERROR: Cannot write '%s'\n", qdFileName);
return 0;
}
fwrite(QDArray, QDSIZE, 1, f);
fclose(f);
return 1;
}
static int load_qd(void)
{
FILE *f = fopen(qdFileName, "rb");
if (!f) {
fprintf(stderr, "ERROR: Cannot open '%s'\n", qdFileName);
return 0;
}
fread(QDArray, QDSIZE, 1, f);
fclose(f);
return 1;
}
/* ------- Commands ------- */
/* Format: create an empty QD image with 0 files */
static void QDFormat(void)
{
uint16_t ptr = 0;
printf("Formatting '%s' (%d bytes)\n", qdFileName, QDSIZE);
memset(QDArray, 0x00, QDSIZE);
/* Disk header: sync + block_count(0) + CRC */
write_sync(&ptr);
QDArray[ptr++] = 0x00; /* 0 blocks */
write_crc(&ptr);
if (!save_qd()) exit(1);
puts("Done.");
}
/* Dir: list files on the QD */
static void QDDir(void)
{
uint16_t ptr, blockSize;
uint8_t blocks, i;
if (!load_qd()) exit(1);
/* Disk header: 4 sync bytes + block_count + 3 CRC */
ptr = 4;
blocks = QDArray[ptr++];
ptr += 3; /* skip CRC */
printf("Directory of '%s': %d block(s), %d file(s)\n\n",
qdFileName, blocks, blocks / 2);
for (i = 0; i < blocks; i++) {
if (ptr + 7 >= QDSIZE) {
fprintf(stderr, "WARNING: Truncated QD image at block %d\n", i);
break;
}
ptr += 4; /* sync: 00 16 16 A5 */
uint8_t blockType = QDArray[ptr++];
blockSize = QDArray[ptr] | (QDArray[ptr + 1] << 8);
ptr += 2;
if (blockType == 0x00 && blockSize == QDHDRSIZE) {
/* File header block */
struct QDHeaderStr *hdr = (struct QDHeaderStr *)&QDArray[ptr];
uint8_t ft = hdr->Attribute;
if (ft >= MAXQDFILETYPES) ft = 0;
/* Format name: stop at CR or end of field */
char name[18];
memcpy(name, hdr->Name, 17);
name[17] = '\0';
for (int j = 0; j < 17; j++) {
if (name[j] == '\r' || name[j] == '\0') { name[j] = '\0'; break; }
}
printf(" %-3s %-17s Size=%-6u Load=0x%04X Exec=0x%04X\n",
QDFileTypes[ft], name, hdr->Size,
hdr->LoadAddress, hdr->ExecAddress);
} else if (blockType == 0x05) {
/* Data block — skip silently */
} else {
printf(" [block %d: type=0x%02X size=%u]\n", i, blockType, blockSize);
}
ptr += blockSize;
ptr += 3; /* skip CRC */
}
printf("\n%u bytes free\n", QDSIZE - ptr);
}
/* Add: append an MZF file to the QD image */
static void AddFileToQD(const char *mzfFileName)
{
FILE *mzfFile;
uint16_t ptr, fileDataSize;
uint8_t blocks, i;
uint16_t blockSize;
struct CMTHeaderStr cmtHdr;
if (!load_qd()) exit(1);
/* Read block count and skip to end of existing data */
ptr = 4;
blocks = QDArray[ptr];
ptr = 5 + 3; /* past block_count + CRC */
for (i = 0; i < blocks; i++) {
ptr += 4; /* sync */
ptr++; /* block type */
blockSize = QDArray[ptr] | (QDArray[ptr + 1] << 8);
ptr += 2;
ptr += blockSize;
ptr += 3; /* CRC */
}
/* Open and read MZF file */
mzfFile = fopen(mzfFileName, "rb");
if (!mzfFile) {
fprintf(stderr, "ERROR: Cannot open '%s'\n", mzfFileName);
exit(1);
}
fseek(mzfFile, 0, SEEK_END);
long mzfTotalSize = ftell(mzfFile);
fseek(mzfFile, 0, SEEK_SET);
if (mzfTotalSize < CMTHDRSIZE) {
fprintf(stderr, "ERROR: '%s' is too small for MZF format (%ld bytes)\n",
mzfFileName, mzfTotalSize);
fclose(mzfFile);
exit(1);
}
fread(&cmtHdr, CMTHDRSIZE, 1, mzfFile);
fileDataSize = (uint16_t)(mzfTotalSize - CMTHDRSIZE);
/* Check available space */
uint32_t needed = (4+1+2+QDHDRSIZE+3) + (4+1+2+(uint32_t)fileDataSize+3);
if (ptr + needed > QDSIZE) {
fprintf(stderr, "ERROR: Not enough space (need %u, have %u)\n",
(unsigned)needed, QDSIZE - ptr);
fclose(mzfFile);
exit(1);
}
/* ---- Write header block ---- */
write_sync(&ptr);
QDArray[ptr++] = 0x00; /* block type: file header */
QDArray[ptr++] = QDHDRSIZE; /* size low */
QDArray[ptr++] = 0x00; /* size high */
struct QDHeaderStr *qdHdr = (struct QDHeaderStr *)&QDArray[ptr];
memset(qdHdr, 0, QDHDRSIZE);
/* Convert CMT header to QD header */
qdHdr->Attribute = cmtHdr.Attribute;
if (qdHdr->Attribute == 0x05)
qdHdr->Attribute = 0x02; /* MZF tape type 05 → QD type 02 (BTX) */
memcpy(qdHdr->Name, cmtHdr.Name, 17);
qdHdr->Unknown = 0;
/*
* Size field handling:
* - If MZF Size > 0: use it directly (normal file)
* - If MZF Size == 0: use actual file data size (convention for
* ROM images where Size=0 means "whole file"). The QD header
* MUST have the real size — the QD loader uses it to determine
* how many bytes to read.
*/
if (cmtHdr.Size != 0)
qdHdr->Size = cmtHdr.Size;
else
qdHdr->Size = fileDataSize;
qdHdr->LoadAddress = cmtHdr.LoadAddress;
qdHdr->ExecAddress = cmtHdr.ExecAddress;
memcpy(qdHdr->Comment, cmtHdr.Comment, 38);
ptr += QDHDRSIZE;
write_crc(&ptr);
/* ---- Write data block ---- */
write_sync(&ptr);
QDArray[ptr++] = 0x05; /* block type: file data */
QDArray[ptr++] = fileDataSize & 0xFF;
QDArray[ptr++] = (fileDataSize >> 8) & 0xFF;
fread(&QDArray[ptr], 1, fileDataSize, mzfFile);
ptr += fileDataSize;
write_crc(&ptr);
fclose(mzfFile);
/* Update block count (+2: one header block, one data block) */
QDArray[4] = blocks + 2;
/* Format name for display */
char name[18];
memcpy(name, cmtHdr.Name, 17);
name[17] = '\0';
for (int j = 0; j < 17; j++) {
if (name[j] == '\r' || name[j] == '\0') { name[j] = '\0'; break; }
}
printf(" Added: type=0x%02X name=\"%s\" size=%u load=0x%04X exec=0x%04X\n",
qdHdr->Attribute, name, qdHdr->Size,
qdHdr->LoadAddress, qdHdr->ExecAddress);
printf(" QD: %d blocks, %u bytes free\n", blocks + 2, QDSIZE - ptr);
if (!save_qd()) exit(1);
}
/* ------- Usage and main ------- */
static void usage(void)
{
printf("Usage:\n");
printf(" MZQDTool format [-o disk.qd] Format empty QD image\n");
printf(" MZQDTool dir [-o disk.qd] List QD directory\n");
printf(" MZQDTool add <file.mzf> [-o disk.qd] Add MZF file to QD\n");
printf("\n");
printf("Options:\n");
printf(" -o <filename> QD image file (default: %s)\n", DEFAULTQDFILE);
printf("\n");
}
int main(int argc, char *argv[])
{
printf("\nMZQDTool V%s (c) 2002 BKK, 2026 Philip Smart\n\n", VERSION);
if (argc < 2) {
usage();
return 1;
}
/* Parse -o option from any position */
for (int i = 1; i < argc - 1; i++) {
if (strcmp("-o", argv[i]) == 0) {
strncpy(qdFileName, argv[i + 1], sizeof(qdFileName) - 1);
qdFileName[sizeof(qdFileName) - 1] = '\0';
/* Remove -o and its argument from argv for command parsing */
for (int j = i; j < argc - 2; j++)
argv[j] = argv[j + 2];
argc -= 2;
break;
}
}
if (strcmp("format", argv[1]) == 0) {
QDFormat();
} else if (strcmp("dir", argv[1]) == 0) {
QDDir();
} else if (strcmp("add", argv[1]) == 0) {
if (argc < 3) {
fprintf(stderr, "ERROR: No MZF file specified\n");
return 2;
}
AddFileToQD(argv[2]);
} else {
fprintf(stderr, "ERROR: Unknown command '%s'\n", argv[1]);
usage();
return 1;
}
return 0;
}

19
tools/MZQD/Makefile vendored Normal file
View File

@@ -0,0 +1,19 @@
# MZQDTool - Sharp MZ-700 Quick Disk image tool
# (c) 2002 BKK, 2026 Philip Smart
#
# Usage:
# make Build MZQDTool
# make clean Remove build artifacts
CC = gcc
CFLAGS = -Wall -Wno-unused-result -O2
TARGET = MZQDTool
SRC = MZQDTool.c
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $<
clean:
rm -f $(TARGET)
.PHONY: clean

BIN
tools/MZQD/side_a/AUTO RUN.mzf vendored Normal file

Binary file not shown.

BIN
tools/MZQD/side_a/BASIC 5Z008A RFS.mzf vendored Normal file

Binary file not shown.

BIN
tools/MZQD/side_a/BASIC 5Z008ADRFS.mzf vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
tools/MZQD/side_a/BASIC MZ-5Z008.mzf vendored Normal file

Binary file not shown.

BIN
tools/MZQD/side_b/DELETE.mzf vendored Normal file

Binary file not shown.

BIN
tools/MZQD/side_b/QDCOPY.mzf vendored Normal file

Binary file not shown.

BIN
tools/MZQD/side_b/TRANS.mzf vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tools/MZQDTool vendored Executable file

Binary file not shown.

View File

@@ -40,7 +40,7 @@ ASM=glass.jar
BUILDROMLIST="monitor_sa1510_hiload monitor_80c_sa1510_hiload monitor_80c_sa1510 mz80afi monitor_sa1510 monitor_80c_sa1510 monitor_1z-013a monitor_80c_1z-013a ipl"
#BUILDMZFLIST="hi-ramcheck sharpmz-test"
BUILDMZFLIST="sa-5510_rfs msbasic_mz80a msbasic_rfs40 msbasic_rfs80 sharpmz-test 1z-013b mz5z009 mz2z009e mz5z008 mz5z008_rfs"
BUILDMZFLIST="sa-5510_rfs msbasic_mz80a msbasic_rfs40 msbasic_rfs80 sharpmz-test 1z-013b mz5z009 mz2z009e_orig mz2z009e_rfs mz5z008_orig mz5z008_rfs"
ASMDIR=${ROOTDIR}/asm
ASMTMPDIR=${ROOTDIR}/tmp
INCDIR=${ROOTDIR}/asm/include

View File

@@ -219,8 +219,10 @@ ROM_INCLUDE_RSV1=""
# | | | | |-- Name and path of the sectored version of the MZF file.
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/sa-5510_rfs.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/1z-013b.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz2z009e.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz5z008.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz2z009e_orig.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz2z009e_rfs.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz5z008_orig.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz5z008_rfs.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/mz5z009.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/msbasic_mz80a.${SECTORSIZE}.bin"
addMZFToROMImageList 1 1 1 0 "${MZB_PATH}/Common/msbasic_rfs40.${SECTORSIZE}.bin"