You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4593 lines
99 KiB

;===============================================================================
; FDU - FLOPPY DISK UTILITY PROGRAM FOR RETROBREW COMPUTERS
;===============================================================================
;
; AUTHOR: WAYNE WARTHEN (DERIVED FROM FDCMON BY ANDREW LYNCH & DAN WERNER)
;_______________________________________________________________________________
;
; CHANGELOG:
; 2011-08-05: v1.0 INITIAL RELEASE
; 2011-08-25: v1.1 SUPPORT ZETA
; SUPPORT INT/WAIT
; 2011-08-28: v1.2 FIX ZETA RESET LOGIC (from Sergey)
; FIX ZETA MOTOR DISPLAY (from Sergey)
; NEW ZETA DISK CHANGE DISPLAY
; 2011-09-01: V1.3 ADDED CONFIGURABLE CPU FREQUENCY FOR DELAYS
; 2011-09-05: V1.4 USE CPU FREQUENCY FOR POLLING TIMEOUT
; 2011-09-19: V1.5 IMPROVED USE OF FDC RESET ON ZETA
; ADDED FDC RESET TO FDC CONTROL MENU
; 2011-09-24: V1.5a MINOR CORRECTION TO POLLING ROUTINE TO AVOID OVERRUN
; 2011-10-07: V2.0 PRELIMINARY SUPPORT FOR DUAL IDE
; 2011-10-13: V2.1 PRELIMINARY SUPPORT FOR N8
; 2011-10-20: V2.2 INCLUDE BUSY & NDMA BITS IN RESULTS BYTE READY CHECKING
; 2011-10-22: V2.3 ADDED VERIFY FUNCTION
; 2011-11-25: V2.4 ADDED SUPPORT FOR DISKIO V3
; 2012-01-09: V2.5 WARM START CP/M AT TERMINATION TO LOGOUT ALL DRIVES
; 2012-01-09: V2.6 EXPERIMENTAL SUPPORT FOR 5 1/4" DRIVES
; 2012-04-05: V2.7 SUPPORT FOR 8" DRIVES
; 2012-04-06: V2.7a FIXED MEDIA SELECTION MENU (DUPLICATE ENTRIES)
; 2012-04-08: V2.7b HANDLE DENSITY SELECT PROPERLY
; 2012-05-22: V2.8 ADDED NEW MEDIA DEFINITIONS (5.25", 320K)
; 2012-06-01: V2.9 ADDED INTERLEAVE CAPABILITY IN FORMAT COMMAND
; 2012-06-05: V3.0 DOCUMENTATION CLEANUP
; 2012-07-01: V3.1 MODIFY HLT FOR 8" MEDIA (50ms PER YD-180 SPEC)
; 2013-06-17: V3.2 CLEANED UP THE SRT, HLT, AND HUT VALUES
; 2015-02-10: V3.3 ADDED ZETA SBC V2 SUPPORT (SERGEY KISELEV)
; 2015-03-25: V4.0 RENAMED APP FDTST --> FD
; 2017-09-02: V5.0 RENAMED APP TO FDU (FLOPPY DISK UTILITY)
; DYNAMIC FDC SELECTION AT STARTUP
; DYNAMIC CPU SPEED ADJUSTMENT
; 2017-12-16: V5.1 IMPROVED POLLING READ/WRITE PERFORMANCE
; 2018-01-08: V5.2 ADDED RC2014 SUPPORT FOR:
; - SCOTT BAKER (SMB) SMC 9266 FDC
; - SCOTT BAKER (SMB) WDC 37C65 FDC
; 2018-09-05: v5.3 ADDED SUPPORT FOR SMALLZ80
; - USE EOT=R TO END R/W AFTER ONE SECTOR INSTEAD
; OF USING PULSE TC
;
;_______________________________________________________________________________
;
; BUILDING:
; CAN BE BUILT WITH TASM LIKE THIS:
; TASM -t80 -b -fFF FDU.ASM FDU.COM FDU.LST
;
; TODO:
; 1) CURRENT TRACK IS UPDATED EVEN IF SEEK FAILS! (DEFER, RECOVERS AUTOMATICALLY)
; 2) CLEAN UP UTILITY ROUTINES (DEFER, NOT IMPORTANT)
; 3) TIGHTEN UP THE TIMING LOOPS (DEFER, LOW PRIORITY, WORKING FINE AS IS)
; 4) MOVE STX EVALUATION TO DIO LEVEL? (NOT SURE..., LOW PRIORITY)
; 5) ALLOW <ESC> TO ABORT AT PROMPTS
; 6) ALLOW <ESC> TO ABORT OPERATION IN PROGRESS
; 7) MOVE CONTINUE PROMPT TO A SEPARATE ROUTINE
;
;_______________________________________________________________________________
;
;
FALSE .EQU 0
TRUE .EQU ~FALSE
;
; FDC ID
;
FDC_DIO .EQU 0
FDC_DIO3 .EQU 1
FDC_ZETA .EQU 2
FDC_ZETA2 .EQU 3
FDC_DIDE .EQU 4
FDC_N8 .EQU 5
FDC_RCSMC .EQU 6
FDC_RCWDC .EQU 7
FDC_SMZ80 .EQU 8
;
; FDC MODE
;
_DIO .EQU $01 ; CUSTOM FOR DIO BOARD
_DIO3 .EQU $02 ; CUSTOM FOR DIO3 BOARD
_ZETA .EQU $04 ; CUSTOM FOR ZETA
_RCSMC .EQU $08 ; CUSTOM FOR RC2014 SMB SMC MODULE
_PCAT .EQU $10 ; PC/AT MODE IN NEWER CONTROLLERS
;
;===============================================================================
; MAIN PROGRAM PROCEDURE
;===============================================================================
;
.ORG 00100H
; SAVE PREVIOUS STACK POINTER, AND SWITCH TO OUR STACK
LD (STACKSAV),SP
LD SP,STACK
; GENERAL INITIALIZATION (BIOS & SPEED DETECTION)
CALL INIT
JR NZ,EXIT
; SELECT FD CONTROLLER
CALL NEWLINE
CALL FDCSEL
JR NZ,EXIT
; SETUP FOR DEFAULT MEDIA AND RUN THE MAIN MENU
CALL DIO_SETMEDIA
LD HL,MM_INFO
CALL RUNMENU
EXIT:
LD C,00H ; CP/M SYSTEM RESET (WARM START)
CALL 0005H ; RETURN TO CP/M
; CLEAN UP AND RETURN TO OS
CALL NEWLINE
LD SP,(STACKSAV)
RET
HALT ; SHOULD NEVER GET HERE
;
;===============================================================================
; FD CONTROLLER SELECTION
;===============================================================================
;
INIT:
; DISPLAY PROGRAM STARTUP BANNER
CALL NEWLINE
LD DE,STR_BANNER
CALL WRITESTR
; UNA UBIOS DETECTION...
LD A,($FFFD) ; FIXED LOCATION OF UNA API VECTOR
CP $C3 ; JP INSTRUCTION?
JR NZ,INIT1 ; IF NOT, NOT UNA
LD HL,($FFFE) ; GET JP ADDRESS
LD A,(HL) ; GET BYTE AT TARGET ADDRESS
CP $FD ; FIRST BYTE OF UNA PUSH IX INSTRUCTION
JR NZ,INIT1 ; IF NOT, NOT UNA
INC HL ; POINT TO NEXT BYTE
LD A,(HL) ; GET NEXT BYTE
CP $E5 ; SECOND BYTE OF UNA PUSH IX INSTRUCTION
JR NZ,INIT1 ; IF NOT, NOT UNA
LD DE,STR_UBIOS ; POINT TO UBIOS TAG
CALL WRITESTR ; AND DISPLAY IT
; GET CPU SPEED FROM UBIOS
LD C,0F8H ; UNA BIOS GET PHI FUNCTION
RST 08 ; RETURNS SPEED IN HZ IN DE:HL
LD B,4 ; DIVIDE MHZ IN DE:HL BY 100000H
INIT0:
SRL D ; ... TO GET APPROX CPU SPEED IN
RR E ; ...MHZ. THROW AWAY HL, AND
DJNZ INIT0 ; ...RIGHT SHIFT DE BY 4.
INC E ; FIX UP FOR VALUE TRUNCATION
LD A,E ; PUT IN A
LD (CPUSPD),A ; SAVE IT
JR INIT3 ; AND DONE
INIT1:
; ROMWBW HBIOS DETECTION
LD HL,(0FFFEH) ; HL := ADR OR ROMWBW HBIOS IDENT
LD A,(HL) ; GET FIRST BYTE OF ROMWBW MARKER
CP 'W' ; MATCH?
JP NZ,INIT2 ; ABORT WITH INVALID CONFIG BLOCK
INC HL ; NEXT BYTE (MARKER BYTE 2)
LD A,(HL) ; LOAD IT
CP ~'W' ; MATCH?
JP NZ,INIT2 ; ABORT WITH INVALID CONFIG BLOCK
LD DE,STR_HBIOS ; POINT TO HBIOS TAG
CALL WRITESTR ; AND DISPLAY IT
; GET CPU SPEED FROM HBIOS
LD B,0F8H ; HBIOS SYSGET FUNCTION 0XF8
LD C,0F0H ; CPUINFO SUBFUNCTION 0XF0
RST 08 ; DO IT, L := CPU SPEED IN MHZ
LD A,L ; MOVE IT TO A
LD (CPUSPD),A ; SAVE IT
JR INIT3 ; AND DONE
INIT2:
;; NO KNOWN BIOS DETECTED, BAIL OUT W/ ERROR
;LD DE,STR_BIOERR
;CALL WRITESTR
;OR 0FFH
;RET
LD A,20
LD (CPUSPD),A
INIT3:
; COMPUTE CPU SCALER FOR DELAY LOOPS
LD A,(CPUSPD)
CP 3 ; TEST FOR <= 2 (SPECIAL HANDLING)
JR C,INIT4 ; IF <= 2, SPECIAL PROCESSING
SUB 2 ; ADJUST AS REQUIRED BY DELAY FUNCTIONS
JR INIT5 ; AND CONTINUE
INIT4:
LD A,1 ; USE THE MIN VALUE OF 1
INIT5:
LD (CPUSCL),A ; UPDATE CPU SCALER VALUE
; REMAINDER OF BANNER
CALL NEWLINE
LD DE,STR_BANNER2
CALL WRITESTR
; INITIALIZATION DONE
XOR A
RET
STR_BANNER .DB "Floppy Disk Utility (FDU) v5.3, 28-Sep-2018$"
STR_BANNER2 .DB "Copyright (C) 2018, Wayne Warthen, GNU GPL v3","$"
STR_HBIOS .DB " [HBIOS]$"
STR_UBIOS .DB " [UBIOS]$"
;
STR_BIOERR .DB "\r\n\r\n*** Unknown BIOS ***\r\n$"
;
CPUSPD .DB 20 ; DEFAULT TO SAFE (HIGH) VALUE
CPUSCL .DB 0 ; CPU SPEED DELAY SCALER (COMPUTED)
;
;===============================================================================
; FD CONTROLLER SELECTION
;===============================================================================
;
FDCSEL:
; PROMPT
LD DE,FSS_MENU
CALL WRITESTR
;
FDCSEL1:
CALL GETKEY
SUB '0' ; ASCII -> BINARY
CP FDCCNT + 1 ; TOO HIGH?
JR NC,FDCSEL1 ; IF SO, TRY AGAIN
;
OR A ; SET FLAGS
JR NZ,FDCSEL2 ; NOT ZERO, KEEP GOING
OR 0FFH ; SET NZ FOR EXIT REQUEST
RET ; AND RETURN
;
FDCSEL2:
; SAVE SELECTED FDC IDENTIFIER
DEC A ; CONVERT TO ZERO-BASED FDC ID
LD (FDCID),A ; RECORD THE FDC ID
RLCA ; TIMES 4
RLCA ; ... FOR 4 BYTE ENTRIES
LD HL,FDCTBL ; POINT TO FDC INSTANCE TABLE
CALL ADDHLA ; OFFSET TO DESRIED ENTRY, A TRASHED
LD E,(HL) ; LOAD LABEL PTR INTO DE
INC HL ; ...
LD D,(HL) ; ...
LD (FDCLBL),DE ; SAVE LABEL PTR
INC HL ; BUMP TO CFG POINTER
LD E,(HL) ; LOAD CFG PTR INTO DE
INC HL ; ...
LD D,(HL) ; ...
LD (FDCCFG),DE ; SAVE CFG PTR
LD IY,(FDCCFG) ; AND INIT A WORKING COPY
LD A,(IY+CFG_MODE) ; GET MODE BITMAP BYTE
LD (FDCBM),A ; SAVE IT TO ACTIVE WORKING COPY
;
LD DE,(FDCLBL) ; GET LABEL POINTER
CALL WRITESTR ; AND DISPLAY IT
;
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
; TABLE OF FDC CONTROLLERS
;
FDCTBL: ; LABEL CONFIG DATA
; ----- -----------
.DW STR_DIO, CFG_DIO
.DW STR_DIO3, CFG_DIO3
.DW STR_ZETA, CFG_ZETA
.DW STR_ZETA2, CFG_ZETA2
.DW STR_DIDE, CFG_DIDE
.DW STR_N8, CFG_N8
.DW STR_RCSMC, CFG_RCSMC
.DW STR_RCWDC, CFG_RCWDC
.DW STR_SMZ80, CFG_SMZ80
FDCCNT .EQU ($-FDCTBL)/4 ; FD CONTROLLER COUNT
;
; FDC LABEL STRINGS
;
STR_DIO .TEXT "DISKIO$"
STR_DIO3 .TEXT "DISKIO3$"
STR_ZETA .TEXT "ZETA$"
STR_ZETA2 .TEXT "ZETA2$"
STR_DIDE .TEXT "D-IDE$"
STR_N8 .TEXT "N8$"
STR_RCSMC .TEXT "RC-SMC$"
STR_RCWDC .TEXT "RC-WDC$"
STR_SMZ80 .TEXT "SMZ80$"
;
; FDC CONFIGURATION BLOCKS
;
CFG_MSR .EQU 0
CFG_DATA .EQU 1
CFG_DIR .EQU 2
CFG_DOR .EQU 3
CFG_DCR .EQU 4
CFG_DACK .EQU 5
CFG_TC .EQU 6
CFG_DMA .EQU 7
CFG_MODE .EQU 8
;
CFG_DIO:
.DB 036H ; FDC MAIN STATUS REGISTER
.DB 037H ; FDC DATA PORT
.DB 038H ; DATA INPUT REGISTER
.DB 03AH ; DIGITAL OUTPUT REGISTER (LATCH)
.DB 0FFH ; DCR
.DB 0FFH ; DACK
.DB 0FFH ; TERMINAL COUNT (W/ DACK)
.DB 03CH ; PSEUDO DMA DATA PORT
.DB _DIO ; MODE=
CFG_DIO3:
.DB 036H ; FDC MAIN STATUS REGISTER
.DB 037H ; FDC DATA PORT
.DB 038H ; DATA INPUT REGISTER
.DB 03AH ; DIGITAL OUTPUT REGISTER (LATCH)
.DB 0FFH ; DCR
.DB 0FFH ; DACK
.DB 0FFH ; TERMINAL COUNT (W/ DACK)
.DB 03CH ; PSEUDO DMA DATA PORT
.DB _DIO3 ; MODE=
CFG_ZETA:
.DB 036H ; FDC MAIN STATUS REGISTER
.DB 037H ; FDC DATA PORT
.DB 038H ; DATA INPUT REGISTER
.DB 03AH ; DIGITAL OUTPUT REGISTER (LATCH)
.DB 0FFH ; DCR
.DB 0FFH ; DACK
.DB 0FFH ; TERMINAL COUNT (W/ DACK)
.DB 03CH ; PSEUDO DMA DATA PORT
.DB _ZETA ; MODE=
;
CFG_ZETA2:
.DB 030H ; FDC MAIN STATUS REGISTER
.DB 031H ; FDC DATA PORT
.DB 0FFH ; DATA INPUT REGISTER
.DB 038H ; DIGITAL OUTPUT REGISTER
.DB 028H ; CONFIGURATION CONTROL REGISTER
.DB 0FFH ; DACK
.DB 038H ; TERMINAL COUNT (W/ DACK)
.DB 0FFH ; NOT USED BY ZETA SBC V2
.DB _PCAT ; MODE=
;
CFG_DIDE:
.DB 02AH ; FDC MAIN STATUS REGISTER
.DB 02BH ; FDC DATA PORT
.DB 0FFH ; DATA INPUT REGISTER
.DB 02CH ; DOR
.DB 02DH ; DCR
.DB 03CH ; DACK
.DB 03DH ; TERMINAL COUNT (W/ DACK)
.DB 0FFH ; NOT USED BY DIDE
.DB _PCAT ; MODE=
;
CFG_N8:
.DB 08CH ; FDC MAIN STATUS REGISTER
.DB 08DH ; FDC DATA PORT
.DB 0FFH ; DATA INPUT REGISTER
.DB 092H ; DOR
.DB 091H ; DCR
.DB 090H ; DACK
.DB 093H ; TERMINAL COUNT (W/ DACK)
.DB 0FFH ; NOT USED BY N8
.DB _PCAT ; MODE=
;
CFG_RCSMC:
.DB 050H ; FDC MAIN STATUS REGISTER
.DB 051H ; FDC DATA PORT
.DB 0FFH ; DATA INPUT REGISTER
.DB 058H ; DIGITAL OUTPUT REGISTER (LATCH)
.DB 0FFH ; DCR
.DB 0FFH ; DACK
.DB 0FFH ; TERMINAL COUNT (W/ DACK)
.DB 0FFH ; PSEUDO DMA DATA PORT
.DB _RCSMC ; MODE=
;
CFG_RCWDC:
.DB 050H ; FDC MAIN STATUS REGISTER
.DB 051H ; FDC DATA PORT
.DB 0FFH ; DATA INPUT REGISTER
.DB 058H ; DIGITAL OUTPUT REGISTER (LATCH)
.DB 048H ; DCR
.DB 0FFH ; DACK
.DB 058H ; TERMINAL COUNT (W/ DACK)
.DB 0FFH ; PSEUDO DMA DATA PORT
.DB _PCAT ; MODE=
;
CFG_SMZ80:
.DB 044H ; FDC MAIN STATUS REGISTER
.DB 045H ; FDC DATA PORT
.DB 0FFH ; DATA INPUT REGISTER
.DB 042H ; DIGITAL OUTPUT REGISTER (LATCH)
.DB 047H ; DCR
.DB 0FFH ; DACK
.DB 0FFH ; TERMINAL COUNT (W/ DACK)
.DB 0FFH ; PSEUDO DMA DATA PORT
.DB _PCAT ; MODE=
;
FDCID .DB 0 ; FDC IDENTIFIER (0 INDEXED)
FDCBM .DB 0 ; FDC ID BITMAP
FDCLBL .DW 0 ; POINTER TO ACTIVE FDC LABEL STRING
FDCCFG .DW 0 ; POINTER TO ACTIVE CFG DATA
;
FSS_MENU:
.TEXT "\r\n"
.TEXT "SELECT FLOPPY DISK CONTROLLER:\r\n"
.TEXT " (0) Exit\r\n"
.TEXT " (1) Disk IO ECB Board\r\n"
.TEXT " (2) Disk IO 3 ECB Board\r\n"
.TEXT " (3) Zeta SBC Onboard FDC\r\n"
.TEXT " (4) Zeta 2 SBC Onboard FDC\r\n"
.TEXT " (5) Dual IDE ECB Board\r\n"
.TEXT " (6) N8 Onboard FDC\r\n"
.TEXT " (7) RC2014 SMC (SMB)\r\n"
.TEXT " (8) RC2014 WDC (SMB)\r\n"
.TEXT " (9) SmallZ80 Expansion\r\n"
.TEXT "=== OPTION ===> $\r\n"
;
;===============================================================================
; MAIN MENU
;===============================================================================
;
; MAIN MENU DATA
;
MM_TABLE .DB 'S' \ .DW MMS_SETUP, MM_SETUP
MM_ENTSIZ .EQU $ - MM_TABLE
.DB 'R' \ .DW MMS_READ, MM_READ
.DB 'W' \ .DW MMS_WRITE, MM_WRITE
.DB 'F' \ .DW MMS_FORMAT, MM_FORMAT
.DB 'V' \ .DW MMS_VERIFY, MM_VERIFY
.DB 'I' \ .DW MMS_INITBUF, MM_INITBUF
.DB 'D' \ .DW MMS_DUMPBUF, MM_DUMPBUF
.DB 'C' \ .DW MMS_FDCMENU, MM_FDCMENU
.DB 'X' \ .DW MMS_EXIT, 0000H
MM_COUNT .EQU (($ - MM_TABLE) / MM_ENTSIZ) ; # ENTRIES IN TABLE
MM_INFO: .DW MM_DRAW
.DW MM_TABLE
.DB MM_ENTSIZ
.DB MM_COUNT
;
; MAIN MENU DISPLAY STRINGS
;
STR_MAINMENU:
.TEXT "=======================<< FDU MAIN MENU >>======================\r\n"
; .TEXT "(S)ETUP: UNIT=XX MEDIA=XXXXXX MODE=XXXXXXXXXX TRACE=XX\r\n"
.TEXT "(S)ETUP: UNIT="
MV_UNIT .TEXT "XX"
.TEXT " MEDIA="
MV_MED .TEXT "XXXXXX"
.TEXT " MODE="
MV_MODE .TEXT "XXXXXXXXXX"
.TEXT " TRACE="
MV_TRC .TEXT "XX"
.TEXT "\r\n"
.TEXT "----------------------------------------------------------------\r\n"
.TEXT "(R)EAD (W)RITE (F)ORMAT (V)ERIFY\r\n"
.TEXT "(I)NIT BUFFER (D)UMP BUFFER FDC (C)MDS E(X)IT\r\n"
.TEXT "=== OPTION ===> $\r\n"
;
MMS_SETUP: .TEXT "SETUP$"
MMS_READ: .TEXT "READ$"
MMS_WRITE: .TEXT "WRITE$"
MMS_FORMAT: .TEXT "FORMAT$"
MMS_VERIFY: .TEXT "VERIFY$"
MMS_INITBUF: .TEXT "INITIALIZE BUFFER$"
MMS_DUMPBUF: .TEXT "DUMP BUFFER$"
MMS_FDCMENU: .TEXT "FDC MENU$"
MMS_EXIT: .TEXT "EXIT$"
;
; MAIN MENU DRAW PROCEDURE
;
MM_DRAW:
CALL NEWLINE
CALL NEWLINE
; UPDATE FDC LABEL
LD DE,STR_MAINMENU + 5
LD A,' '
LD (DE),A
INC DE
LD HL,(FDCLBL)
CALL COPYSTR
LD A,' '
LD (DE),A
; UPDATE UNIT
LD DE,MV_UNIT
LD A,(DCD_UNIT)
CALL HEXSTRBYTE
; UPDATE MEDIA
LD DE,(MDB_LABEL)
LD HL,MV_MED
CALL STRCPY
; UPDATE MODE
LD A,(DCD_MD)
RLA
LD E,A
LD D,0
LD HL,MDT
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
EX DE,HL
LD E,(HL)
INC HL
LD D,(HL)
LD HL,MV_MODE
CALL STRCPY
; UPDATE TRACE
LD DE,MV_TRC
LD A,(DCD_TRACE)
CALL HEXSTRBYTE
; DISPLAY THE MENU
LD DE,STR_MAINMENU
CALL WRITESTR
RET
;
; MAIN MENU FUNCTIONS
;
MM_SETUP:
CALL MM_GETSETUP
CALL DIO_SETMEDIA
RET
MM_READ:
LD A,DOP_READ
LD (DCD_DOP),A
CALL MM_GETTGT
CALL MM_GETTGTPARMS
CALL MMOP_PROC
RET
MM_WRITE:
LD A,DOP_WRITE
LD (DCD_DOP),A
CALL MM_GETTGT
CALL MM_GETTGTPARMS
CALL MMOP_PROC
RET
MM_FORMAT:
LD A,DOP_FORMAT
LD (DCD_DOP),A
CALL MM_GETTGT
CALL MM_GETTGTPARMS
CALL MM_GETINTRLV
CALL MMOP_PROC
RET
MM_VERIFY:
LD A,DOP_VERIFY
LD (DCD_DOP),A
CALL MM_GETTGT
CALL MM_GETTGTPARMS
CALL MM_SETVFYBUF
CALL MMOP_PROC
RET
MM_INITBUF:
CALL PC_SPACE
LD DE,MMPS_IBOPT
CALL WRITESTR
MM_IBKEY:
CALL GETKEYUC
CP 'P' ; PATTERN
JP Z,MM_IBPAT
CP 'F' ; FILL
JP Z,MM_IBFILL
JP MM_IBKEY
MM_IBPAT:
LD DE,MMBS_PATTERN
CALL PC_SPACE
CALL WRITESTR
CALL MM_GETPATTERN
LD HL,BUFFER
LD DE,BUFSIZ
LD A,(DCD_PATTERN)
LD B,A
CALL PAT_BUFFER
RET
MM_IBFILL:
LD DE,MMBS_FILL
CALL WRITESTR
CALL PC_SPACE
CALL MM_GETFILL
LD HL,BUFFER
LD DE,BUFSIZ
LD A,(DCD_FILL)
LD B,A
CALL FILL_BUFFER
RET
MM_DUMPBUF:
LD HL,BUFFER ; SET ADDRESS TO DUMP
LD DE,BUFFER ; SET END ADDRESS
INC D ;
INC D ;
CALL DUMP_BUFFER ; DUMP BUFFER TO CONSOLE
RET
MM_FDCMENU:
CALL DIO_INIT
CALL FDCMENU
CALL DIO_TERM
RET
;
; MAIN MENU SUPPORT FUNCTIONS
;
MM_GETSETUP:
LD DE,MMP_UNIT
LD HL,DCD_UNIT
LD BC,0003H
CALL GETHEXBYTERNG
CALL MM_MEDIALIST
LD DE,MMP_MEDIA
LD HL,DCD_MT
LD B,0
LD A,MIT_ENTCNT
DEC A
LD C,A
CALL GETHEXBYTERNG
MM_GETMODE:
CALL MM_MODELIST
LD DE,MMP_MODE
LD HL,DCD_MD
LD B,0
LD A,MDT_ENTCNT
DEC A
LD C,A
CALL GETHEXBYTERNG
; VALIDATE MODE AGAINST CURRENT FDC
INC A ; PREP VALUE FOR LOOP
LD B,A ; PUT IN LOOP COUNTER
XOR A ; CLEAR A
SCF ; SET CF
MM_GETMODE1:
RLA ; ROTATE BIT ONE POSITION
DJNZ MM_GETMODE1 ; UNTIL BIT SET FOR MODE SPECIFIED
PUSH AF ; SAVE IT
LD A,(FDCID) ; A := FDC ID
LD HL,MD_MAP ; HL := START OF MODE MAP
CALL ADDHLA ; OFFSET TO CORRECT ENTRY FOR FDC
POP AF ; RECOVER MODE BIT VALUE
AND (HL) ; MASK WITH MODE MAP OF FDC
JR NZ,MM_TRACE ; NON-ZERO IS A MODE MATCH FOR FDC, CONTINUE
LD DE,MM_MODEERR ; INVALID MODE FOR FDC ERROR MESSAGE
CALL WRITESTR
JR MM_GETMODE
MM_TRACE:
LD DE,MMP_TRACE
LD HL,DCD_TRACE
LD BC,0001H
CALL GETHEXBYTERNG
RET
MM_GETFILL:
LD DE,MMP_FILL
LD HL,DCD_FILL
CALL GETHEXBYTE
RET
MM_GETPATTERN:
LD DE,MMP_PATTERN
LD HL,DCD_PATTERN
CALL GETHEXBYTE
RET
MM_GETTGT:
CALL PC_SPACE
LD A,(DCD_DOP)
LD DE,MMPS_TGTF
CP DOP_FORMAT
JP Z,MM_GETTGT0
LD DE,MMPS_TGTRW
MM_GETTGT0:
CALL WRITESTR
MM_GETTGT1:
CALL GETKEYUC
LD B,MMT_TRACK
LD DE,MMTS_TRACK
CP 'T'
JP Z,MM_GETTGT3
LD B,MMT_DISK
LD DE,MMTS_DISK
CP 'D'
JP Z,MM_GETTGT3
; FORMAT CANNOT DO THE NEXT ONES (GETTGT2 CHECKS FOR THIS)
LD B,MMT_SECTOR
LD DE,MMTS_SECTOR
CP 'S'
JP Z,MM_GETTGT2
LD B,MMT_RANDOM
LD DE,MMTS_RANDOM
CP 'R'
JP Z,MM_GETTGT2
JP MM_GETTGT1
MM_GETTGT2: ; PREVENT FORMAT FROM USING SECTOR OR RANDOM FUNCTIONS
LD A,(DCD_DOP)
CP DOP_FORMAT
JP Z,MM_GETTGT1
MM_GETTGT3:
LD A,B
LD (MMD_TGT),A
CALL WRITESTR
RET
MM_GETTGTPARMS:
LD A,(MMD_TGT)
CP MMT_DISK
JP Z,MM_GETTGTPARMS1
CP MMT_RANDOM
JP Z,MM_GETTGTPARMS1
CALL MM_GETTRACK
CALL MM_GETHEAD
LD A,(MMD_TGT)
CP MMT_TRACK
JP Z,MM_GETTGTPARMS1
CALL MM_GETSECTOR
JP MM_GETTGTPARMSX
MM_GETTGTPARMS1:
LD A,1 ; FIX UP THE SECTOR VALUE TO BE 1 IF NOT SINGLE SECTOR MODE
LD (DCD_SECTOR),A
MM_GETTGTPARMSX:
RET
MM_GETTRACK:
LD DE,MMP_TRACK
LD HL,DCD_TRACK
LD B,0
LD A,(MDB_NUMCYL)
DEC A
LD C,A
CALL GETHEXBYTERNG
RET
MM_GETHEAD:
LD DE,MMP_HEAD
LD HL,DCD_HEAD
LD B,0
LD A,(MDB_NUMHD)
DEC A
LD C,A
CALL GETHEXBYTERNG
RET
MM_GETSECTOR:
LD DE,MMP_SECTOR
LD HL,DCD_SECTOR
LD A,(MDB_SOT)
LD B,A
LD A,(MDB_EOT)
LD C,A
CALL GETHEXBYTERNG
RET
MM_GETINTRLV:
LD DE,MMP_INTRLV
LD HL,DCD_INTRLV
LD B,1
LD A,(MDB_NUMSEC)
LD C,A
CALL GETHEXBYTERNG
RET
MM_MEDIALIST:
LD HL,MIT
LD B,MIT_ENTCNT
LD C,0
MM_MEDIALISTLOOP:
CALL NEWLINE
LD A,C
CALL PRTHEXBYTE
CALL PC_COLON
CALL PC_SPACE
PUSH HL
LD A,(HL) ; HL = ENTRY VALUE
INC HL ; "
LD H,(HL) ; "
LD L,A ; "
INC HL
INC HL
LD A,(HL) ; HL = ENTRY VALUE
INC HL ; "
LD D,(HL) ; "
LD E,A ; "
CALL WRITESTR
POP HL
INC HL
INC HL
INC C
DJNZ MM_MEDIALISTLOOP
RET
MM_MODELIST:
LD HL,MDT
LD B,MDT_ENTCNT
LD C,0
MM_MODELISTLOOP:
CALL NEWLINE
LD A,C
CALL PRTHEXBYTE
CALL PC_COLON
CALL PC_SPACE
PUSH HL
LD A,(HL) ; HL = ENTRY VALUE
INC HL ; "
LD H,(HL) ; "
LD L,A ; "
INC HL
INC HL
LD A,(HL) ; HL = ENTRY VALUE
INC HL ; "
LD D,(HL) ; "
LD E,A ; "
CALL WRITESTR
POP HL
INC HL
INC HL
INC C
DJNZ MM_MODELISTLOOP
RET
MM_SETVFYBUF:
LD HL,BUFFER
LD DE,VFYBUF
LD BC,BUFSIZ
LDIR
RET
;
; MAIN MENU PROMPTS
;
MMP_FILL .TEXT "FILL VALUE$"
MMP_PATTERN .TEXT "PATTERN START VALUE$"
MMP_UNIT .TEXT "UNIT$"
MMP_TRACE .TEXT "TRACE LEVEL$"
MMP_TRACK .TEXT "TRACK$"
MMP_HEAD .TEXT "HEAD$"
MMP_SECTOR .TEXT "SECTOR$"
MMP_MEDIA .TEXT "MEDIA$"
MMP_MODE .TEXT "MODE$"
MMP_INTRLV .TEXT "INTERLEAVE$"
;
; MAIN MENU TARGET
;
MMT_SECTOR .EQU 'S' ; PERFORM OPERATION ON ONE SECTOR
MMT_TRACK .EQU 'T' ; PERFORM OPERATION ON ONE TRACK
MMT_DISK .EQU 'D' ; PERFORM OPERATION ON ENTIRE DISK
MMT_RANDOM .EQU 'R' ; PERFORM OPERATION ON RANDOM SECTORS
;
; MAIN MENU TARGET STRINGS
;
MMTS_SECTOR .TEXT "SECTOR$"
MMTS_TRACK .TEXT "TRACK$"
MMTS_DISK .TEXT "DISK$"
MMTS_RANDOM .TEXT "RANDOM$"
;
; MAIN MENU DATA
;
MMD_TGT .DB MMT_SECTOR
;
; MAIN MENU PROMPT STRINGS
;
MMPS_TGTRW .TEXT "(S)ECTOR, (T)RACK, (D)ISK, (R)ANDOM ===> $"
MMPS_TGTF .TEXT "(T)RACK, (D)ISK ===> $"
MMPS_IBOPT .TEXT "(P)ATTERN, (F)ILL ===> $"
;
; MAIN MENU BUFFER OPTIONS
;
MMBS_PATTERN .TEXT "PATTERN$"
MMBS_FILL .TEXT "FILL$"
;
;
;
MM_MODEERR .TEXT "\r\n\r\n*** SELECTED MODE NOT SUPPORTED ON HARDWARE ***\r\n$"
;
;________________________________________________________________________________________________________________________________
;
; MAIN MENU OPERATIONS
;________________________________________________________________________________________________________________________________
;
MMOP_PROC:
CALL NEWLINE
CALL NEWLINE
LD A,FALSE
LD (DCD_ABORT),A
CALL DIO_INIT
LD A,(MMD_TGT)
CP MMT_DISK
JP Z,MMOP_PROCDISK
CP MMT_TRACK
JP Z,MMOP_PROCTRK
CP MMT_SECTOR
JP Z,MMOP_PROCSEC
CP MMT_RANDOM
JP Z,MMOP_PROCRND
JP MMOP_PROCX
MMOP_PROCDISK:
CALL MMOP_DISK
JP MMOP_PROCX
MMOP_PROCTRK:
CALL MMOP_TRACK
JP MMOP_PROCX
MMOP_PROCSEC:
CALL MMOP_SECTOR
JP MMOP_PROCX
MMOP_PROCRND:
CALL MMOP_RANDOM
JP MMOP_PROCX
MMOP_PROCX:
CALL DIO_TERM
RET
MMOP_DISK:
LD A,0
LD (DCD_TRACK),A
LD (DCD_HEAD),A
MMOP_DISK1:
LD A,(DCD_ABORT)
CP TRUE
JP Z,MMOP_DISKX
CALL MMOP_TRACK
LD A,(MDB_NUMHD)
LD C,A
LD A,(DCD_HEAD) ; INC HEAD
INC A
LD (DCD_HEAD),A
CP C ; # OF HEADS
JP NZ,MMOP_DISK1 ; LOOP IF LESS THAN # OF HEADS
LD A,0 ; RESET HEAD
LD (DCD_HEAD),A ; AND FALL THROUGH TO INC TRACK
LD A,(MDB_NUMCYL)
LD C,A
LD A,(DCD_TRACK) ; INC TRACK
INC A
LD (DCD_TRACK),A
CP C ; # OF TRACKS
JP NZ,MMOP_DISK1
MMOP_DISKX:
LD A,0 ; RESET TRACK TO A VALID VALUE
LD (DCD_TRACK),A
RET
MMOP_TRACK:
LD A,(DCD_DOP) ; SPECIAL CASE, FORMAT IS TRACK-AT-A-TIME
CP DOP_FORMAT
JP Z,MMOP_TRACKFMT
LD A,(MDB_SOT)
LD (DCD_SECTOR),A
MMOP_TRACK1:
LD A,(DCD_ABORT)
CP TRUE
JP Z,MMOP_TRACKX
CALL DIO_RUN
LD A,(MDB_EOT)
LD C,A
INC C ; ONE MORE THAN EOT
LD A,(DCD_SECTOR) ; INC SECTOR
INC A
LD (DCD_SECTOR),A
CP C ; > MAX SECTOR?
JP NZ,MMOP_TRACK1
JP MMOP_TRACKX
MMOP_TRACKFMT:
CALL DIO_RUN
JP MMOP_TRACKX
MMOP_TRACKX:
LD A,(MDB_SOT) ; RESET SECTOR TO A VALID VALUE
LD (DCD_SECTOR),A
RET
MMOP_SECTOR:
CALL DIO_RUN
RET
MMOP_RANDOM:
LD B,20H ; READ 20H SECTORS RANDOMLY
MMOP_RANDOM0:
LD A,(DCD_ABORT)
CP TRUE
JP Z,MMOP_RANDOMX
PUSH BC
MMOP_RANDOM1: ; GENERATE RANDOM TRACK
LD A,(MDB_NUMCYL)
LD C,A
CALL RNDBYTE
AND 7FH ; USE 7 BITS FOR UP TO 128 TRACKS
CP C ; MAX TRACK IS 4F + 1 = 50H
JP P,MMOP_RANDOM1
LD (DCD_TRACK),A
; GENERATE RANDOM HEAD
CALL RNDBYTE
AND 01H ; JUST USE LOW ORDER BIT
LD (DCD_HEAD),A
MMOP_RANDOM2: ; GENERATE RANDOM SECTOR
LD A,(MDB_EOT)
LD C,A
INC C ; ONE MORE THEN MAX SECTOR
CALL RNDBYTE
AND 1FH ; USE 5 BITS FOR UP TO 32 SECTORS
CP C ; MAX SECTOR NUM IS 9 + 1 = 0AH
JP P,MMOP_RANDOM2
CP 00H ; SECTOR NUM STARTS AT 1, DON'T ALLOW ZERO
JP Z,MMOP_RANDOM2
LD (DCD_SECTOR),A
CALL DIO_RUN
POP BC
DJNZ MMOP_RANDOM0
MMOP_RANDOMX:
RET
;
;===============================================================================
; DISK INPUT/OUTPUT SERVICES, DEVICE INDEPENDENT (LOGICAL) ACCESS TO STORAGE
; TRANSLATES BETWEEN LOGICAL AND PHYSICAL DEVICE OPERATIONS
;===============================================================================
;
;
STR_CONTINUE:
.TEXT "CONTINUE? (A)BORT, (R)ETRY, (I)GNORE ===> $"
;
DIO_SETMEDIA:
; INITIZLIZE THE MEDIA DESCRIPTION BLOCK
; FILL IN MDB BASED ON USER SELECTION
LD A,(DCD_MT) ; A = MEDIA ID (OFFSET IN MEDIA INDEX TABLE)
ADD A,A ; * 2 (2 BYTES PER ENTRY)
LD H,0 ; MOVE IT TO HL
LD L,A ; "
LD DE,MIT ; DE = START OF MEDIA INDEX TABLE
ADD HL,DE ; ADD HL TO DE, HL NOW POINTS TO DESIRED ENTRY
LD A,(HL) ; HL = ENTRY VALUE
INC HL ; "
LD H,(HL) ; "
LD L,A ; "
LD DE,MDB ; HL = SOURCE, DE = DESTINATION
LD BC,MDB_LEN ; BC = BYTES TO COPY
LDIR ; COPY ENTRY TO FCD
LD A,FALSE ; SET DRIVE READY TO FALSE!
LD (DCD_DSKRDY),A ; "
RET
;
DIO_INIT:
; UPDATE DRIVE SELECTTION
LD A,(FCD_DS) ; GET THE CURRENT DRIVE SELECTION
LD B,A ; SAVE IN B
LD A,(DCD_UNIT) ; GET THE NEW DRIVE SELECTION
CP B ; CHANGED?
; WE NEED TO SET DRIVE STATUS TO NOT READY IFF IT CHANGED
JP Z,DIO_INIT1 ; DO NOT RESET DRIVE STATUS!
LD (FCD_DS),A ; UPDATE FCD_DS TO NEW VALUE
LD A,FALSE ; SET DRIVE READY TO FALSE!
LD (DCD_DSKRDY),A ; "
DIO_INIT1:
; INITIALIZE TRACE SETTING
LD A,(DCD_TRACE)
LD (FCD_TRACE),A
LD HL,MDB_FCD ; HL = SOURCE
LD DE,FCD ; DE = DESTINATION
LD BC,FCD_LEN ; BC = BYTES TO COPY
LDIR ; BYTES COPY FROM MDB TO FCD
LD A,0 ; ASSUME DMA (NON-DMA = 0)
LD (FCD_ND),A
LD A,(DCD_MD)
CP MD_DRQWAIT
JP Z,DIO_INIT2 ; YES, DMA NEEDED, DO IT
LD A,1 ; SET TO NON-DMA (NDMA = 1)
LD (FCD_ND),A
DIO_INIT2:
CALL FC_INIT
CALL FC_MOTORON
RET
DIO_TERM:
CALL FC_MOTOROFF
RET
;
; DIO_CLRDSKCHG
;
DIO_CLRDSKCHG:
; PROCESS ANY PENDING DISK CHANGE NOTIFICATIONS
LD B,5
DIO_CLRDSKCHG1:
PUSH BC
CALL FC_SENSEINT
POP BC
CALL DIO_CHKFC
CP FRC_DSKCHG
RET NZ
DJNZ DIO_CLRDSKCHG1
RET
;
; DIO_WTSEEK
;
; WAIT FOR PENDING SEEK OPERATION TO COMPLETE BY POLLING SENSEINT
; AND WAITING FOR ABTERM OR OK.
;
DIO_WTSEEK:
LD BC,1000H
; LD BC,20H ; *DEBUG*
; LD BC,1H ; *DEBUG*
DIO_WTSEEKLOOP:
PUSH BC
CALL FC_SENSEINT
POP BC
LD A,(FST_RC) ; CHECK RC
CP FRC_ABTERM ; ABTERM = DONE
RET Z
CP FRC_OK ; OK = DONE
RET Z
DEC BC ; CHECK LOOP COUNTER IN BC
LD A,B ; "
OR C ; "
JP NZ,DIO_WTSEEKLOOP ; LOOP UNTIL COUNTER EXHAUSTED
DIO_DRIVERESET:
CALL NEWLINE
CALL NEWLINE
LD DE,STR_DRIVERESET
CALL WRITESTR
CALL FC_RESETFDC
CALL DIO_CLRDSKCHG
CALL DIO_CHKFC
CP FRC_INVCMD ; INVALID COMMAND IS CORRECT RESPONSE HERE
JP NZ,DIO_NORESP
; CONTINUE RESET SEQUENCE WITH 'SPECIFY' COMMAND
CALL FC_SPECIFY
CALL DIO_CHKFC
JP NZ,DIO_NORESP
CALL FC_RECAL
CALL DIO_CHKFC
JP NZ,DIO_NORESP
; CAREFUL... FIRST RECAL MAY FAIL TO REACH TRACK 0
; SO WE ALLOW FOR A SECOND TRY IN CASE OF A FAILURE
CALL DIO_WTSEEK
CALL DIO_CHKFC
JP Z,DIO_DRIVERESET1
; SECOND TRY, ONLY IF NEEDED
CALL FC_RECAL
CALL DIO_CHKFC
JP NZ,DIO_NORESP
CALL DIO_WTSEEK
CALL DIO_CHKFC
JP NZ,DIO_NORESP
JP DIO_DRIVERESET1
DIO_NORESP:
CALL NEWLINE
LD DE,STR_NORESP
CALL WRITESTR
RET
DIO_DRIVERESET1:
LD A,TRUE
LD (DCD_DSKRDY),A
LD A,0
LD (DCD_CURTRK),A
RET
DIO_CHKFC:
LD A,(FST_RC)
OR A
RET
DIO_RUN:
LD A,(DCD_DSKRDY)
CP TRUE
JP Z,DIO_RUN0
CALL DIO_DRIVERESET
LD A,(DCD_DSKRDY)
CP TRUE
JP NZ,DIO_RUNERR ; DRIVERESET FAILED!
DIO_RUN0:
CALL DIO_PROGRESS
; COPY PARMS OVER
LD A,(DCD_UNIT)
LD (FCD_DS),A
LD A,(DCD_TRACE)
LD (FCD_TRACE),A
LD A,(DCD_TRACK)
LD (FCD_C),A
LD A,(DCD_HEAD)
LD (FCD_H),A
LD A,(DCD_SECTOR)
LD (FCD_R),A
LD A,(DCD_INTRLV)
LD (FCD_X),A
; FIX: COMBINE WITH DCD_TRACK SETUP ABOVE?
LD A,(DCD_CURTRK)
LD B,A
LD A,(DCD_TRACK)
CP B
JP Z,DIO_RUN1 ; SKIP SEEK IF POSSIBLE
; SEEK AND WAIT FOR COMPLETE
CALL FC_SEEK
CALL DIO_CHKFC
JP NZ,DIO_RUNERR
CALL DIO_WTSEEK
CALL DIO_CHKFC
JP NZ,DIO_RUNERR
; RECORD CURRENT TRACK
; FIX: SHOULD NOT ASSUME SEEK REQUEST SUCCEEDED (FC_READID?)
LD A,(DCD_TRACK)
LD (DCD_CURTRK),A
DIO_RUN1:
LD A,(DCD_DOP)
CP DOP_READ
JP Z,DIO_RUNREAD
CP DOP_WRITE
JP Z,DIO_RUNWRITE
CP DOP_FORMAT
JP Z,DIO_RUNFORMAT
CP DOP_VERIFY
JP Z,DIO_RUNVERIFY
JP DIO_RUNX
DIO_RUNREAD:
CALL FC_READ
JP DIO_RUNCHK
DIO_RUNWRITE:
CALL FC_WRITE
JP DIO_RUNCHK
DIO_RUNFORMAT:
CALL FC_FMTTRK
JP DIO_RUNCHK
DIO_RUNVERIFY:
CALL FC_READ
JP DIO_RUNCHK
DIO_RUNCHK:
LD A,(FST_RC)
OR A
CP FRC_OK
JP NZ,DIO_RUNERR ; HANDLE I/O ERROR
LD A,(DCD_DOP)
CP DOP_VERIFY
JP NZ,DIO_RUNX ; NOT VERIFY, ALL DONE
CALL DIO_VERIFY
LD A,(FST_RC)
OR A
CP FRC_OK
JP NZ,DIO_RUNERR ; HANDLE VERIFY ERROR
JP DIO_RUNX
DIO_RUNERR:
LD A,FALSE
LD (DCD_DSKRDY),A
CALL FC_RESETFDC ; FIX...
CALL NEWLINE
LD DE,STR_CONTINUE ; ABORT/RETRY/IGNORE PROMPT
CALL WRITESTR
DIO_RUNERR1:
CALL GETKEYUC
CP 'A'
JP Z,DIO_ABORT
CP 'R'
JP Z,DIO_RETRY
CP 'I'
JP Z,DIO_IGNORE
JP DIO_RUNERR1
DIO_ABORT:
LD DE,DIOCS_ABORT
CALL WRITESTR
LD A,TRUE
LD (DCD_ABORT),A
JP DIO_RUNX
DIO_RETRY:
LD DE,DIOCS_RETRY
CALL WRITESTR
JP DIO_RUN
DIO_IGNORE:
LD DE,DIOCS_IGNORE
CALL WRITESTR
JP DIO_RUNX
DIO_RUNX:
RET
DIO_PROGRESS:
LD A,(NEWLINE_USED)
OR A
JP Z,DIO_PROGRESS1
CALL NEWLINE
LD A,0
LD (NEWLINE_USED),A
DIO_PROGRESS1:
CALL PC_CR
LD DE,STR_PROGRESS
CALL WRITESTR
CALL PC_COLON
CALL PC_SPACE
LD DE,DPL_TRACK
CALL WRITESTR
CALL PC_EQUAL
LD A,(DCD_TRACK)
CALL PRTHEXBYTE
CALL PC_SPACE
LD DE,DPL_HEAD
CALL WRITESTR
CALL PC_EQUAL
LD A,(DCD_HEAD)
CALL PRTHEXBYTE
CALL PC_SPACE
LD DE,DPL_SECTOR
CALL WRITESTR
CALL PC_EQUAL
LD A,(DCD_SECTOR)
CALL PRTHEXBYTE
RET
DIO_VERIFY:
LD HL,BUFFER
LD DE,VFYBUF
LD BC,BUFSIZ
DIO_VERIFY1:
LD A,(DE)
CP (HL)
JP NZ,DIO_VERIFY2
INC DE
INC HL
DEC BC
LD A,B
OR C
JP NZ,DIO_VERIFY1
RET
DIO_VERIFY2:
PUSH DE
CALL NEWLINE
LD DE,STR_MISMATCH
CALL WRITESTR
POP DE
LD A,D
SUB VFYBUF >> 8
CALL PRTHEXBYTE
LD A,E
CALL PRTHEXBYTE
LD A,FRC_MISMATCH
LD (FST_RC),A
RET
;
; CONTINUE PROMPT OPTION STRINGS
;
DIOCS_ABORT .TEXT "ABORT$"
DIOCS_RETRY .TEXT "RETRY$"
DIOCS_IGNORE .TEXT "IGNORE$"
;
; DISK PROGRESS LABELS
;
DPL_TRACK .TEXT "TRACK$"
DPL_HEAD .TEXT "HEAD$"
DPL_SECTOR .TEXT "SECTOR$"
;
; DISK OPERATIONS
;
DOP_READ .EQU 0 ; READ OPERATION
DOP_WRITE .EQU 1 ; WRITE OPERATION
DOP_FORMAT .EQU 2 ; FORMAT OPERATION
DOP_VERIFY .EQU 3 ; VERIFY OPERATION
;
; DEVICE CONTROL DATA
;
DCD_FILL .DB 0E5H ; DEFAULT TO E5 (EMPTY DIRECTORY BYTE)
DCD_PATTERN .DB 000H ; DEFAULT TO 00
DCD_TRACE .DB 000H ; TRACE LEVEL
DCD_UNIT .DB 000H ; DEFAULT UNIT = 0
DCD_SECTOR .DB 001H ; DEFAULT SECTOR = 1
DCD_HEAD .DB 000H ; DEFAULT HEAD = 0
DCD_TRACK .DB 000H ; DEFAULT TRACK = 0
DCD_INTRLV .DB 002H ; DEFAULT INTERLEAVE = 2
DCD_DOP .DB DOP_READ ; DEFAULT OP = READ
DCD_MT .DB MT_PC720 ; DEFAULT FLOPPY DEVICE = PC720
DCD_MD .DB MD_POLL ; DEFAULT MODE = POLL
;
; DEVICE CONTROL DATA (PRIVATE)
;
DCD_DSKRDY .DB FALSE ; 0 = NOT RDY, 1 = RDY
DCD_ABORT .DB FALSE ; 0 = CONT, 1 = ABORT
DCD_CURTRK .DB 0FFH ; CURRENT TRACK, FF = UNKNOWN
;
; MODES
;
MD_POLL .EQU 0
MD_INT .EQU 1
MD_INTFAST .EQU 2
MD_INTWAIT .EQU 3
MD_DRQWAIT .EQU 4
;
; MODE MAPPING
; BIT IS SET FOR ALLOWED MODES PER FDC
;
MD_MAP:
.DB %00011111 ; DIO POLL,INT,INTFAST,INTWAIT,DRQWAIT
.DB %00000111 ; DIO3 POLL,INT,INTFAST
.DB %00000111 ; ZETA POLL,INT,INTFAST
.DB %00000001 ; ZETA2 POLL
.DB %00000001 ; DIDE POLL
.DB %00000001 ; N8 POLL
.DB %00000001 ; RCSMC POLL
; .DB %00000001 ; RCWDC POLL
.DB %00000001 ; SMZ80 POLL
;
; MEDIA DESCRIPTION BLOCK
;
MDB:
MDB_LABEL .DW 000H ; ADDRESS OF MEDIA LABEL
MDB_DESC .DW 000H ; ADDRESS OF MEDIA DESCRIPTION
MDB_NUMCYL .DB 000H ; NUMBER OF CYLINDERS
MDB_NUMHD .DB 000H ; NUMBER OF HEADS
MDB_NUMSEC .DB 000H ; NUMBER OF SECTORS
MDB_SOT .DB 000H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
MDB_FCD: ; FLOPPY CONFIGURATION DATA (PUBLIC) MANAGED AS A "BLOCK", MUST MATCH FCB BELOW
MDB_EOT ; END OF TRACK SECTOR (SAME AS SC SINCE SOT ALWAYS 1)
MDB_SC .DB 000H ; SECTOR COUNT
MDB_SECSZ .DW 000H ; SECTOR SIZE IN BYTES
MDB_GPL .DB 000H ; GAP LENGTH (R/W)
MDB_GPLF .DB 000H ; GAP LENGTH (FORMAT)
MDB_SRTHUT .DB 000H ; STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME
MDB_HLT .DB 000H ; HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT
MDB_DORA .DB 000H ; OPERATIONS REGISTER VALUE FOR MEDIA
MDB_DORB .DB 000H ; OPERATIONS REGISTER VALUE FOR MEDIA
MDB_DORC .DB 000H ; OPERATIONS REGISTER VALUE FOR MEDIA
MDB_DORD .DB 000H ; OPERATIONS REGISTER VALUE FOR MEDIA
MDB_DCR .DB 000H ; CONTROL REGISTER VALUE FOR MEDIA
MDB_LEN .EQU $ - MDB
;
MDT: ; MODE TABLE
.DW MTB_POLL
.DW MTB_INT
.DW MTB_INTFAST
.DW MTB_INTWAIT
.DW MTB_DRQWAIT
MDT_ENTCNT .EQU (($ - MDT) / 2)
;
MTB_POLL .DW MTL_POLL ; ADDRESS OF MODE LABEL
.DW MTS_POLL ; ADDRESS OF MODE DESCRIPTION
MTL_POLL .TEXT "POLL $"
MTS_POLL .TEXT "POLLING (RECOMMENDED)$"
;
MTB_INT .DW MTL_INT ; ADDRESS OF MODE LABEL
.DW MTS_INT ; ADDRESS OF MODE DESCRIPTION
MTL_INT .TEXT "INT $"
MTS_INT .TEXT "INTERRUPT (!!! READ MANUAL !!!)$"
;
MTB_INTFAST .DW MTL_INTFAST ; ADDRESS OF MODE LABEL
.DW MTS_INTFAST ; ADDRESS OF MODE DESCRIPTION
MTL_INTFAST .TEXT "INT-FAST $"
MTS_INTFAST .TEXT "FAST INTERRUPT (!!! READ MANUAL !!!)$"
;
MTB_INTWAIT .DW MTL_INTWAIT ; ADDRESS OF MODE LABEL
.DW MTS_INTWAIT ; ADDRESS OF MODE DESCRIPTION
MTL_INTWAIT .TEXT "INT/WAIT $"
MTS_INTWAIT .TEXT "INT/WAIT (!!! READ MANUAL !!!)$"
;
MTB_DRQWAIT .DW MTL_DRQWAIT ; ADDRESS OF MODE LABEL
.DW MTS_DRQWAIT ; ADDRESS OF MODE DESCRIPTION
MTL_DRQWAIT .TEXT "DRQ/WAIT $"
MTS_DRQWAIT .TEXT "DRQ/WAIT (!!! NOT YET IMPLEMENTED!!!)$"
;
; MEDIA TYPE INFORMATION
;
MT_PC720 .EQU 0
MT_PC144 .EQU 1
MT_PC320 .EQU 2
MT_PC360 .EQU 3
MT_PC120 .EQU 4
MT_PC111 .EQU 5
;
MIT: ; MEDIA INDEX TABLE
.DW MDB_PC720
.DW MDB_PC144
.DW MDB_PC320
.DW MDB_PC360
.DW MDB_PC120
.DW MDB_PC111
MIT_ENTCNT .EQU (($ - MIT) / 2)
;
; Specify Command:
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
; |Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
; | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
; | 1 | ----- STEP RATE ----- | -- HEAD UNLOAD TIME - |
; | 2 | ------------ HEAD LOAD TIME ----------- | NDM |
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
;
;
; Step Rate (milliseconds): Head Unload Time (milliseconds): Head Load Time (milliseconds):
; +------+------+------+------+------+ +------+------+------+------+------+ +------+------+------+------+------+
; | | BITRATE | | | BITRATE | | | BITRATE |
; | VAL | 1.0M | 500K | 300K | 250K | | VAL | 1.0M | 500K | 300K | 250K | | VAL | 1.0M | 500K | 300K | 250K |
; +------+------+------+------+------+ +------+------+------+------+------+ +------+------+------+------+------+
; | 0 | 8.0 | 16.0 | 26.7 | 32.0 | | 0 | 128 | 256 | 426 | 512 | | 0 | 128 | 256 | 426 | 512 |
; | 1 | 7.5 | 15.0 | 25.0 | 30.0 | | 1 | 8 | 16 | 26.7 | 32 | | 1 | 1 | 2 | 3.3 | 4 |
; | 2 | 7.0 | 14.0 | 23.3 | 28.0 | | 2 | 16 | 32 | 53.3 | 64 | | 2 | 2 | 4 | 6.7 | 8 |
; | ... | ... | ... | ... | ... | | ... | ... | ... | ... | ... | | ... | ... | ... | ... | ... |
; | 14 | 1.0 | 2.0 | 3.3 | 4.0 | | 14 | 112 | 224 | 373 | 448 | | 126 | 126 | 252 | 420 | 504 |
; | 15 | 0.5 | 1.0 | 1.7 | 2.0 | | 15 | 120 | 240 | 400 | 480 | | 127 | 127 | 254 | 423 | 508 |
; +------+------+------+------+------+ +------+------+------+------+------+ +------+------+------+------+------+
;
; IBM PS/2 CALLS FOR:
; STEP RATE: 3ms (6ms FOR ALL 41mm OR 720K DRIVES)
; HEAD LOAD TIME: 15ms
;
; STATIC CONFIGURATION, NEVER CHANGES (PRIVATE)
;
MDB_PC720 .DW DTL_PC720 ; ADDRESS OF MEDIA LABEL
.DW DTS_PC720 ; ADDRESS OF MEDIA DESCRIPTION
.DB 050H ; NUMBER OF CYLINDERS
.DB 002H ; NUMBER OF HEADS
.DB 009H ; NUMBER OF SECTORS
.DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
FCB_PC720 .DB 009H ; SECTOR COUNT
.DW 200H ; SECTOR SIZE IN BYTES
.DB 02AH ; GAP LENGTH (R/W)
.DB 050H ; GAP LENGTH (FORMAT)
.DB (13 << 4) | 0 ; SRT = 6ms, HUT = 512ms
.DB 4 ; HLT = 16ms
.DB DORA_BR250 ; OPERATIONS REGISTER VALUE
.DB DORB_BR250 ; OPERATIONS REGISTER VALUE
.DB DORC_BR250 ; OPERATIONS REGISTER VALUE
.DB DORD_BR250 ; OPERATIONS REGISTER VALUE
.DB DCR_BR250 ; CONTROL REGISTER VALUE
.IF (($ - MDB_PC720) != MDB_LEN)
.ECHO "*** FCB SIZE ERROR!!! ***\n"
.ENDIF
DTL_PC720 .TEXT "720KB $"
DTS_PC720 .TEXT "3.5\" 720KB - 9 SECTORS, 2 SIDES, 80 TRACKS, DOUBLE DENSITY$"
;
MDB_PC144 .DW DTL_PC144 ; ADDRESS OF MEDIA LABEL
.DW DTS_PC144 ; ADDRESS OF MEDIA DESCRIPTION
.DB 050H ; NUMBER OF CYLINDERS
.DB 002H ; NUMBER OF HEADS
.DB 012H ; NUMBER OF SECTORS
.DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
FCB_PC144 .DB 012H ; SECTOR COUNT
.DW 200H ; SECTOR SIZE IN BYTES
.DB 01BH ; GAP LENGTH (R/W)
.DB 06CH ; GAP LENGTH (FORMAT)
.DB (13 << 4) | 0 ; SRT = 3ms, HUT = 256ms
.DB 8 ; HLT = 16ms
.DB DORA_BR500 ; OPERATIONS REGISTER VALUE
.DB DORB_BR500 ; OPERATIONS REGISTER VALUE
.DB DORC_BR500 ; OPERATIONS REGISTER VALUE
.DB DORD_BR500 ; OPERATIONS REGISTER VALUE
.DB DCR_BR500 ; CONTROL REGISTER VALUE
.IF (($ - MDB_PC144) != MDB_LEN)
.ECHO "*** FCB SIZE ERROR!!! ***\n"
.ENDIF
DTL_PC144 .TEXT "1.44MB$"
DTS_PC144 .TEXT "3.5\" 1.44MB - 18 SECTORS, 2 SIDES, 80 TRACKS, HIGH DENSITY$"
;
MDB_PC320 .DW DTL_PC320 ; ADDRESS OF MEDIA LABEL
.DW DTS_PC320 ; ADDRESS OF MEDIA DESCRIPTION
.DB 028H ; NUMBER OF CYLINDERS
.DB 002H ; NUMBER OF HEADS
.DB 008H ; NUMBER OF SECTORS
.DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
FCB_PC320 .DB 008H ; SECTOR COUNT
.DW 200H ; SECTOR SIZE IN BYTES
.DB 02AH ; GAP LENGTH (R/W)
.DB 050H ; GAP LENGTH (FORMAT)
.DB (13 << 4) | 0 ; SRT = 6ms, HUT = 512ms
.DB 4 ; HLT = 16ms
.DB DORA_BR250 ; OPERATIONS REGISTER VALUE
.DB DORB_BR250 ; OPERATIONS REGISTER VALUE
.DB DORC_BR250 ; OPERATIONS REGISTER VALUE
.DB DORD_BR250 ; OPERATIONS REGISTER VALUE
.DB DCR_BR250 ; CONTROL REGISTER VALUE
.IF (($ - MDB_PC320) != MDB_LEN)
.ECHO "*** FCB SIZE ERROR!!! ***\n"
.ENDIF
DTL_PC320 .TEXT "320KB $"
DTS_PC320 .TEXT "5.25\" 320KB - 8 SECTORS, 2 SIDES, 40 TRACKS, DOUBLE DENSITY$"
;
MDB_PC360 .DW DTL_PC360 ; ADDRESS OF MEDIA LABEL
.DW DTS_PC360 ; ADDRESS OF MEDIA DESCRIPTION
.DB 028H ; NUMBER OF CYLINDERS
.DB 002H ; NUMBER OF HEADS
.DB 009H ; NUMBER OF SECTORS
.DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
FCB_PC360 .DB 009H ; SECTOR COUNT
.DW 200H ; SECTOR SIZE IN BYTES
.DB 02AH ; GAP LENGTH (R/W)
.DB 050H ; GAP LENGTH (FORMAT)
.DB (13 << 4) | 0 ; SRT = 6ms, HUT = 512ms
.DB 4 ; HLT = 16ms
.DB DORA_BR250 ; OPERATIONS REGISTER VALUE
.DB DORB_BR250 ; OPERATIONS REGISTER VALUE
.DB DORC_BR250 ; OPERATIONS REGISTER VALUE
.DB DORD_BR250 ; OPERATIONS REGISTER VALUE
.DB DCR_BR250 ; CONTROL REGISTER VALUE
.IF (($ - MDB_PC360) != MDB_LEN)
.ECHO "*** FCB SIZE ERROR!!! ***\n"
.ENDIF
DTL_PC360 .TEXT "360KB $"
DTS_PC360 .TEXT "5.25\" 360KB - 9 SECTORS, 2 SIDES, 40 TRACKS, DOUBLE DENSITY$"
;
MDB_PC120 .DW DTL_PC120 ; ADDRESS OF MEDIA LABEL
.DW DTS_PC120 ; ADDRESS OF MEDIA DESCRIPTION
.DB 050H ; NUMBER OF CYLINDERS
.DB 002H ; NUMBER OF HEADS
.DB 00FH ; NUMBER OF SECTORS
.DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
FCB_PC120 .DB 00FH ; SECTOR COUNT
.DW 200H ; SECTOR SIZE IN BYTES
.DB 01BH ; GAP LENGTH (R/W)
.DB 054H ; GAP LENGTH (FORMAT)
.DB (10 << 4) | 0 ; SRT = 6ms, HUT = 256ms
.DB 8 ; HLT = 16ms
.DB DORA_BR500 ; OPERATIONS REGISTER VALUE
.DB DORB_BR500 ; OPERATIONS REGISTER VALUE
.DB DORC_BR500 ; OPERATIONS REGISTER VALUE
.DB DORD_BR500 ; OPERATIONS REGISTER VALUE
.DB DCR_BR500 ; CONTROL REGISTER VALUE
.IF (($ - MDB_PC120) != MDB_LEN)
.ECHO "*** FCB SIZE ERROR!!! ***\n"
.ENDIF
DTL_PC120 .TEXT "1.2MB $"
DTS_PC120 .TEXT "5.25\" 1.2MB - 15 SECTORS, 2 SIDES, 80 TRACKS, HIGH DENSITY$"
;
MDB_PC111 .DW DTL_PC111 ; ADDRESS OF MEDIA LABEL
.DW DTS_PC111 ; ADDRESS OF MEDIA DESCRIPTION
.DB 04DH ; NUMBER OF CYLINDERS
.DB 002H ; NUMBER OF HEADS
.DB 00FH ; NUMBER OF SECTORS
.DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1)
FCB_PC111 .DB 00FH ; SECTOR COUNT
.DW 200H ; SECTOR SIZE IN BYTES
.DB 01BH ; GAP LENGTH (R/W)
.DB 054H ; GAP LENGTH (FORMAT)
.DB (13 << 4) | 0 ; SRT = 3ms, HUT = 256ms
.DB 25 ; HLT = 50ms
.DB DORA_BR500 ; OPERATIONS REGISTER VALUE
.DB DORB_BR500 ; OPERATIONS REGISTER VALUE
.DB DORC_BR500 ; OPERATIONS REGISTER VALUE
.DB DORD_BR500 ; OPERATIONS REGISTER VALUE
.DB DCR_BR500 ; CONTROL REGISTER VALUE
.IF (($ - MDB_PC111) != MDB_LEN)
.ECHO "*** FCB SIZE ERROR!!! ***\n"
.ENDIF
DTL_PC111 .TEXT "1.11MB$"
DTS_PC111 .TEXT "8\" 1.11MB - 15 SECTORS, 2 SIDES, 77 TRACKS, DOUBLE DENSITY$"
;
;===============================================================================
; FLOPPY DISK CONTROL MENU (DIRECT MENU INTERFACE TO FDC & RELATED HARDWARE)
;===============================================================================
;
; FDC MENU DATA
;
FM_TABLE .DB 'R' \ .DW FMS_READ, FM_READ
FM_ENTSIZ .EQU $ - FM_TABLE
.DB 'D' \ .DW FMS_READDEL, FM_READDEL
.DB 'W' \ .DW FMS_WRITE, FM_WRITE
.DB 'E' \ .DW FMS_WRITEDEL, FM_WRITEDEL
.DB 'T' \ .DW FMS_READTRK, FM_READTRK
.DB 'I' \ .DW FMS_READID, FM_READID
.DB 'F' \ .DW FMS_FMTTRK, FM_FMTTRK
.DB 'Q' \ .DW FMS_SCANEQ, FM_SCANEQ
.DB 'L' \ .DW FMS_SCANLOEQ, FM_SCANLOEQ
.DB 'H' \ .DW FMS_SCANHIEQ, FM_SCANHIEQ
.DB 'C' \ .DW FMS_RECAL, FM_RECAL
.DB 'N' \ .DW FMS_SENSEINT, FM_SENSEINT
.DB 'P' \ .DW FMS_SPECIFY, FM_SPECIFY
.DB 'V' \ .DW FMS_DRVSTAT, FM_DRVSTAT
.DB 'S' \ .DW FMS_SEEK, FM_SEEK
.DB 'O' \ .DW FMS_VERSION, FM_VERSION
.DB 'U' \ .DW FMS_PULSETC, FM_PULSETC
.DB 'A' \ .DW FMS_DOR, FM_DOR
.DB 'M' \ .DW FMS_MOTOR, FM_MOTOR
.DB 'Z' \ .DW FMS_FDCRESET, FM_FDCRESET
.DB 'X' \ .DW FMS_EXIT, 0000H
FM_COUNT .EQU (($ - FM_TABLE) / FM_ENTSIZ) ; # ENTRIES IN TABLE
FM_INFO: .DW FM_DRAW
.DW FM_TABLE
.DB FM_ENTSIZ
.DB FM_COUNT
;
; FDC COMMAND MENU STRINGS
;
STR_FDCMENU:
; .TEXT "===================<< FDU FDC COMMAND MENU >>======= [MSR=XX] ==\r\n"
.TEXT "===================<< FDU FDC COMMAND MENU >>======= [MSR="
MV_MSR .TEXT "XX"
.TEXT "] ==\r\n"
.TEXT "(R)EAD READ (D)EL (W)RITE WRITE D(E)L\r\n"
.TEXT "READ (T)RK READ (I)D (F)ORMAT SCAN E(Q)\r\n"
.TEXT "SCAN (L)O/EQ SCAN (H)I/EQ RE(C)AL SE(N)SE INT\r\n"
.TEXT "S(P)ECIFY DRI(V)E STAT (S)EEK VERSI(O)N\r\n"
; .TEXT "P(U)LSE TC L(A)TCH:XX (M)OTOR:XXX FDC RESET (Z)\r\n"
.TEXT "P(U)LSE TC L(A)TCH:"
MV_LAT .TEXT "XX"
.TEXT " (M)OTOR:"
MV_MOT .TEXT "XXX"
.TEXT " FDC RESET (Z)"
.TEXT "\r\n"
.TEXT "E(X)IT\r\n"
.TEXT "=== OPTION ===> $"
;
FMS_NOP .TEXT "NOP$"
FMS_READ .TEXT "READ$"
FMS_READDEL .TEXT "READ DELETED$"
FMS_WRITE .TEXT "WRITE$"
FMS_WRITEDEL .TEXT "WRITE DELETED$"
FMS_READTRK .TEXT "READ TRACK$"
FMS_READID .TEXT "READ ID$"
FMS_FMTTRK .TEXT "FORMAT TRACK$"
FMS_SCANEQ .TEXT "SCAN EQUAL$"
FMS_SCANLOEQ .TEXT "SCAN LOW OR EQUAL$"
FMS_SCANHIEQ .TEXT "SCAN HIGH OR EQUAL$"
FMS_RECAL .TEXT "RECALIBRATE$"
FMS_SENSEINT .TEXT "SENSE INTERRUPT$"
FMS_SPECIFY .TEXT "SPECIFY$"
FMS_DRVSTAT .TEXT "DRIVE STATUS$"
FMS_SEEK .TEXT "SEEK$"
FMS_VERSION .TEXT "VERSION$"
FMS_PULSETC .TEXT "PULSE TC$"
FMS_DOR .TEXT "DOR$"
FMS_MOTOR .TEXT "MOTOR$"
FMS_FDCRESET .TEXT "FDC RESET$"
FMS_EXIT .TEXT "EXIT$"
;
; ENTRY POINT FOR FDCMENU
;
FDCMENU:
LD A,01H
LD (FCD_TRACE),A ; FORCE TRACING OF ALL FDC COMMANDS
LD HL,FM_INFO
CALL RUNMENU
RET
;
; FDCMENU DRAW PROCEDURE
;
FM_DRAW:
CALL NEWLINE
CALL NEWLINE
; UPDATE MOTOR STATUS
LD HL,FDCBM
LD A,(HL)
AND _DIO
JR NZ,FM_DRAW0A
LD A,(HL)
AND _ZETA | _DIO3
JR NZ,FM_DRAW0B
LD A,(HL)
AND _PCAT
JR NZ,FM_DRAW0C
LD A,(HL)
AND _RCSMC
JR NZ,FM_DRAW0D
JR FM_DRAW3
FM_DRAW0A: ; DIO
LD A,(FST_DOR)
AND 00000010B
XOR 00000010B
JR FM_DRAW1
FM_DRAW0B: ; ZETA, DIO3
LD A,(FST_DOR)
AND 00000010B
JR FM_DRAW1
FM_DRAW0C: ; DIDE, N8, ZETA2, RCWDC, SMZ80
LD A,(FST_DOR)
AND 11110000B
JR FM_DRAW1
FM_DRAW0D: ; RCSMC
LD A,(FST_DOR)
AND 00000110B
JR FM_DRAW1
FM_DRAW1:
LD DE,STR_ON
JP NZ,FM_DRAW2
LD DE,STR_OFF
FM_DRAW2:
LD HL,MV_MOT
CALL STRCPY
FM_DRAW3:
; UPDATE MSR VALUE
LD DE,MV_MSR
LD C,(IY+CFG_MSR)
IN A,(C)
CALL HEXSTRBYTE
; UPDATE FST_DOR VALUE
LD DE,MV_LAT
LD A,(FST_DOR)
CALL HEXSTRBYTE
; DISPLAY THE MENU
LD DE,STR_FDCMENU
CALL WRITESTR
RET
;
; FDCMENU FUNCTIONS
;
FM_READ:
CALL FM_GETTHS
CALL FC_READ
RET
FM_READDEL:
CALL FM_GETTHS
CALL FC_READDEL
RET
FM_WRITE:
CALL FM_GETTHS
CALL FC_WRITE
RET
FM_WRITEDEL:
CALL FM_GETTHS
CALL FC_WRITEDEL
RET
FM_READTRK:
CALL FM_GETTHS
CALL FC_READTRK
RET
FM_READID:
CALL FM_GETHEAD
CALL FC_READID
RET
FM_FMTTRK:
CALL FM_GETTRK
CALL FM_GETHEAD
CALL FC_FMTTRK
RET
FM_SCANEQ:
JP FM_NOTIMPL ; NOT IMPLEMENTED!
CALL FM_GETTHS
CALL FC_SCANEQ
RET
FM_SCANLOEQ:
JP FM_NOTIMPL ; NOT IMPLEMENTED!
CALL FM_GETTHS
CALL FC_SCANLOEQ
RET
FM_SCANHIEQ:
JP FM_NOTIMPL ; NOT IMPLEMENTED!
CALL FM_GETTHS
CALL FC_SCANHIEQ
RET
FM_RECAL:
LD A,0 ; UPDATE CYLINDER FOR FUTURE CALLS
LD (FCD_C),A ; FIX: NOT IN THE RIGHT PLACE
CALL FC_RECAL
RET
FM_SENSEINT:
CALL FC_SENSEINT
RET
FM_SPECIFY:
CALL FC_SPECIFY
RET
FM_DRVSTAT:
CALL FM_GETHEAD
CALL FC_DRVSTAT
RET
FM_SEEK:
CALL FM_GETTRK
CALL FC_SEEK
RET
FM_VERSION:
CALL FC_VERSION
RET
FM_PULSETC:
CALL NEWLINE
CALL FC_PULSETC
RET
FM_DOR:
CALL FM_GETDOR
CALL FC_SETDOR
RET
FM_MOTOR:
; TOGGLE MOTOR STATE
LD HL,FDCBM
LD A,(HL)
AND _DIO
JR NZ,FM_MOTOR0A
LD A,(HL)
AND _ZETA | _DIO3
JR NZ,FM_MOTOR0B
LD A,(HL)
AND _PCAT
JR NZ,FM_MOTOR0C
LD A,(HL)
AND _RCSMC
JR NZ,FM_MOTOR0D
RET
FM_MOTOR0A: ; DIO
LD A,(FST_DOR)
AND 00000010B
XOR 00000010B
JR FM_MOTOR1
FM_MOTOR0B: ; ZETA, DIO3
LD A,(FST_DOR)
AND 00000010B
JR FM_MOTOR1
FM_MOTOR0C: ; DIDE, N8, ZETA2, RCWDC, SMZ80
LD A,(FST_DOR)
AND 11110000B
JR FM_MOTOR1
FM_MOTOR0D: ; RCSMC
LD A,(FST_DOR)
AND 00000110B
JR FM_MOTOR1
FM_MOTOR1:
JP Z,FC_MOTORON
JP FC_MOTOROFF
FM_FDCRESET:
CALL NEWLINE
LD A,(FDCID)
CP FDC_DIO ; RESET NOT POSSIBLE ON DIO
JP NZ,FC_RESETFDC
LD DE,FCS_NORES
JP WRITESTR
FM_NOTIMPL:
CALL PC_SPACE ; NOT IMPLEMENTED
LD DE,STR_NOTIMPL
CALL WRITESTR
RET
FM_GETTHS:
CALL FM_GETTRK
CALL FM_GETHEAD
CALL FM_GETSEC
RET
FM_GETTRK:
LD DE,FCPP_TRK
LD HL,FCD_C
CALL GETHEXBYTE
RET
FM_GETHEAD:
LD DE,FCPP_HEAD
LD HL,FCD_H
CALL GETHEXBYTE
RET
FM_GETSEC:
LD DE,FCPP_SEC
LD HL,FCD_R
CALL GETHEXBYTE
RET
FM_GETDOR:
LD DE,FCPP_DOR
LD HL,FST_DOR
CALL GETHEXBYTE
RET
;
FCS_NORES .TEXT "\r\n*** RESET NOT SUPORTED BY HARDWARE ***$"
;
;===============================================================================
; FLOPPY DISK CONTROL SERVICES (PHYSICAL DEVICE CONTROL FOR FDC HARDWARE)
;===============================================================================
;
; FDC RESULT CODES
;
FRC_OK .EQU 0 ; 00
FRC_NOTIMPL .EQU -01H ; FF
FRC_CMDERR .EQU -02H ; FE
FRC_ERROR .EQU -03H ; FD
FRC_ABORT .EQU -04H ; FC
FRC_BUFMAX .EQU -05H ; FB
FRC_ABTERM .EQU -08H ; F8
FRC_INVCMD .EQU -09H ; F7
FRC_DSKCHG .EQU -0AH ; F6
FRC_ENDCYL .EQU -0BH ; F5
FRC_DATAERR .EQU -0CH ; F4
FRC_OVERRUN .EQU -0DH ; F3
FRC_NODATA .EQU -0EH ; F2
FRC_NOTWRIT .EQU -0FH ; F1
FRC_MISADR .EQU -10H ; F0
FRC_TOFDCRDY .EQU -11H ; EF
FRC_TOSNDCMD .EQU -12H ; EE
FRC_TOGETRES .EQU -13H ; ED
FRC_TOEXEC .EQU -14H ; EC
FRC_TOSEEKWT .EQU -15H ; EB
FRC_MISMATCH .EQU -16H ; EA
;
; FDC STATUS CODE STRINGS
;
FSS_OK .TEXT "OK$"
FSS_NOTIMPL .TEXT "NOT IMPLEMENTED$"
FSS_CMDERR .TEXT "COMMAND ERROR$"
FSS_ERROR .TEXT "ERROR$"
FSS_ABORT .TEXT "ABORT$"
FSS_BUFMAX .TEXT "BUFFER EXCEEDED$"
FSS_ABTERM .TEXT "ABNORMAL TERMINATION$"
FSS_INVCMD .TEXT "INVALID COMMAND$"
FSS_DSKCHG .TEXT "DISK CHANGE$"
FSS_ENDCYL .TEXT "END OF CYLINDER$"
FSS_DATAERR .TEXT "DATA ERROR$"
FSS_OVERRUN .TEXT "OVERRUN$"
FSS_NODATA .TEXT "NO DATA$"
FSS_NOTWRIT .TEXT "NOT WRITABLE$"
FSS_MISADR .TEXT "MISSING ADDRESS MARK$"
FSS_TOFDCRDY .TEXT "FDC READY TIMEOUT$"
FSS_TOSNDCMD .TEXT "SENDCMD TIMEOUT$"
FSS_TOGETRES .TEXT "GET RESULTS TIMEOUT$"
FSS_TOEXEC .TEXT "EXEC TIMEOUT$"
FSS_TOSEEKWT .TEXT "SEEK WAIT TIMEOUT$"
;
; FDC STATUS STRING TABLE
;
FSST: .DB FRC_OK \ .DW FSS_OK
FSST_ENTSIZ .EQU $ - FSST
.DB FRC_NOTIMPL \ .DW FSS_NOTIMPL
.DB FRC_CMDERR \ .DW FSS_CMDERR
.DB FRC_ERROR \ .DW FSS_ERROR
.DB FRC_ABORT \ .DW FSS_ABORT
.DB FRC_BUFMAX \ .DW FSS_BUFMAX
.DB FRC_ABTERM \ .DW FSS_ABTERM
.DB FRC_INVCMD \ .DW FSS_INVCMD
.DB FRC_DSKCHG \ .DW FSS_DSKCHG
.DB FRC_ENDCYL \ .DW FSS_ENDCYL
.DB FRC_DATAERR \ .DW FSS_DATAERR
.DB FRC_OVERRUN \ .DW FSS_OVERRUN
.DB FRC_NODATA \ .DW FSS_NODATA
.DB FRC_NOTWRIT \ .DW FSS_NOTWRIT
.DB FRC_MISADR \ .DW FSS_MISADR
.DB FRC_TOFDCRDY \ .DW FSS_TOFDCRDY
.DB FRC_TOSNDCMD \ .DW FSS_TOSNDCMD
.DB FRC_TOGETRES \ .DW FSS_TOGETRES
.DB FRC_TOEXEC \ .DW FSS_TOEXEC
.DB FRC_TOSEEKWT \ .DW FSS_TOSEEKWT
FSST_COUNT .EQU (($ - FSST) / FSST_ENTSIZ) ; # ENTRIES IN TABLE
;
; FDC COMMAND PHASE
;
FCP_CMD .DB 000H ; INPUT: COMMAND CODE
FCP_BUFLEN .DB 00H
FCP_BUF .DS 10H
FCP_BUFSIZ .EQU $-FCP_BUF
FCP_XFRCNT .DW 00H ; BYTES TRANSFERRED DURING COMMAND PHASE
;
; FDC EXECUTION PHASE
;
FXP_XR .DW 00H ; INPUT: ADDRESS OF EXECUTION ROUTINE TO INVOKE
FXP_TO .DB 00H ; TIMEOUT COUNTDOWN TIMER USED IN SOME VARIATIONS
FXP_ITER .DB 00H ; LOOP ITERATION COUNTER (MUST IMMEDIATELY FOLLOW FXP_TO)
FXP_A .DB 00H ; LAST VALUE OF REG A RECORDED DURING EXECUTION
FXP_BC .DW 00H ; LAST VALUE OF REG BC RECORDED DURING EXECUTION
FXP_DE .DW 00H ; LAST VALUE OF REG DE RECORDED DURING EXECUTION
FXP_HL .DW 00H ; LAST VALUE OF REG HL RECORDED DURING EXECUTION
FXP_BUFLEN .DB 00H
FXP_BUF .DS 50H ; USED FOR CERTAIN EXEC ROUTINES (FORMAT TRACK)
FXP_BUFSIZ .EQU $-FXP_BUF
;
; FDC STATUS
;
FST_RC .DB 00H
FST_MSR .DB 00H
FST_DOR .DB 00H
;
; FDC RESULTS BUFFER
;
FRB_LEN .DB 00H
FRB
FRB_ST0
FRB_ST3 .DB 0
FRB_ST1
FRB_PCN .DB 0
FRB_ST2 .DB 0
FRB_C .DB 0
FRB_H .DB 0
FRB_R .DB 0
FRB_N .DB 0
.FILL 10H ; ALLOWS EXTRA CHARACTERS TO BE RETREIEVED
FRB_SIZ .EQU $-FRB
;
; FDC COMMANDS
;
CMD_READ .EQU 00000110B ; ST0,ST1,ST2,C,H,R,N
CMD_READDEL .EQU 00001100B ; ST0,ST1,ST2,C,H,R,N
CMD_WRITE .EQU 00000101B ; ST0,ST1,ST2,C,H,R,N
CMD_WRITEDEL .EQU 00001001B ; ST0,ST1,ST2,C,H,R,N
CMD_READTRK .EQU 00000010B ; ST0,ST1,ST2,C,H,R,N
CMD_READID .EQU 00001010B ; ST0,ST1,ST2,C,H,R,N
CMD_FMTTRK .EQU 00001101B ; ST0,ST1,ST2,C,H,R,N
CMD_SCANEQ .EQU 00010001B ; ST0,ST1,ST2,C,H,R,N
CMD_SCANLOEQ .EQU 00011001B ; ST0,ST1,ST2,C,H,R,N
CMD_SCANHIEQ .EQU 00011101B ; ST0,ST1,ST2,C,H,R,N
CMD_RECAL .EQU 00000111B ; <EMPTY>
CMD_SENSEINT .EQU 00001000B ; ST0,PCN
CMD_SPECIFY .EQU 00000011B ; <EMPTY>
CMD_DRVSTAT .EQU 00000100B ; ST3
CMD_SEEK .EQU 00001111B ; <EMPTY>
CMD_VERSION .EQU 00010000B ; ST0
;
; FDC COMMAND DATA
;
FCD: ; FLOPPY CONFIGURATION DATA (PUBLIC) MANAGED AS A "BLOCK", SEE FCB BELOW
FCD_EOT ; END OF TRACK SECTOR (SAME AS SC SINCE SOT ALWAYS 1)
FCD_SC .DB 000H ; SECTOR COUNT
FCD_SECSZ .DW 000H ; SECTOR SIZE IN BYTES
FCD_GPL .DB 000H ; GAP LENGTH (R/W)
FCD_GPLF .DB 000H ; GAP LENGTH (FORMAT)
FCD_SRTHUT .DB 000H ; STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME
FCD_HLT .DB 000H ; HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT
FCD_DORA .DB 000H ; DEFAULT DOR VALUE FOR MEDIA
FCD_DORB .DB 000H ; DEFAULT DOR VALUE FOR MEDIA
FCD_DORC .DB 000H ; DEFAULT DOR VALUE FOR MEDIA
FCD_DORD .DB 000H ; DEFAULT DOR VALUE FOR MEDIA
FCD_DCR .DB 000H ; DOR VALUE FOR MEDIA
FCD_LEN .EQU $ - FCD
; DYNAMICALLY MANAGED (PUBLIC)
FCD_DS .DB 001H ; DRIVE SELECT (UNIT NUMBER 0-3)
FCD_C .DB 000H ; CYLINDER
FCD_H .DB 000H ; HEAD
FCD_R .DB 001H ; RECORD
FCD_D .DB 0E5H ; FORMAT DATA FILL BYTE
FCD_X .DB 002H ; FORMAT INTERLEAVE FACTOR (1...N)
FCD_ND .DB 000H ; DMA, 0=DMA, 1=NON-DMA
; STATIC CONFIGURATION, NEVER CHANGES (PRIVATE)
FCD_SOT .DB 001H ; STARTING SECTOR NUMBER OF TRACK
FCD_MT .DB 000H ; MULTI-TRACK, WE DON'T USE, SET TO 0
FCD_MFM .DB 001H ; MFM, 0=FM, 1=MFM, WE USE MFM ALWAYS
FCD_SK .DB 000H ; SKIP MODE, WE DON'T USE, SET TO 0
FCD_N .DB 002H ; SECTOR SIZE, N=2 FOR 512 BYTES
FCD_DTL .DB 0FFH ; DATA LENGTH (WHEN N=0, SET TO FF OTHERWISE)
FCD_STP .DB 001H ; SECTOR SCAN TYPE, 1=CONTIG, 2=ALTERNATING
; CONTROL STUFF (PUBLIC)
FCD_TRACE .DB 00H ; TRACE LEVEL
;
;
; FDC CMD PARM PROMPTS
;
FCPP_TRK .TEXT "TRACK$"
FCPP_HEAD .TEXT "HEAD$"
FCPP_SEC .TEXT "SECTOR$"
FCPP_DOR .TEXT "DOR$"
;
; FDC EXECUTION ROUTINE JUMP TABLE
;
FXRJ_NOP: JP FXR_NOP
FXRJ_READ: JP FXR_READ
FXRJ_READDEL: JP FXR_READDEL
FXRJ_WRITE: JP FXR_WRITE
FXRJ_WRITEDEL: JP FXR_WRITEDEL
FXRJ_READTRK: JP FXR_READTRK
FXRJ_READID: JP FXR_READID
FXRJ_FMTTRK: JP FXR_FMTTRK
FXRJ_SCANEQ: JP FXR_SCANEQ
FXRJ_SCANLOEQ: JP FXR_SCANLOEQ
FXRJ_SCANHIEQ: JP FXR_SCANHIEQ
FXRJ_RECAL: JP FXR_RECAL
FXRJ_SENSEINT: JP FXR_SENSEINT
FXRJ_SPECIFY: JP FXR_SPECIFY
FXRJ_DRVSTAT: JP FXR_DRVSTAT
FXRJ_SEEK: JP FXR_SEEK
FXRJ_VERSION JP FXR_VERSION
;
; FDC COMMAND STRINGS
;
FCS_NOP: .TEXT "NOP$"
FCS_READ: .TEXT "READ$"
FCS_READDEL: .TEXT "READ DELETED$"
FCS_WRITE: .TEXT "WRITE$"
FCS_WRITEDEL: .TEXT "WRITE DELETED$"
FCS_READTRK: .TEXT "READ TRACK$"
FCS_READID: .TEXT "READ ID$"
FCS_FMTTRK: .TEXT "FORMAT TRACK$"
FCS_SCANEQ: .TEXT "SCAN EQUAL$"
FCS_SCANLOEQ: .TEXT "SCAN LOW OR EQUAL$"
FCS_SCANHIEQ: .TEXT "SCAN HIGH OR EQUAL$"
FCS_RECAL: .TEXT "RECALIBRATE$"
FCS_SENSEINT: .TEXT "SENSE INTERRUPT$"
FCS_SPECIFY: .TEXT "SPECIFY$"
FCS_DRVSTAT: .TEXT "DRIVE STATUS$"
FCS_SEEK: .TEXT "SEEK$"
FCS_VERSION: .TEXT "VERSION$"
;
; FDC COMMAND TABLE
;
FCT .DB CMD_READ \ .DW FCS_READ, FXRJ_READ
FCT_ENTSIZ .EQU $ - FCT
.DB CMD_READDEL \ .DW FCS_READDEL, FXRJ_READDEL
.DB CMD_WRITE \ .DW FCS_WRITE, FXRJ_WRITE
.DB CMD_WRITEDEL \ .DW FCS_WRITEDEL, FXRJ_WRITEDEL
.DB CMD_READTRK \ .DW FCS_READTRK, FXRJ_READTRK
.DB CMD_READID \ .DW FCS_READID, FXRJ_READID
.DB CMD_FMTTRK \ .DW FCS_FMTTRK, FXRJ_FMTTRK
.DB CMD_SCANEQ \ .DW FCS_SCANEQ, FXRJ_SCANEQ
.DB CMD_SCANLOEQ \ .DW FCS_SCANLOEQ, FXRJ_SCANLOEQ
.DB CMD_SCANHIEQ \ .DW FCS_SCANHIEQ, FXRJ_SCANHIEQ
.DB CMD_RECAL \ .DW FCS_RECAL, FXRJ_RECAL
.DB CMD_SENSEINT \ .DW FCS_SENSEINT, FXRJ_SENSEINT
.DB CMD_SPECIFY \ .DW FCS_SPECIFY, FXRJ_SPECIFY
.DB CMD_DRVSTAT \ .DW FCS_DRVSTAT, FXRJ_DRVSTAT
.DB CMD_SEEK \ .DW FCS_SEEK, FXRJ_SEEK
.DB CMD_VERSION \ .DW FCS_VERSION, FXRJ_VERSION
FCT_COUNT .EQU (($ - FCT) / FCT_ENTSIZ) ; # ENTRIES IN TABLE
;
; ENTRY POINTS FOR FDC COMMANDS
;
FC_READ:
LD A,CMD_READ
LD B,0FFH ; MT & MFM & SK & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_READ
LD (FXP_XR),HL
CALL FC_SETUPIO
CALL FC_CMDPROC
RET
FC_READDEL:
LD A,CMD_READDEL
LD B,0FFH ; MT & MFM & SK & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_READDEL
LD (FXP_XR),HL
CALL FC_SETUPIO
CALL FC_CMDPROC
RET
FC_WRITE:
LD A,CMD_WRITE
LD B,0DFH ; MT & MFM & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_WRITE
LD (FXP_XR),HL
CALL FC_SETUPIO
CALL FC_CMDPROC
RET
FC_WRITEDEL:
LD A,CMD_WRITEDEL
LD B,0DFH ; MT & MFM & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_WRITEDEL
LD (FXP_XR),HL
CALL FC_SETUPIO
CALL FC_CMDPROC
RET
FC_READTRK:
LD A,CMD_READTRK
LD B,07FH ; MFM & SK & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_READTRK
LD (FXP_XR),HL
CALL FC_SETUPIO
CALL FC_CMDPROC
RET
FC_READID:
LD A,CMD_READID
LD B,05FH ; MFM & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_READID
LD (FXP_XR),HL
CALL FC_SETUPCMD
CALL FC_CMDPROC
RET
FC_FMTTRK:
LD A,CMD_FMTTRK
LD B,05FH ; MFM & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_FMTTRK
LD (FXP_XR),HL
CALL FC_SETUPFMT
CALL FC_CMDPROC
RET
FC_SCANEQ:
LD A,CMD_SCANEQ
LD B,0FFH ; MT & MFM & SK & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_SCANEQ
LD (FXP_XR),HL
CALL FC_SETUPSCAN
CALL FC_CMDPROC
RET
FC_SCANLOEQ:
LD A,CMD_SCANLOEQ
LD B,0FFH ; MT & MFM & SK & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_SCANLOEQ
LD (FXP_XR),HL
CALL FC_SETUPSCAN
CALL FC_CMDPROC
RET
FC_SCANHIEQ:
LD A,CMD_SCANHIEQ
LD B,0FFH ; MT & MFM & SK & CMD BITS
LD (FCP_CMD),A
LD HL,FXR_SCANHIEQ
LD (FXP_XR),HL
CALL FC_SETUPSCAN
CALL FC_CMDPROC
RET
FC_RECAL:
LD A,CMD_RECAL
LD B,01FH ; CMD BITS ONLY
LD (FCP_CMD),A
LD HL,FXR_RECAL
LD (FXP_XR),HL
CALL FC_SETUPSEEK ; SPECIALIZATION OF SEEK
LD A,2 ; GENERIC COMMAND, BUT JUST FIRST COMMAND CODE
LD (FCP_BUFLEN),A
CALL FC_CMDPROC
RET
FC_SENSEINT:
LD A,CMD_SENSEINT
LD B,01FH ; CMD BITS ONLY
LD (FCP_CMD),A
LD HL,FXR_SENSEINT
LD (FXP_XR),HL
CALL FC_SETUPCMD
LD A,1 ; GENERIC COMMAND, BUT JUST FIRST COMMAND CODE
LD (FCP_BUFLEN),A
CALL FC_CMDPROC
RET
FC_SPECIFY:
LD A,CMD_SPECIFY
LD B,01FH ; CMD BITS ONLY
LD (FCP_CMD),A
LD HL,FXR_SPECIFY
LD (FXP_XR),HL
CALL FC_SETUPSPECIFY
CALL FC_CMDPROC
RET
FC_DRVSTAT:
LD A,CMD_DRVSTAT
LD B,01FH ; CMD BITS ONLY
LD (FCP_CMD),A
LD HL,FXR_DRVSTAT
LD (FXP_XR),HL
CALL FC_SETUPCMD
CALL FC_CMDPROC
RET
FC_SEEK:
LD A,CMD_SEEK
LD B,01FH ; CMD BITS ONLY
LD (FCP_CMD),A
LD HL,FXR_SEEK
LD (FXP_XR),HL
CALL FC_SETUPSEEK
CALL FC_CMDPROC
RET
FC_VERSION:
LD A,CMD_VERSION
LD B,01FH ; CMD BITS ONLY
LD (FCP_CMD),A
LD HL,FXR_VERSION
LD (FXP_XR),HL
CALL FC_SETUPCMD
LD A,1 ; GENERIC COMMAND, BUT JUST FIRST COMMAND CODE
LD (FCP_BUFLEN),A
CALL FC_CMDPROC
RET
;
; HELPER FUNCTIONS TO SETUP CMDBUF
;
FC_SETUPCMD:
PUSH BC ; B CONTAINS BIT MASK TO USE FOR FIRST BYTE
; SO THAT WE CAN MASK OFF BITS THAT ARE NOT
; USED FOR CERTAIN COMMANDS
LD DE,FCP_BUF
AND 01FH ; REMOVE ANY EXTRANEOUS BITS FROM COMMAND BYTE
LD C,A ; SAVE THE COMMAND
LD A,(FCD_MT) ; GET MT BIT
AND 01H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY
RLA ; MAKE ROOM FOR MFM
LD B,A ; SAVE WHAT WE HAVE SO FAR IN B
LD A,(FCD_MFM) ; GET MFM BIT
AND 01H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY
OR B ; COMBINE WITH SAVED
RLA ; MAKE ROOM FOR SK
LD B,A ; SAVE WHAT WE HAVE SO FAR IN B
LD A,(FCD_SK) ; GET SK BIT
AND 01H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY
OR B ; COMBINE WITH SAVED
RLA ; MAKE ROOM FOR THE COMMAND BITS
RLA
RLA
RLA
RLA
LD B,C ; RECOVER THE COMMAND VALUE
OR B ; COMBINE WITH SAVED
POP BC ; GET THE BIT MASK FOR FIRST BYTE
AND B ; APPLY IT
LD (DE),A ; SAVE THE BYTE
INC DE
LD A,(FCD_H) ; START WITH HDS
AND 01H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY
RLA ; MAKE ROOM FOR DS BITS
RLA ;
LD B,A ; SAVE WHAT WE HAVE SO FAR IN B
LD A,(FCD_DS) ; GET DS VALUE
AND 03H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY
OR B ; COMBINE WITH SAVED
LD (DE),A ; SAVE THE BYTE
INC DE
LD A,2 ; THIS IS A 2 BYTE COMMAND STRING
LD (FCP_BUFLEN),A
RET
FC_SETUPIO:
CALL FC_SETUPCMD
LD A,(FCD_C)
LD (DE),A
INC DE
LD A,(FCD_H)
LD (DE),A
INC DE
LD A,(FCD_R)
LD (DE),A
INC DE
LD A,(FCD_N)
LD (DE),A
INC DE
; V5.3, USE EOT=R TO R/W ONLY ONE SECTOR
;LD A,(FCD_EOT)
LD A,(FCD_R)
LD (DE),A
INC DE
LD A,(FCD_GPL)
LD (DE),A
INC DE
LD A,(FCD_DTL)
LD (DE),A
INC DE
LD A,9
LD (FCP_BUFLEN),A
RET
FC_SETUPFMT:
CALL FC_SETUPCMD
LD A,(FCD_N)
LD (DE),A
INC DE
LD A,(FCD_SC)
LD (DE),A
INC DE
LD A,(FCD_GPLF)
LD (DE),A
INC DE
LD A,(FCD_D)
LD (DE),A
INC DE
LD A,6
LD (FCP_BUFLEN),A
; SETUP FORMAT BUFFER WITH SECTOR ID INFO FOR ENTIRE TRACK - (C,H,S,N) FOR EACH SECTOR
; INTERLEAVE AS REQUESTED
;
; B = CURRENT INTERLEAVE PASS STARTING SECTOR ID
; C = CURRENT SECTOR ID
; H = INTERLEAVE STEP
; L = LAST SECTOR ID + 1
; DE = BUFFER POINTER
;
PUSH DE
PUSH HL
; COMPUTE INTERLEAVE STEP
LD H,-1
LD A,(FCD_X)
LD B,A
LD A,(FCD_SC)
LOOP:
INC H
SUB B
JR NC,LOOP
LD DE,FXP_BUF ; DE POINTS TO START OF BUFFER
LD A,(FCD_SOT) ; GET FIRST SECTOR ID
LD B,A ; B = FIRST SECTOR ID FOR CURRENT INTERLEAVE PASS
LD C,A ; C = SECTOR ID
LD A,(FCD_SC) ; NUM SECTORS TO SET UP
ADD A,C
LD L,A ; L = LAST SECTOR ID + 1
FC_SETUPFMT1:
; CYLINDER
LD A,(FCD_C)
LD (DE),A
INC DE
; HEAD
LD A,(FCD_H)
LD (DE),A
INC DE
; SECTOR ID
LD A,C
LD (DE),A
INC DE
; SECTOR SIZE
LD A,(FCD_N)
LD (DE),A
INC DE
; INC SECTOR ID BY INTERLEAVE STEP
LD A,H
ADD A,C
LD C,A
; LOOP IF WE HAVE NOT GOTTEN PAST LAST SECTOR ID
CP L
JP M,FC_SETUPFMT1
; SETUP FOR NEXT INTERLEAVE PASS
INC B
LD C,B
; LOOP IF WE ARE NOT DONE
LD A,H
CP C
JP P,FC_SETUPFMT1
; DONE, FINALIZE BUFFER
LD A,(FCD_SC) ; GET SECTOR COUNT
RLCA ; MULTIPLY BY 4
RLCA
LD (FXP_BUFLEN),A ; STORE AS BUFFER LENGTH
POP HL
POP DE
RET
FC_SETUPSCAN:
CALL FC_SETUPIO ; START WITH GENERIC IO CMD
LD DE,FCP_BUF+8 ; REPLACE DTL WITH STP
LD A,(FCD_STP)
LD (DE),A
RET
FC_SETUPSEEK:
CALL FC_SETUPCMD ; START WITH GENERIC IO CMD
LD A,(FCD_C)
LD (DE),A
INC DE
LD DE,FCP_BUF ; REMOVE EXTRANEOUS BITS FROM CC0
LD A,(DE)
AND 0FH
LD (DE),A
LD A,3
LD (FCP_BUFLEN),A
RET
FC_SETUPSPECIFY:
CALL FC_SETUPCMD
DEC DE ; BACKUP 1 BYTE, WE ONLY WANT FIRST BYTE
LD A,(FCD_SRTHUT)
LD (DE),A ; SAVE THE BYTE
INC DE
LD A,(FCD_HLT)
AND 07FH
RLA
LD B,A
LD A,(FCD_ND)
AND 01H
OR B
LD (DE),A ; SAVE THE BYTE
INC DE
LD A,3
LD (FCP_BUFLEN),A
RET
;
; MAIN FDC COMMAND PROCESSOR
;
FC_CMDPROC:
CALL FOP
CALL FC_PRTRESULTS
RET
;
; FDC SEQUENCE INITIALIZATION
;
FC_INIT:
LD HL,FDCBM
LD A,(HL)
AND _DIO
JR NZ,FC_INIT1
LD A,(HL)
AND _ZETA | _DIO3
JR NZ,FC_INIT2
LD A,(HL)
AND _PCAT
JR NZ,FC_INIT3
LD A,(HL)
AND _RCSMC
JR NZ,FC_INIT4
RET
FC_INIT1: ; DIO
LD A,(FCD_DORA)
JR FC_INIT5
FC_INIT2: ; ZETA, DIO3
LD A,(FCD_DORB)
JR FC_INIT5
FC_INIT3: ; DIDE, N8, ZETA2, RCWDC, SMZ80
LD A,(FCD_DORC)
JR FC_INIT5
FC_INIT4: ; WDSMC
LD A,(FCD_DORD)
JR FC_INIT5
FC_INIT5:
LD (FST_DOR),A
CALL FC_SETDOR
RET
;
; SET FST_DOR
;
FC_SETDOR:
PUSH AF
LD A,(FST_DOR)
LD C,(IY+CFG_DOR)
OUT (C),A
POP AF
RET
;
; RESET FDC BY PULSING BIT 7 OF DOR LOW
; NOTE: DIO HARDWARE HAS NO MECHANISM TO PULSE RESET VIA SOFTWARE
;
FC_RESETFDC:
LD C,(IY+CFG_DOR)
LD HL,FDCBM
LD A,(HL)
AND _ZETA | _DIO3 | _RCSMC
JR NZ,FC_RESETFDC1
LD A,(HL)
AND _PCAT
JR NZ,FC_RESETFDC2
RET
FC_RESETFDC1: ; ZETA, DIO3, RCSMC
LD A,(FST_DOR)
PUSH AF
RES 7,A
OUT (C),A
CALL DELAY
POP AF
OUT (C),A
JR FC_RESETFDC3
FC_RESETFDC2: ; DIDE, N8, ZETA2, RCWDC, SMZ80
LD A,0
OUT (C),A
LD A,(FST_DOR)
OUT (C),A
JR FC_RESETFDC3
FC_RESETFDC3:
LD DE,156 ; DELAY: 16us * 156 = 2.5ms
CALL VDELAY
RET
;
; PULSE TERMCT TO TERMINATE ANY ACTIVE EXECUTION PHASE
;
FC_PULSETC:
; V5.3, USE EOT=R TO R/W ONLY ONE SECTOR
;LD A,(FDCBM)
;AND _PCAT
;JR NZ,FC_PULSETC1
;; NOT DIDE, N8, ZETA2, RCSMC, SMZ80
;LD C,(IY+CFG_DOR)
;LD A,(FST_DOR)
;SET 0,A
;OUT (C),A
;RES 0,A
;OUT (C),A
;JR FC_PULSETC2
;FC_PULSETC1: ; DIDE, N8, ZETA2, RCWDC, SMZ80
;LD C,(IY+CFG_TC)
;IN A,(C)
;JR FC_PULSETC2
;FC_PULSETC2:
RET
;
; SET FST_DOR FOR MOTOR CONTROL ON
;
FC_MOTORON:
LD HL,FDCBM
LD A,(HL)
AND _DIO
JR NZ,FC_MOTORON1
LD A,(HL)
AND _ZETA | _DIO3
JR NZ,FC_MOTORON2
LD A,(HL)
AND _PCAT
JR NZ,FC_MOTORON3
LD A,(HL)
AND _RCSMC
JR NZ,FC_MOTORON4
RET
FC_MOTORON1: ; DIO
LD HL,FST_DOR ; POINT TO FDC_DOR
RES 1,(HL) ; SET MOTOR ON
JR FC_MOTORON5
FC_MOTORON2: ; ZETA, DIO3
LD HL,FST_DOR ; POINT TO FDC_DOR
SET 1,(HL)
JR FC_MOTORON5
FC_MOTORON3: ; DIDE, N8, ZETA2, RCWDC, SMZ80
LD HL,FST_DOR ; POINT TO FDC_DOR
LD A,(HL) ; START WITH CURRENT DOR
AND 11111100B ; GET RID OF ANY ACTIVE DS BITS
LD C,A ; SAVE IT FOR NOW
LD A,(FCD_DS) ; NOW GET CURRENT DS
LD B,A ; PUT IN B FOR LATER
OR C ; COMBINE WITH SAVED DOR
LD C,A ; RE-SAVE IT
INC B ; SET UP B AS LOOP COUNTER (DS + 1)
LD A,00001000B ; STARTING BIT PATTERN FOR MOTOR
FC_MOTORON3A:
RLA ; SHIFT LEFT
DJNZ FC_MOTORON3A ; DS TIMES
OR C ; COMBINE WITH SAVED
LD (HL),A ; COMMIT THE NEW VALUE TO FST_DOR
JR FC_MOTORON5
FC_MOTORON4: ; RCSMC
LD A,(FCD_DS) ; GET CURRENT DS
LD C,00000010B ; ASSUME MOTORA (BIT 1)
OR A ; TEST FOR DS 0
JR Z,FC_MOTORON4A ; IF SO, CONTINUE W/ MOTORA
LD C,00000100B ; OTHERWISE, MOTORB (BIT 2)
FC_MOTORON4A:
LD A,(FST_DOR) ; GET CURRENT DOR VALUE
OR C ; APPLY NEW MOTOR BIT
LD (FST_DOR),A ; COMMIT NEW VALUE
JR FC_MOTORON5
FC_MOTORON5:
CALL FC_SETDOR ; OUTPUT TO CONTROLLER
CALL LDELAY ; WAIT 1/2 SEC ON MOTOR START FOR SPIN-UP
LD A,(FDCBM)
AND _PCAT
RET Z
LD A,(FCD_DCR)
LD C,(IY+CFG_DCR)
OUT (C),A
RET
;
; SET FST_DOR FOR MOTOR CONTROL OFF
;
FC_MOTOROFF:
LD HL,FDCBM
LD A,(HL)
AND _DIO
JR NZ,FC_MOTOROFF1
LD A,(HL)
AND _ZETA | _DIO3
JR NZ,FC_MOTOROFF2
LD A,(HL)
AND _PCAT
JR NZ,FC_MOTOROFF3
LD A,(HL)
AND _RCSMC
JR NZ,FC_MOTOROFF4
RET
FC_MOTOROFF1: ; DIO
LD HL,FST_DOR ; POINT TO FDC_DOR
SET 1,(HL) ; SET MOTOR OFF
JR FC_MOTOROFF5
FC_MOTOROFF2: ; ZETA, DIO3
LD HL,FST_DOR ; POINT TO FDC_DOR
RES 1,(HL)
JR FC_MOTOROFF5
FC_MOTOROFF3: ; DIDE, N8, ZETA2, RCWDC, SMZ80
LD HL,FST_DOR ; POINT TO FDC_DOR
LD A,DORC_INIT
LD (HL),A
JR FC_MOTOROFF5
FC_MOTOROFF4: ; RCSMC
LD HL,FST_DOR ; POINT TO FDC_DOR
RES 1,(HL) ; CLEAR MOTORA
RES 2,(HL) ; CLEAR MOTORB
JR FC_MOTOROFF5
FC_MOTOROFF5:
CALL FC_SETDOR ; OUTPUT TO CONTROLLER
RET
;
;===============================================================================
; FDC OPERATIONS
;===============================================================================
;
FOP:
;
; INITIALIZATION
;
LD A,0
LD (FRB_LEN),A
LD A,FRC_OK
LD (FST_RC),A
LD B,0 ; B IS LOOP COUNTER
LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
FOP_CLR1:
CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR
IN A,(C) ; GET STATUS
LD (FST_MSR),A ; SAVE IT FOR POTENTIAL LATER DIAGNOSIS
AND 0C0H ; ISOLATE HIGH NIBBLE, RQM/DIO/EXM/CB
CP 0C0H ; LOOKING FOR RQM=1, DIO=1, BYTES PENDING
JP NZ,FOP_CMD1 ; NO BYTES PENDING, GO TO NEXT PHASE
INC C ; SWITCH TO DATA PORT
IN A,(C) ; GET THE PENDING BYTE AND DISCARD
DEC C ; SWITCH BACK TO MSR PORT
DJNZ FOP_CLR1 ; KEEP CHECKING TILL COUNTER EXHAUSTER
JP FOP_TOFDCRDY ; OTHERWISE, TIMEOUT
;
; SEND COMMAND
;
FOP_CMD1:
LD HL,FCP_BUF
LD A,(FCP_BUFLEN)
LD D,A ; D = CMD BYTES TO SEND
FOP_CMD2: ; START OF LOOP TO SEND NEXT BYTE
LD B,0 ; B IS LOOP COUNTER
FOP_CMD4: ; START OF STATUS LOOP, WAIT FOR FDC TO BE READY FOR BYTE
CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR
; TYPICAL MSR TRANSITIONS: <ENTRY> 80 <AFTER FIRST BYTE> 10 90 <AFTER SECOND/SUBSEQUENT BYTES> 90
LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
IN A,(C) ; READ MAIN STATUS REGISTER
LD (FST_MSR),A ; SAVE IT FOR POTENTIAL LATER DIAGNOSIS
AND 0C0H ; ISOLATE RQM/DIO
CP 080H ; LOOKING FOR RQM=1, DIO=0 (FDC READY FOR A BYTE)
JP Z,FOP_CMD6 ; GOOD, GO TO SEND BYTE
CP 0C0H ; HMMMM... RQM=1 & DIO=1, FDC WANTS TO SEND US DATA, UNEXPECTED
JP Z,FOP_RES ; GO IMMEDIATELY TO RESULTS???
DJNZ FOP_CMD4 ; LOOP TILL COUNTER EXHAUSTED
JP FOP_TOSNDCMD ; COUNTER EXHAUSTED, TIMEOUT / EXIT
FOP_CMD6: ; SEND NEXT BYTE
LD A,(HL) ; POINT TO NEXT BYTE TO SEND
LD C,(IY+CFG_DATA) ; SET C TO DATA PORT
OUT (C),A ; PUSH IT TO FDC
INC HL ; INCREMENT POINTER FOR NEXT TIME
DEC D ; DECREMENT NUM BYTES LEFT TO SEND
JP NZ,FOP_CMD2 ; DO NEXT BYTE
;
; EXECUTION PHASE
;
FOP_X1:
LD HL,(FXP_XR) ; LOAD THE EXECUTION ROUTINE ADDRESS
CALL JPHL ; CALL INDIRECTLY VIA HL
LD A,(FST_RC) ; CURRENT RESULT CODE
;CALL PC_SPACE
;CALL PRTHEXBYTE
CP FRC_OK ; ERROR?
RET NZ ; IF SO, ALL DONE
; JP FOP_RES ; CONTINUE WITH GETRESULTS
;
; RESULTS PHASE
;
FOP_RES:
LD B,0 ; B = BYTES RECEIVED
LD HL,FRB_LEN ; POINT TO BUFFER LENGTH
LD (HL),B ; UPDATE NUMBER OF BYTES RECEIVED
LD HL,FRB ; POINT TO RECEIVE BUFFER
FOP_RES0:
LD DE,0 ; DE IS LOOP COUNTER
LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
FOP_RES1:
CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR
IN A,(C) ; READ MAIN STATUS REGISTER
;CALL PC_SPACE
;CALL PRTHEXBYTE
LD (FST_MSR),A ; SAVE IT FOR POTENTIAL LATER DIAGNOSIS
AND $F0 ; REMOVE SEEK BITS
CP $D0 ; LOOKING FOR RQM=1, DIO=1, BUSY=1 (FDC BYTE PENDING)
JR Z,FOP_RES2 ; GOOD, GO TO RECEIVE BYTE
CP $80 ; DONE?
JR Z,FOP_EVAL ; IF SO, GO TO EVAL
DEC DE
LD A,D
OR E
JP NZ,FOP_RES1
JP FOP_TOGETRES ; OTHERWISE TIMEOUT ERROR
FOP_RES2: ; PROCESS NEXT PENDING BYTE
LD A,FRB_SIZ ; GET BUF SIZE
CP B ; REACHED MAX?
JP Z,FOP_BUFMAX ; HANDLE BUF MAX/EXIT
INC C ; SWITCH TO DATA PORT
IN A,(C) ; GET THE BYTE
DEC C ; SWITCH TO MSR PORT
LD (HL),A ; SAVE VALUE
INC HL ; INCREMENT BUF POS
INC B ; INCREMENT BYTES RECEIVED
PUSH HL ; SAVE HL
LD HL,FRB_LEN ; POINT TO BUFFER LENGTH
LD (HL),B ; UPDATE NUMBER OF BYTES RECEIVED
POP HL ; RESTORE HL
JR FOP_RES0 ; CONTINUE READ LOOP
;
; EXIT POINTS
;
FOP_NOTIMPL:
LD A,FRC_NOTIMPL
JP FOP_ERR
FOP_CMDERR:
LD A,FRC_CMDERR
JP FOP_ERR
FOP_ERROR:
LD A,FRC_ERROR
JP FOP_ERR
FOP_ABORT:
LD A,FRC_ABORT
JP FOP_ERR
FOP_BUFMAX:
LD A,FRC_BUFMAX
JP FOP_ERR
FOP_TOFDCRDY:
LD A,FRC_TOFDCRDY
JP FOP_ERR
FOP_TOSNDCMD:
LD A,FRC_TOSNDCMD
JP FOP_ERR
FOP_TOGETRES:
LD A,FRC_TOGETRES
JP FOP_ERR
FOP_TOEXEC:
LD A,FRC_TOEXEC
JP FOP_ERR
FOP_ERR:
LD (FST_RC),A
FOP_EVAL:
LD A,(FCP_CMD)
; DRVSTAT IS WEIRD, HAS ONLY ST3, NOTHING TO EVAL
CP CMD_DRVSTAT
JP Z,FOP_EXIT
; DO WE HAVE ST0?
LD A,(FRB_LEN)
CP 1
JP M,FOP_EXIT
FOP_EVALST0:
LD A,(FRB_ST0)
AND 11000000B
CP 01000000B ; ABTERM
JR Z,FOP_ABTERM
CP 10000000B ; INVCMD
JR Z,FOP_INVCMD
CP 11000000B ; DSKCHG
JR Z,FOP_DSKCHG
JR FOP_EXIT
FOP_ABTERM:
; SENSEINT DOES NOT USE ST1
LD A,(FCP_CMD)
CP CMD_SENSEINT
JR Z,FOP_ABTERM1
; DO WE HAVE ST1?
LD A,(FRB_LEN)
CP 2
JP M,FOP_ABTERM1
JR FOP_EVALST1
FOP_ABTERM1: ; NO FURTHER DATA, SET FST TO ABTERM
LD A,FRC_ABTERM
JP FOP_SETFST
FOP_INVCMD:
LD A,FRC_INVCMD
JP FOP_SETFST
FOP_DSKCHG:
LD A,FRC_DSKCHG
JP FOP_SETFST
FOP_EVALST1:
LD A,(FRB_ST1)
BIT 7,A
JP NZ,FOP_ENDCYL
BIT 5,A
JP NZ,FOP_DATAERR
BIT 4,A
JP NZ,FOP_OVERRUN
BIT 2,A
JP NZ,FOP_NODATA
BIT 1,A
JP NZ,FOP_NOTWRIT
BIT 0,A
JP NZ,FOP_MISADR
JP FOP_EXIT
FOP_ENDCYL:
; V5.3, USE EOT=R TO R/W ONLY ONE SECTOR
;LD A,FRC_ENDCYL
;JP FOP_SETFST
JP FOP_EXIT
FOP_DATAERR:
LD A,FRC_DATAERR
JP FOP_SETFST
FOP_OVERRUN:
LD A,FRC_OVERRUN
JP FOP_SETFST
FOP_NODATA:
LD A,FRC_NODATA
JP FOP_SETFST
FOP_NOTWRIT:
LD A,FRC_NOTWRIT
JP FOP_SETFST
FOP_MISADR:
LD A,FRC_MISADR
JP FOP_SETFST
FOP_SETFST:
LD (FST_RC),A
FOP_EXIT:
RET
;
; EXECUTION ROUTINES
;
FXR_READID:
JP FXRX
FXR_READ:
LD HL,BUFFER ; POINT TO SECTOR BUFFER START
LD DE,(FCD_SECSZ)
LD A,(DCD_MD) ; FIX: SHOULD NOT BE USING DCD HERE
CP MD_POLL
JP Z,FXRR
CP MD_INT
JP Z,IFXRR
CP MD_INTFAST
JP Z,FFXRR
CP MD_INTWAIT
JP Z,WFXRR
CP MD_DRQWAIT
JP Z,WFXRR
JP FXR_NOTIMPL
FXR_WRITE:
LD HL,BUFFER ; POINT TO SECTOR BUFFER START
LD DE,(FCD_SECSZ)
LD A,(DCD_MD) ; FIX: SHOULD NOT BE USING DCD HERE
CP MD_POLL
JP Z,FXRW
CP MD_INT
JP Z,IFXRW
CP MD_INTFAST
JP Z,FFXRW
CP MD_INTWAIT
JP Z,WFXRW
CP MD_DRQWAIT
JP Z,WFXRW
JP FXR_NOTIMPL
FXR_FMTTRK:
LD HL,FXP_BUF ; POINT TO BUFFER START
LD D,0
LD A,(FXP_BUFLEN) ; GET BYTE COUNT TO WRITE
LD E,A
LD A,(DCD_MD) ; FIX: SHOULD NOT BE USING DCD HERE
CP MD_POLL
JP Z,FXRW
CP MD_INT
JP Z,IFXRW
CP MD_INTFAST
JP Z,IFXRW ; CAN'T USE FFXRW BECAUSE IT IS NOT 512 BYTES
CP MD_INTWAIT
JP Z,WFXRW
CP MD_DRQWAIT
JP Z,WFXRW
JP FXR_NOTIMPL
FXR_NOTIMPL:
FXR_READDEL:
FXR_WRITEDEL:
FXR_READTRK:
FXR_SCANEQ:
FXR_SCANLOEQ:
FXR_SCANHIEQ:
LD A,FRC_NOTIMPL
LD (FST_RC),A
; FALL THROUGH TO RET BELOW
FXR_NOP:
FXR_RECAL:
FXR_SENSEINT:
FXR_SPECIFY:
FXR_DRVSTAT:
FXR_SEEK:
FXR_VERSION:
RET
;
; NULL EXECUTION, NO DATA TO READ/WRITE (USED BY READID)
;
FXRX:
LD DE,1000H ; DE IS LOOP COUNTER, 4096 ITERATIONS OF 25ms
LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
FXRX1:
CALL DELAY
IN A,(C) ; GET MSR
;AND 0E0H ; ISOLATE RQM/DIO/EXM
CP $D0 ; WE WANT RQM=1,DIO=1,EXM=0 (READY TO READ A BYTE W/ EXEC INACTIVE)
JP Z,FXR_END ; GOT IT, EXIT CLEAN
DEC DE ; DECREMENT COUNTER (16 BIT)
LD A,D ; CHECK FOR ZERO
OR E ; "
JR NZ,FXRX1 ; NOT ZERO YET, KEEP CHECKING
JP FXR_TO ; OTHERWISE, TIMEOUT ERROR
RET
;
; READ DATA
;
FXRR: LD A,E ; LOW BYTE OF COUNT TO ACCUM
OR A ; TEST FOR ZERO
JR Z,FXRR1 ; IF ZERO, DO NOT ADJUST ITERATIONS
INC D ; OTHERWISE, ITERATIONS IS ONE MORE THAN HIGH BYTE
FXRR1: LD B,E ; LOW BYTE OF COUNT TO B
LD A,D ; HIGH BYTE OF COUNT
LD (FXP_ITER),A ; ... IS ITERATION COUNT
LD A,(CPUSPD) ; CPU SPEED SCALER
LD (FXP_TO),A ; SAVE IT AS OUTER LOOP TIMEOUT
LD IX,FXP_TO ; (IX) IS FXP_TO, (IX+1) IS FCP_ITER
LD C,(IY+CFG_DATA) ; SET C TO DATA PORT
LD DE,0
DI ; DISABLE INTERRUPTS TO AVOID OVERRUN
FXRR2: DEC C ; [04] SET C TO MSR PORT
FXRR3: LD DE,0 ; [10] TIMEOUT COUNTER
FXRR4: IN A,(C) ; [12] GET MSR
CP $F0 ; [07] BYTE READY?
JR Z,FXRR5 ; [12/7] GET IT
;LD (FST_MSR),A ; [13] *DEBUG* SAVE MSR FOR LATER
DEC E ; [04] DEC LSB OF INNER TIMEOUT COUNTER
JR NZ,FXRR4 ; [12/7] LOOP IF LSB IS NOT EXHAUSTED
CP $D0 ; [07] IF RQM=1, DIO=1, EXM=0, CB=1, EXECUTION ABORTED
JP Z,FXR_ABORT ; [10] IF NOT SET, EXECUTION ABORTED
DEC D ; [04] DEC MSB OF INNER TIMEOUT COUNTER
JR NZ,FXRR4 ; [12/7] LOOP IF MSB IS NOT EXHAUSTED
DEC (IX) ; [23] DECREMENT OUTER LOOP COUNTER
JR NZ,FXRR3 ; [12/7] LOOP IF NOT EXHAUSTED
JP FXR_TO ; [10] OTHERWISE, HANDLE TIMEOUT
FXRR5: INC C ; [04] POINT TO DATA PORT
INI ; [16] (HL) := (C), HL++, B--
JR NZ,FXRR2 ; [12/7] LOOP
DEC (IX+1) ; [23] DECREMENT ITERATION COUNT
JR NZ,FXRR2 ; [12] IF MORE ITERATIONS, LOOP
JP FXR_END ; [10] ELSE DONE
;
; INT READ DATA - SAFE VERSION
; HANDLES FDC ERRORS, BUT NO TIMEOUT
;
; AVOID RETURN FROM HALT IN PROBLEMATIC ADDRESS RANGE XX30-XX3F!!!
.IF ((($ & 0F0H) == 20H) | (($ & 0F0H) == 30H))
.ORG (($ & 0FF00H) + 40H)
.ENDIF
;
IFXRR:
DI
LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
IFXRR2:
EI
IFXRRX .EQU $ - IFXRR
HALT
IN A,(C)
BIT 5,A
JP Z,FXR_ABORT
INC C ; SWITCH C TO DATA PORT
INI
DEC C ; SWITCH C BACK TO MSR PORT
DEC DE
LD A,E
OR D
JP NZ,IFXRR2
JP FXR_END
;
; INT READ DATA - FAST VERSION
; FIXED SECTOR SIZE OF 512 BYTES
; HANGS ON FDC ERRORS, NO TIMEOUT
;
; AVOID RETURN FROM HALT IN PROBLEMATIC ADDRESS RANGE XX30-XX3F!!!
.IF ((($ & 0F0H) == 20H) | (($ & 0F0H) == 30H))
.ORG (($ & 0FF00H) + 40H)
.ENDIF
;
FFXRR:
DI
LD C,(IY+CFG_DATA) ; SET C TO DATA PORT FOR INI
FFXRR2 EI
HALT
FFXRRX1 .EQU $ - FFXRR
INI
JP NZ,FFXRR2
FFXRR3 EI
HALT
FFXRRX2 .EQU $ - FFXRR
INI
JP NZ,FFXRR3
JP FXR_END
;
; WAIT READ DATA
; HANGS ON FDC ERRORS, NO TIMEOUT
;
WFXRR:
DI
LD C,(IY+CFG_DMA)
WFXRR2:
INI ; GET PENDING BYTE
DEC DE ; DECREMENT BYTE COUNT
LD A,D
OR E
JP NZ,WFXRR2 ; IF NOT ZERO, REPEAT LOOP
JP FXR_END ; CLEAN EXIT
;
; WRITE DATA
;
FXRW: LD A,E ; LOW BYTE OF COUNT TO ACCUM
OR A ; TEST FOR ZERO
JR Z,FXRW1 ; IF ZERO, DO NOT ADJUST ITERATIONS
INC D ; OTHERWISE, ITERATIONS IS ONE MORE THAN HIGH BYTE
FXRW1: LD B,E ; LOW BYTE OF COUNT TO B
LD A,D ; HIGH BYTE OF COUNT
LD (FXP_ITER),A ; ... IS ITERATION COUNT
LD A,(CPUSPD) ; CPU SPEED SCALER
LD (FXP_TO),A ; SAVE IT AS OUTER LOOP TIMEOUT
LD IX,FXP_TO ; (IX) IS FXP_TO, (IX+1) IS FCP_ITER
LD C,(IY+CFG_DATA) ; SET C TO DATA PORT
LD DE,0
DI ; DISABLE INTERRUPTS TO AVOID OVERRUN
FXRW2: DEC C ; [04] SET C TO MSR PORT
FXRW3: LD DE,0 ; [10] TIMEOUT COUNTER
FXRW4: IN A,(C) ; [12] GET MSR
CP $B0 ; [07] BYTE READY?
JR Z,FXRW5 ; [12/7] GET IT
;LD (FST_MSR),A ; [13] *DEBUG* SAVE MSR FOR LATER
DEC E ; [04] DEC LSB OF INNER TIMEOUT COUNTER
JR NZ,FXRW4 ; [12/7] LOOP IF LSB IS NOT EXHAUSTED
CP $D0 ; [07] IF RQM=1, DIO=1, EXM=0, CB=1, EXECUTION ABORTED
JP Z,FXR_ABORT ; [10] IF NOT SET, EXECUTION ABORTED
DEC D ; [04] DEC MSB OF INNER TIMEOUT COUNTER
JR NZ,FXRW4 ; [12/7] LOOP IF MSB IS NOT EXHAUSTED
DEC (IX) ; [23] DECREMENT OUTER LOOP COUNTER
JR NZ,FXRW3 ; [12/7] LOOP IF NOT EXHAUSTED
JP FXR_TO ; [10] OTHERWISE, HANDLE TIMEOUT
FXRW5: INC C ; [04] POINT TO DATA PORT
OUTI ; [16] (C) := (HL), HL++, B--
JR NZ,FXRW2 ; [12/7] LOOP
DEC (IX+1) ; [23] DECREMENT ITERATION COUNT
JR NZ,FXRW2 ; [12] IF MORE ITERATIONS, GO DO IT
JP FXR_END ; [10] ELSE DONE
;
; INT WRITE DATA - SAFE VERSION
; HANDLES FDC ERRORS, BUT NO TIMEOUT
;
; AVOID RETURN FROM HALT IN PROBLEMATIC ADDRESS RANGE XX30-XX3F!!!
.IF ((($ & 0F0H) == 20H) | (($ & 0F0H) == 30H))
.ORG (($ & 0FF00H) + 40H)
.ENDIF
;
IFXRW:
DI
LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
IFXRW2: EI
HALT
IN A,(C)
BIT 5,A
JP Z,FXR_ABORT
INC C ; SWITCH TO DATA PORT
OUTI
DEC C ; SWITCH BACK TO MSR PORT
DEC DE
LD A,E
OR D
JP NZ,IFXRW2
JP FXR_END
;
; INT WRITE DATA - FAST VERSION
; FIXED SECTOR SIZE OF 512 BYTES
; HANGS ON FDC ERRORS, NO TIMEOUT
;
; AVOID RETURN FROM HALT IN PROBLEMATIC ADDRESS RANGE XX30-XX3F!!!
.IF ((($ & 0F0H) == 20H) | (($ & 0F0H) == 30H))
.ORG (($ & 0FF00H) + 40H)
.ENDIF
;
FFXRW:
DI
LD C,(IY+CFG_DATA) ; SET C TO DATA PORT
FFXRW2 EI
HALT
OUTI
JP NZ,FFXRW2
FFXRW3 EI
HALT
OUTI
JP NZ,FFXRW3
JP FXR_END
;
; WAIT WRITE DATA
; HANGS ON FDC ERRORS, NO TIMEOUT
;
WFXRW:
DI
LD C,(IY+CFG_DMA)
WFXRW2:
OUTI ; WRITE IT 16ts
DEC DE ; DECREMENT BYTE COUNT 6ts
LD A,D ; 4ts
OR E ; 4ts
JP NZ,WFXRW2 ; IF NOT ZERO, REPEAT LOOP 10ts = 40
JP FXR_END ; CLEAN EXIT
;
; COMMON COMPLETION CODE FOR ALL EXECUTION ROUTINES
;
FXR_TO:
; SAVE CURRENT MSR VALUE
;LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
;IN A,(C)
LD (FST_MSR),A
; SET ERROR AND GET OUT W/O PULSING TC
LD A,FRC_TOEXEC
LD (FST_RC),A
JR FXR_END2
FXR_ABORT:
; SAVE CURRENT MSR VALUE
;LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
;IN A,(C)
LD (FST_MSR),A
; LET RESULTS PHASE HANDLE ERROR, DO NOT PULSE TC, COMMAND ALREADY TERMINATED
;LD A,FRC_ABORT
;LD (FST_RC),A
JR FXR_END2
FXR_END:
; SAVE CURRENT MSR VALUE
;LD C,(IY+CFG_MSR) ; SET C TO MSR PORT
;IN A,(C)
LD (FST_MSR),A
; DO NOT PULSE TC AT END OF FORMAT OR READID, THOSE COMMANDS SELF-TERMINATE
;LD A,(FCP_CMD)
;CP CMD_FMTTRK
;JR Z,FXR_END2
;CP CMD_READID
;JR Z,FXR_END2
CALL FC_PULSETC
FXR_END2:
#IF 0
LD (FXP_A),A
LD (FXP_BC),BC
LD (FXP_DE),DE
LD (FXP_HL),HL
CALL FXR_DUMP
#ENDIF
EI ; I/O FINISHED, INTS BACK ON
RET
;
;===============================================================================
; COMMAND PROCESSING STATUS DISPLAY
;===============================================================================
;
; PRINT STATUS
;
FC_PRTFST:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
LD A,(FST_RC) ; A GETS FST_RC
LD B,FSST_COUNT ; B GETS TABLE ENTRY COUNT
LD HL,FSST
LD DE,FSST_ENTSIZ ; TABLE ENTRY LENGTH
FC_PRTFST0: ; START OF LOOP
LD C,(HL)
CP C
JP Z,FC_PRTFST1 ; FOUND CODE
ADD HL,DE ; POINT TO NEXT ENTRY
DJNZ FC_PRTFST0 ; CHECK NEXT ENTRY TILL COUNT IS ZERO
; NO MATCHING ENTRY, PRINT THE HEX VALUE
CALL PC_SPACE
CALL PC_LBKT
CALL PRTHEXBYTE
CALL PC_RBKT
JP FC_PRTFSTX
FC_PRTFST1: ; ENTRY FOUND, PRINT IT
CALL PC_SPACE
INC HL
LD E,(HL)
INC HL
LD D,(HL)
CALL PC_LBKT
CALL WRITESTR
CALL PC_RBKT
FC_PRTFSTX:
POP HL
POP DE
POP BC
POP AF
RET
;
; PRINT COMMAND
;
FC_PRTCMD:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
LD A,(FCP_CMD) ; A GETS THE COMMAND CODE
LD B,FCT_COUNT ; B GETS TABLE ENTRY COUNT
LD HL,FCT
LD DE,FCT_ENTSIZ ; TABLE ENTRY LENGTH
FCPC_LOOP: ; START OF LOOP
LD C,(HL)
CP C
JP Z,FCPC_MATCH ; FOUND CODE
ADD HL,DE ; POINT TO NEXT ENTRY
DJNZ FCPC_LOOP ; CHECK NEXT ENTRY TILL COUNT IS ZERO
; NO MATCHING ENTRY, PRINT THE HEX VALUE
CALL PC_SPACE
CALL PC_LBKT
CALL PRTHEXBYTE
CALL PC_RBKT
JP FCPC_EXIT
FCPC_MATCH: ; ENTRY FOUND, PRINT IT
INC HL
LD E,(HL)
INC HL
LD D,(HL)
CALL WRITESTR
FCPC_EXIT:
POP HL
POP DE
POP BC
POP AF
RET
;
; PRINT RESULTS
;
FC_PRTRESULTS:
; IF TRACE IS SET, FORCE PRINT RESULTS
LD A,(FCD_TRACE)
OR A
JP NZ,FCPR2
; IF RC=OK, GET OUT, NOTHING TO PRINT
LD A,(FST_RC)
CP FRC_OK
RET Z
; SPECIAL CASE, DON'T PRINT IF SENSEINT & INVCMD/DSK CHG/ABTERM
LD A,(FCP_CMD)
CP CMD_SENSEINT
JP NZ,FCPR2
LD A,(FST_RC)
CP FRC_INVCMD
JP Z,FCPR_EXIT
CP FRC_DSKCHG
JP Z,FCPR_EXIT
CP FRC_ABTERM
JP Z,FCPR_EXIT
JP FCPR_EXIT
FCPR2:
CALL NEWLINE
CALL FC_PRTCMD
CALL PC_COLON
LD A,(FCP_BUFLEN)
LD DE,FCP_BUF
CALL PRTHEXBUF
LD DE,STR_ARROW
CALL WRITESTR
LD A,(FRB_LEN)
LD DE,FRB
CALL PRTHEXBUF
LD A,(FDCBM)
AND _ZETA | _DIO3
JR Z,FCPR3
LD DE,STR_DSKCHG
CALL WRITESTR
LD C,(IY+CFG_DIR)
IN A,(C)
AND 01H
CALL PRTHEXBYTE
FCPR3:
LD A,(FST_RC)
CALL FC_PRTFST
FCPR_EXIT:
RET
;
; DUMP EXECUTION INFO
;
FXR_DUMP:
CALL NEWLINE
LD DE,STR_OP
CALL WRITESTR
CALL PC_COLON
LD DE,STR_MSR
CALL WRITESTR
LD A,(FST_MSR)
CALL PRTHEXBYTE
LD DE,STR_A
CALL WRITESTR
LD A,(FXP_A)
CALL PRTHEXBYTE
LD DE,STR_BC
CALL WRITESTR
LD BC,(FXP_BC)
LD A,B
CALL PRTHEXBYTE
LD A,C
CALL PRTHEXBYTE
LD DE,STR_DE
CALL WRITESTR
LD BC,(FXP_DE)
LD A,B
CALL PRTHEXBYTE
LD A,C
CALL PRTHEXBYTE
LD DE,STR_HL
CALL WRITESTR
LD BC,(FXP_HL)
LD A,B
CALL PRTHEXBYTE
LD A,C
CALL PRTHEXBYTE
LD DE,STR_ITER
CALL WRITESTR
LD A,(FXP_ITER)
CALL PRTHEXBYTE
LD DE,STR_TO
CALL WRITESTR
LD A,(FXP_TO)
CALL PRTHEXBYTE
RET
;
; DOR BITS (3AH)
;
; DISKIO 250KBPS 500KBPS
; ------- ------- -------
;D7 /DC/RDY 1 (N/A) 1 (N/A)
;D6 /REDWC (DENSITY) 0 (DD) 1 (HD)
;D5 P0* (PRECOMP BIT 0) 1 \ 0 \
;D4 P1* (PRECOMP BIT 1) 0 (125NS) 1 (125NS)
;D3 P2* (PRECOMP BIT 2) 0 / 0 /
;D2 MINI (BITRATE) 1 (250KBPS) 0 (500KBPS)
;D1 /MOTOR (ACTIVE LO) 1 (OFF) 1 (OFF)
;D0 TC (TERMINAL COUNT) 0 (OFF) 0 (OFF)
;
; *NOTE: FOR 9229 DATA SEPARATOR USED IN DISKIO, VALUE OF PRECOMP BITS CHANGES WITH MINI
; IF MINI=1 (250KBPS), USE 001 FOR 125NS PRECOMP, IF MINI=0, USE 010 FOR 125NS PRECOMP
;
DORA_BR250 .EQU 10100110B ; 250KBPS
DORA_BR500 .EQU 11010010B ; 500KBPS
;
DORA_INIT .EQU DORA_BR250
;
; ZETA/DISKIO3 250KBPS 500KBPS
; ------------ ------- -------
;D7 /FDC_RST 1 (RUN) 1 (RUN)
;D6 DENSEL 1 (DD) 0 (HD)
;D5 P0 (PRECOMP BIT 0) 1 \ 1 \
;D4 P1 (PRECOMP BIT 1) 0 (125NS) 0 (125NS)
;D3 P2 (PRECOMP BIT 2) 0 / 0 /
;D2 MINI (BITRATE) 1 (250KBPS) 0 (500KBPS)
;D1 MOTOR 0 (OFF) 0 (OFF)
;D0 TC 0 (OFF) 0 (OFF)
;
; MOTOR AND DENSITY SELECT ARE INVERTED ON ZETA/DISKIO3
;
DORB_BR250 .EQU 11100100B ; 250KBPS
DORB_BR500 .EQU 10100000B ; 500KBPS
;
DORB_INIT .EQU DORB_BR250
;
; *** DIDE/N8/ZETA2/RCWDC/SMZ80 ***
;
DORC_INIT .EQU 00001100B ; SOFT RESET INACTIVE, DMA ENABLED
;
DORC_BR250 .EQU DORC_INIT
DORC_BR500 .EQU DORC_INIT
;
; *** RCSMC ***
;
DORD_BR250 .EQU 10100000B ; 250KBPS
DORD_BR500 .EQU 11100000B ; 500KBPS
;
DORD_INIT .EQU DORB_BR250
;
; DCR (ONLY APPLIES TO DIDE, N8, AND ZETA2)
;
DCR_BR250 .EQU 01H ; 250KBPS
DCR_BR500 .EQU 00H ; 500KBPS
;
;===============================================================================
; GENERAL UTILITY ROUTINES
;===============================================================================
;
; INITIALIZE BUFFER WITH FILLER BYTE
; HL = ADDRESS OF BUFFER
; DE = SIZE OF BUFFER
; B = FILLER BYTE VALUE
;
FILL_BUFFER:
LD A,B
LD (HL),A
INC HL
DEC DE
LD A,D
OR E
JP NZ,FILL_BUFFER
RET
;
; INITIALIZE BUFFER WITH PATTERN
; HL = ADDRESS OF BUFFER
; DE = SIZE OF BUFFER
; B = STARTING BYTE VALUE
;
PAT_BUFFER:
LD A,B
LD (HL),A
INC HL
DEC DE
INC B
LD A,D
OR E
JP NZ,PAT_BUFFER
RET
;
; PRINT A BLOCK OF MEMORY NICELY FORMATTED
;
DUMP_BUFFER:
CALL NEWLINE ;
BLKRD:
CALL PHL ; PRINT START LOCATION
LD C,16 ; SET FOR 16 LOCS
PUSH HL ; SAVE STARTING HL
NXTONE:
LD A,(HL) ; GET BYTE
CALL PRTHEXBYTE ; PRINT IT
CALL PC_SPACE ;
UPDH:
INC HL ; POINT NEXT
DEC C ; DEC. LOC COUNT
JR NZ,NXTONE ; IF LINE NOT DONE
; NOW PRINT 'DECODED' DATA TO RIGHT OF DUMP
PCRLF:
CALL PC_SPACE ; SPACE IT
LD C,16 ; SET FOR 16 CHARS
POP HL ; GET BACK START
PCRLF0:
LD A,(HL) ; GET BYTE
AND 060H ; SEE IF A 'DOT'
LD A,(HL) ; O.K. TO GET
JR NZ,PDOT ;
DOT:
LD A,2EH ; LOAD A DOT
PDOT:
CALL COUT ; PRINT IT
INC HL ;
LD A,D ;
CP H ;
JR NZ,UPDH1 ;
LD A,E ;
CP L ;
JP Z,DUMP_END ;
;
;IF BLOCK NOT DUMPED, DO NEXT CHARACTER OR LINE
UPDH1:
DEC C ; DEC. CHAR COUNT
JR NZ,PCRLF0 ; DO NEXT
CONTD:
CALL NEWLINE ;
JP BLKRD ;
DUMP_END:
RET ;
;
; UTILITY PROCS TO PRINT SINGLE CHARACTERS
;
PC_SPACE:
PUSH AF ; Store AF
LD A,' ' ; LOAD A "SPACE"
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_HYPHEN:
PUSH AF ; Store AF
LD A,'-' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_COLON:
PUSH AF ; Store AF
LD A,':' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_EQUAL:
PUSH AF ; Store AF
LD A,'=' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_CR:
PUSH AF ; Store AF
LD A,CHR_CR ; LOAD A <CR>
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_LF:
PUSH AF ; Store AF
LD A,CHR_LF ; LOAD A <LF>
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_LBKT:
PUSH AF ; Store AF
LD A,'[' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_RBKT:
PUSH AF ; Store AF
LD A,']' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_LPAREN:
PUSH AF ; Store AF
LD A,'(' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_RPAREN:
PUSH AF ; Store AF
LD A,')' ; LOAD A COLON
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
PC_BS:
PUSH AF ; Store AF
LD A,CHR_BS ; LOAD A <BS>
CALL COUT ; SCREEN IT
POP AF ; RESTORE AF
RET ; DONE
NEWLINE_USED .DB 1
NEWLINE:
CALL PC_CR
CALL PC_LF
LD A,1
PUSH AF
LD (NEWLINE_USED),A
POP AF ; RESTORE AF
RET ; DONE
COPYSTR:
LD A,(HL)
CP '$'
RET Z
LDI
JR COPYSTR
;
;__COUT_________________________________________________________________________________________________________________________
;
; PRINT CONTENTS OF A
;________________________________________________________________________________________________________________________________
;
COUT:
PUSH BC ;
PUSH AF ;
PUSH HL ;
PUSH DE ;
LD C,2 ; BDOS FUNC: CONSOLE WRITE CHAR
LD E,A ; CHARACTER TO E
CALL $0005 ; CALL BDOS
POP DE ;
POP HL ;
POP AF ;
POP BC ;
RET ; DONE
;
;__PHL_________________________________________________________________________________________________________________________
;
; PRINT THE HL REG ON THE SERIAL PORT
;________________________________________________________________________________________________________________________________
;
PHL:
LD A,H ; GET HI BYTE
CALL PRTHEXBYTE ; DO HEX OUT ROUTINE
LD A,L ; GET LOW BYTE
CALL PRTHEXBYTE ; HEX IT
CALL PC_SPACE ;
RET ; DONE
;
; GET A LINE BUFFER WITH 2 HEX CHARS, HL=ADDRESS OF LINE BUFFER
; EXIT WITH C = NUMBER OF CHARS, C=0 MEANS NOTHING ENTERED
;
GETLNHEX:
LD C,0 ; C = CHAR COUNT
GLH_LOOP:
CALL GETKEYUC
OR A
JP Z,GLH_LOOP
CP CHR_CR
JP Z,GLH_CHK
CP CHR_BS
JP Z,GLH_BS
CP '0'
JP M,GLH_LOOP
CP '9' + 1
JP M,GLH_APPEND
CP 'A'
JP M,GLH_LOOP
CP 'F' + 1
JP M,GLH_APPEND
JP GLH_LOOP
GLH_BS:
LD A,C
OR A
JP Z,GLH_LOOP
CALL PC_BS
CALL PC_SPACE
CALL PC_BS
DEC C
DEC HL
JP GLH_LOOP
GLH_APPEND:
LD B,A
LD A,C
CP 2
JP P,GLH_LOOP
LD A,B
CALL COUT
LD (HL),A
INC C
INC HL
JP GLH_LOOP
GLH_CHK:
LD A,C
CP 2
JP Z,GLH_EXIT
CP 0
JP Z,GLH_EXIT
JP GLH_LOOP
GLH_EXIT:
RET
;
;__HEXIN__________________________________________________________________________________________________________________________
;
; GET ONE BYTE OF HEX DATA FROM BUFFER IN HL, RETURN IN A
;________________________________________________________________________________________________________________________________
;
HEXIN:
PUSH BC ; SAVE BC REGS.
CALL NIBL ; DO A NIBBLE
RLC A ; MOVE FIRST BYTE UPPER NIBBLE
RLC A ;
RLC A ;
RLC A ;
LD B,A ; SAVE ROTATED BYTE
CALL NIBL ; DO NEXT NIBBLE
ADD A,B ; COMBINE NIBBLES IN ACC.
POP BC ; RESTORE BC
RET ; DONE
NIBL:
LD A,(HL) ; GET K.B. DATA
INC HL ; INC KB POINTER
CP 40H ; TEST FOR ALPHA
JR NC,ALPH ;
AND 0FH ; GET THE BITS
RET ;
ALPH:
AND 0FH ; GET THE BITS
ADD A,09H ; MAKE IT HEX A-F
RET ;
;
; COPY A $ TERMINATED STRING FROM ADDRESS IN DE TO ADDRESS IN HL
; DE = ADDRESS OF SOURCE STRING
; LH = ADDRESS OF TARGET LOCATION
;
STRCPY:
LD A,(DE)
CP '$'
JP Z,STRCPYX
LD (HL),A
INC HL
INC DE
JP STRCPY
STRCPYX:
RET
;
; GET A HEX BYTE VALUE FROM THE USER
; WILL UPDATE STORED VALUE, EMPTY RESPONSE LEAVES VALUE ALONE
; DE = ADDRESS OF PROMPT STRING
; HL = ADDRESS OF VALUE
; BC = HI/BO ALLOWABLE RANGE OF VALID VALUES
;
GHB_PROMPTP .DW 0
GHB_RANGE .DW 0
GHB_VALUEP .DW 0
GHB_CLEAR .DB " \b\b$"
GETHEXBYTE:
LD BC,000FFH
GETHEXBYTERNG:
LD (GHB_PROMPTP),DE
LD (GHB_RANGE),BC
LD (GHB_VALUEP),HL
CALL NEWLINE
GHB_LOOP:
CALL PC_CR
LD DE,STR_ENTER
CALL WRITESTR
CALL PC_SPACE
LD DE,(GHB_PROMPTP)
CALL WRITESTR
CALL PC_SPACE
LD BC,(GHB_RANGE)
CALL PC_LBKT
LD A,B
CALL PRTHEXBYTE
CALL PC_HYPHEN
LD A,C
CALL PRTHEXBYTE
CALL PC_RBKT
CALL PC_SPACE
CALL PC_LPAREN
LD HL,(GHB_VALUEP)
LD A,(HL)
CALL PRTHEXBYTE
CALL PC_RPAREN
CALL PC_COLON
CALL PC_SPACE
LD DE,GHB_CLEAR
CALL WRITESTR
LD HL,KEYBUF
CALL GETLNHEX
LD A,C
CP 0 ; RETAIN CURRENT VALUE
JP Z,GHB_EXIT
CP 2 ; INPUT LOOKS OK, UPDATE IT
JP Z,GHB_CHK
JP GHB_LOOP ; ANYTHING ELSE, BAD INPUT, DO OVER
GHB_CHK:
LD HL,KEYBUF
CALL HEXIN
LD BC,(GHB_RANGE)
CP B
JP C,GHB_LOOP
CP C
JP Z,GHB_OK
JP NC,GHB_LOOP
GHB_OK:
LD HL,(GHB_VALUEP)
LD (HL),A
GHB_EXIT:
RET
;
; PRINT THE HEX BYTE VALUE IN A
;
HEXSTRBUF .TEXT "XX$"
;
PRTHEXBYTE:
PUSH AF
PUSH DE
LD DE,HEXSTRBUF
CALL HEXSTRBYTE
LD A,'$'
LD (DE),A
LD DE,HEXSTRBUF
CALL WRITESTR
POP DE
POP AF
RET
;
; PRINT THE HEX WORD VALUE IN BC
;
PRTHEXWORD:
PUSH AF
LD A,B
CALL PRTHEXBYTE
LD A,C
CALL PRTHEXBYTE
POP AF
RET
;
; CONVERT VALUE IN A TO A 2 CHARACTER HEX STRING AT DE
;
HEXCHR .TEXT "0123456789ABCDEF"
;
HEXSTRBYTE:
PUSH BC
PUSH HL
PUSH AF
LD BC,0
RRA
RRA
RRA
RRA
AND 0FH
LD C,A
LD HL,HEXCHR
ADD HL,BC
LD A,(HL)
LD (DE),A
INC DE
POP AF
PUSH AF
LD BC,0
AND 0FH
LD C,A
LD HL,HEXCHR
ADD HL,BC
LD A,(HL)
LD (DE),A
INC DE
POP AF
POP HL
POP BC
RET
;
; CONVERT VALUE IN BC TO A 4 CHARACTER HEX STRING AT DE
;
HEXSTRWORD:
LD A,B
CALL HEXSTRBYTE
LD A,C
CALL HEXSTRBYTE
RET
;
; PRINT A BYTE BUFFER IN HEX POINTED TO BY DE
; REGISTER A HAS SIZE OF BUFFER
;
PRTHEXBUF:
CP 0 ; EMPTY BUFFER?
JP Z,PRTHEXBUF2
LD B,A
PRTHEXBUF1:
CALL PC_SPACE
LD A,(DE)
CALL PRTHEXBYTE
INC DE
DJNZ PRTHEXBUF1
JP PRTHEXBUFX
PRTHEXBUF2:
CALL PC_SPACE
LD DE,STR_EMPTY
CALL WRITESTR
PRTHEXBUFX:
RET
;
; JP TO ADDRESS IN HL IN HEX POINTED TO BY DE
; MOSTLY USEFUL TO PERFORM AN INDIRECT CALL LIKE:
; LD HL,xxxx
; CALL JPHL
;
JPHL JP (HL)
;
; GENERATE A RANDOM BYTE
;
; RETURNS PSEUDO RANDOM 8 BIT NUMBER IN A. ONLY AFFECTS A.
; (SEED) IS THE BYTE FROM WHICH THE NUMBER IS GENERATED AND MUST BE
; INITIALIZED TO A NON ZERO VALUE OR THIS FUNCTION WILL ALWAYS RETURN
; ZERO.
;
RB_SEED .DB 1 ; RNDBYTE SEED (MUST NOT BE ZERO)
;
RNDBYTE:
LD A,(RB_SEED) ; GET SEED
AND 0B8H ; MASK NON-FEEDBACK BITS
SCF ; SET CARRY
JP PO,RB_NC ; SKIP CLEAR IF ODD
CCF ; COMPLEMENT CARRY (CLEAR IT)
RB_NC LD A,(RB_SEED) ; GET SEED BACK
RLA ; ROTATE CARRY INTO BYTE
LD (RB_SEED),A ; SAVE BACK FOR NEXT
RET ; DONE
;
; ADD HL,A
;
; A REGISTER IS DESTROYED!
;
ADDHLA:
ADD A,L
LD L,A
RET NC
INC H
RET
;
; OUTPUT A '$' TERMINATED STRING
;
WRITESTR:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
LD C,09H
CALL 0005H
POP HL
POP DE
POP BC
POP AF
RET
;
; READ A KEY, RETURN VALUE IN A
;
GETKEY:
PUSH BC
PUSH DE
PUSH HL
LD C,06H
LD E,0FFH
CALL 0005H
POP HL
POP DE
POP BC
CP 03
JP Z,EXIT
RET
GETKEYUC:
CALL GETKEY
CP 'a'
JP M,GETKEYUC_EXIT
CP 'z' + 1
JP M,GETKEYUC_FIX
JP GETKEYUC_EXIT
GETKEYUC_FIX:
AND 11011111B
GETKEYUC_EXIT:
RET
;
; DELAY 16US (CPU SPEED COMPENSATED) INCUDING CALL/RET INVOCATION
; REGISTER A AND FLAGS DESTROYED
; NO COMPENSATION FOR Z180 MEMORY WAIT STATES
; THERE IS AN OVERHEAD OF 3TS PER INVOCATION
; IMPACT OF OVERHEAD DIMINISHES AS CPU SPEED INCREASES
;
; CPU SCALER (CPUSCL) = (CPUHMZ - 2) FOR 16US + 3TS DELAY
; NOTE: CPUSCL MUST BE >= 1!
;
; EXAMPLE: 8MHZ CPU (DELAY GOAL IS 16US)
; LOOP = ((6 * 16) - 5) = 91TS
; TOTAL COST = (91 + 40) = 131TS
; ACTUAL DELAY = (131 / 8) = 16.375US
;
; --- TOTAL COST = (LOOP COST + 40) TS -----------------+
DELAY: ; 17TS (FROM INVOKING CALL) |
LD A,(CPUSCL) ; 13TS |
; |
DELAY1: ; |
; --- LOOP = ((CPUSCL * 16) - 5) TS ------------+ |
DEC A ; 4TS | |
#IFDEF CPU_Z180 ; | |
OR A ; +4TS FOR Z180 | |
#ENDIF ; | |
JR NZ,DELAY1 ; 12TS (NZ) / 7TS (Z) | |
; ----------------------------------------------+ |
; |
RET ; 10TS (RETURN) |
;-------------------------------------------------------+
;
; DELAY 16US * DE (CPU SPEED COMPENSATED)
; REGISTER DE, A, AND FLAGS DESTROYED
; NO COMPENSATION FOR Z180 MEMORY WAIT STATES
; THERE IS A 27TS OVERHEAD FOR CALL/RET PER INVOCATION
; IMPACT OF OVERHEAD DIMINISHES AS DE AND/OR CPU SPEED INCREASES
;
; CPU SCALER (CPUSCL) = (CPUHMZ - 2) FOR 16US OUTER LOOP COST
; NOTE: CPUSCL MUST BE > 0!
;
; EXAMPLE: 8MHZ CPU, DE=6250 (DELAY GOAL IS .1 SEC OR 100,000US)
; INNER LOOP = ((16 * 6) - 5) = 91TS
; OUTER LOOP = ((91 + 37) * 6250) = 800,000TS
; ACTUAL DELAY = ((800,000 + 27) / 8) = 100,003US
;
; --- TOTAL COST = (OUTER LOOP + 27) TS ------------------------+
VDELAY: ; 17TS (FROM INVOKING CALL) |
; |
; --- OUTER LOOP = ((INNER LOOP + 37) * DE) TS ---------+ |
LD A,(CPUSCL) ; 13TS | |
; | |
VDELAY1: ; | |
; --- INNER LOOP = ((CPUSCL * 16) - 5) TS ------+ | |
#IFDEF CPU_Z180 ; | | |
OR A ; +4TS FOR Z180 | | |
#ENDIF ; | | |
DEC A ; 4TS | | |
JR NZ,VDELAY1 ; 12TS (NZ) / 7TS (Z) | | |
; ----------------------------------------------+ | |
; | |
DEC DE ; 6TS | |
#IFDEF CPU_Z180 ; | |
OR A ; +4TS FOR Z180 | |
#ENDIF ; | |
LD A,D ; 4TS | |
OR E ; 4TS | |
JP NZ,VDELAY ; 10TS | |
;-------------------------------------------------------+ |
; |
RET ; 10TS (FINAL RETURN) |
;---------------------------------------------------------------+
;
; DELAY ABOUT 0.5 SECONDS
; 500000US / 16US = 31250
;
LDELAY:
PUSH AF
PUSH DE
LD DE,31250
CALL VDELAY
POP DE
POP AF
RET
;
; HANDLE USER INPUT FOR A MENU BASED ON TABLE OF MENU DATA. DISPATCH MENU FUNCTIONS.
; ON INPUT, HL=ADDRESS OF MENU TABLE, B=COUNT OF MENU ENTRIES
;
.module MenuInfo
MenuInfo ; TRANSIENT STORAGE FOR CURRENT MENU
_DrawProc .dw 0 ; ADDRESS OF MENU DRAW ROUTINE
_TableAdr .dw 0 ; ADDRESS OF MENU TABLE DATA
_EntryInfo .dw 0 ; ENTRY COUNT / ENTRY SIZE
_Size .equ $ - MenuInfo
;
RUNMENU:
push hl ; save address of menu info data
_Run:
pop hl ; restore/resave menu init address
push hl
ld de,MenuInfo
ld bc,_Size
ldir
ld hl,(_DrawProc)
call JPHL ; call menu draw routine
_GetKey:
call GETKEYUC ; GET USER KEYPRESS
ld hl,(_TableAdr)
ld bc,(_EntryInfo) ; B=COUNT, C=ENTRY SIZE
ld d,0 ; put entry size in de
ld e,c ; "
; a=key pressed, hl=menu table address, b=entry count, de=entry size
_Loop:
ld c,(hl)
cp c
jp z,_Match ; found code
add hl,de ; point to next entry
djnz _Loop ; check next entry till count is zero
jp _GetKey ; keep trying
_Match:
inc hl ; load string
ld e,(hl)
inc hl
ld d,(hl)
call WRITESTR ; display it
inc hl ; load code address
ld e,(hl)
inc hl
ld d,(hl)
ld a,d ; check for zero
or e
jp z,_Exit ; zero means exit
ex de,hl
call JPHL ; indirect call to menu function
jp _Run
_Exit:
pop hl
ret
;
; CONTROL CHARACTERS
;
CHR_CR .EQU 0DH
CHR_LF .EQU 0AH
CHR_BS .EQU 08H
CHR_ESC .EQU 1BH
;
STR_DRIVERESET .TEXT "RESET DRIVE...$"
STR_EXECUTE .TEXT "EXECUTION$"
STR_OP .TEXT "OPERATION$"
STR_FORMAT .TEXT "FORMAT$"
STR_SENDCMD .TEXT "SEND COMMAND$"
STR_GETRESULTS .TEXT "GET RESULTS$"
STR_SEEKWAIT .TEXT "SEEK WAIT$"
STR_DOR .TEXT "SET DOR$"
STR_PROGRESS .TEXT "PROGRESS$"
STR_MISMATCH .TEXT "DATA MISMATCH AT $"
STR_RESET .TEXT "FDCRESET...$"
STR_NOTIMPL .TEXT "*** NOT IMPLEMENTED ***$"
STR_NORESP .TEXT "*** DRIVE NOT RESPONDING ***$"
STR_EOD .TEXT "<EOD>$"
STR_EMPTY .TEXT "<EMPTY>$"
STR_TIMEOUT .TEXT "<TIMEOUT>$"
STR_ARROW .TEXT " -->$"
STR_ENTER .TEXT "ENTER$"
STR_ON .TEXT "ON $"
STR_OFF .TEXT "OFF$"
STR_DRV720 .TEXT "720KB $"
STR_DRV144 .TEXT "1.44MB$"
STR_MODEPOLL .TEXT "POLLING $"
STR_MODEINT .TEXT "INTERRUPT $"
STR_MODEDMA .TEXT "DMA $"
STR_CC0 .TEXT " CC0=$"
STR_CC1 .TEXT " CC1=$"
STR_CC2 .TEXT " CC2=$"
STR_N .TEXT " N=$"
STR_SC .TEXT " SC=$"
STR_GPL .TEXT " GPL=$"
STR_D .TEXT " D=$"
STR_ST0 .TEXT " ST0=$"
STR_ST1 .TEXT " ST1=$"
STR_ST2 .TEXT " ST2=$"
STR_CYL .TEXT " CYL=$"
STR_UNIT .TEXT " UNIT=$"
STR_HEAD .TEXT " HD=$"
STR_REC .TEXT " SEC=$"
STR_NUM .TEXT " NUM=$"
STR_DENS .TEXT " DENS=$"
STR_EOTSEC .TEXT " EOTSEC=$"
STR_GAP .TEXT " GAP=$"
STR_DTL .TEXT " DTL=$"
STR_SN .TEXT " SN=$"
STR_NCN .TEXT " NCN=$"
STR_PCN .TEXT " PCN=$"
STR_MSR .TEXT " MSR=$"
STR_A .TEXT " A=$"
STR_BC .TEXT " BC=$"
STR_DE .TEXT " DE=$"
STR_HL .TEXT " HL=$"
STR_TO .TEXT " TO=$"
STR_ITER .TEXT " ITER=$"
STR_DSKCHG .TEXT " DC=$"
;
KEYBUFLEN .EQU 80
KEYBUF .FILL KEYBUFLEN,' '
;
STACKSAV .DW 0
STACKSIZ .EQU 40H ; WE ARE A STACK PIG
.FILL STACKSIZ,0
STACK .EQU $
;
BUFFER .EQU 4000H
VFYBUF .EQU 5000H
BUFSIZ .EQU 0200H
.END