Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb496c9309 |
BIN
projects/tzpuPico/tools/MZFD/MZFDTool
vendored
Executable file
BIN
projects/tzpuPico/tools/MZFD/MZFDTool
vendored
Executable file
Binary file not shown.
618
projects/tzpuPico/tools/MZFD/MZFDTool.c
Executable file
618
projects/tzpuPico/tools/MZFD/MZFDTool.c
Executable file
@@ -0,0 +1,618 @@
|
||||
/* =========================================================================
|
||||
* MZFDTool — Sharp MZ-700 Floppy Disk image tool
|
||||
*
|
||||
* Creates and manages raw floppy disk images for the MZ-700 FDC system.
|
||||
* Supports format, directory listing, adding/extracting MZF files, and
|
||||
* setting a boot program.
|
||||
*
|
||||
* Original V1.01 (c) 2002 by BKK (DOS BIOS int13h version)
|
||||
* Updated V2.00 (c) 2026 Philip Smart — rewritten for Linux with raw
|
||||
* image file I/O, proper directory management, MZF conversion,
|
||||
* and robust error handling.
|
||||
*
|
||||
* MZ-700 Floppy Disk format (327,680 bytes raw image):
|
||||
*
|
||||
* Geometry: 40 cylinders, 2 heads, 16 sectors/track, 256 bytes/sector.
|
||||
* Data on disk is INVERTED (XOR 0xFF) due to MZ-700 hardware.
|
||||
*
|
||||
* Logical sector = (cylinder * 2 + head) * 16 + (phys_sector - 1)
|
||||
* Total sectors: 40 * 2 * 16 = 1280
|
||||
*
|
||||
* Boot sector: Logical sector 0 (Cyl 0, Head 0, Sector 1)
|
||||
* Directory: Logical sectors 16-31 (Cyl 0, Head 1, Sectors 1-16)
|
||||
* 16 sectors * 8 entries/sector = 128 entries
|
||||
* Entry 0 of sector 16 = volume/FAT header
|
||||
* Data area: Logical sector 32+ (Cyl 1+)
|
||||
*
|
||||
* Boot sector (32 bytes used):
|
||||
* +00: Type (03 = MZ-700 bootable)
|
||||
* +01: Signature "IPLPRO" (6 bytes)
|
||||
* +07: Program name (11 bytes, CR-terminated)
|
||||
* +12: Load address (2 bytes LE)
|
||||
* +14: File size (2 bytes LE)
|
||||
* +16: Reserved (8 bytes)
|
||||
* +1E: Start data sector (2 bytes LE)
|
||||
*
|
||||
* Directory entry (32 bytes):
|
||||
* +00: FileType (01=OBJ, 02=BTX, 00=deleted, >=80h=header)
|
||||
* +01: FileName (17 bytes, CR-terminated, space-padded)
|
||||
* +12: LockFlag (1 byte)
|
||||
* +13: DummyFlag (1 byte)
|
||||
* +14: FileSize (2 bytes LE, in bytes)
|
||||
* +16: LoadAddress (2 bytes LE)
|
||||
* +18: ExecAddress (2 bytes LE)
|
||||
* +1A: Reserved (4 bytes)
|
||||
* +1E: SectorAddress (2 bytes LE, logical)
|
||||
*
|
||||
* Usage:
|
||||
* MZFDTool format [-o disk.img] Format empty disk image
|
||||
* MZFDTool dir [-o disk.img] List directory
|
||||
* MZFDTool add <file.mzf> [-o disk.img] Add MZF file to directory
|
||||
* MZFDTool extract <name> [-o disk.img] Extract file to MZF
|
||||
* MZFDTool boot <file.mzf> [-o disk.img] Set boot program
|
||||
* ========================================================================= */
|
||||
|
||||
#define VERSION "2.00"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define CYLS 40
|
||||
#define HEADS 2
|
||||
#define SECTORS 16
|
||||
#define SECSIZE 256
|
||||
#define TOTAL_SECTORS (CYLS * HEADS * SECTORS)
|
||||
#define IMGSIZE (TOTAL_SECTORS * SECSIZE)
|
||||
#define DIR_FIRST_SEC 16 /* First directory logical sector */
|
||||
#define DIR_SECTORS 16 /* Number of directory sectors */
|
||||
#define DIR_ENTRIES 8 /* Entries per sector */
|
||||
#define DATA_FIRST_SEC 32 /* First data logical sector */
|
||||
#define MAXFILETYPES 12
|
||||
#define DEFAULTIMAGE "MZ700.img"
|
||||
#define CMTHDRSIZE 128 /* MZF/CMT file header size */
|
||||
#define BOOT_SIG_TYPE 3 /* MZ-700 boot type */
|
||||
#define BOOT_SIG "IPLPRO"
|
||||
#define BOOT_SIG_LEN 6
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/* Boot sector structure (first 32 bytes of logical sector 0) */
|
||||
struct BootSector {
|
||||
uint8_t type; /* +00: 03 = MZ-700 bootable */
|
||||
char signature[6]; /* +01: "IPLPRO" */
|
||||
char name[11]; /* +07: Program name (CR-terminated) */
|
||||
uint16_t loadAddress; /* +12: Load address */
|
||||
uint16_t fileSize; /* +14: File size in bytes */
|
||||
uint8_t reserved[8]; /* +16: Reserved */
|
||||
uint16_t sectorAddress; /* +1E: Start data sector */
|
||||
};
|
||||
|
||||
/* Directory entry (32 bytes) */
|
||||
struct DirEntry {
|
||||
uint8_t fileType; /* +00: 01=OBJ, 02=BTX, 00=deleted */
|
||||
char fileName[17]; /* +01: CR-terminated, space-padded */
|
||||
uint8_t lockFlag; /* +12: Lock flag */
|
||||
uint8_t dummyFlag; /* +13: Reserved */
|
||||
uint16_t fileSize; /* +14: File size in bytes */
|
||||
uint16_t loadAddress; /* +16: Load address */
|
||||
uint16_t execAddress; /* +18: Exec address */
|
||||
uint8_t dummy[4]; /* +1A: Reserved */
|
||||
uint16_t sectorAddress; /* +1E: Start sector (logical) */
|
||||
};
|
||||
|
||||
/* MZF/CMT tape file header (128 bytes) */
|
||||
struct CMTHeader {
|
||||
uint8_t attribute; /* File type: 01=OBJ, 02=BTX, etc. */
|
||||
char name[17]; /* Filename (CR-terminated) */
|
||||
uint16_t size; /* Data size */
|
||||
uint16_t loadAddress; /* Load address */
|
||||
uint16_t execAddress; /* Execution address */
|
||||
char comment[104]; /* Comment area */
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static const char *FileTypes[MAXFILETYPES] = {
|
||||
"???", "OBJ", "BTX", "BSD", "BRD", "RB ",
|
||||
"???", "LIB", "???", "???", "SYS", "GR "
|
||||
};
|
||||
|
||||
static uint8_t diskImage[IMGSIZE];
|
||||
static char imgFileName[256] = DEFAULTIMAGE;
|
||||
|
||||
/* ------- Sector I/O helpers ------- */
|
||||
|
||||
/* Convert logical sector to byte offset in raw image */
|
||||
static int sec_offset(int logical_sec)
|
||||
{
|
||||
/* Logical sector mapping:
|
||||
* phys_sector = logical % 16 + 1 (but stored 0-based in image)
|
||||
* head = (logical / 16) % 2
|
||||
* cylinder = logical / 16 / 2
|
||||
* Raw image is sequential: cyl0/head0/sec1..16, cyl0/head1/sec1..16, ... */
|
||||
return logical_sec * SECSIZE;
|
||||
}
|
||||
|
||||
/* Invert a buffer (XOR 0xFF) — MZ-700 data bus inversion */
|
||||
static void invert_buf(uint8_t *buf, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
buf[i] ^= 0xFF;
|
||||
}
|
||||
|
||||
/* Read a logical sector from image into buffer (un-inverted) */
|
||||
static void read_sector(int logical_sec, uint8_t *buf)
|
||||
{
|
||||
memcpy(buf, &diskImage[sec_offset(logical_sec)], SECSIZE);
|
||||
invert_buf(buf, SECSIZE);
|
||||
}
|
||||
|
||||
/* Write a buffer to a logical sector in image (inverts before writing) */
|
||||
static void write_sector(int logical_sec, const uint8_t *buf)
|
||||
{
|
||||
memcpy(&diskImage[sec_offset(logical_sec)], buf, SECSIZE);
|
||||
invert_buf(&diskImage[sec_offset(logical_sec)], SECSIZE);
|
||||
}
|
||||
|
||||
/* Load disk image from file */
|
||||
static int load_image(void)
|
||||
{
|
||||
FILE *f = fopen(imgFileName, "rb");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open '%s'\n", imgFileName);
|
||||
return 0;
|
||||
}
|
||||
size_t n = fread(diskImage, 1, IMGSIZE, f);
|
||||
fclose(f);
|
||||
if (n != IMGSIZE) {
|
||||
fprintf(stderr, "ERROR: '%s' is not a valid disk image (%zu bytes, expected %d)\n",
|
||||
imgFileName, n, IMGSIZE);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Save disk image to file */
|
||||
static int save_image(void)
|
||||
{
|
||||
FILE *f = fopen(imgFileName, "wb");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot write '%s'\n", imgFileName);
|
||||
return 0;
|
||||
}
|
||||
fwrite(diskImage, IMGSIZE, 1, f);
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Format a filename for display: stop at CR, null-terminate */
|
||||
static void format_name(char *dst, const char *src, int maxlen)
|
||||
{
|
||||
memcpy(dst, src, maxlen);
|
||||
dst[maxlen] = '\0';
|
||||
for (int i = 0; i < maxlen; i++) {
|
||||
if (dst[i] == '\r' || dst[i] == '\0') { dst[i] = '\0'; break; }
|
||||
}
|
||||
}
|
||||
|
||||
/* ------- Commands ------- */
|
||||
|
||||
/* Format: create an empty formatted disk image */
|
||||
static void cmd_format(void)
|
||||
{
|
||||
uint8_t sec[SECSIZE];
|
||||
|
||||
printf("Formatting '%s' (%d bytes, %d sectors)\n", imgFileName, IMGSIZE, TOTAL_SECTORS);
|
||||
|
||||
/* Fill entire image with 0xFF (which inverts to 0x00 = empty) */
|
||||
memset(diskImage, 0xFF, IMGSIZE);
|
||||
|
||||
/* Write volume header in directory sector 16, entry 0 */
|
||||
memset(sec, 0, SECSIZE);
|
||||
sec[0] = 0x81; /* Volume header marker */
|
||||
sec[1] = 'O'; /* Volume type */
|
||||
/* +14: capacity hint = 100 (not used by RFS) */
|
||||
sec[0x14] = 100;
|
||||
/* +1E: next free sector (first data sector) */
|
||||
sec[0x1E] = DATA_FIRST_SEC & 0xFF;
|
||||
sec[0x1F] = DATA_FIRST_SEC >> 8;
|
||||
write_sector(DIR_FIRST_SEC, sec);
|
||||
|
||||
if (!save_image()) exit(1);
|
||||
puts("Done.");
|
||||
}
|
||||
|
||||
/* Dir: list directory contents */
|
||||
static void cmd_dir(void)
|
||||
{
|
||||
uint8_t sec[SECSIZE];
|
||||
char name[18];
|
||||
int files = 0;
|
||||
|
||||
if (!load_image()) exit(1);
|
||||
|
||||
/* Check boot sector */
|
||||
read_sector(0, sec);
|
||||
struct BootSector *boot = (struct BootSector *)sec;
|
||||
if (boot->type == BOOT_SIG_TYPE && memcmp(boot->signature, BOOT_SIG, BOOT_SIG_LEN) == 0) {
|
||||
format_name(name, boot->name, 11);
|
||||
printf("\nBoot program: %-17s Size=%u Load=0x%04X Sector=%u\n",
|
||||
name, boot->fileSize, boot->loadAddress, boot->sectorAddress);
|
||||
} else {
|
||||
printf("\nDisk is not bootable.\n");
|
||||
}
|
||||
|
||||
printf("\nDirectory of '%s':\n\n", imgFileName);
|
||||
printf(" %-17s %-3s %5s %s %4s %4s %6s (C H S)\n",
|
||||
"Name", "Typ", "Size", "L", "Load", "Exec", "Sector");
|
||||
printf(" %-17s %-3s %5s %s %4s %4s %6s %s\n",
|
||||
"-----------------", "---", "-----", "-", "----", "----", "------", "-------");
|
||||
|
||||
for (int ds = 0; ds < DIR_SECTORS; ds++) {
|
||||
read_sector(DIR_FIRST_SEC + ds, sec);
|
||||
|
||||
for (int e = 0; e < DIR_ENTRIES; e++) {
|
||||
/* Skip entry 0 of first directory sector (volume header) */
|
||||
if (ds == 0 && e == 0) continue;
|
||||
|
||||
struct DirEntry *ent = (struct DirEntry *)&sec[e * sizeof(struct DirEntry)];
|
||||
if (ent->fileType == 0x00 || ent->fileType >= 0x80)
|
||||
continue;
|
||||
|
||||
uint8_t ft = ent->fileType;
|
||||
if (ft >= MAXFILETYPES) ft = 0;
|
||||
format_name(name, ent->fileName, 17);
|
||||
|
||||
int ls = ent->sectorAddress;
|
||||
int ps = ls % 16 + 1;
|
||||
int hd = (ls / 16) % 2;
|
||||
int cy = ls / 16 / 2;
|
||||
|
||||
printf(" %-17s %s %5u %c %04X %04X %5u (%2d %d %2d)\n",
|
||||
name, FileTypes[ft], ent->fileSize,
|
||||
ent->lockFlag ? 'X' : ' ',
|
||||
ent->loadAddress, ent->execAddress,
|
||||
ent->sectorAddress, cy, hd, ps);
|
||||
files++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate free space */
|
||||
int highSec = DATA_FIRST_SEC;
|
||||
for (int ds = 0; ds < DIR_SECTORS; ds++) {
|
||||
read_sector(DIR_FIRST_SEC + ds, sec);
|
||||
for (int e = 0; e < DIR_ENTRIES; e++) {
|
||||
struct DirEntry *ent = (struct DirEntry *)&sec[e * sizeof(struct DirEntry)];
|
||||
if (ent->fileType > 0 && ent->fileType < 0x80 && ent->sectorAddress > 0) {
|
||||
int endSec = ent->sectorAddress + (ent->fileSize + SECSIZE - 1) / SECSIZE;
|
||||
if (endSec > highSec) highSec = endSec;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n%d file(s), %d sectors used, %d sectors free\n",
|
||||
files, highSec, TOTAL_SECTORS - highSec);
|
||||
}
|
||||
|
||||
/* Add: add an MZF file to the disk directory */
|
||||
static void cmd_add(const char *mzfFileName)
|
||||
{
|
||||
FILE *mzfFile;
|
||||
uint8_t sec[SECSIZE];
|
||||
struct CMTHeader cmtHdr;
|
||||
char name[18];
|
||||
|
||||
if (!load_image()) exit(1);
|
||||
|
||||
/* 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 mzfSize = ftell(mzfFile);
|
||||
fseek(mzfFile, 0, SEEK_SET);
|
||||
|
||||
if (mzfSize < CMTHDRSIZE) {
|
||||
fprintf(stderr, "ERROR: '%s' too small for MZF format (%ld bytes)\n", mzfFileName, mzfSize);
|
||||
fclose(mzfFile);
|
||||
exit(1);
|
||||
}
|
||||
fread(&cmtHdr, CMTHDRSIZE, 1, mzfFile);
|
||||
uint16_t dataSize = cmtHdr.size;
|
||||
if (dataSize == 0) dataSize = (uint16_t)(mzfSize - CMTHDRSIZE);
|
||||
|
||||
/* Find free directory entry and highest used sector */
|
||||
int freeDirSec = -1, freeDirIdx = -1;
|
||||
int highSec = DATA_FIRST_SEC;
|
||||
|
||||
for (int ds = 0; ds < DIR_SECTORS; ds++) {
|
||||
read_sector(DIR_FIRST_SEC + ds, sec);
|
||||
for (int e = 0; e < DIR_ENTRIES; e++) {
|
||||
if (ds == 0 && e == 0) continue; /* Skip volume header */
|
||||
struct DirEntry *ent = (struct DirEntry *)&sec[e * sizeof(struct DirEntry)];
|
||||
|
||||
if (ent->fileType == 0x00 && freeDirSec < 0) {
|
||||
freeDirSec = ds;
|
||||
freeDirIdx = e;
|
||||
}
|
||||
if (ent->fileType > 0 && ent->fileType < 0x80 && ent->sectorAddress > 0) {
|
||||
int endSec = ent->sectorAddress + (ent->fileSize + SECSIZE - 1) / SECSIZE;
|
||||
if (endSec > highSec) highSec = endSec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (freeDirSec < 0) {
|
||||
fprintf(stderr, "ERROR: Directory full\n");
|
||||
fclose(mzfFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int dataSectors = (dataSize + SECSIZE - 1) / SECSIZE;
|
||||
if (highSec + dataSectors > TOTAL_SECTORS) {
|
||||
fprintf(stderr, "ERROR: Not enough space (need %d sectors, have %d)\n",
|
||||
dataSectors, TOTAL_SECTORS - highSec);
|
||||
fclose(mzfFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Write file data sectors */
|
||||
for (int s = 0; s < dataSectors; s++) {
|
||||
memset(sec, 0, SECSIZE);
|
||||
fread(sec, 1, SECSIZE, mzfFile);
|
||||
write_sector(highSec + s, sec);
|
||||
}
|
||||
fclose(mzfFile);
|
||||
|
||||
/* Update directory entry */
|
||||
read_sector(DIR_FIRST_SEC + freeDirSec, sec);
|
||||
struct DirEntry *ent = (struct DirEntry *)&sec[freeDirIdx * sizeof(struct DirEntry)];
|
||||
memset(ent, 0, sizeof(struct DirEntry));
|
||||
|
||||
ent->fileType = cmtHdr.attribute;
|
||||
if (ent->fileType == 0x05) ent->fileType = 0x02; /* CMT type 05 → FD type 02 (BTX) */
|
||||
memcpy(ent->fileName, cmtHdr.name, 17);
|
||||
ent->fileSize = dataSize;
|
||||
ent->loadAddress = cmtHdr.loadAddress;
|
||||
ent->execAddress = cmtHdr.execAddress;
|
||||
ent->sectorAddress = highSec;
|
||||
write_sector(DIR_FIRST_SEC + freeDirSec, sec);
|
||||
|
||||
format_name(name, cmtHdr.name, 17);
|
||||
printf(" Added: \"%s\" type=%s size=%u load=0x%04X exec=0x%04X sector=%d\n",
|
||||
name, FileTypes[ent->fileType < MAXFILETYPES ? ent->fileType : 0],
|
||||
dataSize, cmtHdr.loadAddress, cmtHdr.execAddress, highSec);
|
||||
printf(" %d sectors free\n", TOTAL_SECTORS - highSec - dataSectors);
|
||||
|
||||
if (!save_image()) exit(1);
|
||||
}
|
||||
|
||||
/* Extract: extract a file from disk to MZF format */
|
||||
static void cmd_extract(const char *fileName)
|
||||
{
|
||||
uint8_t sec[SECSIZE];
|
||||
char entName[18], outName[256];
|
||||
|
||||
if (!load_image()) exit(1);
|
||||
|
||||
/* Search directory for matching filename */
|
||||
static struct DirEntry foundEntry;
|
||||
int foundIt = 0;
|
||||
|
||||
for (int ds = 0; ds < DIR_SECTORS && !foundIt; ds++) {
|
||||
read_sector(DIR_FIRST_SEC + ds, sec);
|
||||
for (int e = 0; e < DIR_ENTRIES && !foundIt; e++) {
|
||||
if (ds == 0 && e == 0) continue;
|
||||
struct DirEntry *ent = (struct DirEntry *)&sec[e * sizeof(struct DirEntry)];
|
||||
if (ent->fileType > 0 && ent->fileType < 0x80) {
|
||||
format_name(entName, ent->fileName, 17);
|
||||
if (strcmp(fileName, entName) == 0) {
|
||||
memcpy(&foundEntry, ent, sizeof(foundEntry));
|
||||
foundIt = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundIt) {
|
||||
/* Also check boot sector */
|
||||
read_sector(0, sec);
|
||||
struct BootSector *boot = (struct BootSector *)sec;
|
||||
if (boot->type == BOOT_SIG_TYPE && memcmp(boot->signature, BOOT_SIG, BOOT_SIG_LEN) == 0) {
|
||||
format_name(entName, boot->name, 11);
|
||||
if (strcmp(fileName, entName) == 0) {
|
||||
memset(&foundEntry, 0, sizeof(foundEntry));
|
||||
foundEntry.fileType = 0x01;
|
||||
memcpy(foundEntry.fileName, boot->name, 11);
|
||||
foundEntry.fileSize = boot->fileSize;
|
||||
foundEntry.loadAddress = boot->loadAddress;
|
||||
foundEntry.sectorAddress = boot->sectorAddress;
|
||||
foundIt = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundIt) {
|
||||
fprintf(stderr, "ERROR: '%s' not found on disk\n", fileName);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct DirEntry *found = &foundEntry;
|
||||
|
||||
/* Build output filename */
|
||||
snprintf(outName, sizeof(outName), "%s.mzf", fileName);
|
||||
for (char *p = outName; *p; p++) {
|
||||
if (*p == ' ') *p = '_';
|
||||
}
|
||||
|
||||
/* Write MZF file */
|
||||
FILE *out = fopen(outName, "wb");
|
||||
if (!out) {
|
||||
fprintf(stderr, "ERROR: Cannot create '%s'\n", outName);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct CMTHeader hdr;
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.attribute = (found->fileType == 0x02) ? 0x05 : found->fileType;
|
||||
memcpy(hdr.name, found->fileName, 17);
|
||||
hdr.size = found->fileSize;
|
||||
hdr.loadAddress = found->loadAddress;
|
||||
hdr.execAddress = found->execAddress;
|
||||
snprintf(hdr.comment, sizeof(hdr.comment), "Extracted by MZFDTool V%s", VERSION);
|
||||
fwrite(&hdr, sizeof(hdr), 1, out);
|
||||
|
||||
/* Read and write data sectors */
|
||||
uint16_t remaining = found->fileSize;
|
||||
int curSec = found->sectorAddress;
|
||||
while (remaining > 0) {
|
||||
read_sector(curSec, sec);
|
||||
uint16_t chunk = (remaining > SECSIZE) ? SECSIZE : remaining;
|
||||
fwrite(sec, 1, chunk, out);
|
||||
remaining -= chunk;
|
||||
curSec++;
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
format_name(entName, found->fileName, 17);
|
||||
printf(" Extracted: \"%s\" → %s (%u bytes)\n", entName, outName, found->fileSize);
|
||||
}
|
||||
|
||||
/* Boot: set boot program from MZF file */
|
||||
static void cmd_boot(const char *mzfFileName)
|
||||
{
|
||||
FILE *mzfFile;
|
||||
uint8_t sec[SECSIZE];
|
||||
struct CMTHeader cmtHdr;
|
||||
char name[18];
|
||||
|
||||
if (!load_image()) exit(1);
|
||||
|
||||
mzfFile = fopen(mzfFileName, "rb");
|
||||
if (!mzfFile) {
|
||||
fprintf(stderr, "ERROR: Cannot open '%s'\n", mzfFileName);
|
||||
exit(1);
|
||||
}
|
||||
fseek(mzfFile, 0, SEEK_END);
|
||||
long mzfSize = ftell(mzfFile);
|
||||
fseek(mzfFile, 0, SEEK_SET);
|
||||
|
||||
if (mzfSize < CMTHDRSIZE) {
|
||||
fprintf(stderr, "ERROR: '%s' too small for MZF format\n", mzfFileName);
|
||||
fclose(mzfFile);
|
||||
exit(1);
|
||||
}
|
||||
fread(&cmtHdr, CMTHDRSIZE, 1, mzfFile);
|
||||
uint16_t dataSize = cmtHdr.size;
|
||||
if (dataSize == 0) dataSize = (uint16_t)(mzfSize - CMTHDRSIZE);
|
||||
|
||||
/* Find space for boot data — use sectors 1-15 (logical), before directory */
|
||||
int dataSectors = (dataSize + SECSIZE - 1) / SECSIZE;
|
||||
int bootDataStart = 1; /* Sector 1 (sector 0 is the boot sector itself) */
|
||||
if (dataSectors > 15) {
|
||||
fprintf(stderr, "ERROR: Boot program too large (%d sectors, max 15)\n", dataSectors);
|
||||
fclose(mzfFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Write boot data to sectors 1-15 */
|
||||
for (int s = 0; s < dataSectors; s++) {
|
||||
memset(sec, 0, SECSIZE);
|
||||
fread(sec, 1, SECSIZE, mzfFile);
|
||||
write_sector(bootDataStart + s, sec);
|
||||
}
|
||||
fclose(mzfFile);
|
||||
|
||||
/* Write boot sector (sector 0) */
|
||||
memset(sec, 0, SECSIZE);
|
||||
struct BootSector *boot = (struct BootSector *)sec;
|
||||
boot->type = BOOT_SIG_TYPE;
|
||||
memcpy(boot->signature, BOOT_SIG, BOOT_SIG_LEN);
|
||||
format_name(name, cmtHdr.name, 11);
|
||||
memcpy(boot->name, cmtHdr.name, 11);
|
||||
boot->loadAddress = cmtHdr.loadAddress;
|
||||
boot->fileSize = dataSize;
|
||||
boot->sectorAddress = bootDataStart;
|
||||
write_sector(0, sec);
|
||||
|
||||
format_name(name, cmtHdr.name, 11);
|
||||
printf(" Boot set: \"%s\" size=%u load=0x%04X exec=0x%04X sector=%d\n",
|
||||
name, dataSize, cmtHdr.loadAddress, cmtHdr.execAddress, bootDataStart);
|
||||
|
||||
if (!save_image()) exit(1);
|
||||
}
|
||||
|
||||
/* ------- Usage and main ------- */
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" MZFDTool format [-o disk.img] Format empty disk image\n");
|
||||
printf(" MZFDTool dir [-o disk.img] List directory\n");
|
||||
printf(" MZFDTool add <file.mzf> [-o disk.img] Add MZF file to disk\n");
|
||||
printf(" MZFDTool extract <name> [-o disk.img] Extract file to MZF\n");
|
||||
printf(" MZFDTool boot <file.mzf> [-o disk.img] Set boot program\n");
|
||||
printf("\n");
|
||||
printf("Options:\n");
|
||||
printf(" -o <filename> Disk image file (default: %s)\n", DEFAULTIMAGE);
|
||||
printf("\n");
|
||||
printf("Disk geometry: %d cyls, %d heads, %d sectors, %d bytes/sector = %d bytes\n",
|
||||
CYLS, HEADS, SECTORS, SECSIZE, IMGSIZE);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("\nMZFDTool 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(imgFileName, argv[i + 1], sizeof(imgFileName) - 1);
|
||||
imgFileName[sizeof(imgFileName) - 1] = '\0';
|
||||
for (int j = i; j < argc - 2; j++)
|
||||
argv[j] = argv[j + 2];
|
||||
argc -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp("format", argv[1]) == 0) {
|
||||
cmd_format();
|
||||
} else if (strcmp("dir", argv[1]) == 0) {
|
||||
cmd_dir();
|
||||
} else if (strcmp("add", argv[1]) == 0) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "ERROR: No MZF file specified\n");
|
||||
return 2;
|
||||
}
|
||||
cmd_add(argv[2]);
|
||||
} else if (strcmp("extract", argv[1]) == 0) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "ERROR: No filename specified\n");
|
||||
return 2;
|
||||
}
|
||||
cmd_extract(argv[2]);
|
||||
} else if (strcmp("boot", argv[1]) == 0) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "ERROR: No MZF file specified\n");
|
||||
return 2;
|
||||
}
|
||||
cmd_boot(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Unknown command '%s'\n", argv[1]);
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
630
projects/tzpuPico/tools/MZFD/MZFDTool.c.original
vendored
Executable file
630
projects/tzpuPico/tools/MZFD/MZFDTool.c.original
vendored
Executable file
@@ -0,0 +1,630 @@
|
||||
#define VERSION "1.01"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <mem.h>
|
||||
#include <dos.h>
|
||||
|
||||
|
||||
|
||||
union REGS regs;
|
||||
struct SREGS sregs;
|
||||
|
||||
|
||||
struct MZ700BootStruct
|
||||
{
|
||||
unsigned char Type;
|
||||
char Signature[6];
|
||||
char Name[11];
|
||||
unsigned short StartAddress;
|
||||
unsigned short FileSize;
|
||||
unsigned char Dummy[8];
|
||||
unsigned short SectorAddress;
|
||||
};
|
||||
|
||||
|
||||
struct MZ700DirectoryStruct
|
||||
{
|
||||
unsigned char FileType; // 0x00 -> 1
|
||||
char FileName[17]; // 0x01 ... 0x11 -> 17
|
||||
unsigned char LockFlag; // 0x12 -> 1
|
||||
unsigned char DummyFlag; // 0x13 -> 1
|
||||
unsigned short FileSize; // 0x14 ... 0x15 -> 2
|
||||
unsigned short LoadAddress; // 0x16 ... 0x17 -> 2
|
||||
unsigned short ExecAddress; // 0x18 ... 0x19 -> 2
|
||||
char Dummy[4]; // 0x1A ... 0x1D -> 4
|
||||
unsigned short SectorAddress; // 0x1E ... 0x1F -> 2
|
||||
};
|
||||
|
||||
|
||||
struct CMTHeader
|
||||
{
|
||||
unsigned char Attribute;
|
||||
char Name[17];
|
||||
unsigned short Size;
|
||||
unsigned short LoadAddress;
|
||||
unsigned short ExecAddress;
|
||||
char Comment[104];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
char FileTypes[][4] = {
|
||||
"???",
|
||||
"OBJ",
|
||||
"BTX",
|
||||
"BSD",
|
||||
"BRD",
|
||||
"RB ",
|
||||
"???",
|
||||
"LIB",
|
||||
"???",
|
||||
"???",
|
||||
"SYS",
|
||||
"GR "
|
||||
};
|
||||
|
||||
|
||||
|
||||
unsigned char DiskParameters[11] =
|
||||
{0xDF, 0x02, 0x25, 0x01, 16, 0x4E, 0xFF, 0x6C, 0xE5, 100, 8};
|
||||
// {0xDF, 0x02, 0x25, 0x02, 18, 0x1B, 0xFF, 0x6C, 0xF6, 100, 8}; /* 1.44MB */
|
||||
|
||||
|
||||
char *ErrorMsg[] =
|
||||
{
|
||||
"success",
|
||||
"invalid function",
|
||||
"address mark not found",
|
||||
"disk write-protected",
|
||||
"sector not found / read error",
|
||||
"reset faild",
|
||||
"data did not verify correctly",
|
||||
"disk changed",
|
||||
"drive parameter activity failed",
|
||||
"DMA overrun",
|
||||
"data boundary error",
|
||||
"bad sector detected",
|
||||
"bad track detected",
|
||||
"unsupported track or invalid media",
|
||||
"invalid number of sectors",
|
||||
"control data address mark detected",
|
||||
"DMA arbitration level out of range",
|
||||
"uncorrectable CRC or ECCerror",
|
||||
"data ECC corrected"
|
||||
};
|
||||
|
||||
|
||||
unsigned char SectorBuffer[1024];
|
||||
|
||||
unsigned char Drive;
|
||||
unsigned char Cylinder;
|
||||
unsigned char Head;
|
||||
unsigned char Sector;
|
||||
|
||||
|
||||
unsigned int OrgInt1EOffset;
|
||||
unsigned int OrgInt1ESegment;
|
||||
|
||||
|
||||
|
||||
|
||||
void Error(unsigned char Index)
|
||||
{
|
||||
printf("Error: %02X - ", Index);
|
||||
if(Index < 0x12) printf("%s\n", ErrorMsg[Index]);
|
||||
if(Index == 0x80) puts("No disc in drive!");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ShowSectorBuffer(void)
|
||||
{
|
||||
unsigned char ByteCounter;
|
||||
unsigned char LineCounter;
|
||||
int Counter;
|
||||
|
||||
|
||||
Counter = 0;
|
||||
|
||||
for(LineCounter = 0; LineCounter < 16; LineCounter++)
|
||||
{
|
||||
printf("\n%04X : ", Counter);
|
||||
for(ByteCounter = 0; ByteCounter < 16; ByteCounter++)
|
||||
{
|
||||
printf("%02X ", SectorBuffer[Counter + ByteCounter]);
|
||||
}
|
||||
printf(" ");
|
||||
for(ByteCounter = 0; ByteCounter < 16; ByteCounter++)
|
||||
{
|
||||
printf("%c", iscntrl(SectorBuffer[Counter]) ? ' ' : SectorBuffer[Counter]);
|
||||
Counter++;
|
||||
}
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int ResetFloppy(char Drive)
|
||||
{
|
||||
regs.h.ah = 0;
|
||||
regs.h.dl = Drive;
|
||||
|
||||
int86(0x13, ®s, ®s);
|
||||
|
||||
return(regs.h.ah);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int ReadSector(char Drive, char Cylinder, char Head, char Sector)
|
||||
{
|
||||
int Counter;
|
||||
|
||||
|
||||
if(Head == 0) Head = 1;
|
||||
else Head = 0;
|
||||
|
||||
|
||||
regs.h.ah = 0x02;
|
||||
Counter = 3;
|
||||
|
||||
while((regs.h.ah != 0) && (Counter != 0))
|
||||
{
|
||||
regs.h.ah = 0x02;
|
||||
regs.h.al = 1;
|
||||
regs.h.ch = Cylinder;
|
||||
regs.h.cl = Sector;
|
||||
regs.h.dh = Head;
|
||||
regs.h.dl = Drive;
|
||||
|
||||
sregs.es = FP_SEG(SectorBuffer);
|
||||
regs.x.bx = FP_OFF(SectorBuffer);
|
||||
|
||||
int86x(0x13, ®s, ®s, &sregs);
|
||||
Counter--;
|
||||
}
|
||||
|
||||
for(Counter = 0; Counter < sizeof(SectorBuffer); Counter++)
|
||||
SectorBuffer[Counter] = ~SectorBuffer[Counter];
|
||||
|
||||
return(regs.x.ax);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SaveInt1E(void)
|
||||
{
|
||||
OrgInt1EOffset = peek(0x0000, 0x1E * 4);
|
||||
OrgInt1ESegment = peek(0x0000, 0x1E * 4 + 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SetInt1E(unsigned char Type)
|
||||
{
|
||||
Type++;
|
||||
asm cli;
|
||||
poke(0x0000, 0x1E * 4, FP_OFF(DiskParameters));
|
||||
poke(0x0000, 0x1E * 4 + 2, FP_SEG(DiskParameters));
|
||||
asm sti;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ResetInt1E(void)
|
||||
{
|
||||
asm cli;
|
||||
poke(0x0000, 0x1E * 4, OrgInt1EOffset);
|
||||
poke(0x0000, 0x1E * 4 + 2, OrgInt1ESegment);
|
||||
asm sti;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ShowDirectory(void)
|
||||
{
|
||||
unsigned char SectorCounter;
|
||||
unsigned char Counter;
|
||||
unsigned char C, H, S;
|
||||
struct MZ700BootStruct *Boot;
|
||||
struct MZ700DirectoryStruct *Entry;
|
||||
char FileName[18];
|
||||
unsigned int Result;
|
||||
// unsigned short LastUsedSector;
|
||||
|
||||
|
||||
puts("");
|
||||
|
||||
Result = ReadSector(Drive, 0, 0, 1);
|
||||
Result = Result >> 8;
|
||||
if(Result != 0) Error(Result);
|
||||
Boot = (struct MZ700BootStruct *) SectorBuffer;
|
||||
memcpy(FileName, Boot->Signature, 6);
|
||||
FileName[6] = '\0';
|
||||
if((Boot->Type == 3) && (strcmp(FileName, "IPLPRO") == 0))
|
||||
{
|
||||
puts("Floppy is bootable:");
|
||||
puts("");
|
||||
|
||||
memcpy(FileName, Boot->Name, 11);
|
||||
if(strchr(FileName, 0x0D) != NULL) *strchr(FileName, 0x0D) = '\0';
|
||||
else FileName[11] = '\0';
|
||||
|
||||
printf(" %-17s OBJ %5u ", FileName, Boot->FileSize);
|
||||
S = Boot->SectorAddress % 16 + 1;
|
||||
H = (Boot->SectorAddress / 16) % 2;
|
||||
C = Boot->SectorAddress / 16 / 2;
|
||||
printf(" %4u (%2u %u %2u)\n", Boot->SectorAddress, C, H, S);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("Floppy is not bootable.");
|
||||
}
|
||||
|
||||
puts("");
|
||||
puts("Directory:");
|
||||
puts("");
|
||||
puts(" Name Type Size Lock Load Exec Pos ( C H S)");
|
||||
puts("");
|
||||
|
||||
for(SectorCounter = 1; SectorCounter < 17; SectorCounter++)
|
||||
{
|
||||
ReadSector(Drive, 0, 1, SectorCounter);
|
||||
|
||||
|
||||
|
||||
for(Counter = 0; Counter < 256 / 32; Counter++)
|
||||
{
|
||||
Entry = (struct MZ700DirectoryStruct *) &SectorBuffer[Counter * sizeof(struct MZ700DirectoryStruct)];
|
||||
|
||||
// if((SectorCounter == 1) && (Counter == 0)) LastUsedSector = Entry->SectorAddress;
|
||||
|
||||
if((Entry->FileType > 0) && (Entry->FileType < 0x80))
|
||||
{
|
||||
memcpy(FileName, Entry->FileName, 17);
|
||||
if(strchr(FileName, 0x0D) != NULL) *strchr(FileName, 0x0D) = '\0';
|
||||
else FileName[17] = '\0';
|
||||
|
||||
printf(" %-17s %s %5u %c %04X %04X", FileName, FileTypes[Entry->FileType], Entry->FileSize, Entry->LockFlag ? 'X' : ' ', Entry->LoadAddress, Entry->ExecAddress);
|
||||
S = Entry->SectorAddress % 16 + 1;
|
||||
H = (Entry->SectorAddress / 16) % 2;
|
||||
C = Entry->SectorAddress / 16 / 2;
|
||||
printf(" %4u (%2u %u %2u)\n", Entry->SectorAddress, C, H, S);
|
||||
}
|
||||
}
|
||||
}
|
||||
// printf("\nLast used Sector: %u\n\n", LastUsedSector);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CopyFDToMZF(char *FileName)
|
||||
{
|
||||
char MZFFileName[13];
|
||||
char EntryFileName[18];
|
||||
unsigned char SectorCounter, Counter;
|
||||
FILE *MZFFile;
|
||||
struct MZ700DirectoryStruct *Entry;
|
||||
struct CMTHeader MZFHeader;
|
||||
unsigned char C, H, S;
|
||||
unsigned short WriteSize;
|
||||
unsigned int Result;
|
||||
|
||||
|
||||
S = 0;
|
||||
|
||||
Result = ReadSector(Drive, 0, 0, 1); // BootSector
|
||||
Result = Result >> 8;
|
||||
if(Result != 0) Error(Result);
|
||||
SectorBuffer[33] = '\0'; // emergency stop
|
||||
if(strstr(SectorBuffer, FileName) != NULL)
|
||||
{
|
||||
Entry = (struct MZ700DirectoryStruct *) SectorBuffer;
|
||||
S = Entry->SectorAddress % 16 + 1;
|
||||
H = (Entry->SectorAddress / 16) % 2;
|
||||
C = Entry->SectorAddress / 16 / 2;
|
||||
Entry->FileType = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(SectorCounter = 1; (SectorCounter < 17) && (S == 0); SectorCounter++)
|
||||
{
|
||||
ReadSector(Drive, 0, 1, SectorCounter);
|
||||
|
||||
for(Counter = 0; (Counter < 256 / 32) && (S == 0); Counter++)
|
||||
{
|
||||
Entry = (struct MZ700DirectoryStruct *) &SectorBuffer[Counter * sizeof(struct MZ700DirectoryStruct)];
|
||||
if((Entry->FileType > 0) && (Entry->FileType < 0x80))
|
||||
{
|
||||
memcpy(EntryFileName, Entry->FileName, 17);
|
||||
if(strchr(EntryFileName, 0x0D) != NULL) *strchr(EntryFileName, 0x0D) = '\0';
|
||||
else EntryFileName[17] = '\0';
|
||||
if(strcmp(FileName, EntryFileName) == 0)
|
||||
{
|
||||
S = Entry->SectorAddress % 16 + 1;
|
||||
H = (Entry->SectorAddress / 16) % 2;
|
||||
C = Entry->SectorAddress / 16 / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(S != 0)
|
||||
{
|
||||
memset(MZFFileName, 0, sizeof(MZFFileName));
|
||||
strncpy(MZFFileName, FileName, 8);
|
||||
strcat(MZFFileName, ".MZF");
|
||||
printf("%s found save it as %s\n", FileName, MZFFileName);
|
||||
MZFFile = fopen(MZFFileName , "wb");
|
||||
memset(&MZFHeader, 0, sizeof(MZFHeader));
|
||||
if(Entry->FileType == 0x02) MZFHeader.Attribute = 0x05;
|
||||
else MZFHeader.Attribute = Entry->FileType;
|
||||
memcpy(MZFHeader.Name, Entry->FileName, 17);
|
||||
MZFHeader.Size = Entry->FileSize;
|
||||
strcat(MZFHeader.Comment, "by MZFDTool");
|
||||
|
||||
if((Entry->FileType == 0x01) && (Entry->LoadAddress == 0x0000))
|
||||
{
|
||||
MZFHeader.Comment[24] = 0x21;
|
||||
MZFHeader.Comment[25] = 0x30;
|
||||
MZFHeader.Comment[26] = 0x11;
|
||||
|
||||
MZFHeader.Comment[27] = 0x01;
|
||||
MZFHeader.Comment[28] = 0x10;
|
||||
MZFHeader.Comment[29] = 0x00;
|
||||
|
||||
MZFHeader.Comment[30] = 0x11;
|
||||
MZFHeader.Comment[31] = 0xF0;
|
||||
MZFHeader.Comment[32] = 0xCF;
|
||||
|
||||
MZFHeader.Comment[33] = 0xED;
|
||||
MZFHeader.Comment[34] = 0xB0;
|
||||
|
||||
MZFHeader.Comment[35] = 0xC3;
|
||||
MZFHeader.Comment[36] = 0xF0;
|
||||
MZFHeader.Comment[37] = 0xCF;
|
||||
|
||||
|
||||
|
||||
MZFHeader.Comment[40] = 0x21;
|
||||
MZFHeader.Comment[41] = 0x00;
|
||||
MZFHeader.Comment[42] = 0x12;
|
||||
|
||||
MZFHeader.Comment[43] = 0x01;
|
||||
MZFHeader.Comment[44] = (unsigned char) Entry->FileSize & 0xFF;
|
||||
MZFHeader.Comment[45] = Entry->FileSize >> 8;
|
||||
|
||||
MZFHeader.Comment[46] = 0x11;
|
||||
MZFHeader.Comment[47] = 0x00;
|
||||
MZFHeader.Comment[48] = 0x00;
|
||||
|
||||
MZFHeader.Comment[49] = 0xD3;
|
||||
MZFHeader.Comment[50] = 0xE0;
|
||||
|
||||
MZFHeader.Comment[51] = 0xED;
|
||||
MZFHeader.Comment[52] = 0xB0;
|
||||
|
||||
MZFHeader.Comment[53] = 0xC3;
|
||||
MZFHeader.Comment[54] = 0x00;
|
||||
MZFHeader.Comment[55] = 0x00;
|
||||
|
||||
MZFHeader.LoadAddress = 0x1200;
|
||||
MZFHeader.ExecAddress = 0x1120;
|
||||
}
|
||||
else
|
||||
{
|
||||
MZFHeader.LoadAddress = Entry->LoadAddress;
|
||||
MZFHeader.ExecAddress = Entry->ExecAddress;
|
||||
}
|
||||
fwrite(&MZFHeader, sizeof(MZFHeader), 1, MZFFile);
|
||||
|
||||
while(MZFHeader.Size != 0)
|
||||
{
|
||||
WriteSize = 256;
|
||||
if(MZFHeader.Size < WriteSize) WriteSize = MZFHeader.Size;
|
||||
MZFHeader.Size = MZFHeader.Size - WriteSize;
|
||||
ReadSector(Drive, C, H, S);
|
||||
fwrite(SectorBuffer, WriteSize, 1, MZFFile);
|
||||
S++;
|
||||
if(S == 17)
|
||||
{
|
||||
S = 1;
|
||||
if(H == 0) H = 1;
|
||||
else
|
||||
{
|
||||
C++;
|
||||
H = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(MZFFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("");
|
||||
printf("%s not found!\n", FileName);
|
||||
puts("");
|
||||
puts("Remember that capital letters are differenced!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CopyMZFToFD(char *FileName)
|
||||
{
|
||||
printf("Not implemented yet (%s)\n", FileName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Copy(char *FileName)
|
||||
{
|
||||
if((strstr(FileName, ".MZF") == NULL) && (strstr(FileName, ".mzf") == NULL)) CopyFDToMZF(FileName);
|
||||
else CopyMZFToFD(FileName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ShowMap(void)
|
||||
{
|
||||
unsigned short UsedSectors;
|
||||
unsigned short Counter;
|
||||
unsigned char BitCounter;
|
||||
// unsigned char BitMask;
|
||||
unsigned short BitMask;
|
||||
unsigned short *SectorsPerTrack;
|
||||
unsigned char StartTrack;
|
||||
unsigned int Result;
|
||||
|
||||
|
||||
puts("");
|
||||
|
||||
Result = ReadSector(Drive, 0, 0, 16);
|
||||
Result = Result >> 8;
|
||||
if(Result != 0) Error(Result);
|
||||
UsedSectors = SectorBuffer[3] * 256 + SectorBuffer[4];
|
||||
StartTrack = SectorBuffer[5];
|
||||
|
||||
printf("Volume: %c%c%c Used Sectors: %4u\n\n", SectorBuffer[0], SectorBuffer[1], SectorBuffer[2], UsedSectors);
|
||||
puts("");
|
||||
|
||||
puts(" 1111111");
|
||||
puts("Track ( C H S) 1234567890123456");
|
||||
puts("");
|
||||
|
||||
for(Counter = StartTrack; Counter <= 80; Counter++)
|
||||
{
|
||||
printf(" %3d (%2d %s 1) ", Counter, (Counter - 1) / 2, (Counter - 1) % 2 ? "1" : "0");
|
||||
BitMask = 0x0001;
|
||||
SectorsPerTrack = (unsigned short *) &SectorBuffer[6 + 2 * (Counter - StartTrack)];
|
||||
|
||||
for(BitCounter = 0; BitCounter < 16; BitCounter++)
|
||||
{
|
||||
if(*SectorsPerTrack & BitMask) printf("X");
|
||||
else printf("-");
|
||||
BitMask = BitMask << 1;
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
puts("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Init(void)
|
||||
{
|
||||
memset(SectorBuffer, 0, sizeof(SectorBuffer));
|
||||
Drive = 0;
|
||||
Cylinder = 0;
|
||||
Head = 0;
|
||||
Sector = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void Usage(void)
|
||||
{
|
||||
puts("usage: mzfdtool dir [DRIVE:]");
|
||||
puts(" map [DRIVE:]");
|
||||
puts(" copy [DRIVE:] FILENAME");
|
||||
puts(" DRIVE: C H S");
|
||||
puts("");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int Result;
|
||||
|
||||
|
||||
printf("\nMZFDTool V %s (c) 2002 by BKK\n\n", VERSION);
|
||||
|
||||
if(argc == 1) Usage();
|
||||
|
||||
Init();
|
||||
|
||||
SetInt1E(0);
|
||||
|
||||
ResetFloppy(Drive);
|
||||
|
||||
if(strcmp(argv[1], "dir") == 0)
|
||||
{
|
||||
if(argc == 3)
|
||||
if(toupper(argv[2][0]) == 'B') Drive = 1;
|
||||
ShowDirectory();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strcmp(argv[1], "copy") == 0)
|
||||
{
|
||||
if(argc == 4)
|
||||
{
|
||||
if(toupper(argv[2][0]) == 'B') Drive = 1;
|
||||
Copy(argv[3]);
|
||||
}
|
||||
else Copy(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strcmp(argv[1], "map") == 0)
|
||||
{
|
||||
if(argc == 3)
|
||||
if(toupper(argv[2][0]) == 'B') Drive = 1;
|
||||
ShowMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argc < 3) exit(1);
|
||||
|
||||
if(toupper(argv[1][0]) == 'B') Drive = 1;
|
||||
Cylinder = atoi(argv[2]);
|
||||
Head = atoi(argv[3]);
|
||||
Sector = atoi(argv[4]);
|
||||
|
||||
printf("Drive: %c CHS: %u %u %u\n", Drive ? 'B' : 'A', Cylinder, Head, Sector);
|
||||
|
||||
// Set_Floppy_Medis_Type();
|
||||
|
||||
Result = ReadSector(Drive, Cylinder, Head, Sector);
|
||||
Result = Result >> 8;
|
||||
|
||||
if(Result == 0) ShowSectorBuffer();
|
||||
else Error(Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResetInt1E();
|
||||
ResetFloppy(Drive);
|
||||
|
||||
return(0);
|
||||
}
|
||||
19
projects/tzpuPico/tools/MZFD/Makefile
vendored
Normal file
19
projects/tzpuPico/tools/MZFD/Makefile
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# MZFDTool - Sharp MZ-700 Floppy Disk image tool
|
||||
# (c) 2002 BKK, 2026 Philip Smart
|
||||
#
|
||||
# Usage:
|
||||
# make Build MZFDTool
|
||||
# make clean Remove build artifacts
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wno-unused-result -O2
|
||||
TARGET = MZFDTool
|
||||
SRC = MZFDTool.c
|
||||
|
||||
$(TARGET): $(SRC)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
|
||||
.PHONY: clean
|
||||
Reference in New Issue
Block a user