Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b004979d5 |
@@ -102,7 +102,7 @@ HWSEL2: LD A,(BNKCTRLRST)
|
|||||||
LD A,BNKDEFMROM_MZ700 ; Setup default MROM for an MZ700, this is a 4K Window into the UROM at F000.
|
LD A,BNKDEFMROM_MZ700 ; Setup default MROM for an MZ700, this is a 4K Window into the UROM at F000.
|
||||||
HWSEL21: OUT (REG_FXXX),A
|
HWSEL21: OUT (REG_FXXX),A
|
||||||
LD A,BNKDEFUROM ; Setup default UROM, this is a 2K Window into the UROM at E800 and contains the RFS.
|
LD A,BNKDEFUROM ; Setup default UROM, this is a 2K Window into the UROM at E800 and contains the RFS.
|
||||||
OUT (REG_EXXX),A
|
OUT (REG_EXXX),A
|
||||||
NOP ; Nops to allocate space to match RomDisk block.
|
NOP ; Nops to allocate space to match RomDisk block.
|
||||||
NOP
|
NOP
|
||||||
NOP
|
NOP
|
||||||
@@ -112,7 +112,6 @@ HWSEL21: OUT (REG_FXXX),A
|
|||||||
NOP
|
NOP
|
||||||
NOP
|
NOP
|
||||||
NOP
|
NOP
|
||||||
NOP
|
|
||||||
ENDIF
|
ENDIF
|
||||||
ENDM
|
ENDM
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,6 @@ MMIO7 EQU 0E7H ; MZ-70
|
|||||||
;
|
;
|
||||||
REG_EXXX EQU 060H ; A write copies D6:0 into the EXXX page address register to set a uniform 4K block in the region E300:EFFF window.
|
REG_EXXX EQU 060H ; A write copies D6:0 into the EXXX page address register to set a uniform 4K block in the region E300:EFFF window.
|
||||||
REG_FXXX EQU 061H ; A write copies D6:0 into the FXXX page address register to set a uniform 4k block in the region F000:FFFF.
|
REG_FXXX EQU 061H ; A write copies D6:0 into the FXXX page address register to set a uniform 4k block in the region F000:FFFF.
|
||||||
REG_MEMMODE EQU 062H ; A write with D0 = low enables FlashROM, D0 = high enables RAM.
|
|
||||||
SFD700_MODE EQU 063H ; FDC Interface card configured target mode.
|
SFD700_MODE EQU 063H ; FDC Interface card configured target mode.
|
||||||
FDC_CMD EQU 0D8H ; WD1773 Command Register.
|
FDC_CMD EQU 0D8H ; WD1773 Command Register.
|
||||||
FDC_STATUS EQU 0D8H ; WD1773 Status Register.
|
FDC_STATUS EQU 0D8H ; WD1773 Status Register.
|
||||||
|
|||||||
31
asm/rfs.asm
31
asm/rfs.asm
@@ -93,9 +93,15 @@ CMDTABLE2: IF BUILD_SFD700 = 1
|
|||||||
DB 000H | 018H | 001H
|
DB 000H | 018H | 001H
|
||||||
DB 'D' ; Dump Memory.
|
DB 'D' ; Dump Memory.
|
||||||
DW DUMPX
|
DW DUMPX
|
||||||
|
DB 000H | 018H | 002H
|
||||||
|
DB "FC" ; Save memory to Floppy.
|
||||||
|
DW SAVEFDCARD
|
||||||
DB 000H | 008H | 002H
|
DB 000H | 008H | 002H
|
||||||
DB "FL" ; 'FL' Floppy disk boot (built-in WD1773 FDC).
|
DB "FL" ; 'FL' Floppy disk boot (built-in WD1773 FDC).
|
||||||
DW FLOPPY
|
DW FLOPPY
|
||||||
|
DB 000H | 018H | 004H
|
||||||
|
DB "FD2T" ; Copy Floppy to Tape.
|
||||||
|
DW FD2TAPE
|
||||||
DB 000H | 008H | 002H
|
DB 000H | 008H | 002H
|
||||||
DB "FD" ; 'FD' Floppy disk directory listing.
|
DB "FD" ; 'FD' Floppy disk directory listing.
|
||||||
DW FDDIR
|
DW FDDIR
|
||||||
@@ -144,6 +150,9 @@ CMDTABLE2: IF BUILD_SFD700 = 1
|
|||||||
DB 000H | 020H | 001H
|
DB 000H | 020H | 001H
|
||||||
DB 'S' ; Save to CMT
|
DB 'S' ; Save to CMT
|
||||||
DW SAVEX
|
DW SAVEX
|
||||||
|
DB 000H | 018H | 004H
|
||||||
|
DB "T2FD" ; Copy Tape to Floppy.
|
||||||
|
DW TAPE2FD
|
||||||
DB 000H | 000H | 004H
|
DB 000H | 000H | 004H
|
||||||
DB "TEST" ; A test function used in debugging.
|
DB "TEST" ; A test function used in debugging.
|
||||||
DW LOCALTEST
|
DW LOCALTEST
|
||||||
@@ -571,15 +580,19 @@ CMDTABLE: IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
|||||||
DB 000H | 010H | 002H
|
DB 000H | 010H | 002H
|
||||||
DB "EC" ; Erase file.
|
DB "EC" ; Erase file.
|
||||||
DW ERASESD
|
DW ERASESD
|
||||||
|
IF BUILD_MZ700 = 1
|
||||||
DB 000H | 008H | 002H
|
DB 000H | 008H | 002H
|
||||||
DB "FL" ; 'FL' RFS Floppy load/boot.
|
DB "FL" ; 'FL' Floppy boot (built-in MZ-700 WD1773).
|
||||||
DW FLOPPY
|
DW FLOPPY
|
||||||
DB 000H | 008H | 002H
|
DB 000H | 008H | 002H
|
||||||
DB "FD" ; 'FD' Floppy directory.
|
DB "FD" ; 'FD' Floppy directory.
|
||||||
DW FDDIR
|
DW FDDIR
|
||||||
DB 000H | 008H | 001H
|
ENDIF
|
||||||
DB 0AAH ; 'f' Original Floppy boot code.
|
IF BUILD_MZ80A = 1
|
||||||
|
DB 000H | 008H | 002H
|
||||||
|
DB "FL" ; 'FL' Floppy boot (external FI ROM at F000H).
|
||||||
DW FDCK
|
DW FDCK
|
||||||
|
ENDIF
|
||||||
DB 000H | 058H | 001H
|
DB 000H | 058H | 001H
|
||||||
DB 'H' ; Help screen (bank 11).
|
DB 'H' ; Help screen (bank 11).
|
||||||
DW HELP
|
DW HELP
|
||||||
@@ -1316,9 +1329,11 @@ LOADBASIC: LD DE,BASICFILENM
|
|||||||
|
|
||||||
ENDIF ; BUILD_SFD700
|
ENDIF ; BUILD_SFD700
|
||||||
|
|
||||||
|
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
||||||
LOADPROG: LD HL,LOADSDCARD
|
LOADPROG: LD HL,LOADSDCARD
|
||||||
CALL BKSW0to2
|
CALL BKSW0to2
|
||||||
RET
|
RET
|
||||||
|
ENDIF
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; END OF RFS COMMAND FUNCTIONS.
|
; END OF RFS COMMAND FUNCTIONS.
|
||||||
@@ -1575,10 +1590,14 @@ DEFAULTFNE: EQU $
|
|||||||
INCLUDE "rfs_utilities.asm"
|
INCLUDE "rfs_utilities.asm"
|
||||||
;
|
;
|
||||||
; Ensure we fill the entire 2K by padding with FF's.
|
; Ensure we fill the entire 2K by padding with FF's.
|
||||||
|
; RomDisk/picoZ80: EFF8-EFFF are coded latch control registers.
|
||||||
|
; SFD700: no control registers, bank switching via I/O ports.
|
||||||
;
|
;
|
||||||
ALIGN 0EFF8h
|
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
||||||
ORG 0EFF8h
|
ALIGN 0EFF8h
|
||||||
DB 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0AAh
|
ORG 0EFF8h
|
||||||
|
DB 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0AAh
|
||||||
|
ENDIF
|
||||||
|
|
||||||
IF BUILD_SFD700 = 1
|
IF BUILD_SFD700 = 1
|
||||||
ALIGN 0F000H
|
ALIGN 0F000H
|
||||||
|
|||||||
@@ -145,6 +145,14 @@ TRK0FD3 EQU 01004H
|
|||||||
TRK0FD4 EQU 01005H
|
TRK0FD4 EQU 01005H
|
||||||
RETRIES EQU 01006H
|
RETRIES EQU 01006H
|
||||||
BPARA EQU 01008H
|
BPARA EQU 01008H
|
||||||
|
; SAVEFDX work variables (after BPARA's 11 bytes at 1008H-1012H).
|
||||||
|
FREEDSEC EQU 01014H ; Logical sector of free dir entry.
|
||||||
|
FREEDDIX EQU 01016H ; Index (0-7) of free entry in sector.
|
||||||
|
NXTDATASEC EQU 01017H ; Next free data sector (2 bytes LE).
|
||||||
|
SAVEDRVNO EQU 01019H ; Saved drive number for save operations.
|
||||||
|
; Temporary variables for TMPSTACKP save/restore (MUST be in RAM, not ROM).
|
||||||
|
FD7RS_TSP EQU 0101AH ; FD7READSAFE saved TMPSTACKP (2 bytes).
|
||||||
|
FD7ERR_TSP EQU 0101CH ; FD7ERR saved TMPSTACKP (2 bytes).
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; START OF FLOPPY DISK CONTROLLER FUNCTIONALITY
|
; START OF FLOPPY DISK CONTROLLER FUNCTIONALITY
|
||||||
@@ -160,7 +168,12 @@ FDCKROM: LD A,(0F000h)
|
|||||||
RET
|
RET
|
||||||
|
|
||||||
FLOPPY: IF BUILD_ROMDISK+BUILD_PICOZ80+BUILD_SFD700 = 1
|
FLOPPY: IF BUILD_ROMDISK+BUILD_PICOZ80+BUILD_SFD700 = 1
|
||||||
IF BUILD_MZ80A = 1
|
;
|
||||||
|
; NOTE: MZ-80A FDC code removed from bank 1.
|
||||||
|
; - SFD700+MZ80A: handled by bank 8 (FD80A_BOOT) with HW acceleration.
|
||||||
|
; - ROMDISK/picoZ80+MZ80A: uses physical MZ-80A FI ROM at F000H via FDCK.
|
||||||
|
;
|
||||||
|
IF 0 = 1 ; MZ-80A section removed.
|
||||||
PUSH DE ; Preserve pointer to input buffer.
|
PUSH DE ; Preserve pointer to input buffer.
|
||||||
LD DE,BPARA ; Copy disk parameter block into RAM work area. (From)
|
LD DE,BPARA ; Copy disk parameter block into RAM work area. (From)
|
||||||
LD HL,PRMBLK ; (To)
|
LD HL,PRMBLK ; (To)
|
||||||
@@ -545,8 +558,24 @@ L0300: IN A,(0D8H) ; State
|
|||||||
; RETRIES (1006H): Retry counter
|
; RETRIES (1006H): Retry counter
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
|
||||||
; Method to boot from MZ-700 floppy disk.
|
; Boot entry. MZ-80A mode dispatch temporarily disabled for testing.
|
||||||
;
|
; Initialize timer (as MZ-1E05 does) and reset FDC.
|
||||||
|
PUSH DE ; Save command line pointer.
|
||||||
|
XOR A
|
||||||
|
LD DE,0
|
||||||
|
CALL ?TMST ; Timer init.
|
||||||
|
POP DE ; Restore command line pointer.
|
||||||
|
XOR A
|
||||||
|
OUT (FDC_DRIVE),A ; Deselect all drives, motor off.
|
||||||
|
LD A,0D8H ; Force interrupt.
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
LD B,0 ; ~1.7ms delay for FDC to settle.
|
||||||
|
FLDLY1: DJNZ FLDLY1
|
||||||
|
XOR A
|
||||||
|
LD (MOTON),A
|
||||||
|
LD (TRK0FD1),A
|
||||||
|
LD (FDCCMD),A
|
||||||
PUSH DE ; Preserve pointer to input buffer.
|
PUSH DE ; Preserve pointer to input buffer.
|
||||||
LD DE,BPARA ; Copy disk parameter block into RAM work area.
|
LD DE,BPARA ; Copy disk parameter block into RAM work area.
|
||||||
LD HL,PRMBLK
|
LD HL,PRMBLK
|
||||||
@@ -556,7 +585,6 @@ L0300: IN A,(0D8H) ; State
|
|||||||
LD A,(DE) ; Check if drive number given on command line.
|
LD A,(DE) ; Check if drive number given on command line.
|
||||||
CP 00DH
|
CP 00DH
|
||||||
JR NZ,FD7BOOT
|
JR NZ,FD7BOOT
|
||||||
CALL FD7INIT ; Initialise disk and flags.
|
|
||||||
FD7PRMPT: LDDE MSGBOOTDRV
|
FD7PRMPT: LDDE MSGBOOTDRV
|
||||||
LD HL,PRINTMSG
|
LD HL,PRINTMSG
|
||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
@@ -602,6 +630,7 @@ FD7CHK: LD C,(HL)
|
|||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
;
|
;
|
||||||
; Extract load parameters from boot sector.
|
; Extract load parameters from boot sector.
|
||||||
|
LD IX,BPARA ; Restore IX (PRINTMSG may corrupt it).
|
||||||
LD HL,(0CF16H) ; Load/target address.
|
LD HL,(0CF16H) ; Load/target address.
|
||||||
LD A,H
|
LD A,H
|
||||||
OR L
|
OR L
|
||||||
@@ -649,12 +678,18 @@ FD7NOTMST: CALL FD7INIT
|
|||||||
LDDE MSGDSKNOTMST
|
LDDE MSGDSKNOTMST
|
||||||
JR FD7ERR
|
JR FD7ERR
|
||||||
FD7LOADERR: LDDE MSGLOADERR
|
FD7LOADERR: LDDE MSGLOADERR
|
||||||
FD7ERR: LD HL,PRINTMSG
|
FD7ERR: LD HL,(TMPSTACKP) ; Save TMPSTACKP before BKSW overwrites it.
|
||||||
|
LD (FD7ERR_TSP),HL
|
||||||
|
LD HL,PRINTMSG
|
||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
LD DE,ERRTONE
|
LD DE,ERRTONE
|
||||||
CALL MELDY
|
CALL MELDY
|
||||||
LD SP,(TMPSTACKP) ; Recover stack pointer.
|
LD HL,(FD7ERR_TSP) ; Restore saved TMPSTACKP.
|
||||||
|
LD SP,HL ; Recover stack pointer.
|
||||||
RET
|
RET
|
||||||
|
; FD7ERR_TSP now in RAM (EQU 0101CH).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; MZ-700 FDC LOW-LEVEL ROUTINES
|
; MZ-700 FDC LOW-LEVEL ROUTINES
|
||||||
@@ -687,6 +722,7 @@ FD7INIT: PUSH AF
|
|||||||
; Motor on: enable motor and wait for spinup.
|
; Motor on: enable motor and wait for spinup.
|
||||||
FD7MOTON: LD A,080H
|
FD7MOTON: LD A,080H
|
||||||
OUT (FDC_DRIVE),A
|
OUT (FDC_DRIVE),A
|
||||||
|
CALL FD7DLY80U ; Settle delay after motor on.
|
||||||
LD B,16
|
LD B,16
|
||||||
FD7MTD1: CALL FD7DLY60M
|
FD7MTD1: CALL FD7DLY60M
|
||||||
DJNZ FD7MTD1
|
DJNZ FD7MTD1
|
||||||
@@ -701,6 +737,7 @@ FD7READY: LD A,(MOTON)
|
|||||||
LD A,(IX+0) ; Drive number.
|
LD A,(IX+0) ; Drive number.
|
||||||
OR 084H
|
OR 084H
|
||||||
OUT (FDC_DRIVE),A ; Drive select + motor on.
|
OUT (FDC_DRIVE),A ; Drive select + motor on.
|
||||||
|
CALL FD7DLY80U ; Settle delay after drive select.
|
||||||
XOR A
|
XOR A
|
||||||
LD (FDCCMD),A
|
LD (FDCCMD),A
|
||||||
CALL FD7DLY60M
|
CALL FD7DLY60M
|
||||||
@@ -798,6 +835,33 @@ FD7BSF3: DEC E
|
|||||||
POP DE
|
POP DE
|
||||||
JP FD7DSKERR
|
JP FD7DSKERR
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; FD7READSAFE - Safe read wrapper. Catches FD7ERR longjmp and returns
|
||||||
|
; with carry set instead of corrupting the caller's stack.
|
||||||
|
; IX = parameter block (BPARA). Returns: carry clear=OK, carry set=error.
|
||||||
|
; Mechanism: pushes a recovery address on the stack, then sets TMPSTACKP
|
||||||
|
; to SP. FD7ERR's "LD SP,(TMPSTACKP) / RET" pops the recovery address,
|
||||||
|
; landing at FD7RS_REC instead of unwinding the entire call chain.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
FD7READSAFE: LD HL,(TMPSTACKP)
|
||||||
|
LD (FD7RS_TSP),HL ; Save original TMPSTACKP.
|
||||||
|
LD HL,FD7RS_REC ; Recovery address.
|
||||||
|
PUSH HL ; Push onto stack.
|
||||||
|
LD (TMPSTACKP),SP ; FD7ERR longjmp lands here → pops FD7RS_REC.
|
||||||
|
CALL FD7READ ; Normal return if success.
|
||||||
|
POP HL ; Remove recovery address.
|
||||||
|
LD HL,(FD7RS_TSP)
|
||||||
|
LD (TMPSTACKP),HL ; Restore TMPSTACKP.
|
||||||
|
OR A ; Clear carry = success.
|
||||||
|
RET
|
||||||
|
; FD7ERR longjmp caught: SP restored, RET popped FD7RS_REC → here.
|
||||||
|
; Error message and tone already displayed by FD7ERR.
|
||||||
|
FD7RS_REC: LD HL,(FD7RS_TSP)
|
||||||
|
LD (TMPSTACKP),HL ; Restore TMPSTACKP.
|
||||||
|
SCF ; Set carry = error.
|
||||||
|
RET
|
||||||
|
; FD7RS_TSP now in RAM (EQU 0101AH).
|
||||||
|
|
||||||
; Sequential read from disk.
|
; Sequential read from disk.
|
||||||
; IX = parameter block (BPARA).
|
; IX = parameter block (BPARA).
|
||||||
FD7READ: CALL FD7CNVRT ; Convert logical sector to track/sector.
|
FD7READ: CALL FD7CNVRT ; Convert logical sector to track/sector.
|
||||||
@@ -952,7 +1016,22 @@ FD7DLYT: DEC DE
|
|||||||
; Input: DE = pointer to optional drive number on command line.
|
; Input: DE = pointer to optional drive number on command line.
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
|
||||||
FDDIR: ; Parse drive number (default = drive 1 = index 0).
|
FDDIR: ; Initialize timer and reset FDC.
|
||||||
|
XOR A
|
||||||
|
LD DE,0
|
||||||
|
CALL ?TMST ; Timer init.
|
||||||
|
XOR A
|
||||||
|
OUT (FDC_DRIVE),A ; Deselect all drives, motor off.
|
||||||
|
LD A,0D8H ; Force interrupt.
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
LD B,0 ; ~1.7ms delay.
|
||||||
|
FDDLY1: DJNZ FDDLY1
|
||||||
|
XOR A
|
||||||
|
LD (MOTON),A
|
||||||
|
LD (TRK0FD1),A
|
||||||
|
LD (FDCCMD),A
|
||||||
|
; Parse drive number (default = drive 1 = index 0).
|
||||||
LD A,(DE)
|
LD A,(DE)
|
||||||
CP 00DH
|
CP 00DH
|
||||||
JR Z,FDDIR_DEF
|
JR Z,FDDIR_DEF
|
||||||
@@ -990,6 +1069,7 @@ FDDIR_GO: LD (BPARA),A ; Store
|
|||||||
; Read boot sector (sector 0 = IPL) and verify signature.
|
; Read boot sector (sector 0 = IPL) and verify signature.
|
||||||
LD IX,BPARA
|
LD IX,BPARA
|
||||||
CALL FD7READ
|
CALL FD7READ
|
||||||
|
JP C,FDDIR_END ; Read error.
|
||||||
LD HL,0CF00H
|
LD HL,0CF00H
|
||||||
LD DE,DSKID
|
LD DE,DSKID
|
||||||
LD B,7
|
LD B,7
|
||||||
@@ -1003,11 +1083,11 @@ FDDIR_IPL: LD A,(DE)
|
|||||||
LD DE,0CF07H
|
LD DE,0CF07H
|
||||||
LD HL,PRTFN
|
LD HL,PRTFN
|
||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
LD HL,(0CF16H)
|
LD HL,(0CF18H) ; Exec addr.
|
||||||
PUSH HL
|
PUSH HL ; Stack bottom: exec.
|
||||||
LD HL,(0CF18H)
|
LD HL,(0CF16H) ; Load addr.
|
||||||
PUSH HL
|
PUSH HL ; Stack top: load.
|
||||||
LD BC,(0CF14H)
|
LD BC,(0CF14H) ; Size.
|
||||||
LDDE MSGFDINFO
|
LDDE MSGFDINFO
|
||||||
LD HL,PRINTMSG
|
LD HL,PRINTMSG
|
||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
@@ -1022,17 +1102,19 @@ FDDIR_IPL: LD A,(DE)
|
|||||||
; Get number of directory sectors from IPL offset +1EH.
|
; Get number of directory sectors from IPL offset +1EH.
|
||||||
LD A,(0CF1EH) ; Start data sector (low byte).
|
LD A,(0CF1EH) ; Start data sector (low byte).
|
||||||
SUB 16 ; Directory sectors = startDataSec - 16.
|
SUB 16 ; Directory sectors = startDataSec - 16.
|
||||||
JR Z,FDDIR_END ; No directory sectors.
|
JP Z,FDDIR_END ; No directory sectors.
|
||||||
JR C,FDDIR_END
|
JP C,FDDIR_END
|
||||||
LD C,A ; C = number of directory sectors.
|
LD C,A ; C = number of directory sectors.
|
||||||
LD A,16 ; First directory sector.
|
LD A,16 ; First directory sector.
|
||||||
;
|
;
|
||||||
FDDIR_SEC: ; Read next directory sector.
|
FDDIR_SEC: ; Read next directory sector.
|
||||||
PUSH AF ; Save current sector number.
|
PUSH AF ; Save current sector number.
|
||||||
PUSH BC ; Save remaining sector count.
|
PUSH BC ; Save remaining sector count.
|
||||||
|
LD IX,BPARA ; Restore IX (may be corrupted by PRINTMSG).
|
||||||
LD (IX+1),A
|
LD (IX+1),A
|
||||||
LD (IX+2),0
|
LD (IX+2),0
|
||||||
CALL FD7READ
|
CALL FD7READ
|
||||||
|
JR C,FDDIR_RERR ; Read error → clean stack and exit.
|
||||||
;
|
;
|
||||||
; First sector (16): skip entry 0 (FAT header), scan entries 1-7.
|
; First sector (16): skip entry 0 (FAT header), scan entries 1-7.
|
||||||
; Subsequent sectors: scan all 8 entries.
|
; Subsequent sectors: scan all 8 entries.
|
||||||
@@ -1048,12 +1130,25 @@ FDDIR_SEC: ; Read next directory sector.
|
|||||||
FDDIR_AL8: LD HL,0CF00H ; Start from entry 0.
|
FDDIR_AL8: LD HL,0CF00H ; Start from entry 0.
|
||||||
LD B,8 ; 8 entries per sector.
|
LD B,8 ; 8 entries per sector.
|
||||||
;
|
;
|
||||||
FDDIR_ENT: ; Check type byte at (HL). 00 = empty/deleted, FF = unused → skip.
|
FDDIR_ENT: ; Check type byte at (HL). Only 01-7F are valid file entries.
|
||||||
LD A,(HL)
|
LD A,(HL)
|
||||||
OR A
|
OR A
|
||||||
JR Z,FDDIR_NXE
|
JR Z,FDDIR_NXE ; 00 = deleted/empty.
|
||||||
|
CP 080H
|
||||||
|
JR NC,FDDIR_NXE ; >= 80H = header/system/uninit.
|
||||||
|
; Validate: check SectorAddress is not 0000 or FFFF (uninit garbage).
|
||||||
|
PUSH HL
|
||||||
|
LD DE,01EH
|
||||||
|
ADD HL,DE
|
||||||
|
LD A,(HL)
|
||||||
|
INC HL
|
||||||
|
LD D,(HL) ; D=high, A=low of SectorAddress.
|
||||||
|
POP HL
|
||||||
|
OR D
|
||||||
|
JR Z,FDDIR_NXE ; SectorAddress=0000 → skip.
|
||||||
|
AND D
|
||||||
CP 0FFH
|
CP 0FFH
|
||||||
JR Z,FDDIR_NXE
|
JR Z,FDDIR_NXE ; SectorAddress=FFFF → skip.
|
||||||
;
|
;
|
||||||
; Valid entry: print filename and load/exec/size.
|
; Valid entry: print filename and load/exec/size.
|
||||||
LD (TMPADR),HL ; Save entry base.
|
LD (TMPADR),HL ; Save entry base.
|
||||||
@@ -1063,23 +1158,27 @@ FDDIR_ENT: ; Check type byte at (HL). 00 = empty/deleted, FF = unused → skip
|
|||||||
EX DE,HL
|
EX DE,HL
|
||||||
LD HL,PRTFN
|
LD HL,PRTFN
|
||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
; Read size from base+12H, load from base+14H, exec from base+16H.
|
; Read size from +14H, load from +16H, exec from +18H.
|
||||||
|
; (Dir entry: +12=LockFlag, +13=DummyFlag, +14=FileSize,
|
||||||
|
; +16=LoadAddress, +18=ExecAddress, +1E=SectorAddress.)
|
||||||
LD HL,(TMPADR)
|
LD HL,(TMPADR)
|
||||||
LD DE,012H
|
LD DE,014H
|
||||||
ADD HL,DE
|
ADD HL,DE
|
||||||
LD C,(HL)
|
LD C,(HL)
|
||||||
INC HL
|
INC HL
|
||||||
LD B,(HL) ; BC = size.
|
LD B,(HL) ; BC = file size.
|
||||||
INC HL ; +14H = load addr.
|
INC HL ; +16H = load addr.
|
||||||
LD E,(HL)
|
LD E,(HL)
|
||||||
INC HL
|
INC HL
|
||||||
LD D,(HL)
|
LD D,(HL)
|
||||||
PUSH DE ; Stack: load addr.
|
PUSH DE ; Save load addr.
|
||||||
INC HL ; +16H = exec addr.
|
INC HL ; +18H = exec addr.
|
||||||
LD E,(HL)
|
LD E,(HL)
|
||||||
INC HL
|
INC HL
|
||||||
LD D,(HL)
|
LD D,(HL) ; DE = exec addr.
|
||||||
PUSH DE ; Stack: exec addr.
|
POP HL ; HL = load addr.
|
||||||
|
PUSH DE ; Stack bottom: exec.
|
||||||
|
PUSH HL ; Stack top: load (MSGFDINFO pops load first).
|
||||||
LDDE MSGFDINFO
|
LDDE MSGFDINFO
|
||||||
LD HL,PRINTMSG
|
LD HL,PRINTMSG
|
||||||
CALL BKSW1to6
|
CALL BKSW1to6
|
||||||
@@ -1098,10 +1197,474 @@ FDDIR_NXE: LD DE,32 ; Next 3
|
|||||||
INC A ; Next sector.
|
INC A ; Next sector.
|
||||||
DEC C
|
DEC C
|
||||||
JR NZ,FDDIR_SEC ; More directory sectors.
|
JR NZ,FDDIR_SEC ; More directory sectors.
|
||||||
|
JP FDDIR_END ; Done — skip error recovery POPs.
|
||||||
;
|
;
|
||||||
|
FDDIR_RERR: POP BC ; Clean stack from FDDIR_SEC PUSH.
|
||||||
|
POP AF
|
||||||
FDDIR_END: CALL FD7INIT
|
FDDIR_END: CALL FD7INIT
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; FD7WRITE - Sequential write to disk.
|
||||||
|
; Mirror of FD7READ but uses OUTI for data output.
|
||||||
|
; IX = parameter block (BPARA): drive, logical sector, size, source addr.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; Sequential write to disk.
|
||||||
|
; Returns: carry clear = success, carry set = error.
|
||||||
|
; Does NOT call FD7DSKERR — caller handles errors via carry flag.
|
||||||
|
FD7WRITE: CALL FD7CNVRT ; Convert logical sector to track/sector.
|
||||||
|
CALL FD7PRST1 ; Setup params, HL = source address.
|
||||||
|
FD7WE8: CALL FD7SIDST ; Set side/head.
|
||||||
|
CALL FD7SEEK
|
||||||
|
JR NZ,FD7WERR ; Seek failed.
|
||||||
|
CALL FD7PRST2 ; Set track & sector registers.
|
||||||
|
DI
|
||||||
|
LD A,0A4H ; Write sector (multiple records).
|
||||||
|
CALL FD7CMD2
|
||||||
|
FD7WE6: LD B,0 ; 256 bytes per sector.
|
||||||
|
FD7WE4: IN A,(FDC_CMD)
|
||||||
|
RRCA
|
||||||
|
JR C,FD7WE3 ; Busy dropped = done.
|
||||||
|
RRCA
|
||||||
|
JR C,FD7WE4 ; DRQ not set, keep waiting.
|
||||||
|
OUTI ; Write byte: OUT(C)=(HL), B--, HL++.
|
||||||
|
JR NZ,FD7WE4
|
||||||
|
;
|
||||||
|
INC (IX+8) ; Next sector.
|
||||||
|
LD A,(IX+8)
|
||||||
|
CP 17 ; Past last sector on track?
|
||||||
|
JR Z,FD7WESEC
|
||||||
|
DEC D ; Decrement sector count.
|
||||||
|
JR NZ,FD7WE6 ; More sectors to write.
|
||||||
|
JR FD7WEDONE
|
||||||
|
FD7WESEC: DEC D
|
||||||
|
FD7WEDONE: LD A,0D8H ; Force interrupt.
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
CALL FD7BSYON
|
||||||
|
FD7WE3: EI
|
||||||
|
IN A,(FDC_CMD)
|
||||||
|
CPL
|
||||||
|
AND 07CH ; Check error bits (WP, WF, RNF, CRC, lost data).
|
||||||
|
JR NZ,FD7WERR ; Write error.
|
||||||
|
CALL FD7ADJ ; Adjust sector/track.
|
||||||
|
JR Z,FD7WEND ; All sectors written.
|
||||||
|
LD A,(IX+7) ; Next track.
|
||||||
|
JR FD7WE8
|
||||||
|
FD7WEND: LD A,080H
|
||||||
|
OUT (FDC_DRIVE),A ; Keep motor on.
|
||||||
|
OR A ; Clear carry = success.
|
||||||
|
RET
|
||||||
|
FD7WERR: EI
|
||||||
|
SCF ; Set carry = error.
|
||||||
|
RET
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; LOADFDCP - Load file from floppy into memory, populating CMT header.
|
||||||
|
; Reads boot sector, extracts file info, reads program data to 0x1200.
|
||||||
|
; Sets RESULT=0 on success, non-zero on error.
|
||||||
|
; Called from bank 3 for FD2T command.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; LOADFDCP - Load FIRST file from floppy directory into memory at 0x1200.
|
||||||
|
; Scans directory for first valid entry, populates CMT header, loads data.
|
||||||
|
; Output: RESULT = 0 success, 0xFE FD7ERR handled, 0xFF caller shows error.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
LOADFDCP: LD A,0FEH
|
||||||
|
LD (RESULT),A ; 0xFE = FD7ERR will handle errors.
|
||||||
|
; Full FDC init: timer, deselect, force interrupt, clear flags.
|
||||||
|
PUSH DE
|
||||||
|
XOR A
|
||||||
|
LD DE,0
|
||||||
|
CALL ?TMST
|
||||||
|
POP DE
|
||||||
|
XOR A
|
||||||
|
OUT (FDC_DRIVE),A
|
||||||
|
LD A,0D8H
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
LD B,0
|
||||||
|
LFDCP_DLY: DJNZ LFDCP_DLY
|
||||||
|
XOR A
|
||||||
|
LD (MOTON),A
|
||||||
|
LD (TRK0FD1),A
|
||||||
|
; Init BPARA.
|
||||||
|
LD HL,PRMBLK
|
||||||
|
LD DE,BPARA
|
||||||
|
LD BC,11
|
||||||
|
LDIR
|
||||||
|
LD IX,BPARA
|
||||||
|
;
|
||||||
|
; Scan directory for first valid file entry.
|
||||||
|
LD A,16 ; First directory sector.
|
||||||
|
LD C,16 ; 16 sectors.
|
||||||
|
LFDCP_DSC: PUSH AF
|
||||||
|
PUSH BC
|
||||||
|
LD (IX+1),A
|
||||||
|
LD (IX+2),0
|
||||||
|
LD HL,0CF00H
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
LD (IX+3),0
|
||||||
|
LD (IX+4),1
|
||||||
|
CALL FD7READ ; (FD7ERR longjumps on error.)
|
||||||
|
POP BC
|
||||||
|
POP AF
|
||||||
|
;
|
||||||
|
LD HL,0CF00H
|
||||||
|
LD B,8
|
||||||
|
LFDCP_ENT: LD A,(HL)
|
||||||
|
OR A
|
||||||
|
JR Z,LFDCP_NXE ; 00 = empty.
|
||||||
|
CP 080H
|
||||||
|
JR NC,LFDCP_NXE ; >=80 = header/system.
|
||||||
|
; Valid entry — check if filename matches NAME.
|
||||||
|
PUSH HL
|
||||||
|
PUSH BC
|
||||||
|
INC HL ; +01 = filename in entry.
|
||||||
|
LD DE,NAME
|
||||||
|
LD B,17 ; Compare 17 bytes.
|
||||||
|
LFDCP_CMP: LD A,(DE)
|
||||||
|
CP (HL)
|
||||||
|
JR NZ,LFDCP_NOM ; Mismatch.
|
||||||
|
CP 00DH ; Both end with CR?
|
||||||
|
JR Z,LFDCP_MAT ; Match!
|
||||||
|
INC HL
|
||||||
|
INC DE
|
||||||
|
DJNZ LFDCP_CMP
|
||||||
|
LFDCP_MAT: POP BC
|
||||||
|
POP HL
|
||||||
|
JP LFDCP_GOT ; Found matching file.
|
||||||
|
LFDCP_NOM: POP BC
|
||||||
|
POP HL
|
||||||
|
LFDCP_NXE: LD DE,32
|
||||||
|
ADD HL,DE
|
||||||
|
DJNZ LFDCP_ENT
|
||||||
|
; No entry in this sector, try next.
|
||||||
|
POP AF ; Wait, stack issue...
|
||||||
|
; Actually the POP AF/BC was already done above. Just continue.
|
||||||
|
INC A
|
||||||
|
DEC C
|
||||||
|
JP NZ,LFDCP_DSC
|
||||||
|
; No file found on disk.
|
||||||
|
JP LFDCP_ERR
|
||||||
|
;
|
||||||
|
LFDCP_GOT: ; HL = entry base of first valid file.
|
||||||
|
; Populate CMT header from directory entry.
|
||||||
|
LD A,(HL) ; +00 = FileType.
|
||||||
|
LD (ATRB),A
|
||||||
|
PUSH HL
|
||||||
|
INC HL ; +01 = Filename.
|
||||||
|
LD DE,NAME
|
||||||
|
LD BC,17
|
||||||
|
LDIR
|
||||||
|
POP HL
|
||||||
|
PUSH HL
|
||||||
|
LD DE,014H
|
||||||
|
ADD HL,DE ; +14 = FileSize.
|
||||||
|
LD E,(HL)
|
||||||
|
INC HL
|
||||||
|
LD D,(HL)
|
||||||
|
LD (SIZE),DE
|
||||||
|
INC HL ; +16 = LoadAddress.
|
||||||
|
LD E,(HL)
|
||||||
|
INC HL
|
||||||
|
LD D,(HL)
|
||||||
|
LD (DTADR),DE
|
||||||
|
INC HL ; +18 = ExecAddress.
|
||||||
|
LD E,(HL)
|
||||||
|
INC HL
|
||||||
|
LD D,(HL)
|
||||||
|
LD (EXADR),DE
|
||||||
|
POP HL
|
||||||
|
PUSH HL
|
||||||
|
LD DE,01EH
|
||||||
|
ADD HL,DE ; +1E = SectorAddress.
|
||||||
|
LD E,(HL)
|
||||||
|
INC HL
|
||||||
|
LD D,(HL)
|
||||||
|
POP HL
|
||||||
|
; DE = start sector, load data to 0x1200.
|
||||||
|
LD (IX+1),E
|
||||||
|
LD (IX+2),D
|
||||||
|
LD HL,(SIZE)
|
||||||
|
LD (IX+3),L
|
||||||
|
LD (IX+4),H
|
||||||
|
LD HL,01200H
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
LD (DTADR),HL ; Override load addr for copy.
|
||||||
|
CALL FD7READ
|
||||||
|
CALL FD7INIT
|
||||||
|
XOR A
|
||||||
|
LD (RESULT),A ; Success.
|
||||||
|
RET
|
||||||
|
LFDCP_ERR: CALL FD7INIT
|
||||||
|
LD A,0FFH
|
||||||
|
LD (RESULT),A
|
||||||
|
RET
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; SAVEFDX - Save memory to floppy disk with IPL boot header.
|
||||||
|
; Writes an IPL boot sector at sector 0 and program data from sector 1+.
|
||||||
|
; Uses CMT header fields: NAME, SIZE, DTADR, EXADR.
|
||||||
|
; Called from bank 3 for T2FD and FC commands.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; SAVEFDX - Save file to floppy disk directory.
|
||||||
|
; Scans directory for a free entry, calculates next free data sector,
|
||||||
|
; writes program data, then updates the directory entry.
|
||||||
|
; Input: NAME, SIZE, DTADR, EXADR, ATRB set by caller.
|
||||||
|
; Output: RESULT = 0 on success, 0xFF on error.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
SAVEFDX: LD A,0FFH
|
||||||
|
LD (RESULT),A ; Default = error.
|
||||||
|
; Full FDC init: timer, deselect, force interrupt, clear flags.
|
||||||
|
PUSH DE
|
||||||
|
XOR A
|
||||||
|
LD DE,0
|
||||||
|
CALL ?TMST ; Timer init (required for FDC).
|
||||||
|
POP DE
|
||||||
|
XOR A
|
||||||
|
OUT (FDC_DRIVE),A ; Deselect drives.
|
||||||
|
LD A,0D8H
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A ; Force interrupt.
|
||||||
|
LD B,0
|
||||||
|
SFDX_DLY: DJNZ SFDX_DLY ; Settle delay.
|
||||||
|
XOR A
|
||||||
|
LD (MOTON),A
|
||||||
|
LD (TRK0FD1),A
|
||||||
|
; Init BPARA from PRMBLK and set drive 0.
|
||||||
|
LD HL,PRMBLK
|
||||||
|
LD DE,BPARA
|
||||||
|
LD BC,11
|
||||||
|
LDIR
|
||||||
|
LD IX,BPARA
|
||||||
|
; Init scan variables.
|
||||||
|
LD A,0FFH
|
||||||
|
LD (FREEDSEC),A ; FF = no free entry found yet.
|
||||||
|
LD HL,32 ; First data sector after directory.
|
||||||
|
LD (NXTDATASEC),HL
|
||||||
|
;
|
||||||
|
; --- Scan directory: logical sectors 16-31 (Track 0, Head 1). ---
|
||||||
|
LD A,16 ; First directory sector.
|
||||||
|
LD C,16 ; 16 sectors to scan.
|
||||||
|
SFDX_DSEC: LD (SAVEDRVNO),A ; Save current sector for SFDX_FREE.
|
||||||
|
PUSH AF
|
||||||
|
PUSH BC
|
||||||
|
LD IX,BPARA
|
||||||
|
LD (IX+1),A ; Logical sector.
|
||||||
|
LD (IX+2),0
|
||||||
|
LD HL,0CF00H ; Buffer.
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
LD (IX+3),0
|
||||||
|
LD (IX+4),1 ; 1 sector = 256 bytes.
|
||||||
|
CALL FD7READ
|
||||||
|
POP BC
|
||||||
|
POP AF
|
||||||
|
JP C,SFDX_ERR ; Read error.
|
||||||
|
PUSH AF
|
||||||
|
PUSH BC
|
||||||
|
;
|
||||||
|
; Scan 8 entries in this sector.
|
||||||
|
LD HL,0CF00H
|
||||||
|
LD B,8
|
||||||
|
SFDX_DENT: PUSH HL
|
||||||
|
PUSH BC
|
||||||
|
LD A,(HL) ; FileType.
|
||||||
|
OR A
|
||||||
|
JR Z,SFDX_FREE ; 00 = deleted/free entry.
|
||||||
|
CP 0FFH
|
||||||
|
JR Z,SFDX_FREE ; FF = uninitialized/free entry.
|
||||||
|
CP 080H
|
||||||
|
JR NC,SFDX_NXTE ; >=80H = header/system, skip.
|
||||||
|
; Check SectorAddress — if 0000 or FFFF, treat as free (uninit garbage).
|
||||||
|
PUSH HL
|
||||||
|
LD DE,01EH
|
||||||
|
ADD HL,DE
|
||||||
|
LD E,(HL)
|
||||||
|
INC HL
|
||||||
|
LD D,(HL) ; DE = SectorAddress.
|
||||||
|
POP HL
|
||||||
|
LD A,E
|
||||||
|
OR D
|
||||||
|
JR Z,SFDX_FREE ; SectorAddress=0000 → free.
|
||||||
|
LD A,E
|
||||||
|
AND D
|
||||||
|
CP 0FFH
|
||||||
|
JR Z,SFDX_FREE ; SectorAddress=FFFF → free.
|
||||||
|
PUSH HL
|
||||||
|
LD BC,014H
|
||||||
|
ADD HL,BC
|
||||||
|
LD C,(HL)
|
||||||
|
INC HL
|
||||||
|
LD B,(HL) ; BC = FileSize.
|
||||||
|
POP HL
|
||||||
|
; Sectors used = (FileSize + 255) / 256 = (FileSize >> 8) + ((FileSize & FF) ? 1 : 0).
|
||||||
|
LD A,C
|
||||||
|
OR A
|
||||||
|
JR Z,SFDX_NRU
|
||||||
|
INC B ; Round up.
|
||||||
|
SFDX_NRU: LD C,B
|
||||||
|
LD B,0 ; BC = sectors used.
|
||||||
|
EX DE,HL ; HL = SectorAddress.
|
||||||
|
ADD HL,BC ; HL = end sector.
|
||||||
|
EX DE,HL ; DE = end sector.
|
||||||
|
; Update NXTDATASEC if this file ends later.
|
||||||
|
PUSH HL
|
||||||
|
LD HL,(NXTDATASEC)
|
||||||
|
OR A
|
||||||
|
SBC HL,DE ; HL = NXTDATASEC - endSec.
|
||||||
|
POP HL
|
||||||
|
JR NC,SFDX_NXTE ; NXTDATASEC >= endSec, no update.
|
||||||
|
LD (NXTDATASEC),DE ; Update with higher value.
|
||||||
|
JR SFDX_NXTE
|
||||||
|
;
|
||||||
|
SFDX_FREE: ; Found a free entry. Record if first one found.
|
||||||
|
LD A,(FREEDSEC)
|
||||||
|
CP 0FFH
|
||||||
|
JR NZ,SFDX_NXTE ; Already have one.
|
||||||
|
; Record: FREEDSEC = current logical sector, FREEDDIX = entry index.
|
||||||
|
; Entry index = 8 - B (since B counts down from 8).
|
||||||
|
POP BC ; B = entries remaining.
|
||||||
|
POP HL
|
||||||
|
PUSH HL
|
||||||
|
PUSH BC
|
||||||
|
LD A,8
|
||||||
|
SUB B
|
||||||
|
LD (FREEDDIX),A
|
||||||
|
LD A,(SAVEDRVNO) ; Sector number saved at loop start.
|
||||||
|
LD (FREEDSEC),A
|
||||||
|
;
|
||||||
|
SFDX_NXTE: POP BC
|
||||||
|
POP HL
|
||||||
|
LD DE,32 ; Next 32-byte entry.
|
||||||
|
ADD HL,DE
|
||||||
|
DEC B
|
||||||
|
JR NZ,SFDX_DENT
|
||||||
|
;
|
||||||
|
POP BC
|
||||||
|
POP AF
|
||||||
|
INC A ; Next directory sector.
|
||||||
|
DEC C
|
||||||
|
JP NZ,SFDX_DSEC
|
||||||
|
;
|
||||||
|
; --- Check we found a free entry. ---
|
||||||
|
LD A,(FREEDSEC)
|
||||||
|
CP 0FFH
|
||||||
|
RET Z ; No free entry → error.
|
||||||
|
;
|
||||||
|
; --- Write file data at NXTDATASEC. ---
|
||||||
|
LD IX,BPARA
|
||||||
|
LD HL,(NXTDATASEC)
|
||||||
|
LD (IX+1),L
|
||||||
|
LD (IX+2),H
|
||||||
|
LD HL,(SIZE)
|
||||||
|
LD (IX+3),L
|
||||||
|
LD (IX+4),H
|
||||||
|
LD HL,(DTADR)
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
CALL FD7WRITE
|
||||||
|
JP C,SFDX_ERR
|
||||||
|
;
|
||||||
|
; --- Re-read directory sector with free entry. ---
|
||||||
|
LD IX,BPARA
|
||||||
|
LD A,(FREEDSEC)
|
||||||
|
LD (IX+1),A
|
||||||
|
LD (IX+2),0
|
||||||
|
LD HL,0CF00H
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
LD (IX+3),0
|
||||||
|
LD (IX+4),1
|
||||||
|
CALL FD7READ
|
||||||
|
JP C,SFDX_ERR ; Read error.
|
||||||
|
;
|
||||||
|
; --- Fill directory entry. ---
|
||||||
|
LD A,(FREEDDIX)
|
||||||
|
LD HL,0CF00H
|
||||||
|
OR A
|
||||||
|
JR Z,SFDX_FILL ; Index 0 → HL already at CF00.
|
||||||
|
LD DE,32
|
||||||
|
SFDX_FMUL: ADD HL,DE
|
||||||
|
DEC A
|
||||||
|
JR NZ,SFDX_FMUL
|
||||||
|
SFDX_FILL: ; HL = entry base. Clear 32 bytes.
|
||||||
|
PUSH HL
|
||||||
|
LD D,H
|
||||||
|
LD E,L
|
||||||
|
INC DE
|
||||||
|
LD (HL),0
|
||||||
|
LD BC,31
|
||||||
|
LDIR
|
||||||
|
POP HL
|
||||||
|
; +00: FileType from ATRB (with CMT→FD type conversion).
|
||||||
|
LD A,(ATRB)
|
||||||
|
CP 005H ; CMT type 05 (RB) → FD type 02 (BTX).
|
||||||
|
JR NZ,SFDX_FT1
|
||||||
|
LD A,002H
|
||||||
|
SFDX_FT1: LD (HL),A
|
||||||
|
; +01: FileName from NAME (17 bytes).
|
||||||
|
PUSH HL
|
||||||
|
INC HL
|
||||||
|
EX DE,HL
|
||||||
|
LD HL,NAME
|
||||||
|
LD BC,17
|
||||||
|
LDIR
|
||||||
|
POP HL
|
||||||
|
; +14: FileSize from SIZE.
|
||||||
|
PUSH HL
|
||||||
|
LD DE,014H
|
||||||
|
ADD HL,DE
|
||||||
|
LD DE,(SIZE)
|
||||||
|
LD (HL),E
|
||||||
|
INC HL
|
||||||
|
LD (HL),D
|
||||||
|
; +16: LoadAddress from DTADR.
|
||||||
|
INC HL
|
||||||
|
LD DE,(DTADR)
|
||||||
|
LD (HL),E
|
||||||
|
INC HL
|
||||||
|
LD (HL),D
|
||||||
|
; +18: ExecAddress from EXADR.
|
||||||
|
INC HL
|
||||||
|
LD DE,(EXADR)
|
||||||
|
LD (HL),E
|
||||||
|
INC HL
|
||||||
|
LD (HL),D
|
||||||
|
POP HL
|
||||||
|
; +1E: SectorAddress = NXTDATASEC.
|
||||||
|
PUSH HL
|
||||||
|
LD DE,01EH
|
||||||
|
ADD HL,DE
|
||||||
|
LD DE,(NXTDATASEC)
|
||||||
|
LD (HL),E
|
||||||
|
INC HL
|
||||||
|
LD (HL),D
|
||||||
|
POP HL
|
||||||
|
;
|
||||||
|
; --- Write directory sector back. ---
|
||||||
|
LD A,(FREEDSEC)
|
||||||
|
LD (IX+1),A
|
||||||
|
LD (IX+2),0
|
||||||
|
LD HL,0CF00H
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
LD (IX+3),0
|
||||||
|
LD (IX+4),1
|
||||||
|
CALL FD7WRITE
|
||||||
|
JP C,SFDX_ERR
|
||||||
|
;
|
||||||
|
CALL FD7INIT
|
||||||
|
XOR A
|
||||||
|
LD (RESULT),A ; Success.
|
||||||
|
RET
|
||||||
|
SFDX_ERR: CALL FD7INIT
|
||||||
|
RET ; RESULT still = 0xFF.
|
||||||
|
|
||||||
ENDIF
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
@@ -1119,19 +1682,27 @@ FDDIR_END: CALL FD7INIT
|
|||||||
; Error tone.
|
; Error tone.
|
||||||
ERRTONE: DB "A0", 0D7H, "ARA", 0D7H, "AR", 00DH
|
ERRTONE: DB "A0", 0D7H, "ARA", 0D7H, "AR", 00DH
|
||||||
|
|
||||||
; Boot disk identifier - 002H prefix for MZ-80A, 003H prefix for MZ-700.
|
; Boot disk identifier - prefix set at runtime for SFD700, compile-time otherwise.
|
||||||
DSKID: IF BUILD_MZ80A = 1
|
; (Glass: label must be outside IF for global visibility.)
|
||||||
DB 002H, "IPLPRO"
|
DSKID: IF BUILD_SFD700 = 1
|
||||||
|
DB 003H, "IPLPRO" ; Default MZ-700; compile-time value for BUILD_MZ700.
|
||||||
ELSE
|
ELSE
|
||||||
DB 003H, "IPLPRO"
|
IF BUILD_MZ80A = 1
|
||||||
|
DB 002H, "IPLPRO"
|
||||||
|
ELSE
|
||||||
|
DB 003H, "IPLPRO"
|
||||||
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
; Parameter block: drive 0, sector 0, 256 bytes, load address differs.
|
; Parameter block: drive 0, sector 0, 256 bytes, load address set at runtime for SFD700.
|
||||||
; MZ-80A loads boot sector to CE00H, MZ-700 loads to CF00H.
|
PRMBLK: IF BUILD_SFD700 = 1
|
||||||
PRMBLK: IF BUILD_MZ80A = 1
|
DB 000H, 000H, 000H, 000H, 001H, 000H, 0CFH, 000H, 000H, 000H, 000H ; Default MZ-700; patched at runtime.
|
||||||
DB 000H, 000H, 000H, 000H, 001H, 000H, 0CEH, 000H, 000H, 000H, 000H
|
|
||||||
ELSE
|
ELSE
|
||||||
DB 000H, 000H, 000H, 000H, 001H, 000H, 0CFH, 000H, 000H, 000H, 000H
|
IF BUILD_MZ80A = 1
|
||||||
|
DB 000H, 000H, 000H, 000H, 001H, 000H, 0CEH, 000H, 000H, 000H, 000H
|
||||||
|
ELSE
|
||||||
|
DB 000H, 000H, 000H, 000H, 001H, 000H, 0CFH, 000H, 000H, 000H, 000H
|
||||||
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
IF BUILD_MZ80A = 1
|
IF BUILD_MZ80A = 1
|
||||||
|
|||||||
@@ -389,7 +389,10 @@ HELPSCR: IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
|||||||
DB "DXXXX[YYYY] - dump mem X to Y.", 00DH
|
DB "DXXXX[YYYY] - dump mem X to Y.", 00DH
|
||||||
DB "DASMXXXX[YYYY]", 00DH
|
DB "DASMXXXX[YYYY]", 00DH
|
||||||
DB " disassemble X to Y", 00DH
|
DB " disassemble X to Y", 00DH
|
||||||
|
DB "FC[XXXXYYYYZZZZ] - save mem to floppy.", 00DH
|
||||||
|
DB " X=start,Y=end,Z=exec", 00DH
|
||||||
DB "FD/FL - fd dir/boot", 00DH
|
DB "FD/FL - fd dir/boot", 00DH
|
||||||
|
DB "FD2T - copy floppy to tape.", 00DH
|
||||||
DB "H - this help screen.", 00DH
|
DB "H - this help screen.", 00DH
|
||||||
DB "IR - rfs rom dir listing.", 00DH
|
DB "IR - rfs rom dir listing.", 00DH
|
||||||
DB "JXXXX - jump to location X.", 00DH
|
DB "JXXXX - jump to location X.", 00DH
|
||||||
@@ -400,12 +403,13 @@ HELPSCR: IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
|||||||
DB "P - test printer.", 00DH
|
DB "P - test printer.", 00DH
|
||||||
;DB "QD/QL - QD dir/boot", 00DH
|
;DB "QD/QL - QD dir/boot", 00DH
|
||||||
DB "R - test dram memory.", 00DH
|
DB "R - test dram memory.", 00DH
|
||||||
DB "SD2T - copy sd card to tape.", 00DH
|
;DB "SD2T - copy sd card to tape.", 00DH
|
||||||
DB "ST[XXXXYYYYZZZZ] - save mem to tape.", 00DH
|
DB "ST[XXXXYYYYZZZZ] - save mem to tape.", 00DH
|
||||||
DB "SC[XXXXYYYYZZZZ] - save mem to card.", 00DH
|
;DB "SC[XXXXYYYYZZZZ] - save mem to card.", 00DH
|
||||||
DB " X=start,Y=end,Z=exec", 00DH
|
DB " X=start,Y=end,Z=exec", 00DH
|
||||||
DB "T - test timer.", 00DH
|
DB "T - test timer.", 00DH
|
||||||
DB "T2SD - copy tape to sd card.", 00DH
|
;DB "T2SD - copy tape to sd card.", 00DH
|
||||||
|
DB "T2FD - copy tape to floppy.", 00DH
|
||||||
DB "V - verify tape save.", 00DH
|
DB "V - verify tape save.", 00DH
|
||||||
DB 000H
|
DB 000H
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|||||||
@@ -218,7 +218,28 @@ TDELAYB1: RRA
|
|||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; START OF SD CONTROLLER FUNCTIONALITY
|
; START OF SD CONTROLLER FUNCTIONALITY
|
||||||
|
; SD card hardware not present on SFD700 — exclude for that build.
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
; Dummy EQUs for SD functions — not used on SFD700 (no SD hardware).
|
||||||
|
; Bank 0 CMT intercept handlers reference these. Must be outside IF for Glass visibility.
|
||||||
|
SDINIT EQU BUILD_SFD700 * 0
|
||||||
|
LOADSDCARD EQU BUILD_SFD700 * 0
|
||||||
|
LOADSDCARDX EQU BUILD_SFD700 * 0
|
||||||
|
LOADSDCP EQU BUILD_SFD700 * 0
|
||||||
|
LOADSDINF EQU BUILD_SFD700 * 0
|
||||||
|
LOADSDDATA EQU BUILD_SFD700 * 0
|
||||||
|
LOADSD3 EQU BUILD_SFD700 * 0
|
||||||
|
SAVESDCARD EQU BUILD_SFD700 * 0
|
||||||
|
SAVESDCARDX EQU BUILD_SFD700 * 0
|
||||||
|
SAVESDDATA EQU BUILD_SFD700 * 0
|
||||||
|
DIRSDCARD EQU BUILD_SFD700 * 0
|
||||||
|
FINDSDX EQU BUILD_SFD700 * 0
|
||||||
|
SDPRINT EQU BUILD_SFD700 * 0
|
||||||
|
LOADSD9BC EQU BUILD_SFD700 * 0
|
||||||
|
LOADSD9 EQU BUILD_SFD700 * 0
|
||||||
|
LOADSD11 EQU BUILD_SFD700 * 0
|
||||||
|
|
||||||
|
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; Hardware SPI SD Controller (HW_SPI_ENA = 1)
|
; Hardware SPI SD Controller (HW_SPI_ENA = 1)
|
||||||
@@ -1612,6 +1633,7 @@ LOADSD9BC: LD H,B
|
|||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; END OF SD CONTROLLER FUNCTIONALITY
|
; END OF SD CONTROLLER FUNCTIONALITY
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
ENDIF ; BUILD_ROMDISK+BUILD_PICOZ80 (SD controller)
|
||||||
|
|
||||||
; RomDisk, top 8 bytes are used by the control registers when enabled so dont use the space.
|
; RomDisk, top 8 bytes are used by the control registers when enabled so dont use the space.
|
||||||
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
||||||
|
|||||||
@@ -143,21 +143,16 @@ BKSWRET3: POP AF ; G
|
|||||||
RET
|
RET
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; START OF TAPE/SD CMDLINE TOOLS FUNCTIONALITY
|
; START OF TAPE/SD/FD CMDLINE TOOLS FUNCTIONALITY
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
|
||||||
; Method to copy an application on a tape to an SD stored application. The tape drive is read and the first
|
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
||||||
; encountered program is loaded into memory at 0x1200. The CMT header is populated with the correct details (even if
|
; Method to copy an application on a tape to an SD stored application.
|
||||||
; the load address isnt 0x1200, the CMT Header contains the correct value).
|
TAPE2SD: LD HL,LOADTAPECP
|
||||||
; A call is then made to write the application to the SD card.
|
|
||||||
;
|
|
||||||
TAPE2SD: ; Load from tape into memory, filling the tape CMT header and loading data into location 0x1200.
|
|
||||||
LD HL,LOADTAPECP ; Call the Loadtape command, non execute version to get the tape contents into memory.
|
|
||||||
CALL BKSW3to4
|
CALL BKSW3to4
|
||||||
LD A,(RESULT)
|
LD A,(RESULT)
|
||||||
OR A
|
OR A
|
||||||
JR NZ,TAPE2SDERR
|
JR NZ,TAPE2SDERR
|
||||||
; Save to SD Card.
|
|
||||||
LD HL,SAVESDCARDX
|
LD HL,SAVESDCARDX
|
||||||
CALL BKSW3to2
|
CALL BKSW3to2
|
||||||
LD A,(RESULT)
|
LD A,(RESULT)
|
||||||
@@ -171,12 +166,7 @@ TAPE2SDERR2:LD HL,PRINTMSG
|
|||||||
RET
|
RET
|
||||||
|
|
||||||
; Method to copy an SD stored application to a Cassette tape in the CMT.
|
; Method to copy an SD stored application to a Cassette tape in the CMT.
|
||||||
; The directory entry number or filename is passed to the command and the entry is located within the SD
|
SD2TAPE: LD HL,LOADSDCP
|
||||||
; directory structure. The file is then loaded into memory and the CMT header populated. A call is then made
|
|
||||||
; to write out the data to tap.
|
|
||||||
;
|
|
||||||
SD2TAPE: ; Load from SD, fill the CMT header then call CMT save.
|
|
||||||
LD HL,LOADSDCP
|
|
||||||
CALL BKSW3to2
|
CALL BKSW3to2
|
||||||
LD A,(RESULT)
|
LD A,(RESULT)
|
||||||
OR A
|
OR A
|
||||||
@@ -190,8 +180,97 @@ SD2TAPE: ; Load from SD, fill the CMT header then call CMT save.
|
|||||||
SD2TAPEERR: LDDE MSGSD2TERR
|
SD2TAPEERR: LDDE MSGSD2TERR
|
||||||
JR TAPE2SDERR2
|
JR TAPE2SDERR2
|
||||||
RET
|
RET
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
IF BUILD_SFD700 = 1
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
; END OF TAPE/SD CMDLINE TOOLS FUNCTIONALITY
|
; FD2TAPE - Copy floppy disk file to cassette tape.
|
||||||
|
; Reads boot sector + file from floppy, populates CMT header, writes to tape.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
FD2TAPE: ; Prompt for filename to extract from floppy.
|
||||||
|
CALL NL
|
||||||
|
LDDE MSGFDFNAME
|
||||||
|
CALL MSG ; "FILENAME? "
|
||||||
|
LD DE,BUFER
|
||||||
|
CALL GETL ; Get user input.
|
||||||
|
LD HL,BUFER+10 ; Skip past prompt echo.
|
||||||
|
LD DE,NAME
|
||||||
|
LD BC,FNSIZE
|
||||||
|
LDIR ; Copy filename to NAME.
|
||||||
|
;
|
||||||
|
LD HL,LOADFDCP ; Load named file from floppy (bank 1).
|
||||||
|
CALL BKSW3to1
|
||||||
|
LD A,(RESULT)
|
||||||
|
OR A
|
||||||
|
JR Z,FD2T_SAV ; Success → save to tape.
|
||||||
|
CP 0FEH
|
||||||
|
RET Z ; 0xFE = FD7ERR already showed error.
|
||||||
|
JR FD2TERR ; 0xFF = show our error message.
|
||||||
|
FD2T_SAV: LD HL,SAVECMT ; Write to tape (bank 4).
|
||||||
|
CALL BKSW3to4
|
||||||
|
LD A,(RESULT)
|
||||||
|
OR A
|
||||||
|
JR NZ,FD2TERR
|
||||||
|
LDDE MSGFD2TOK
|
||||||
|
JR FDTMSG
|
||||||
|
FD2TERR: LDDE MSGFD2TERR
|
||||||
|
; Print local message: DE = string in THIS bank (CR-terminated).
|
||||||
|
; Uses monitor ROM MSG function directly (no bank switch needed).
|
||||||
|
FDTMSG: CALL NL
|
||||||
|
CALL MSG ; Print CR-terminated string at DE.
|
||||||
|
RET
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; TAPE2FD - Copy cassette tape file to floppy disk.
|
||||||
|
; Loads from tape, then writes IPL header + data to floppy.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
TAPE2FD: LD HL,LOADTAPECP ; Load from tape (bank 4).
|
||||||
|
CALL BKSW3to4
|
||||||
|
LD A,(RESULT)
|
||||||
|
OR A
|
||||||
|
JR NZ,T2FDERR
|
||||||
|
LD HL,SAVEFDX ; Write to floppy (bank 1).
|
||||||
|
CALL BKSW3to1
|
||||||
|
LD A,(RESULT)
|
||||||
|
OR A
|
||||||
|
JR NZ,T2FDERR
|
||||||
|
LDDE MSGT2FDOK
|
||||||
|
JR FDTMSG
|
||||||
|
T2FDERR: LDDE MSGT2FDERR
|
||||||
|
JR FDTMSG
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; SAVEFDCARD - Save memory region to floppy disk (FC command).
|
||||||
|
; Gets CMT parameters (name, start, size, exec) then writes to floppy.
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
SAVEFDCARD: CALL GETCMTPARM ; Get parameters (same bank).
|
||||||
|
LD A,C
|
||||||
|
OR A
|
||||||
|
JR NZ,SFDC_ERR ; C=1 means input error.
|
||||||
|
LD A,001H ; Default file type = OBJ.
|
||||||
|
LD (ATRB),A
|
||||||
|
LD HL,SAVEFDX ; Write to floppy (bank 1).
|
||||||
|
CALL BKSW3to1
|
||||||
|
LD A,(RESULT)
|
||||||
|
OR A
|
||||||
|
JR NZ,SFDC_ERR
|
||||||
|
LDDE MSGFCSAVEOK
|
||||||
|
JR FDTMSG
|
||||||
|
SFDC_ERR: LDDE MSGFCSAVEERR
|
||||||
|
JR FDTMSG
|
||||||
|
|
||||||
|
; Messages for floppy/tape transfer commands (local to bank 3).
|
||||||
|
MSGFDFNAME: DB "FILENAME? ", 00DH
|
||||||
|
MSGFD2TOK: DB "FLOPPY -> TAPE OK.", 00DH
|
||||||
|
MSGFD2TERR: DB "FLOPPY -> TAPE ERROR.", 00DH
|
||||||
|
MSGT2FDOK: DB "TAPE -> FLOPPY OK.", 00DH
|
||||||
|
MSGT2FDERR: DB "TAPE -> FLOPPY ERROR.", 00DH
|
||||||
|
MSGFCSAVEOK:DB "SAVED TO FLOPPY OK.", 00DH
|
||||||
|
MSGFCSAVEERR:DB "SAVE TO FLOPPY ERROR.", 00DH
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------------------
|
||||||
|
; END OF TAPE/SD/FD CMDLINE TOOLS FUNCTIONALITY
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@@ -402,7 +481,7 @@ GETCMTPARM: CALL READ4HEX ; Start
|
|||||||
CALL NL
|
CALL NL
|
||||||
LDDE MSGSAVE ; 'FILENAME? '
|
LDDE MSGSAVE ; 'FILENAME? '
|
||||||
LD HL,PRINTMSG
|
LD HL,PRINTMSG
|
||||||
CALL BKSW2to6 ; Print out the filename.
|
CALL BKSW3to6 ; Print out the filename prompt.
|
||||||
LD DE,BUFER
|
LD DE,BUFER
|
||||||
CALL GETL
|
CALL GETL
|
||||||
LD HL,BUFER+10
|
LD HL,BUFER+10
|
||||||
|
|||||||
@@ -586,13 +586,355 @@ CPY2SP_EX8: RET
|
|||||||
; END OF METHODS
|
; END OF METHODS
|
||||||
;-------------------------------------------------------------------------------
|
;-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
;===============================================================================
|
||||||
|
; MZ-80A FLOPPY DISK CONTROLLER (SFD700) — Bank 8 (8K: E300-FFFF).
|
||||||
|
;
|
||||||
|
; Hardware-accelerated read using A10 address toggle:
|
||||||
|
; F3FE: DD E9 = JP (IX) — spin loop (A10=0, DRQ low).
|
||||||
|
; F7FE: FD E9 = JP (IY) — data handler (A10=1, DRQ high).
|
||||||
|
; These are the ORIGINAL MZ-80A FI ROM addresses that BASIC expects.
|
||||||
|
;
|
||||||
|
; Bank 8 = ROMBANK8 = 12 (>= ROMBANK6), so E-page + F-page are both mapped.
|
||||||
|
;===============================================================================
|
||||||
|
IF BUILD_SFD700 = 1
|
||||||
|
|
||||||
|
; MZ-80A specific data.
|
||||||
|
DSKID80A: DB 002H, "IPLPRO"
|
||||||
|
PRMBLK80A: DB 000H, 000H, 000H, 000H, 001H, 000H, 0CEH, 000H, 000H, 000H, 000H
|
||||||
|
ERRTONE8: DB "A0", 0D7H, "ARA", 0D7H, "AR", 00DH
|
||||||
|
FD80A_TSP EQU 0101EH ; In RAM, not ROM.
|
||||||
|
|
||||||
|
ENDIF
|
||||||
|
; Glass: label outside IF for global visibility.
|
||||||
|
FD80A_BOOT:
|
||||||
|
IF BUILD_SFD700 = 1
|
||||||
|
PUSH DE
|
||||||
|
LD DE,BPARA
|
||||||
|
LD HL,PRMBLK80A
|
||||||
|
LD BC,11
|
||||||
|
LDIR
|
||||||
|
POP DE
|
||||||
|
LD A,(DE)
|
||||||
|
CP 00DH
|
||||||
|
JR NZ,FD80A_GDSK
|
||||||
|
CALL FD80A_INIT
|
||||||
|
FD80A_PRM: LDDE MSGBOOTDRV
|
||||||
|
LD HL,PRINTMSG
|
||||||
|
CALL BKSW8to6
|
||||||
|
LD DE,011A3H
|
||||||
|
CALL GETL
|
||||||
|
LD A,(DE)
|
||||||
|
CP 01BH
|
||||||
|
JP Z,FD80A_BRK
|
||||||
|
LD HL,19
|
||||||
|
ADD HL,DE
|
||||||
|
LD A,(HL)
|
||||||
|
CP 00DH
|
||||||
|
JR Z,FD80A_RD1
|
||||||
|
FD80A_GDSK: CALL HEX
|
||||||
|
JR C,FD80A_PRM
|
||||||
|
DEC A
|
||||||
|
CP 004H
|
||||||
|
JR NC,FD80A_PRM
|
||||||
|
LD (BPARA),A
|
||||||
|
FD80A_RD1: LD IX,BPARA
|
||||||
|
CALL FD80A_READ
|
||||||
|
LD HL,0CE00H
|
||||||
|
LD DE,DSKID80A
|
||||||
|
LD B,007H
|
||||||
|
FD80A_CHK: LD C,(HL)
|
||||||
|
LD A,(DE)
|
||||||
|
CP C
|
||||||
|
JP NZ,FD80A_NMS
|
||||||
|
INC HL
|
||||||
|
INC DE
|
||||||
|
DJNZ FD80A_CHK
|
||||||
|
LDDE MSGIPLLOAD
|
||||||
|
LD HL,PRINTMSG
|
||||||
|
CALL BKSW8to6
|
||||||
|
LD DE,0CE07H
|
||||||
|
LD HL,PRTFN
|
||||||
|
CALL BKSW8to6
|
||||||
|
LD IX,BPARA
|
||||||
|
LD HL,(0CE16H)
|
||||||
|
LD (IX+5),L
|
||||||
|
LD (IX+6),H
|
||||||
|
LD HL,(0CE14H)
|
||||||
|
LD (IX+3),L
|
||||||
|
LD (IX+4),H
|
||||||
|
LD HL,(0CE1EH)
|
||||||
|
LD (IX+1),L
|
||||||
|
LD (IX+2),H
|
||||||
|
CALL FD80A_READ
|
||||||
|
CALL FD80A_INIT
|
||||||
|
LD HL,(0CE18H)
|
||||||
|
JP (HL)
|
||||||
|
|
||||||
|
FD80A_LERR: LDDE MSGLOADERR
|
||||||
|
JR FD80A_ERR
|
||||||
|
FD80A_NMS: LDDE MSGDSKNOTMST
|
||||||
|
FD80A_ERR: LD HL,(TMPSTACKP)
|
||||||
|
LD (FD80A_TSP),HL
|
||||||
|
LD HL,PRINTMSG
|
||||||
|
CALL BKSW8to6
|
||||||
|
LD DE,ERRTONE8
|
||||||
|
CALL MELDY
|
||||||
|
LD HL,(FD80A_TSP)
|
||||||
|
LD SP,HL
|
||||||
|
RET
|
||||||
|
FD80A_BRK: LD SP,(TMPSTACKP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
; --- Low-level FDC routines ---
|
||||||
|
FD80A_RDY: LD A,(MOTON)
|
||||||
|
RRCA
|
||||||
|
CALL NC,FD80A_MON
|
||||||
|
LD A,(IX+0)
|
||||||
|
OR 084H
|
||||||
|
OUT (FDC_DRIVE),A
|
||||||
|
XOR A
|
||||||
|
LD (FDCCMD),A
|
||||||
|
LD HL,0
|
||||||
|
FD80A_RDW: DEC HL
|
||||||
|
LD A,H
|
||||||
|
OR L
|
||||||
|
JP Z,FD80A_DSKE
|
||||||
|
IN A,(FDC_CMD)
|
||||||
|
CPL
|
||||||
|
RLCA
|
||||||
|
JR C,FD80A_RDW
|
||||||
|
LD C,(IX+0)
|
||||||
|
LD HL,TRK0FD1
|
||||||
|
LD B,0
|
||||||
|
ADD HL,BC
|
||||||
|
BIT 0,(HL)
|
||||||
|
RET NZ
|
||||||
|
CALL FD80A_SK0
|
||||||
|
SET 0,(HL)
|
||||||
|
RET
|
||||||
|
FD80A_MON: LD A,080H
|
||||||
|
OUT (FDC_DRIVE),A
|
||||||
|
LD B,16
|
||||||
|
FD80A_MNW: CALL FD80A_DL60
|
||||||
|
DJNZ FD80A_MNW
|
||||||
|
LD A,1
|
||||||
|
LD (MOTON),A
|
||||||
|
RET
|
||||||
|
FD80A_SEEK: LD A,01BH
|
||||||
|
CALL FD80A_CMD
|
||||||
|
AND 099H
|
||||||
|
RET
|
||||||
|
FD80A_INIT: XOR A
|
||||||
|
OUT (FDC_DRIVE),A
|
||||||
|
LD (TRK0FD1),A
|
||||||
|
LD (TRK0FD2),A
|
||||||
|
LD (TRK0FD3),A
|
||||||
|
LD (TRK0FD4),A
|
||||||
|
LD (MOTON),A
|
||||||
|
RET
|
||||||
|
FD80A_SK0: LD A,00BH
|
||||||
|
CALL FD80A_CMD
|
||||||
|
AND 085H
|
||||||
|
XOR 004H
|
||||||
|
RET Z
|
||||||
|
JP FD80A_DSKE
|
||||||
|
FD80A_CMD: LD (FDCCMD),A
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
CALL FD80A_WBR
|
||||||
|
IN A,(FDC_CMD)
|
||||||
|
CPL
|
||||||
|
RET
|
||||||
|
FD80A_WBR: PUSH DE
|
||||||
|
PUSH HL
|
||||||
|
CALL FD80A_DL7
|
||||||
|
LD E,7
|
||||||
|
FD80A_WB1: LD HL,0
|
||||||
|
FD80A_WB2: DEC HL
|
||||||
|
LD A,H
|
||||||
|
OR L
|
||||||
|
JR Z,FD80A_WB3
|
||||||
|
IN A,(FDC_CMD)
|
||||||
|
CPL
|
||||||
|
RRCA
|
||||||
|
JR C,FD80A_WB2
|
||||||
|
POP HL
|
||||||
|
POP DE
|
||||||
|
RET
|
||||||
|
FD80A_WB3: DEC E
|
||||||
|
JR NZ,FD80A_WB1
|
||||||
|
POP HL
|
||||||
|
POP DE
|
||||||
|
JP FD80A_DSKE
|
||||||
|
FD80A_WBA: PUSH DE
|
||||||
|
PUSH HL
|
||||||
|
CALL FD80A_DL7
|
||||||
|
LD E,7
|
||||||
|
FD80A_WA1: LD HL,0
|
||||||
|
FD80A_WA2: DEC HL
|
||||||
|
LD A,H
|
||||||
|
OR L
|
||||||
|
JR Z,FD80A_WA3
|
||||||
|
IN A,(FDC_CMD)
|
||||||
|
CPL
|
||||||
|
RRCA
|
||||||
|
JR NC,FD80A_WA2
|
||||||
|
POP HL
|
||||||
|
POP DE
|
||||||
|
RET
|
||||||
|
FD80A_WA3: DEC E
|
||||||
|
JR NZ,FD80A_WA1
|
||||||
|
POP HL
|
||||||
|
POP DE
|
||||||
|
JP FD80A_DSKE
|
||||||
|
|
||||||
|
; --- Hardware-accelerated sector read ---
|
||||||
|
; Uses A10 toggle: F3FE=JP(IX) spin, F7FE=JP(IY) data.
|
||||||
|
FD80A_READ: CALL FD80A_CNV
|
||||||
|
FD80A_R1: CALL FD80A_PRS
|
||||||
|
FD80A_R2: CALL FD80A_SID
|
||||||
|
CALL FD80A_SEEK
|
||||||
|
JR NZ,FD80A_RET
|
||||||
|
CALL FD80A_STR
|
||||||
|
PUSH IX
|
||||||
|
LD IX,0F3FEH ; Spin loop at F3FE (original FI ROM addr).
|
||||||
|
LD IY,FD80A_INI ; Data handler.
|
||||||
|
LD A,094H
|
||||||
|
CALL FD80A_CM2
|
||||||
|
FD80A_R3: LD B,0
|
||||||
|
JP (IX) ; Enter spin loop.
|
||||||
|
FD80A_INI: INI
|
||||||
|
JP NZ,0F3FEH ; Back to spin loop.
|
||||||
|
POP IX
|
||||||
|
INC (IX+8)
|
||||||
|
LD A,(IX+8)
|
||||||
|
PUSH IX
|
||||||
|
LD IX,0F3FEH
|
||||||
|
CP 17
|
||||||
|
JR Z,FD80A_SEC
|
||||||
|
DEC D
|
||||||
|
JR NZ,FD80A_R3
|
||||||
|
JR FD80A_RDN
|
||||||
|
FD80A_SEC: DEC D
|
||||||
|
FD80A_RDN: CALL FD80A_FI
|
||||||
|
POP IX
|
||||||
|
IN A,(FDC_CMD)
|
||||||
|
CPL
|
||||||
|
AND 0FFH
|
||||||
|
JR NZ,FD80A_RET
|
||||||
|
CALL FD80A_ADJ
|
||||||
|
JP Z,FD80A_END
|
||||||
|
LD A,(IX+7)
|
||||||
|
JR FD80A_R2
|
||||||
|
FD80A_RET: LD A,(RETRIES)
|
||||||
|
DEC A
|
||||||
|
LD (RETRIES),A
|
||||||
|
JP Z,FD80A_DSKE
|
||||||
|
CALL FD80A_SK0
|
||||||
|
JR FD80A_R1
|
||||||
|
FD80A_END: LD A,080H
|
||||||
|
OUT (FDC_DRIVE),A
|
||||||
|
RET
|
||||||
|
|
||||||
|
; --- Helpers ---
|
||||||
|
FD80A_PRS: CALL FD80A_RDY
|
||||||
|
LD D,(IX+4)
|
||||||
|
LD A,(IX+3)
|
||||||
|
OR A
|
||||||
|
JR Z,FD80A_PS1
|
||||||
|
INC D
|
||||||
|
FD80A_PS1: LD A,(IX+10)
|
||||||
|
LD (IX+8),A
|
||||||
|
LD A,(IX+9)
|
||||||
|
LD (IX+7),A
|
||||||
|
LD L,(IX+5)
|
||||||
|
LD H,(IX+6)
|
||||||
|
RET
|
||||||
|
FD80A_SID: SRL A
|
||||||
|
CPL
|
||||||
|
OUT (FDC_DATA),A
|
||||||
|
JR NC,FD80A_S0
|
||||||
|
LD A,1
|
||||||
|
JR FD80A_S1
|
||||||
|
FD80A_S0: XOR A
|
||||||
|
FD80A_S1: CPL
|
||||||
|
OUT (FDC_SIDE),A
|
||||||
|
RET
|
||||||
|
FD80A_STR: LD C,FDC_DATA
|
||||||
|
LD A,(IX+7)
|
||||||
|
SRL A
|
||||||
|
CPL
|
||||||
|
OUT (FDC_TRACK),A
|
||||||
|
LD A,(IX+8)
|
||||||
|
CPL
|
||||||
|
OUT (FDC_SECTOR),A
|
||||||
|
RET
|
||||||
|
FD80A_ADJ: LD A,(IX+8)
|
||||||
|
CP 17
|
||||||
|
JR NZ,FD80A_AJ1
|
||||||
|
LD A,1
|
||||||
|
LD (IX+8),A
|
||||||
|
INC (IX+7)
|
||||||
|
FD80A_AJ1: LD A,D
|
||||||
|
OR A
|
||||||
|
RET
|
||||||
|
FD80A_CNV: LD B,0
|
||||||
|
LD DE,16
|
||||||
|
LD L,(IX+1)
|
||||||
|
LD H,(IX+2)
|
||||||
|
XOR A
|
||||||
|
FD80A_CN1: SBC HL,DE
|
||||||
|
JR C,FD80A_CN2
|
||||||
|
INC B
|
||||||
|
JR FD80A_CN1
|
||||||
|
FD80A_CN2: ADD HL,DE
|
||||||
|
LD H,B
|
||||||
|
INC L
|
||||||
|
LD (IX+9),H
|
||||||
|
LD (IX+10),L
|
||||||
|
LD A,10
|
||||||
|
LD (RETRIES),A
|
||||||
|
RET
|
||||||
|
FD80A_CM2: LD (FDCCMD),A
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
CALL FD80A_WBA
|
||||||
|
RET
|
||||||
|
FD80A_FI: LD A,0D8H
|
||||||
|
CPL
|
||||||
|
OUT (FDC_CMD),A
|
||||||
|
CALL FD80A_WBR
|
||||||
|
RET
|
||||||
|
FD80A_DSKE: CALL FD80A_INIT
|
||||||
|
JP FD80A_LERR
|
||||||
|
FD80A_DL7: PUSH DE
|
||||||
|
LD DE,7
|
||||||
|
JR FD80A_DLP
|
||||||
|
FD80A_DL60: PUSH DE
|
||||||
|
LD DE,01013H
|
||||||
|
FD80A_DLP: DEC DE
|
||||||
|
LD A,E
|
||||||
|
OR D
|
||||||
|
JR NZ,FD80A_DLP
|
||||||
|
POP DE
|
||||||
|
RET
|
||||||
|
|
||||||
|
; --- Hardware acceleration alignment points (F-page) ---
|
||||||
|
; JP (IX) at F3FE: A10=0, DRQ low spin loop.
|
||||||
|
ALIGN_NOPS 0F3FEH
|
||||||
|
JP (IX) ; DD E9 at F3FE/F3FF.
|
||||||
|
; JP (IY) at F7FE: A10=1, DRQ high data handler.
|
||||||
|
ALIGN_NOPS 0F7FEH
|
||||||
|
JP (IY) ; FD E9 at F7FE/F7FF.
|
||||||
|
|
||||||
|
; SFD700 - Pad to end of 8K bank (F-page through FFFFH).
|
||||||
|
ALIGN 10000H
|
||||||
|
|
||||||
|
ENDIF ; BUILD_SFD700
|
||||||
|
|
||||||
; RomDisk - Pad to EFFF boundary.
|
; RomDisk - Pad to EFFF boundary.
|
||||||
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
|
||||||
ALIGN 0EFF8h
|
ALIGN 0EFF8h
|
||||||
ORG 0EFF8h
|
ORG 0EFF8h
|
||||||
DB 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh
|
DB 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh
|
||||||
ENDIF
|
|
||||||
; SFD700 - Pad to 10000H
|
|
||||||
IF BUILD_SFD700 = 1
|
|
||||||
ALIGN 10000H
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|||||||
BIN
roms/rfs.rom
vendored
BIN
roms/rfs.rom
vendored
Binary file not shown.
BIN
tools/MZFD/MZFDTool
vendored
Executable file
BIN
tools/MZFD/MZFDTool
vendored
Executable file
Binary file not shown.
618
tools/MZFD/MZFDTool.c
Executable file
618
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
tools/MZFD/MZFDTool.c.original
vendored
Executable file
630
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
tools/MZFD/Makefile
vendored
Normal file
19
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
|
||||||
BIN
tools/MZFDTool
vendored
Executable file
BIN
tools/MZFDTool
vendored
Executable file
Binary file not shown.
@@ -147,8 +147,8 @@ cat ${ROM_PATH}/rfs.rom \
|
|||||||
# The SFD700 ROM is built as follows:
|
# The SFD700 ROM is built as follows:
|
||||||
# 0x00000 : 0x00FFF - MZ80A Floppy ROM MZ80AFI.rom (duplicated ROM at 0x00400)
|
# 0x00000 : 0x00FFF - MZ80A Floppy ROM MZ80AFI.rom (duplicated ROM at 0x00400)
|
||||||
# 0x01000 : 0x01FFF - MZ-1E05 MZ700 Floppy ROM mz-1e05.rom
|
# 0x01000 : 0x01FFF - MZ-1E05 MZ700 Floppy ROM mz-1e05.rom
|
||||||
# 0x02000 : 0x0BFFF - RFS rfs.rom
|
# 0x02000 : 0x11FFF - RFS rfs.rom (6x4096 pages, 6x8192 pages).
|
||||||
# 0x0C000 : 0x7FFFF - USER / ROM File System
|
# 0x12000 : 0x7FFFF - USER / ROM File System
|
||||||
cat ${ROM_PATH}/mz80afi_sfd700.rom ${ROM_PATH}/mz80afi_sfd700.rom ${ROM_PATH}/mz-1e05.rom ${ROM_PATH}/rfs.rom \
|
cat ${ROM_PATH}/mz80afi_sfd700.rom ${ROM_PATH}/mz80afi_sfd700.rom ${ROM_PATH}/mz-1e05.rom ${ROM_PATH}/rfs.rom \
|
||||||
>> ${SFD700_ROM}
|
>> ${SFD700_ROM}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user