diff --git a/Source/Apps/FDU/fdu.asm b/Source/Apps/FDU/fdu.asm index 82e89aac..4774e119 100644 --- a/Source/Apps/FDU/fdu.asm +++ b/Source/Apps/FDU/fdu.asm @@ -1,4774 +1,4774 @@ -;=============================================================================== -; 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 RCBUS 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 -; 2020-01-05: V5.4 ADDED SUPPORT FOR DYNO FDC -; 2020-04-29: v5.5 ADDED SUPPORT FOR ETCHED PIXELS FDC -; 2020-12-12: v5.6 UPDATED SMALLZ80 TO NEW I/O ADDRESSES -; 2021-03-24: v5.7 ADDED SOME SINGLE-SIDED FORMATS -; 2021-07-26: v5.8 ADDED SUPPORT FOR NHYODYNE (MBC) FDC -; 2023-12-10: v5.9 ADDED SUPPORT FOR DUODYNE (DUO) FDC -; -;_______________________________________________________________________________ -; -; 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 TO ABORT AT PROMPTS -; 6) ALLOW 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_DYNO .EQU 9 -FDC_EPFDC .EQU 10 -FDC_MBC .EQU 11 -FDC_DUO .EQU 12 -; -; 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 RCBUS 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.9, 10-Dec-2023$" -STR_BANNER2 .DB "Copyright (C) 2023, 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 GETKEYUC - CP 'X' ; EXIT? - JR NZ,FDCSEL2 ; IF NOT, CONTINUE - OR 0FFH ; ELSE SET NZ FOR EXIT REQUEST - RET ; AND RETURN -; -FDCSEL2: - SUB 'A' ; ASCII -> BINARY - CP FDCCNT ; TOO HIGH? - JR NC,FDCSEL1 ; IF SO, TRY AGAIN -; - ; SAVE SELECTED FDC IDENTIFIER - 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 - .DW STR_DYNO, CFG_DYNO - .DW STR_EPFDC, CFG_EPFDC - .DW STR_MBC, CFG_MBC - .DW STR_DUO, CFG_DUO -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$" -STR_DYNO .TEXT "DYNO$" -STR_EPFDC .TEXT "EPFDC$" -STR_MBC .TEXT "NHYODYNE$" -STR_DUO .TEXT "DUODYNE$" -; -; 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 074H ; FDC MAIN STATUS REGISTER - .DB 075H ; FDC DATA PORT - .DB 0FFH ; DATA INPUT REGISTER - .DB 072H ; DIGITAL OUTPUT REGISTER (LATCH) - .DB 077H ; DCR - .DB 0FFH ; DACK - .DB 0FFH ; TERMINAL COUNT (W/ DACK) - .DB 0FFH ; PSEUDO DMA DATA PORT - .DB _PCAT ; MODE= -; -CFG_DYNO: - .DB 084H ; FDC MAIN STATUS REGISTER - .DB 085H ; FDC DATA PORT - .DB 0FFH ; DATA INPUT REGISTER - .DB 086H ; DIGITAL OUTPUT REGISTER (LATCH) - .DB 087H ; DCR - .DB 0FFH ; DACK - .DB 086H ; TERMINAL COUNT (W/ DACK) - .DB 0FFH ; PSEUDO DMA DATA PORT - .DB _PCAT ; MODE= -; -CFG_EPFDC: - .DB 048H ; FDC MAIN STATUS REGISTER - .DB 049H ; FDC DATA PORT - .DB 0FFH ; DATA INPUT REGISTER - .DB 04AH ; DIGITAL OUTPUT REGISTER (LATCH) - .DB 04BH ; DCR - .DB 0FFH ; DACK - .DB 04CH ; TERMINAL COUNT (W/ DACK) - .DB 0FFH ; PSEUDO DMA DATA PORT - .DB _PCAT ; MODE= -; -CFG_MBC: - .DB 030H ; FDC MAIN STATUS REGISTER - .DB 031H ; FDC DATA PORT - .DB 0FFH ; DATA INPUT REGISTER - .DB 036H ; DIGITAL OUTPUT REGISTER (WHEN WRITTEN) - .DB 035H ; CONFIGURATION CONTROL REGISTER - .DB 036H ; DACK (WHEN READ) - .DB 037H ; TERMINAL COUNT (W/ DACK) - .DB 0FFH ; NOT USED - .DB _PCAT ; MODE= -; -CFG_DUO: - .DB 080H ; FDC MAIN STATUS REGISTER - .DB 081H ; FDC DATA PORT - .DB 0FFH ; DATA INPUT REGISTER - .DB 086H ; DIGITAL OUTPUT REGISTER (WHEN WRITTEN) - .DB 085H ; CONFIGURATION CONTROL REGISTER - .DB 086H ; DACK (WHEN READ) - .DB 087H ; TERMINAL COUNT (W/ DACK) - .DB 0FFH ; NOT USED - .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 " (A) Disk IO ECB Board\r\n" - .TEXT " (B) Disk IO 3 ECB Board\r\n" - .TEXT " (C) Zeta SBC Onboard FDC\r\n" - .TEXT " (D) Zeta 2 SBC Onboard FDC\r\n" - .TEXT " (E) Dual IDE ECB Board\r\n" - .TEXT " (F) N8 Onboard FDC\r\n" - .TEXT " (G) RCBus SMC (SMB)\r\n" - .TEXT " (H) RCBus WDC (SMB)\r\n" - .TEXT " (I) SmallZ80 Expansion\r\n" - .TEXT " (J) Dyno-Card FDC, D1030\r\n" - .TEXT " (K) RCBus EPFDC\r\n" - .TEXT " (L) Nhyodyne FDC\r\n" - .TEXT " (M) Duodyne FDC\r\n" - .TEXT " (X) Exit\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=XXXXXXXXXXXXX MODE=XXXXXXXXXX TRACE=XX\r\n" - .TEXT "(S)ETUP: UNIT=" -MV_UNIT .TEXT "XX" - .TEXT " MEDIA=" -MV_MED .TEXT "XXXXXXXXXXXXX" - .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 - -MMOP_RANDOM2: ; GENERATE RANDOM HEAD - ;OR A - ;CALL RNDBYTE - ;AND 01H ; JUST USE LOW ORDER BIT - ;LD (DCD_HEAD),A - LD A,(MDB_NUMHD) - LD C,A - CALL RNDBYTE - AND 01H ; USE 1 BIT FOR UP TO 2 HEADS - CP C - JP P,MMOP_RANDOM2 - LD (DCD_HEAD),A - -MMOP_RANDOM3: ; 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_RANDOM3 - CP 00H ; SECTOR NUM STARTS AT 1, DON'T ALLOW ZERO - JP Z,MMOP_RANDOM3 - 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 - .DB %00000001 ; DYNO POLL - .DB %00000001 ; EPFDC POLL - .DB %00000001 ; MBC POLL - .DB %00000001 ; DUO 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 -MT_PC160 .EQU 6 -MT_PC180 .EQU 7 -MT_PC320SS .EQU 8 -MT_PC360SS .EQU 9 -; -MIT: ; MEDIA INDEX TABLE - .DW MDB_PC720 - .DW MDB_PC144 - .DW MDB_PC320 - .DW MDB_PC360 - .DW MDB_PC120 - .DW MDB_PC111 - .DW MDB_PC160 - .DW MDB_PC180 - .DW MDB_PC320SS - .DW MDB_PC360SS -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 DS/DD $" -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 DS/HD $" -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 DS/DD $" -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 DS/DD $" -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 DS/HD $" -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 DS/DD $" -DTS_PC111 .TEXT "8\" 1.11MB - 15 SECTORS, 2 SIDES, 77 TRACKS, DOUBLE DENSITY$" -; -MDB_PC160 .DW DTL_PC160 ; ADDRESS OF MEDIA LABEL - .DW DTS_PC160 ; ADDRESS OF MEDIA DESCRIPTION - .DB 028H ; NUMBER OF CYLINDERS - .DB 001H ; NUMBER OF HEADS - .DB 008H ; NUMBER OF SECTORS - .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) -FCB_PC160 .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_PC160) != MDB_LEN) - .ECHO "*** FCB SIZE ERROR!!! ***\n" - .ENDIF -DTL_PC160 .TEXT "160KB SS/DD $" -DTS_PC160 .TEXT "5.25\" 160KB - 8 SECTORS, 1 SIDE, 40 TRACKS, DOUBLE DENSITY$" -; -MDB_PC180 .DW DTL_PC180 ; ADDRESS OF MEDIA LABEL - .DW DTS_PC180 ; ADDRESS OF MEDIA DESCRIPTION - .DB 028H ; NUMBER OF CYLINDERS - .DB 001H ; NUMBER OF HEADS - .DB 009H ; NUMBER OF SECTORS - .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) -FCB_PC180 .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_PC180) != MDB_LEN) - .ECHO "*** FCB SIZE ERROR!!! ***\n" - .ENDIF -DTL_PC180 .TEXT "180KB SS/DD $" -DTS_PC180 .TEXT "5.25\" 180KB - 9 SECTORS, 1 SIDE, 40 TRACKS, DOUBLE DENSITY$" -; -MDB_PC320SS .DW DTL_PC320SS ; ADDRESS OF MEDIA LABEL - .DW DTS_PC320SS ; ADDRESS OF MEDIA DESCRIPTION - .DB 050H ; NUMBER OF CYLINDERS - .DB 001H ; NUMBER OF HEADS - .DB 008H ; NUMBER OF SECTORS - .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) -FCB_PC320SS .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_PC320SS) != MDB_LEN) - .ECHO "*** FCB SIZE ERROR!!! ***\n" - .ENDIF -DTL_PC320SS .TEXT "320KB SS/DD $" -DTS_PC320SS .TEXT "5.25\" 320KB - 8 SECTORS, 1 SIDE, 80 TRACKS, DOUBLE DENSITY$" -; -MDB_PC360SS .DW DTL_PC360SS ; ADDRESS OF MEDIA LABEL - .DW DTS_PC360SS ; ADDRESS OF MEDIA DESCRIPTION - .DB 050H ; NUMBER OF CYLINDERS - .DB 001H ; NUMBER OF HEADS - .DB 009H ; NUMBER OF SECTORS - .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) -FCB_PC360SS .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_PC360SS) != MDB_LEN) - .ECHO "*** FCB SIZE ERROR!!! ***\n" - .ENDIF -DTL_PC360SS .TEXT "360KB SS/DD $" -DTS_PC360SS .TEXT "5.25\" 360KB - 9 SECTORS, 1 SIDE, 80 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, DYNO, EPFDC, MBC, DUO - 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, DYNO, EPFDC, MBC, DUO - 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 .FILL 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 .FILL 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 ; -CMD_SENSEINT .EQU 00001000B ; ST0,PCN -CMD_SPECIFY .EQU 00000011B ; -CMD_DRVSTAT .EQU 00000100B ; ST3 -CMD_SEEK .EQU 00001111B ; -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, DYNO, EPFDC, MBC, DUO - 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, DYNO, EPFDC, MBC, DUO - 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, DYNO, EPFDC, MBC, DUO - ;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, DYNO, EPFDC, MBC, DUO - 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, DYNO, EPFDC, MBC, DUO - 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: 80 10 90 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)) - .FILL (($ & 0FF00H) + 40H) - $ - ; .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)) - .FILL (($ & 0FF00H) + 40H) - $ - ; .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)) - .FILL (($ & 0FF00H) + 40H) - $ - ; .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)) - .FILL (($ & 0FF00H) + 40H) - $ - ; .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/DYNO/EPFDC/MBC/DUO *** -; -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 - CALL COUT ; SCREEN IT - POP AF ; RESTORE AF - RET ; DONE - -PC_LF: - PUSH AF ; Store AF - LD A,CHR_LF ; LOAD A - 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 - 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 "$" -STR_EMPTY .TEXT "$" -STR_TIMEOUT .TEXT "$" -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 +;=============================================================================== +; 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 RCBUS 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 +; 2020-01-05: V5.4 ADDED SUPPORT FOR DYNO FDC +; 2020-04-29: v5.5 ADDED SUPPORT FOR ETCHED PIXELS FDC +; 2020-12-12: v5.6 UPDATED SMALLZ80 TO NEW I/O ADDRESSES +; 2021-03-24: v5.7 ADDED SOME SINGLE-SIDED FORMATS +; 2021-07-26: v5.8 ADDED SUPPORT FOR NHYODYNE (MBC) FDC +; 2023-12-10: v5.9 ADDED SUPPORT FOR DUODYNE (DUO) FDC +; +;_______________________________________________________________________________ +; +; 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 TO ABORT AT PROMPTS +; 6) ALLOW 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_DYNO .EQU 9 +FDC_EPFDC .EQU 10 +FDC_MBC .EQU 11 +FDC_DUO .EQU 12 +; +; 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 RCBUS 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,(0FFFCH) ; 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.9, 10-Dec-2023$" +STR_BANNER2 .DB "Copyright (C) 2023, 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 GETKEYUC + CP 'X' ; EXIT? + JR NZ,FDCSEL2 ; IF NOT, CONTINUE + OR 0FFH ; ELSE SET NZ FOR EXIT REQUEST + RET ; AND RETURN +; +FDCSEL2: + SUB 'A' ; ASCII -> BINARY + CP FDCCNT ; TOO HIGH? + JR NC,FDCSEL1 ; IF SO, TRY AGAIN +; + ; SAVE SELECTED FDC IDENTIFIER + 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 + .DW STR_DYNO, CFG_DYNO + .DW STR_EPFDC, CFG_EPFDC + .DW STR_MBC, CFG_MBC + .DW STR_DUO, CFG_DUO +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$" +STR_DYNO .TEXT "DYNO$" +STR_EPFDC .TEXT "EPFDC$" +STR_MBC .TEXT "NHYODYNE$" +STR_DUO .TEXT "DUODYNE$" +; +; 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 074H ; FDC MAIN STATUS REGISTER + .DB 075H ; FDC DATA PORT + .DB 0FFH ; DATA INPUT REGISTER + .DB 072H ; DIGITAL OUTPUT REGISTER (LATCH) + .DB 077H ; DCR + .DB 0FFH ; DACK + .DB 0FFH ; TERMINAL COUNT (W/ DACK) + .DB 0FFH ; PSEUDO DMA DATA PORT + .DB _PCAT ; MODE= +; +CFG_DYNO: + .DB 084H ; FDC MAIN STATUS REGISTER + .DB 085H ; FDC DATA PORT + .DB 0FFH ; DATA INPUT REGISTER + .DB 086H ; DIGITAL OUTPUT REGISTER (LATCH) + .DB 087H ; DCR + .DB 0FFH ; DACK + .DB 086H ; TERMINAL COUNT (W/ DACK) + .DB 0FFH ; PSEUDO DMA DATA PORT + .DB _PCAT ; MODE= +; +CFG_EPFDC: + .DB 048H ; FDC MAIN STATUS REGISTER + .DB 049H ; FDC DATA PORT + .DB 0FFH ; DATA INPUT REGISTER + .DB 04AH ; DIGITAL OUTPUT REGISTER (LATCH) + .DB 04BH ; DCR + .DB 0FFH ; DACK + .DB 04CH ; TERMINAL COUNT (W/ DACK) + .DB 0FFH ; PSEUDO DMA DATA PORT + .DB _PCAT ; MODE= +; +CFG_MBC: + .DB 030H ; FDC MAIN STATUS REGISTER + .DB 031H ; FDC DATA PORT + .DB 0FFH ; DATA INPUT REGISTER + .DB 036H ; DIGITAL OUTPUT REGISTER (WHEN WRITTEN) + .DB 035H ; CONFIGURATION CONTROL REGISTER + .DB 036H ; DACK (WHEN READ) + .DB 037H ; TERMINAL COUNT (W/ DACK) + .DB 0FFH ; NOT USED + .DB _PCAT ; MODE= +; +CFG_DUO: + .DB 080H ; FDC MAIN STATUS REGISTER + .DB 081H ; FDC DATA PORT + .DB 0FFH ; DATA INPUT REGISTER + .DB 086H ; DIGITAL OUTPUT REGISTER (WHEN WRITTEN) + .DB 085H ; CONFIGURATION CONTROL REGISTER + .DB 086H ; DACK (WHEN READ) + .DB 087H ; TERMINAL COUNT (W/ DACK) + .DB 0FFH ; NOT USED + .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 " (A) Disk IO ECB Board\r\n" + .TEXT " (B) Disk IO 3 ECB Board\r\n" + .TEXT " (C) Zeta SBC Onboard FDC\r\n" + .TEXT " (D) Zeta 2 SBC Onboard FDC\r\n" + .TEXT " (E) Dual IDE ECB Board\r\n" + .TEXT " (F) N8 Onboard FDC\r\n" + .TEXT " (G) RCBus SMC (SMB)\r\n" + .TEXT " (H) RCBus WDC (SMB)\r\n" + .TEXT " (I) SmallZ80 Expansion\r\n" + .TEXT " (J) Dyno-Card FDC, D1030\r\n" + .TEXT " (K) RCBus EPFDC\r\n" + .TEXT " (L) Nhyodyne FDC\r\n" + .TEXT " (M) Duodyne FDC\r\n" + .TEXT " (X) Exit\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=XXXXXXXXXXXXX MODE=XXXXXXXXXX TRACE=XX\r\n" + .TEXT "(S)ETUP: UNIT=" +MV_UNIT .TEXT "XX" + .TEXT " MEDIA=" +MV_MED .TEXT "XXXXXXXXXXXXX" + .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 + +MMOP_RANDOM2: ; GENERATE RANDOM HEAD + ;OR A + ;CALL RNDBYTE + ;AND 01H ; JUST USE LOW ORDER BIT + ;LD (DCD_HEAD),A + LD A,(MDB_NUMHD) + LD C,A + CALL RNDBYTE + AND 01H ; USE 1 BIT FOR UP TO 2 HEADS + CP C + JP P,MMOP_RANDOM2 + LD (DCD_HEAD),A + +MMOP_RANDOM3: ; 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_RANDOM3 + CP 00H ; SECTOR NUM STARTS AT 1, DON'T ALLOW ZERO + JP Z,MMOP_RANDOM3 + 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 + .DB %00000001 ; DYNO POLL + .DB %00000001 ; EPFDC POLL + .DB %00000001 ; MBC POLL + .DB %00000001 ; DUO 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 +MT_PC160 .EQU 6 +MT_PC180 .EQU 7 +MT_PC320SS .EQU 8 +MT_PC360SS .EQU 9 +; +MIT: ; MEDIA INDEX TABLE + .DW MDB_PC720 + .DW MDB_PC144 + .DW MDB_PC320 + .DW MDB_PC360 + .DW MDB_PC120 + .DW MDB_PC111 + .DW MDB_PC160 + .DW MDB_PC180 + .DW MDB_PC320SS + .DW MDB_PC360SS +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 DS/DD $" +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 DS/HD $" +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 DS/DD $" +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 DS/DD $" +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 DS/HD $" +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 DS/DD $" +DTS_PC111 .TEXT "8\" 1.11MB - 15 SECTORS, 2 SIDES, 77 TRACKS, DOUBLE DENSITY$" +; +MDB_PC160 .DW DTL_PC160 ; ADDRESS OF MEDIA LABEL + .DW DTS_PC160 ; ADDRESS OF MEDIA DESCRIPTION + .DB 028H ; NUMBER OF CYLINDERS + .DB 001H ; NUMBER OF HEADS + .DB 008H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) +FCB_PC160 .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_PC160) != MDB_LEN) + .ECHO "*** FCB SIZE ERROR!!! ***\n" + .ENDIF +DTL_PC160 .TEXT "160KB SS/DD $" +DTS_PC160 .TEXT "5.25\" 160KB - 8 SECTORS, 1 SIDE, 40 TRACKS, DOUBLE DENSITY$" +; +MDB_PC180 .DW DTL_PC180 ; ADDRESS OF MEDIA LABEL + .DW DTS_PC180 ; ADDRESS OF MEDIA DESCRIPTION + .DB 028H ; NUMBER OF CYLINDERS + .DB 001H ; NUMBER OF HEADS + .DB 009H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) +FCB_PC180 .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_PC180) != MDB_LEN) + .ECHO "*** FCB SIZE ERROR!!! ***\n" + .ENDIF +DTL_PC180 .TEXT "180KB SS/DD $" +DTS_PC180 .TEXT "5.25\" 180KB - 9 SECTORS, 1 SIDE, 40 TRACKS, DOUBLE DENSITY$" +; +MDB_PC320SS .DW DTL_PC320SS ; ADDRESS OF MEDIA LABEL + .DW DTS_PC320SS ; ADDRESS OF MEDIA DESCRIPTION + .DB 050H ; NUMBER OF CYLINDERS + .DB 001H ; NUMBER OF HEADS + .DB 008H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) +FCB_PC320SS .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_PC320SS) != MDB_LEN) + .ECHO "*** FCB SIZE ERROR!!! ***\n" + .ENDIF +DTL_PC320SS .TEXT "320KB SS/DD $" +DTS_PC320SS .TEXT "5.25\" 320KB - 8 SECTORS, 1 SIDE, 80 TRACKS, DOUBLE DENSITY$" +; +MDB_PC360SS .DW DTL_PC360SS ; ADDRESS OF MEDIA LABEL + .DW DTS_PC360SS ; ADDRESS OF MEDIA DESCRIPTION + .DB 050H ; NUMBER OF CYLINDERS + .DB 001H ; NUMBER OF HEADS + .DB 009H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) +FCB_PC360SS .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_PC360SS) != MDB_LEN) + .ECHO "*** FCB SIZE ERROR!!! ***\n" + .ENDIF +DTL_PC360SS .TEXT "360KB SS/DD $" +DTS_PC360SS .TEXT "5.25\" 360KB - 9 SECTORS, 1 SIDE, 80 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, DYNO, EPFDC, MBC, DUO + 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, DYNO, EPFDC, MBC, DUO + 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 .FILL 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 .FILL 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 ; +CMD_SENSEINT .EQU 00001000B ; ST0,PCN +CMD_SPECIFY .EQU 00000011B ; +CMD_DRVSTAT .EQU 00000100B ; ST3 +CMD_SEEK .EQU 00001111B ; +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, DYNO, EPFDC, MBC, DUO + 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, DYNO, EPFDC, MBC, DUO + 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, DYNO, EPFDC, MBC, DUO + ;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, DYNO, EPFDC, MBC, DUO + 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, DYNO, EPFDC, MBC, DUO + 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: 80 10 90 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)) + .FILL (($ & 0FF00H) + 40H) - $ + ; .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)) + .FILL (($ & 0FF00H) + 40H) - $ + ; .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)) + .FILL (($ & 0FF00H) + 40H) - $ + ; .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)) + .FILL (($ & 0FF00H) + 40H) - $ + ; .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/DYNO/EPFDC/MBC/DUO *** +; +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 + CALL COUT ; SCREEN IT + POP AF ; RESTORE AF + RET ; DONE + +PC_LF: + PUSH AF ; Store AF + LD A,CHR_LF ; LOAD A + 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 + 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 "$" +STR_EMPTY .TEXT "$" +STR_TIMEOUT .TEXT "$" +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 diff --git a/Source/Apps/HTalk/htalk.asm b/Source/Apps/HTalk/htalk.asm index 4ee7720e..c1e66d82 100644 --- a/Source/Apps/HTalk/htalk.asm +++ b/Source/Apps/HTalk/htalk.asm @@ -31,7 +31,7 @@ STKSIZ .EQU $FF ; ; HBIOS SYSTEM CALLS AND ID STRING ADDRESS ; -ROMWBW_ID .EQU $FFFE ; ROMWBW ID STRING ADDRESS +ROMWBW_ID .EQU $FFFC ; ROMWBW ID STRING ADDRESS HBIOS_SYS .EQU $FFF0 ; HBIOS SYSCALL ADDRESS H_SYSGET .EQU $F8 ; GET SYSTEM INFO diff --git a/Source/Apps/Test/I2C/srom.asm b/Source/Apps/Test/I2C/srom.asm index 8429c168..6db97d1b 100644 --- a/Source/Apps/Test/I2C/srom.asm +++ b/Source/Apps/Test/I2C/srom.asm @@ -1,1679 +1,1679 @@ -; -;======================================================================= -; I2C Serial ROM Read/Write Utility (SROM) -;======================================================================= -; -; Read or write the contents of a 24LC512 Serial EEPROM via an I2C -; PCF8584 controller. -; -; WBW 2023-09-05: Initial release -; WBW 2023-09-07: Code clean up -; -;======================================================================= -; -; PCF8584 controller port addresses (adjust as needed) -; -pcfbase_sbc .equ $F0 ; SBC PCF8584 I/O base port address -pcfbase_duo .equ $56 ; Duodyne PCF8584 I/O base port address -; -; I2C identification (own slave id) -; -pcf_adr .equ $55 ; Our "own" I2C slave address -; -; 24LC512 ROM id (target device) -; -rom0_adr .equ $50 ; I2C SROM first I2C address -rom_pgsiz .equ 128 ; SROM page size -; -; General operational equates (should not require adjustment) -; -stksiz .equ $40 ; Working stack size -; -restart .equ $0000 ; CP/M restart vector -bdos .equ $0005 ; BDOS invocation vector -fcb1 .equ $005C ; first CP/M parsed FCB -fcb2 .equ $006C ; second CP/M parsed FCB -; -cr .equ 13 ; carriage return -lf .equ 10 ; line feed -; -ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr -; -bf_sysver .equ $F1 ; BIOS: VER function -bf_sysget .equ $F8 ; HBIOS: SYSGET function -bf_sysset .equ $F9 ; HBIOS: SYSGET function -bf_sysgettimer .equ $D0 ; TIMER subfunction -bf_syssettimer .equ $D0 ; TIMER subfunction -bf_sysgetsecs .equ $D1 ; SECONDS subfunction -bf_syssetsecs .equ $D1 ; SECONDS subfunction -; -; Control register bits -; -pcf_ctl_pin .equ %10000000 ; reset ; 0x80 -pcf_ctl_eso .equ %01000000 ; enable serial output ; 0x40 -pcf_ctl_es1 .equ %00100000 ; register selection bit 1 ; 0x20 -pcf_ctl_es2 .equ %00010000 ; register selection bit 2 ; 0x10 -pcf_ctl_eni .equ %00001000 ; enable external interrupt ; 0x08 -pcf_ctl_sta .equ %00000100 ; generate start ; 0x04 -pcf_ctl_sto .equ %00000010 ; generate stop ; 0x02 -pcf_ctl_ack .equ %00000001 ; enable auto acknowledge ; 0x01 -; -pcf_op_start .equ (pcf_ctl_pin | pcf_ctl_eso | pcf_ctl_sta | pcf_ctl_ack) ; 0xC5 -pcf_op_stop .equ (pcf_ctl_pin | pcf_ctl_eso | pcf_ctl_sto | pcf_ctl_ack) ; 0xC3 -pcf_op_repstart .equ (pcf_ctl_eso | pcf_ctl_sta | pcf_ctl_ack) ; 0x45 -pcf_op_idle .equ (pcf_ctl_pin | pcf_ctl_eso | pcf_ctl_ack) ; 0xC1 -; -; Status register bits -; -pcf_st_pin .equ %10000000 ; pending interrupt not ; 0x80 -pcf_st_ini .equ %01000000 ; normally 0, 1 if not initialized ; 0x40 -pcf_st_sts .equ %00100000 ; stop detected ; 0x20 -pcf_st_ber .equ %00010000 ; bus error detected ; 0x10 -pcf_st_ad0 .equ %00001000 ; slave address received = 0x00 ; 0x08 -pcf_st_lrb .equ %00001000 ; last received bit ; 0x08 -pcf_st_aas .equ %00000100 ; addressed as slave ; 0x04 -pcf_st_lab .equ %00000010 ; lost arbitration ; 0x02 -pcf_st_bb .equ %00000001 ; bus busy not ; 0x01 -; -; Transmission frequencies -; -pcf_trns_90 .equ $00 ; 90 KHz -pcf_trns_45 .equ $01 ; 45 KHz -pcf_trns_11 .equ $02 ; 11 KHz -pcf_trns_15 .equ $03 ; 1.5 KHz -; -; Clock chip frequencies -; -pcf_clk_3 .equ $00 ; 3 MHz -pcf_clk_443 .equ $10 ; 4.43 MHz -pcf_clk_6 .equ $14 ; 6 MHz -pcf_clk_8 .equ $18 ; 8 MHz -pcf_clk_12 .equ $1C ; 12 MHz -; -; Divisor settings -; -pcf_clk .equ pcf_clk_12 ; $1C -pcf_trns .equ pcf_trns_90 ; $00 -; -; Error codes -; -ec_ok .equ 0 ; No error -ec_bio .equ -1 ; HBIOS invalid or not present -ec_plt .equ -2 ; HBIOS platform not supported -ec_usage .equ -3 ; Command line usage error -ec_init .equ -4 ; PCF8584 init failed -ec_timeout .equ -5 ; I2C protocol timeout -ec_nak .equ -6 ; Unexpected NAK -ec_fopen .equ -7 ; File open error -ec_fio .equ -8 ; File I/O error -ec_exists .equ -9 ; File already exists -ec_verify .equ -10 ; Data verification mismatch -; -;======================================================================= -; - .org $100 ; standard CP/M executable -; -; - ; Setup stack (save old value) - ld (stksav),sp ; save stack - ld sp,stack ; set new stack -; - ; Announce program - call crlf - ld de,str_banner ; banner - call prtstr -; - call parse ; parse options - jr nz,exit ; abort if problems -; - call init ; initialize - jr nz,exit ; abort if problems -; - call main ; do the real work -; -exit: - call prterr -; - ; Announce end of program - call crlf2 - ld de,str_exit - call prtstr -; - ; Restore stack and return to OS - call crlf ; formatting - ld sp,(stksav) ; restore stack - jp restart ; return to CP/M via restart -; -;======================================================================= -; Command Line Parsing -;======================================================================= -; -; We take advantage of CP/M OS command line processing which treats -; the first two parameters on the command line as filenames and places -; corresponding FCBs at $5C and $6C. -; -; The first FCB is not actually handled as a file. Instead, the first -; two characters are used as control parameters. First character is -; the function to perform (R=read, W=write) and the second character -; is the serial ROM address (0-7) which maps to I2C addresses $50-$57. -; -parse: - ld a,(fcb1+1) ; function parm - cp 'R' ; read? - jr z,parse1 ; if so, valid, continue - cp 'W' ; write? - jr z,parse1 ; if so, valid, continue - cp 'T' ; write? - jr z,parse1 ; if so, valid, continue - cp 'D' ; write? - jr z,parse1 ; if so, valid, continue - jp err_usage ; else, handle usage error -; -parse1: - ld (func),a ; save function - ld a,(fcb1+2) ; ROM adr parm - cp '0' ; start of range - jp c,err_usage ; if less, handle usage error - cp '7' + 1 ; end of range - jp nc,err_usage ; if more, handle usage error - sub '0' ; convert to binary - add a,rom0_adr ; offset to first srom adr - ld (romadr),a ; save it -; - ld a,(func) ; recall function - cp 'T' ; test command? - jr z,parse_z -; - ld a,(fcb2+1) ; first char of page/filename - cp ' ' ; blank? - jp z,err_usage ; if so, handle usage error -; - ld a,(func) ; recall function - cp 'D' ; dump command? - jr z,parse2 ; parse page number -; - ; copy FCB to working location - ld hl,fcb2 ; parsed CP/M FCB 2 - ld de,fcb ; our FCB buffer - ld bc,16 ; only first 16 bytes - ldir ; copy it - jr parse_z -; -parse2: - ; parse page number - ld hl,0 ; initialize page number - ld de,fcb2+1 ; pointer to start of page num -parse3: - ld a,(de) ; get next char - inc de - cp ' ' ; space char? - jr z,parse4 ; return w/ ZF set - cp '0' ; start of range - jp c,err_usage ; if less, handle usage error - cp '9' + 1 ; end of range - jp nc,err_usage ; if more, handle usage error -; - ; multiply working page num by 10, then add new digit - push hl - pop bc - add hl,hl - add hl,hl - add hl,bc - add hl,hl - sub '0' - call addhla -; - ; check for overflow - ld a,h - cp 2 - jp nc,err_usage -; - jr parse3 -; -parse4: - ld (page),hl -; -parse_z: - xor a - ret -; -;======================================================================= -; Hardware Initialization -;======================================================================= -; -init: - call idbio ; identify hardware BIOS - cp 1 ; is it RomWBW? - jp nz,err_bio ; if not, handle error -; - ; Setup I/O ports based on HBIOS platform ID - ld a,l ; idbio puts platform id in L - ld c,pcfbase_sbc ; assume SBC - cp 1 ; compare to platform id - jr z,init1 ; if SBC, commit - ld c,pcfbase_duo ; assume SBC - cp 17 ; compare to platform id - jr z,init1 ; if DUO, commit - jp err_plt ; unsupported platform error -; -init1: - ; Record and display PCF8584 port addresses - call crlf2 ; formatting - ld de,str_hwmsg1 ; first part of h/w message - call prtstr ; print it - ld a,c ; get base port - call prthex ; print port number - ld (pcf_dat),a ; save data port - ld de,str_hwmsg2 ; second part of h/w message - call prtstr ; print port number - inc a ; bump to data port - ld (pcf_ctl),a ; save control port - call prthex ; print port number - ld de,str_hwmsg3 ; third part of h/w message - call prtstr ; print it -; - ; Initialize PCF8584 - call pcf_init ; sets A with result - ret nz -; - ; "Reading/Writing/Testing Serial ROM # (I2C address 0xnn)" - call crlf2 - ld a,(func) - ld de,str_inforead - cp 'R' - call z,prtstr ; "Reading" - ld de,str_infowrite - cp 'W' - call z,prtstr ; "Writing" - ld de,str_infotest - cp 'T' - call z,prtstr ; "Testing" - ld de,str_infodump - cp 'D' - call z,prtstr ; "Dumping" - ld de,str_info1 - call prtstr ; " Serial ROM #" - ld a,(romadr) - push af - sub rom0_adr - call prtdecb ; # - pop af - ld de,str_info2 - call prtstr ; " (I2C address " - call prthex ; 0x## - ld de,str_info3 - call prtstr ; ")" -; -init2: - xor a - ret -; -;======================================================================= -; Mainline -;======================================================================= -; -main: - ; Get requested function and dispatch - ld a,(func) ; get function - cp 'T' ; SROM test? - jp z,test ; if so, do it - cp 'D' ; SROM dump? - jp z,dump ; if so, do it - cp 'R' ; SROM read - jp z,read ; if so, do it - cp 'W' ; SROM write - jp z,write ; if so, do it - ret ; this should never happen -; -; -; -test: - call confirm - ret nz -; - call fillbufseq - ld hl,0 - call test_write - ret nz - call fillbufrev - ld hl,1 - call test_write - ret nz - call fillbufseq - ld hl,510 - call test_write - ret nz - call fillbufrev - ld hl,511 - call test_write - ret nz -; - ld hl,0 - call test_read - ret nz - call checkseq - ret nz - ld hl,1 - call test_read - ret nz - call checkrev - ret nz - ld hl,510 - call test_read - ret nz - call checkseq - ret nz - ld hl,511 - call test_read - ret nz - call checkrev - ret nz -; - xor a - ret -; -; -; -test_read: - call crlf2 - ld de,str_readpage - call prtstr - call prtdecw - call clrbuf -; - call readpage - ret nz -; - ld hl,pagebuf - ld c,rom_pgsiz - call crlf - call dumpbuf -; - xor a - ret -; -; -; -test_write: - call crlf2 - ld de,str_writepage - call prtstr - call prtdecw - jp writepage -; -; -; -dump: - ld hl,(page) - call crlf2 - ld de,str_readpage - call prtstr - call prtdecw - call clrbuf -; - call readpage - ret nz -; - ld hl,pagebuf - ld c,rom_pgsiz - call crlf - call dumpbuf -; - xor a - ret -; -; -; -read: - ; Ensure output file does not exist! - ld de,fcb ; FCB pointer - ld c,15 ; BDOS open file function - call bdos ; do it - cp $FF ; failed to open? - jr z,read0 ; if so, good, continue - call read_z ; close the file - jp err_exists ; handle error -; -read0: - ; Create output file (must not exist) - ld de,fcb ; FCB pointer - ld c,22 ; BDOS create file function - call bdos ; do it - cp $FF ; error? - jp z,err_fopen ; handle file open error -; - ; SROM read / File write loop - call crlf ; formatting - ld de,pagebuf ; BDOS DMA is pagebuf - ld c,26 ; BDOS set DMA function - call bdos ; do it - ld hl,0 ; init SROM page num -; -read1: - ; Read SROM page - push hl ; save SROM page num - call readpage ; get SROM page - pop hl ; restore page num - jr nz,read_z ; bail out on error - inc hl ; inc page num -; - ; Write page to file - push hl ; save SROM page num - ld de,fcb ; point to FCB - ld c,21 ; BDOS write seq function - call bdos ; do it - pop hl ; restore page num - or a ; set flags - call nz,err_fio ; handle file I/O error - jr nz,read_z ; close file and bail out -; - ; Show progress and loop till done - call prtdot ; display progress - ld a,h ; check high byte - cp 2 ; done when we hit 512 pages - jr nz,read1 ; loop till done - xor a ; signal success -; -read_z: - ; Close file - push af ; preserve status - ld de,fcb ; FCB pointer - ld c,16 ; BDOS close file function - call bdos ; do it - pop af ; restore status -; - ret -; -; -; -write: - ; Confirm intent to overwrite SROM - call confirm ; confirm SROM overwrite - ret nz ; bail out if not confirmed -; - ; Open file - ld de,fcb ; FCB pointer - ld c,15 ; BDOS open file function - call bdos ; do it' - cp $FF ; error? - jp z,err_fopen ; handle file open error -; - ; File read / SROM write loop - call crlf ; formatting - ld de,pagebuf ; BDOS DMA is pagebuf - ld c,26 ; BDOS set DMA function - call bdos ; do it - ld hl,0 ; init SROM page num -; -write1: - ; Read page data from file - push hl ; save SROM page num - ld de,fcb ; FCB pointer - ld c,20 ; BDOS read file function - call bdos ; do it - pop hl ; restore SROM page num - or a ; set flags - call nz,err_fio ; handle file I/O error - jr nz,write_z ; close file and bail out -; - ; Write SROM page - push hl ; save SROM page num - call writepage ; write SROM page - pop hl ; restore page num - jr nz,read_z ; bail out on error - inc hl ; inc page num -; - ; Show progress and loop till done - call prtdot ; display progress - ld a,h ; check high byte - cp 2 ; done when we hit 512 pages - jr nz,write1 ; loop till done - xor a ; signal success -; -write_z: - ; Close file - push af ; preserve status - ld de,fcb ; FCB pointer - ld c,16 ; BDOS close file function - call bdos ; do it - pop af ; restore status -; - ret -; -; -; -readpage: - ; Convert page number to byte offset - add hl,hl ; * 2 - add hl,hl ; * 4 - add hl,hl ; * 8 - add hl,hl ; * 16 - add hl,hl ; * 32 - add hl,hl ; * 64 - add hl,hl ; * 128 -; - ; Read page - ld de,pagebuf - ld bc,rom_pgsiz - jp rom_read -; -; -; -writepage: - ; Convert page number to byte offset - add hl,hl ; * 2 - add hl,hl ; * 4 - add hl,hl ; * 8 - add hl,hl ; * 16 - add hl,hl ; * 32 - add hl,hl ; * 64 - add hl,hl ; * 128 -; - ; Write page - ld de,pagebuf - ld bc,rom_pgsiz - jp rom_write -; -; -; -clrbuf: - xor a -fillbuf: - push af - push bc - push de - push hl - ld hl,pagebuf - ld de,pagebuf + 1 - ld bc,rom_pgsiz - 1 - ld (hl),a - ldir - pop hl - pop de - pop bc - pop af - ret -; -; -; -fillbufseq: - push af - push bc - push de - push hl - xor a - ld b,rom_pgsiz - ld hl,pagebuf -fillbufseq1: - ld (hl),a - inc a - inc hl - djnz fillbufseq1 - pop hl - pop de - pop bc - pop af - ret -; -; -; -fillbufrev: - push af - push bc - push de - push hl - ld a,rom_pgsiz - 1 - ld b,rom_pgsiz - ld hl,pagebuf -fillbufrev1: - ld (hl),a - dec a - inc hl - djnz fillbufrev1 - pop hl - pop de - pop bc - pop af - ret -; -; -; -checkseq: - push bc - push de - push hl - xor a - ld b,rom_pgsiz - ld hl,pagebuf -checkseq1: - cp (hl) - call nz,err_verify - jr nz,checkseq_z - inc a - inc hl - djnz checkseq1 - xor a -checkseq_z: - pop hl - pop de - pop bc - ret -; -; -; -checkrev: - push bc - push de - push hl - ld a,rom_pgsiz - 1 - ld b,rom_pgsiz - ld hl,pagebuf -checkrev1: - cp (hl) - call nz,err_verify - jr nz,checkrev_z - dec a - inc hl - djnz checkrev1 - xor a -checkrev_z: - pop hl - pop de - pop bc - ret -; -; Confirm intention to overwrite SROM -; -confirm: - call crlf2 - ld de,str_confirm - call prtstr -; - ld c,10 ; CP/M read line - ld de,confirm_buf ; line buffer - call bdos ; get line from user -; - ld a,(confirm_buf + 1) ; number of chars returned - or a ; set flags - jr z,confirm1 - ld a,(confirm_buf + 2) ; get first char entered - cp 'Y' ; confirmed? - ret z ; if so, done, ZF set - cp 'y' ; lower case variant - ret z ; if so, done, ZF set -; -confirm1: - or $FF ; signal non-confirm - ret -; -;======================================================================= -; 24LC512 ROM Routines -;======================================================================= -; -; Write a buffer of data to ROM -; DE=buffer adr -; HL=ROM byte offset -; BC=buffer len -; -rom_write: - ; Move offset to buffer, convert to big endian!!! - ld a,h ; high byte - ld (adrbuf+0),a ; ... to first buffer pos - ld a,l ; low byte - ld (adrbuf+1),a ; ... to second buffer pos -; - ; Save count to HL for later - push bc ; move count from BC - pop hl ; ... to HL -; - ; Generate start condition - ld a,(romadr) ; load ROM I2C adress - rlca ; move to top 7 bits - res 0,a ; clear low bit for write - call pcf_start ; generate start - jr nz,rom_write_z ; if error, skip write -; - ; Send ROM address - push de ; save buffer pointer - push hl ; save buffer length - ld hl,2 ; 2 byte address - ld de,adrbuf ; memory address pointer - call pcf_write ; set memory pointer - pop hl ; restore buffer length - pop de ; restore buffer pointer - jr nz,rom_write_z ; if error, skip write -; - ; Write data from buffer - call pcf_write ; write the page -; -rom_write_z: - push af ; save current status - call pcf_stop ; generate stop - pop af ; restore status - ret nz ; bail out if error status -; - jr rom_write_wait ; exit via write wait -; -; -; -rom_write_wait: - ; While SROM is updating page data, it will NAK any - ; start request. Loop on start requests until an ACK is - ; received or loop timeout. - ld b,0 ; try 256 times -rom_write_wait1: - push bc ; save loop control - ld a,(romadr) ; load ROM I2C adress - rlca ; move to top 7 bits - res 0,a ; clear low bit for write - call pcf_start ; generate start - jr nz,rom_write_wait2 ; skip ahead - call pcf_waitpin ; wait for bus and get status - ;call prthex -rom_write_wait2: - push af ; save current status - call pcf_stop ; generate stop - pop af ; restore status - pop bc ; restore loop control - cp $FF ; timeout? - jp z,err_timeout ; handle timeout error - and pcf_st_lrb ; isolate LRB (ACK bit) - jr z,rom_write_wait3 ; done - djnz rom_write_wait1 ; else loop until timeout - jp err_timeout ; handle timeout -; -rom_write_wait3: - ;ld a,b - ;neg - ;call prthex - xor a ; set flags - ret ; done -; -; Read ROM data into buffer -; DE=buffer adr -; HL=ROM byte offset -; BC=buffer len -; -rom_read: - ; Move offset to buffer, convert to big endian!!! - ld a,h ; high byte - ld (adrbuf+0),a ; ... to first buffer pos - ld a,l ; low byte - ld (adrbuf+1),a ; ... to second buffer pos -; - ; Save count to HL for later - push bc ; move count from BC - pop hl ; ... to HL -; - ; Generate start condition - ld a,(romadr) ; load ROM I2C adress - rlca ; move to top 7 bits - res 0,a ; clear low bit for write - call pcf_start ; generate start - jr nz,rom_read_z ; if error, skip write -; -rom_read2: - ; Send ROM address - push de ; save buffer pointer - push hl ; save buffer length - ld hl,2 ; 2 byte address - ld de,adrbuf ; memory address pointer - call pcf_write ; set memory pointer - pop hl ; restore buffer length - pop de ; restore buffer pointer - jr nz,rom_read_z ; if error, bail out -; - ; Repeat start, switch to read - ld a,(romadr) ; load ROM I2C address - rlca ; move to top 7 bits - set 0,a ; set low bit for read - call pcf_repstart ; generate repeat start - jr nz,rom_read_z ; if error, bail out -; - ; Read data into buffer - call pcf_read ; read the page -; -rom_read_z: - push af ; save current status - call pcf_stop ; generate stop - pop af ; restore status - or a ; set flags - ret ; done -; -;======================================================================= -; PCF8584 Routines -;======================================================================= -; -; General PCF8584 initialization -; -pcf_init: - ; Select S0' (own address) 0x80 -> 0x00 - ld a,(pcf_ctl) ; ctl port - ld c,a ; to C - ld a,pcf_ctl_pin ; PCF reset, select S0' - out (c),a ; do it - nop - in a,(c) ; read status - ;call crlf2 - ;call prtsp - ;call prthex - and $7F ; remove pin bit - jp nz,err_init ; all should be zero -; - ; Set S0' (own address) 0x55 - dec c ; data port - ld a,pcf_adr ; own address - out (c),a ; set own address in S0' (own << 1) - nop - in a,(c) ; read back S0' - ;call prtsp - ;call prthex - cp pcf_adr ; correct? - jp nz,err_init ; if not, init error -; - ; Select S2 (clock) 0xA0 -> 0x20 - inc c ; ctl port - ld a,pcf_ctl_pin | pcf_ctl_es1 ; select S2 - out (c),a ; do it - nop - in a,(c) ; read status - ;call prtsp - ;call prthex - and 07fh ; remove pin bit - cp pcf_ctl_es1 ; verify S2 selected - jp nz,err_init ; it not, init error -; - ; Set S2 (clock) 0x1C - dec c ; data port - ld a,pcf_trns | pcf_clk ; load clock register s2 - out (c),a ; do it - nop - in a,(c) ; read back S2 - ;call prtsp - ;call prthex - and $1F ; only the lower 5 bits are used - cp pcf_trns | pcf_clk - jp nz,err_init -; - ; Enter idle 0xC1 - inc c ; ctl port - ld a,pcf_op_idle - out (c),a ; do it - nop - in a,(c) ; read status - ;call prtsp - ;call prthex - cp pcf_st_pin | pcf_st_bb ; expected status - jp nz,err_init -; - xor a - ret -; -; Generate an I2C start condition -; A=start byte value (slave address + r/w bit) -; -pcf_start: - ;call crlf - ;push de - ;ld de,str_start - ;call prtstr - ;pop de -; - ; Wait for I2C bus clear - ld b,a ; move start byte to B - call pcf_waitbb ; wait while bus busy - cp $FF ; timeout? - jp z,err_timeout ; timeout error return -; - ; Set start byte w/ slave address in S0 - ld a,(pcf_dat) ; data port - ld c,a ; ... into C - ;ld a,b - ;call prtsp - ;call prthex - out (c),b ; send start byte -; - ; Initiate start operation - inc c ; ctl port - ld a,pcf_op_start ; command - out (c),a ; do it -; - xor a ; signal success - ret ; done -; -; Generate an I2C repeat start condition -; A=start byte value (slave address + r/w bit) -; -pcf_repstart: - ;call crlf - ;push de - ;ld de,str_repstart - ;call prtstr - ;pop de -; - ; Send repeat start command - ld b,a ; move start byte to B - ld a,(pcf_ctl) ; control port - ld c,a ; ... into C - ld a,pcf_op_repstart ; command - out (c),a ; do it -; - ; Set start byte w/ slave address in S0 - ld a,(pcf_dat) ; data port - ld c,a ; ... into C - ;ld a,b - ;call prtsp - ;call prthex - out (c),b ; send start byte -; - xor a ; signal success - ret ; done -; -; Generate an I2C stop condition -; -pcf_stop: - ;call crlf - ;push de - ;ld de,str_stop - ;call prtstr - ;pop de -; - ld a,(pcf_ctl) ; control port - ld c,a ; ... into C - ld a,pcf_op_stop ; command - ;call prtsp - ;call prthex - out (c),a ; do it -; - xor a ; signal success - ret ; done -; -; Write bytes to I2C -; HL=byte count to write -; DE=buffer pointer -; -pcf_write: - ;push af - ;push bc - ;push de - ;push hl - ;push hl - ;push de - ;pop hl - ;call crlf - ;ld de,str_write - ;call prtstr - ;call prtsp - ;call prthexword - ;call prtsp - ;pop hl - ;call prthexword - ;call crlf - ;pop hl - ;pop de - ;pop bc - ;pop af -; -pcf_write1: - call pcf_waitack ; wait for ack - ret nz ; abort on failure -; - ld a,h ; check for - or l ; ... counter exhausted - ret z ; if so, done, exit w/ ZF set -; - ld a,(pcf_dat) ; data port - ld c,a ; ... into C - ld a,(de) ; get byte to write - ;call prtsp - ;call prthex - out (c),a ; send it -; - dec hl ; decrement byte counter - inc de ; bump buf ptr - jr pcf_write1 ; loop till done -; -; Read bytes from I2C -; HL=byte count to read -; -pcf_read: - ;push af - ;push bc - ;push de - ;push hl - ;call crlf - ;ld de,str_read - ;call prtstr - ;call prtsp - ;call prthexword - ;call crlf - ;pop hl - ;pop de - ;pop bc - ;pop af -; - ; First byte is a "dummy", must be discarded - call pcf_waitack ; wait for ack - ret nz ; abort on failure - ld a,(pcf_dat) ; data port - ld c,a ; ... into C - in a,(c) ; get dummy byte -; -pcf_read0: - call pcf_waitack ; wait for ack - ret nz ; abort on failure -; - ; Loop control - dec hl ; pre-decrement byte counter - ld a,h ; check for - or l ; ... counter exhausted - 1 - jr z,pcf_read2 ; handle end game -; -pcf_read1: - ; Get next data byte - ld a,(pcf_dat) ; data port - ld c,a ; ... into C - in a,(c) ; get next byte of ROM - ;call prtsp - ;call prthex - ld (de),a ; save byte received in buf - inc de ; bump buf pointer -; - jr pcf_read0 ; loop till done -; -pcf_read2: - ; Special treatment for final character - ld a,(pcf_ctl) ; control port - ld c,a ; ... into C - ld a,$40 ; prep for neg ack - out (c),a ; send it -; - ; Get final data byte - ld a,(pcf_dat) ; data port - ld c,a ; ... into C - in a,(c) ; get next byte of ROM - ;call prtsp - ;call prtdot - ;call prthex - ld (de),a ; save byte received in buf -; - call pcf_waitpin ; wait for PIN - cp $FF ; timeout? - jp z,err_timeout ; handle it -; - xor a ; signal success - ret ; done -; -; Wait for I2C bus to not be busy (BB = 1) -; Return PCF status in A, 0xFF for timeout -; -pcf_waitbb: - push bc ; save BC - ld a,(pcf_ctl) ; control port value - ld c,a ; ... into C - ld b,0 ; timeout counter -; -pcf_waitbb1: - in a,(c) ; get status byte - bit 0,a ; test busy bit (inverted) - jr nz,pcf_waitbb_z ; if BB=1, bus clear, return - djnz pcf_waitbb1 ; loop to keep trying - or $FF ; signal timeout -; -pcf_waitbb_z: - pop bc ; restore BC - ret ; done -; -; Wait for PIN (PIN = 0) -; Return PCF status in A, 0xFF for timeout -; -pcf_waitpin: - push bc ; save BC - ld a,(pcf_ctl) ; control port value - ld c,a ; ... into C - ld b,0 ; timeout counter -; -pcf_waitpin1: - ; Wait till done with send/receive (PIN=0) - in a,(c) ; get status byte - bit 7,a ; test PIN bit - jr z,pcf_waitpin_z ; if 0, done - djnz pcf_waitpin1 ; loop till timeout - or $FF ; signal timeout -; -pcf_waitpin_z: - pop bc ; restore BC - ret ; done -; -; Wait for slave (PIN = 0) and check for acknowledge (LRB = 0) -; Return error code -; -pcf_waitack: - call pcf_waitpin ; wait for PIN - cp $FF ; timeout? - jp z,err_timeout ; handle it - ; Evaluate response - and pcf_st_lrb ; isolate LRB bit - jp nz,err_nak ; handle NAK error - xor a ; set status - ret -; -; Error Handlers -; -err_bio: - ld a,ec_bio - jr err_ret -; -err_plt: - ld a,ec_plt - jr err_ret -; -err_usage: - ld a,ec_usage - jr err_ret -; -err_init: - ld a,ec_init - jr err_ret -; -err_timeout: - ld a,ec_timeout - jr err_ret -; -err_nak: - ld a,ec_nak - jr err_ret -; -err_fopen: - ld a,ec_fopen - jr err_ret -; -err_fio: - ld a,ec_fio - jr err_ret -; -err_exists: - ld a,ec_exists - jr err_ret -; -err_verify: - ld a,ec_verify - jr err_ret -; -err_ret: - or a ; set flags - ret -; -; -; -prterr: - push de - push hl - neg - rlca - ld hl,str_err_table - call addhla - ld e,(hl) - inc hl - ld d,(hl) - call crlf2 - call prtstr - pop hl - pop de - ret -; -;======================================================================= -; Utility Routines -;======================================================================= -; -; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 -; -idbio: -; - ; Check for UNA (UBIOS) - ld a,($FFFD) ; fixed location of UNA API vector - cp $C3 ; jp instruction? - jr nz,idbio1 ; 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,idbio1 ; 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,idbio1 ; if not, not UNA, check others -; - ld bc,$04FA ; UNA: get BIOS date and version - rst 08 ; DE := ver, HL := date -; - ld a,2 ; UNA BIOS id = 2 - ret ; and done -; -idbio1: - ; Check for RomWBW (HBIOS) - ld hl,($FFFE) ; HL := HBIOS ident location - ld a,'W' ; First byte of ident - cp (hl) ; Compare - jr nz,idbio2 ; Not HBIOS - inc hl ; Next byte of ident - ld a,~'W' ; Second byte of ident - cp (hl) ; Compare - jr nz,idbio2 ; Not HBIOS -; - ld b,bf_sysver ; HBIOS: VER function - ld c,0 ; required reserved value - rst 08 ; DE := version, L := platform id -; - ld a,1 ; HBIOS BIOS id = 1 - ret ; and done -; -idbio2: - ; No idea what this is - xor a ; Setup return value of 0 - ret ; and done - -; -; Print character in A without destroying any registers -; -prtchr: - push af ; save registers - push bc - push de - push hl - ld e,a ; character to print in E - ld c,$02 ; BDOS function to output a character - call bdos ; do it - pop hl ; restore registers - pop de - pop bc - pop af - ret -; -prtsp3: - call prtsp -prtsp2: - call prtsp -prtsp: -; - ; shortcut to print a space character preserving all regs - push af ; save af - ld a,' ' ; load dot char - call prtchr ; print it - pop af ; restore af - ret ; done -; -prtdot: -; - ; shortcut to print a dot character preserving all regs - push af ; save af - ld a,'.' ; load dot char - call prtchr ; print it - pop af ; restore af - ret ; done -; -; Uppercase character in A -; -upcase: - cp 'a' ; below 'a'? - ret c ; if so, nothing to do - cp 'z'+1 ; above 'z'? - ret nc ; if so, nothing to do - and ~$20 ; convert character to lower - ret ; done -; -; Print a zero terminated string at (de) without destroying any registers -; -prtstr: - push af - push de -; -prtstr1: - ld a,(de) ; get next char - or a - jr z,prtstr2 - call prtchr - inc de - jr prtstr1 -; -prtstr2: - pop de ; restore registers - pop af - ret -; -; Print a hex value prefix "0x" -; -prthexpre: - push af - ld a,'0' - call prtchr - ld a,'x' - call prtchr - pop af - ret -; -; Print the value in A in hex without destroying any registers -; -prthex: - call prthexpre -prthex1: - push af ; save AF - push de ; save DE - call hexascii ; convert value in A to hex chars in DE - ld a,d ; get the high order hex char - call prtchr ; print it - ld a,e ; get the low order hex char - call prtchr ; print it - pop de ; restore DE - pop af ; restore AF - ret ; done -; -; print the hex word value in hl -; -prthexword: - call prthexpre -prthexword1: - push af - ld a,h - call prthex1 - ld a,l - call prthex1 - pop af - ret -; -; print the hex dword value in de:hl -; -prthex32: - call prthexpre - push bc - push de - pop bc - call prthexword1 - push hl - pop bc - call prthexword1 - pop bc - ret -; -; Convert binary value in A to ascii hex characters in DE -; -hexascii: - ld d,a ; save A in D - call hexconv ; convert low nibble of A to hex - ld e,a ; save it in E - ld a,d ; get original value back - rlca ; rotate high order nibble to low bits - rlca - rlca - rlca - call hexconv ; convert nibble - ld d,a ; save it in D - ret ; done -; -; Convert low nibble of A to ascii hex -; -hexconv: - and $0F ; low nibble only - add a,$90 - daa - adc a,$40 - daa - ret -; -; Print value of A or HL in decimal with leading zero suppression -; Use prtdecb for A or prtdecw for HL -; -prtdecb: - push hl - ld h,0 - ld l,a - call prtdecw ; print it - pop hl - ret -; -prtdecw: - push af - push bc - push de - push hl - call prtdec0 - pop hl - pop de - pop bc - pop af - ret -; -prtdec0: - ld e,'0' - ld bc,-10000 - call prtdec1 - ld bc,-1000 - call prtdec1 - ld bc,-100 - call prtdec1 - ld c,-10 - call prtdec1 - ld e,0 - ld c,-1 -prtdec1: - ld a,'0' - 1 -prtdec2: - inc a - add hl,bc - jr c,prtdec2 - sbc hl,bc - cp e - ret z - ld e,0 - call prtchr - ret -; -; Start a new line -; -crlf2: - call crlf ; two of them -crlf: - push af ; preserve AF - ld a,13 ; - call prtchr ; print it - ld a,10 ; - call prtchr ; print it - pop af ; restore AF - ret -; -; Dump a buffer in hex and ascii -; -; HL=buffer address -; C=buffer length, 0 for 256 bytes -; Uses AF, BC, DE, HL -; - -dumpbuf: - ld de,0 ; init buffer offset -dumpbuf1: - call dumpline - ld a,d - inc a - ret z - jr dumpbuf1 -; -dumpline: - ; HL=buf ptr, DE=buf offset, C=bytes left to print - call crlf ; start line - ex de,hl ; offset in HL - call prthexword1 ; print in hex - ld a,16 ; increment - call addhla ; ... for next time - ex de,hl ; restore DE/HL - ld a,':' - call prtchr -; - ; hex byte loop, C=bytes to print - ld b,16 ; bytes per row - push bc - push hl -dumpline1: - ld a,b - cp 8 - jr nz,dumpline2 - call prtsp - ld a,'-' - call prtchr -; -dumpline2: - call prtsp - ld a,d - inc a - jr z,dumpline3 - ld a,(hl) ; get byte - inc hl ; bump position - call prthex1 ; print it - dec c - jr nz,dumpline4 - ld d,$FF ; flag end of buf - jr dumpline4 -dumpline3: - call prtsp - call prtsp -dumpline4: - djnz dumpline1 -; - call prtsp - call prtsp - ld a,'|' - call prtchr -; - ; ascii byte loop, C=bytes to print - pop hl - pop bc -dumpline5: - ld a,(hl) ; get real byte - inc hl - call dumpchar - dec c - jr z,dumpline6 ; if done, just exit loop - djnz dumpline5 -dumpline6: - ld a,'|' - call prtchr - ret -; -dumpchar: - ; Print character. Replace non-printable with '.' - cp ' ' - jr c,dumpchar1 ; first printable char is ' ' - cp '~' + 1 - jr nc,dumpchar1 ; last printable char is '~' - jp prtchr ; print and return -dumpchar1: - ld a,'.' ; replace with '.' - jp prtchr ; print and return -; -; Add hl,a -; -; A register is destroyed! -; -addhla: - add a,l - ld l,a - ret nc - inc h - ret -; -; -; -delay: - push af - push hl - ld hl,0 -delay1: - ld a,h - or l - jr nz,delay1 - pop hl - pop af - ret -; -;======================================================================= -; String Data -;======================================================================= -; -str_banner .db "I2C Serial ROM Utility v0.1, 26-Aug-2023",0 -str_hwmsg1 .db "PCF8584 Data port=",0 -str_hwmsg2 .db ", Control/Status port=",0 -str_hwmsg3 .db "",0 -str_inforead .db "Reading",0 -str_infowrite .db "Writing",0 -str_infotest .db "Testing",0 -str_infodump .db "Dumping",0 -str_infodump2 .db ", Page #",0 -str_info1 .db " Serial ROM #",0 -str_info2 .db " (I2C address ",0 -str_info3 .db ")",0 -str_exit .db "Done, Thank you for using I2C Serial ROM Utility!",0 -str_confirm .db "Serial ROM will be overwritten, continue (y/N)?",0 -str_err_ok .db "Successful completion",0 -str_err_bio .db "RomWBW BIOS required, but not present!",0 -str_err_plt .db "Hardware platform not currently supported!",0 -str_err_usage .db "Usage:", cr, lf - .db " SROM Tn Test SROM", cr, lf - .db " SROM Dn Dump SROM n (0-511)", cr, lf - .db " SROM Rn Read SROM n into ", cr, lf - .db " SROM Wn Write SROM n from ", cr, lf - .db "", cr, lf - .db " n=SROM Id (0-7)", 0 -str_err_init .db "PCF8584 failed during initialization!",0 -str_err_timeout .db "I2C protocol timeout!",0 -str_err_nak .db "Slave negative acknowledge!",0 -str_err_fopen .db "Failed to open specified file!",0 -str_err_fio .db "File input/output error!",0 -str_err_exists .db "Output file already exists!",0 -str_err_verify .db "Data mismatch during verification!",0 -str_start .db "I2C Start...",0 -str_repstart .db "I2C Repeat Start...",0 -str_stop .db "I2C Stop...",0 -str_read .db "I2C Read...",0 -str_write .db "I2C Write...",0 -str_readpage .db "Reading ROM page ",0 -str_writepage .db "Writing ROM page ",0 -str_writepage2 .db " with Data=",0 -; -str_err_table: - .dw str_err_ok - .dw str_err_bio - .dw str_err_plt - .dw str_err_usage - .dw str_err_init - .dw str_err_timeout - .dw str_err_nak - .dw str_err_fopen - .dw str_err_fio - .dw str_err_exists - .dw str_err_verify -; -;======================================================================= -; Working Data -;======================================================================= -; -stksav .dw 0 ; stack pointer saved at start - .fill stksiz,0 ; stack -stack .equ $ ; stack top -; -pcf_dat .db 0 ; PCF8584 data port -pcf_ctl .db 0 ; PCF8584 control/status port -; -func .db 0 ; Function requested: T/D/R/W -romadr .db 0 ; ROM device I2C address -page .dw 0 ; Page requested for dump -; -confirm_buf .db 3 ; 3 bytes in buffer - .db 0 ; bytes filled by BDOS - .fill 3,0 ; actual character buffer -; -fcb .fill 36,0 ; FCB -; -adrbuf .fill 2,0 ; ROM address buffer (big endian!!!) -pagebuf .fill rom_pgsiz,$55 ; ROM page buffer -; -;======================================================================= -; - .end +; +;======================================================================= +; I2C Serial ROM Read/Write Utility (SROM) +;======================================================================= +; +; Read or write the contents of a 24LC512 Serial EEPROM via an I2C +; PCF8584 controller. +; +; WBW 2023-09-05: Initial release +; WBW 2023-09-07: Code clean up +; +;======================================================================= +; +; PCF8584 controller port addresses (adjust as needed) +; +pcfbase_sbc .equ $F0 ; SBC PCF8584 I/O base port address +pcfbase_duo .equ $56 ; Duodyne PCF8584 I/O base port address +; +; I2C identification (own slave id) +; +pcf_adr .equ $55 ; Our "own" I2C slave address +; +; 24LC512 ROM id (target device) +; +rom0_adr .equ $50 ; I2C SROM first I2C address +rom_pgsiz .equ 128 ; SROM page size +; +; General operational equates (should not require adjustment) +; +stksiz .equ $40 ; Working stack size +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +fcb1 .equ $005C ; first CP/M parsed FCB +fcb2 .equ $006C ; second CP/M parsed FCB +; +cr .equ 13 ; carriage return +lf .equ 10 ; line feed +; +ident .equ $FFFC ; loc of RomWBW HBIOS ident ptr +; +bf_sysver .equ $F1 ; BIOS: VER function +bf_sysget .equ $F8 ; HBIOS: SYSGET function +bf_sysset .equ $F9 ; HBIOS: SYSGET function +bf_sysgettimer .equ $D0 ; TIMER subfunction +bf_syssettimer .equ $D0 ; TIMER subfunction +bf_sysgetsecs .equ $D1 ; SECONDS subfunction +bf_syssetsecs .equ $D1 ; SECONDS subfunction +; +; Control register bits +; +pcf_ctl_pin .equ %10000000 ; reset ; 0x80 +pcf_ctl_eso .equ %01000000 ; enable serial output ; 0x40 +pcf_ctl_es1 .equ %00100000 ; register selection bit 1 ; 0x20 +pcf_ctl_es2 .equ %00010000 ; register selection bit 2 ; 0x10 +pcf_ctl_eni .equ %00001000 ; enable external interrupt ; 0x08 +pcf_ctl_sta .equ %00000100 ; generate start ; 0x04 +pcf_ctl_sto .equ %00000010 ; generate stop ; 0x02 +pcf_ctl_ack .equ %00000001 ; enable auto acknowledge ; 0x01 +; +pcf_op_start .equ (pcf_ctl_pin | pcf_ctl_eso | pcf_ctl_sta | pcf_ctl_ack) ; 0xC5 +pcf_op_stop .equ (pcf_ctl_pin | pcf_ctl_eso | pcf_ctl_sto | pcf_ctl_ack) ; 0xC3 +pcf_op_repstart .equ (pcf_ctl_eso | pcf_ctl_sta | pcf_ctl_ack) ; 0x45 +pcf_op_idle .equ (pcf_ctl_pin | pcf_ctl_eso | pcf_ctl_ack) ; 0xC1 +; +; Status register bits +; +pcf_st_pin .equ %10000000 ; pending interrupt not ; 0x80 +pcf_st_ini .equ %01000000 ; normally 0, 1 if not initialized ; 0x40 +pcf_st_sts .equ %00100000 ; stop detected ; 0x20 +pcf_st_ber .equ %00010000 ; bus error detected ; 0x10 +pcf_st_ad0 .equ %00001000 ; slave address received = 0x00 ; 0x08 +pcf_st_lrb .equ %00001000 ; last received bit ; 0x08 +pcf_st_aas .equ %00000100 ; addressed as slave ; 0x04 +pcf_st_lab .equ %00000010 ; lost arbitration ; 0x02 +pcf_st_bb .equ %00000001 ; bus busy not ; 0x01 +; +; Transmission frequencies +; +pcf_trns_90 .equ $00 ; 90 KHz +pcf_trns_45 .equ $01 ; 45 KHz +pcf_trns_11 .equ $02 ; 11 KHz +pcf_trns_15 .equ $03 ; 1.5 KHz +; +; Clock chip frequencies +; +pcf_clk_3 .equ $00 ; 3 MHz +pcf_clk_443 .equ $10 ; 4.43 MHz +pcf_clk_6 .equ $14 ; 6 MHz +pcf_clk_8 .equ $18 ; 8 MHz +pcf_clk_12 .equ $1C ; 12 MHz +; +; Divisor settings +; +pcf_clk .equ pcf_clk_12 ; $1C +pcf_trns .equ pcf_trns_90 ; $00 +; +; Error codes +; +ec_ok .equ 0 ; No error +ec_bio .equ -1 ; HBIOS invalid or not present +ec_plt .equ -2 ; HBIOS platform not supported +ec_usage .equ -3 ; Command line usage error +ec_init .equ -4 ; PCF8584 init failed +ec_timeout .equ -5 ; I2C protocol timeout +ec_nak .equ -6 ; Unexpected NAK +ec_fopen .equ -7 ; File open error +ec_fio .equ -8 ; File I/O error +ec_exists .equ -9 ; File already exists +ec_verify .equ -10 ; Data verification mismatch +; +;======================================================================= +; + .org $100 ; standard CP/M executable +; +; + ; Setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + ; Announce program + call crlf + ld de,str_banner ; banner + call prtstr +; + call parse ; parse options + jr nz,exit ; abort if problems +; + call init ; initialize + jr nz,exit ; abort if problems +; + call main ; do the real work +; +exit: + call prterr +; + ; Announce end of program + call crlf2 + ld de,str_exit + call prtstr +; + ; Restore stack and return to OS + call crlf ; formatting + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart +; +;======================================================================= +; Command Line Parsing +;======================================================================= +; +; We take advantage of CP/M OS command line processing which treats +; the first two parameters on the command line as filenames and places +; corresponding FCBs at $5C and $6C. +; +; The first FCB is not actually handled as a file. Instead, the first +; two characters are used as control parameters. First character is +; the function to perform (R=read, W=write) and the second character +; is the serial ROM address (0-7) which maps to I2C addresses $50-$57. +; +parse: + ld a,(fcb1+1) ; function parm + cp 'R' ; read? + jr z,parse1 ; if so, valid, continue + cp 'W' ; write? + jr z,parse1 ; if so, valid, continue + cp 'T' ; write? + jr z,parse1 ; if so, valid, continue + cp 'D' ; write? + jr z,parse1 ; if so, valid, continue + jp err_usage ; else, handle usage error +; +parse1: + ld (func),a ; save function + ld a,(fcb1+2) ; ROM adr parm + cp '0' ; start of range + jp c,err_usage ; if less, handle usage error + cp '7' + 1 ; end of range + jp nc,err_usage ; if more, handle usage error + sub '0' ; convert to binary + add a,rom0_adr ; offset to first srom adr + ld (romadr),a ; save it +; + ld a,(func) ; recall function + cp 'T' ; test command? + jr z,parse_z +; + ld a,(fcb2+1) ; first char of page/filename + cp ' ' ; blank? + jp z,err_usage ; if so, handle usage error +; + ld a,(func) ; recall function + cp 'D' ; dump command? + jr z,parse2 ; parse page number +; + ; copy FCB to working location + ld hl,fcb2 ; parsed CP/M FCB 2 + ld de,fcb ; our FCB buffer + ld bc,16 ; only first 16 bytes + ldir ; copy it + jr parse_z +; +parse2: + ; parse page number + ld hl,0 ; initialize page number + ld de,fcb2+1 ; pointer to start of page num +parse3: + ld a,(de) ; get next char + inc de + cp ' ' ; space char? + jr z,parse4 ; return w/ ZF set + cp '0' ; start of range + jp c,err_usage ; if less, handle usage error + cp '9' + 1 ; end of range + jp nc,err_usage ; if more, handle usage error +; + ; multiply working page num by 10, then add new digit + push hl + pop bc + add hl,hl + add hl,hl + add hl,bc + add hl,hl + sub '0' + call addhla +; + ; check for overflow + ld a,h + cp 2 + jp nc,err_usage +; + jr parse3 +; +parse4: + ld (page),hl +; +parse_z: + xor a + ret +; +;======================================================================= +; Hardware Initialization +;======================================================================= +; +init: + call idbio ; identify hardware BIOS + cp 1 ; is it RomWBW? + jp nz,err_bio ; if not, handle error +; + ; Setup I/O ports based on HBIOS platform ID + ld a,l ; idbio puts platform id in L + ld c,pcfbase_sbc ; assume SBC + cp 1 ; compare to platform id + jr z,init1 ; if SBC, commit + ld c,pcfbase_duo ; assume SBC + cp 17 ; compare to platform id + jr z,init1 ; if DUO, commit + jp err_plt ; unsupported platform error +; +init1: + ; Record and display PCF8584 port addresses + call crlf2 ; formatting + ld de,str_hwmsg1 ; first part of h/w message + call prtstr ; print it + ld a,c ; get base port + call prthex ; print port number + ld (pcf_dat),a ; save data port + ld de,str_hwmsg2 ; second part of h/w message + call prtstr ; print port number + inc a ; bump to data port + ld (pcf_ctl),a ; save control port + call prthex ; print port number + ld de,str_hwmsg3 ; third part of h/w message + call prtstr ; print it +; + ; Initialize PCF8584 + call pcf_init ; sets A with result + ret nz +; + ; "Reading/Writing/Testing Serial ROM # (I2C address 0xnn)" + call crlf2 + ld a,(func) + ld de,str_inforead + cp 'R' + call z,prtstr ; "Reading" + ld de,str_infowrite + cp 'W' + call z,prtstr ; "Writing" + ld de,str_infotest + cp 'T' + call z,prtstr ; "Testing" + ld de,str_infodump + cp 'D' + call z,prtstr ; "Dumping" + ld de,str_info1 + call prtstr ; " Serial ROM #" + ld a,(romadr) + push af + sub rom0_adr + call prtdecb ; # + pop af + ld de,str_info2 + call prtstr ; " (I2C address " + call prthex ; 0x## + ld de,str_info3 + call prtstr ; ")" +; +init2: + xor a + ret +; +;======================================================================= +; Mainline +;======================================================================= +; +main: + ; Get requested function and dispatch + ld a,(func) ; get function + cp 'T' ; SROM test? + jp z,test ; if so, do it + cp 'D' ; SROM dump? + jp z,dump ; if so, do it + cp 'R' ; SROM read + jp z,read ; if so, do it + cp 'W' ; SROM write + jp z,write ; if so, do it + ret ; this should never happen +; +; +; +test: + call confirm + ret nz +; + call fillbufseq + ld hl,0 + call test_write + ret nz + call fillbufrev + ld hl,1 + call test_write + ret nz + call fillbufseq + ld hl,510 + call test_write + ret nz + call fillbufrev + ld hl,511 + call test_write + ret nz +; + ld hl,0 + call test_read + ret nz + call checkseq + ret nz + ld hl,1 + call test_read + ret nz + call checkrev + ret nz + ld hl,510 + call test_read + ret nz + call checkseq + ret nz + ld hl,511 + call test_read + ret nz + call checkrev + ret nz +; + xor a + ret +; +; +; +test_read: + call crlf2 + ld de,str_readpage + call prtstr + call prtdecw + call clrbuf +; + call readpage + ret nz +; + ld hl,pagebuf + ld c,rom_pgsiz + call crlf + call dumpbuf +; + xor a + ret +; +; +; +test_write: + call crlf2 + ld de,str_writepage + call prtstr + call prtdecw + jp writepage +; +; +; +dump: + ld hl,(page) + call crlf2 + ld de,str_readpage + call prtstr + call prtdecw + call clrbuf +; + call readpage + ret nz +; + ld hl,pagebuf + ld c,rom_pgsiz + call crlf + call dumpbuf +; + xor a + ret +; +; +; +read: + ; Ensure output file does not exist! + ld de,fcb ; FCB pointer + ld c,15 ; BDOS open file function + call bdos ; do it + cp $FF ; failed to open? + jr z,read0 ; if so, good, continue + call read_z ; close the file + jp err_exists ; handle error +; +read0: + ; Create output file (must not exist) + ld de,fcb ; FCB pointer + ld c,22 ; BDOS create file function + call bdos ; do it + cp $FF ; error? + jp z,err_fopen ; handle file open error +; + ; SROM read / File write loop + call crlf ; formatting + ld de,pagebuf ; BDOS DMA is pagebuf + ld c,26 ; BDOS set DMA function + call bdos ; do it + ld hl,0 ; init SROM page num +; +read1: + ; Read SROM page + push hl ; save SROM page num + call readpage ; get SROM page + pop hl ; restore page num + jr nz,read_z ; bail out on error + inc hl ; inc page num +; + ; Write page to file + push hl ; save SROM page num + ld de,fcb ; point to FCB + ld c,21 ; BDOS write seq function + call bdos ; do it + pop hl ; restore page num + or a ; set flags + call nz,err_fio ; handle file I/O error + jr nz,read_z ; close file and bail out +; + ; Show progress and loop till done + call prtdot ; display progress + ld a,h ; check high byte + cp 2 ; done when we hit 512 pages + jr nz,read1 ; loop till done + xor a ; signal success +; +read_z: + ; Close file + push af ; preserve status + ld de,fcb ; FCB pointer + ld c,16 ; BDOS close file function + call bdos ; do it + pop af ; restore status +; + ret +; +; +; +write: + ; Confirm intent to overwrite SROM + call confirm ; confirm SROM overwrite + ret nz ; bail out if not confirmed +; + ; Open file + ld de,fcb ; FCB pointer + ld c,15 ; BDOS open file function + call bdos ; do it' + cp $FF ; error? + jp z,err_fopen ; handle file open error +; + ; File read / SROM write loop + call crlf ; formatting + ld de,pagebuf ; BDOS DMA is pagebuf + ld c,26 ; BDOS set DMA function + call bdos ; do it + ld hl,0 ; init SROM page num +; +write1: + ; Read page data from file + push hl ; save SROM page num + ld de,fcb ; FCB pointer + ld c,20 ; BDOS read file function + call bdos ; do it + pop hl ; restore SROM page num + or a ; set flags + call nz,err_fio ; handle file I/O error + jr nz,write_z ; close file and bail out +; + ; Write SROM page + push hl ; save SROM page num + call writepage ; write SROM page + pop hl ; restore page num + jr nz,read_z ; bail out on error + inc hl ; inc page num +; + ; Show progress and loop till done + call prtdot ; display progress + ld a,h ; check high byte + cp 2 ; done when we hit 512 pages + jr nz,write1 ; loop till done + xor a ; signal success +; +write_z: + ; Close file + push af ; preserve status + ld de,fcb ; FCB pointer + ld c,16 ; BDOS close file function + call bdos ; do it + pop af ; restore status +; + ret +; +; +; +readpage: + ; Convert page number to byte offset + add hl,hl ; * 2 + add hl,hl ; * 4 + add hl,hl ; * 8 + add hl,hl ; * 16 + add hl,hl ; * 32 + add hl,hl ; * 64 + add hl,hl ; * 128 +; + ; Read page + ld de,pagebuf + ld bc,rom_pgsiz + jp rom_read +; +; +; +writepage: + ; Convert page number to byte offset + add hl,hl ; * 2 + add hl,hl ; * 4 + add hl,hl ; * 8 + add hl,hl ; * 16 + add hl,hl ; * 32 + add hl,hl ; * 64 + add hl,hl ; * 128 +; + ; Write page + ld de,pagebuf + ld bc,rom_pgsiz + jp rom_write +; +; +; +clrbuf: + xor a +fillbuf: + push af + push bc + push de + push hl + ld hl,pagebuf + ld de,pagebuf + 1 + ld bc,rom_pgsiz - 1 + ld (hl),a + ldir + pop hl + pop de + pop bc + pop af + ret +; +; +; +fillbufseq: + push af + push bc + push de + push hl + xor a + ld b,rom_pgsiz + ld hl,pagebuf +fillbufseq1: + ld (hl),a + inc a + inc hl + djnz fillbufseq1 + pop hl + pop de + pop bc + pop af + ret +; +; +; +fillbufrev: + push af + push bc + push de + push hl + ld a,rom_pgsiz - 1 + ld b,rom_pgsiz + ld hl,pagebuf +fillbufrev1: + ld (hl),a + dec a + inc hl + djnz fillbufrev1 + pop hl + pop de + pop bc + pop af + ret +; +; +; +checkseq: + push bc + push de + push hl + xor a + ld b,rom_pgsiz + ld hl,pagebuf +checkseq1: + cp (hl) + call nz,err_verify + jr nz,checkseq_z + inc a + inc hl + djnz checkseq1 + xor a +checkseq_z: + pop hl + pop de + pop bc + ret +; +; +; +checkrev: + push bc + push de + push hl + ld a,rom_pgsiz - 1 + ld b,rom_pgsiz + ld hl,pagebuf +checkrev1: + cp (hl) + call nz,err_verify + jr nz,checkrev_z + dec a + inc hl + djnz checkrev1 + xor a +checkrev_z: + pop hl + pop de + pop bc + ret +; +; Confirm intention to overwrite SROM +; +confirm: + call crlf2 + ld de,str_confirm + call prtstr +; + ld c,10 ; CP/M read line + ld de,confirm_buf ; line buffer + call bdos ; get line from user +; + ld a,(confirm_buf + 1) ; number of chars returned + or a ; set flags + jr z,confirm1 + ld a,(confirm_buf + 2) ; get first char entered + cp 'Y' ; confirmed? + ret z ; if so, done, ZF set + cp 'y' ; lower case variant + ret z ; if so, done, ZF set +; +confirm1: + or $FF ; signal non-confirm + ret +; +;======================================================================= +; 24LC512 ROM Routines +;======================================================================= +; +; Write a buffer of data to ROM +; DE=buffer adr +; HL=ROM byte offset +; BC=buffer len +; +rom_write: + ; Move offset to buffer, convert to big endian!!! + ld a,h ; high byte + ld (adrbuf+0),a ; ... to first buffer pos + ld a,l ; low byte + ld (adrbuf+1),a ; ... to second buffer pos +; + ; Save count to HL for later + push bc ; move count from BC + pop hl ; ... to HL +; + ; Generate start condition + ld a,(romadr) ; load ROM I2C adress + rlca ; move to top 7 bits + res 0,a ; clear low bit for write + call pcf_start ; generate start + jr nz,rom_write_z ; if error, skip write +; + ; Send ROM address + push de ; save buffer pointer + push hl ; save buffer length + ld hl,2 ; 2 byte address + ld de,adrbuf ; memory address pointer + call pcf_write ; set memory pointer + pop hl ; restore buffer length + pop de ; restore buffer pointer + jr nz,rom_write_z ; if error, skip write +; + ; Write data from buffer + call pcf_write ; write the page +; +rom_write_z: + push af ; save current status + call pcf_stop ; generate stop + pop af ; restore status + ret nz ; bail out if error status +; + jr rom_write_wait ; exit via write wait +; +; +; +rom_write_wait: + ; While SROM is updating page data, it will NAK any + ; start request. Loop on start requests until an ACK is + ; received or loop timeout. + ld b,0 ; try 256 times +rom_write_wait1: + push bc ; save loop control + ld a,(romadr) ; load ROM I2C adress + rlca ; move to top 7 bits + res 0,a ; clear low bit for write + call pcf_start ; generate start + jr nz,rom_write_wait2 ; skip ahead + call pcf_waitpin ; wait for bus and get status + ;call prthex +rom_write_wait2: + push af ; save current status + call pcf_stop ; generate stop + pop af ; restore status + pop bc ; restore loop control + cp $FF ; timeout? + jp z,err_timeout ; handle timeout error + and pcf_st_lrb ; isolate LRB (ACK bit) + jr z,rom_write_wait3 ; done + djnz rom_write_wait1 ; else loop until timeout + jp err_timeout ; handle timeout +; +rom_write_wait3: + ;ld a,b + ;neg + ;call prthex + xor a ; set flags + ret ; done +; +; Read ROM data into buffer +; DE=buffer adr +; HL=ROM byte offset +; BC=buffer len +; +rom_read: + ; Move offset to buffer, convert to big endian!!! + ld a,h ; high byte + ld (adrbuf+0),a ; ... to first buffer pos + ld a,l ; low byte + ld (adrbuf+1),a ; ... to second buffer pos +; + ; Save count to HL for later + push bc ; move count from BC + pop hl ; ... to HL +; + ; Generate start condition + ld a,(romadr) ; load ROM I2C adress + rlca ; move to top 7 bits + res 0,a ; clear low bit for write + call pcf_start ; generate start + jr nz,rom_read_z ; if error, skip write +; +rom_read2: + ; Send ROM address + push de ; save buffer pointer + push hl ; save buffer length + ld hl,2 ; 2 byte address + ld de,adrbuf ; memory address pointer + call pcf_write ; set memory pointer + pop hl ; restore buffer length + pop de ; restore buffer pointer + jr nz,rom_read_z ; if error, bail out +; + ; Repeat start, switch to read + ld a,(romadr) ; load ROM I2C address + rlca ; move to top 7 bits + set 0,a ; set low bit for read + call pcf_repstart ; generate repeat start + jr nz,rom_read_z ; if error, bail out +; + ; Read data into buffer + call pcf_read ; read the page +; +rom_read_z: + push af ; save current status + call pcf_stop ; generate stop + pop af ; restore status + or a ; set flags + ret ; done +; +;======================================================================= +; PCF8584 Routines +;======================================================================= +; +; General PCF8584 initialization +; +pcf_init: + ; Select S0' (own address) 0x80 -> 0x00 + ld a,(pcf_ctl) ; ctl port + ld c,a ; to C + ld a,pcf_ctl_pin ; PCF reset, select S0' + out (c),a ; do it + nop + in a,(c) ; read status + ;call crlf2 + ;call prtsp + ;call prthex + and $7F ; remove pin bit + jp nz,err_init ; all should be zero +; + ; Set S0' (own address) 0x55 + dec c ; data port + ld a,pcf_adr ; own address + out (c),a ; set own address in S0' (own << 1) + nop + in a,(c) ; read back S0' + ;call prtsp + ;call prthex + cp pcf_adr ; correct? + jp nz,err_init ; if not, init error +; + ; Select S2 (clock) 0xA0 -> 0x20 + inc c ; ctl port + ld a,pcf_ctl_pin | pcf_ctl_es1 ; select S2 + out (c),a ; do it + nop + in a,(c) ; read status + ;call prtsp + ;call prthex + and 07fh ; remove pin bit + cp pcf_ctl_es1 ; verify S2 selected + jp nz,err_init ; it not, init error +; + ; Set S2 (clock) 0x1C + dec c ; data port + ld a,pcf_trns | pcf_clk ; load clock register s2 + out (c),a ; do it + nop + in a,(c) ; read back S2 + ;call prtsp + ;call prthex + and $1F ; only the lower 5 bits are used + cp pcf_trns | pcf_clk + jp nz,err_init +; + ; Enter idle 0xC1 + inc c ; ctl port + ld a,pcf_op_idle + out (c),a ; do it + nop + in a,(c) ; read status + ;call prtsp + ;call prthex + cp pcf_st_pin | pcf_st_bb ; expected status + jp nz,err_init +; + xor a + ret +; +; Generate an I2C start condition +; A=start byte value (slave address + r/w bit) +; +pcf_start: + ;call crlf + ;push de + ;ld de,str_start + ;call prtstr + ;pop de +; + ; Wait for I2C bus clear + ld b,a ; move start byte to B + call pcf_waitbb ; wait while bus busy + cp $FF ; timeout? + jp z,err_timeout ; timeout error return +; + ; Set start byte w/ slave address in S0 + ld a,(pcf_dat) ; data port + ld c,a ; ... into C + ;ld a,b + ;call prtsp + ;call prthex + out (c),b ; send start byte +; + ; Initiate start operation + inc c ; ctl port + ld a,pcf_op_start ; command + out (c),a ; do it +; + xor a ; signal success + ret ; done +; +; Generate an I2C repeat start condition +; A=start byte value (slave address + r/w bit) +; +pcf_repstart: + ;call crlf + ;push de + ;ld de,str_repstart + ;call prtstr + ;pop de +; + ; Send repeat start command + ld b,a ; move start byte to B + ld a,(pcf_ctl) ; control port + ld c,a ; ... into C + ld a,pcf_op_repstart ; command + out (c),a ; do it +; + ; Set start byte w/ slave address in S0 + ld a,(pcf_dat) ; data port + ld c,a ; ... into C + ;ld a,b + ;call prtsp + ;call prthex + out (c),b ; send start byte +; + xor a ; signal success + ret ; done +; +; Generate an I2C stop condition +; +pcf_stop: + ;call crlf + ;push de + ;ld de,str_stop + ;call prtstr + ;pop de +; + ld a,(pcf_ctl) ; control port + ld c,a ; ... into C + ld a,pcf_op_stop ; command + ;call prtsp + ;call prthex + out (c),a ; do it +; + xor a ; signal success + ret ; done +; +; Write bytes to I2C +; HL=byte count to write +; DE=buffer pointer +; +pcf_write: + ;push af + ;push bc + ;push de + ;push hl + ;push hl + ;push de + ;pop hl + ;call crlf + ;ld de,str_write + ;call prtstr + ;call prtsp + ;call prthexword + ;call prtsp + ;pop hl + ;call prthexword + ;call crlf + ;pop hl + ;pop de + ;pop bc + ;pop af +; +pcf_write1: + call pcf_waitack ; wait for ack + ret nz ; abort on failure +; + ld a,h ; check for + or l ; ... counter exhausted + ret z ; if so, done, exit w/ ZF set +; + ld a,(pcf_dat) ; data port + ld c,a ; ... into C + ld a,(de) ; get byte to write + ;call prtsp + ;call prthex + out (c),a ; send it +; + dec hl ; decrement byte counter + inc de ; bump buf ptr + jr pcf_write1 ; loop till done +; +; Read bytes from I2C +; HL=byte count to read +; +pcf_read: + ;push af + ;push bc + ;push de + ;push hl + ;call crlf + ;ld de,str_read + ;call prtstr + ;call prtsp + ;call prthexword + ;call crlf + ;pop hl + ;pop de + ;pop bc + ;pop af +; + ; First byte is a "dummy", must be discarded + call pcf_waitack ; wait for ack + ret nz ; abort on failure + ld a,(pcf_dat) ; data port + ld c,a ; ... into C + in a,(c) ; get dummy byte +; +pcf_read0: + call pcf_waitack ; wait for ack + ret nz ; abort on failure +; + ; Loop control + dec hl ; pre-decrement byte counter + ld a,h ; check for + or l ; ... counter exhausted - 1 + jr z,pcf_read2 ; handle end game +; +pcf_read1: + ; Get next data byte + ld a,(pcf_dat) ; data port + ld c,a ; ... into C + in a,(c) ; get next byte of ROM + ;call prtsp + ;call prthex + ld (de),a ; save byte received in buf + inc de ; bump buf pointer +; + jr pcf_read0 ; loop till done +; +pcf_read2: + ; Special treatment for final character + ld a,(pcf_ctl) ; control port + ld c,a ; ... into C + ld a,$40 ; prep for neg ack + out (c),a ; send it +; + ; Get final data byte + ld a,(pcf_dat) ; data port + ld c,a ; ... into C + in a,(c) ; get next byte of ROM + ;call prtsp + ;call prtdot + ;call prthex + ld (de),a ; save byte received in buf +; + call pcf_waitpin ; wait for PIN + cp $FF ; timeout? + jp z,err_timeout ; handle it +; + xor a ; signal success + ret ; done +; +; Wait for I2C bus to not be busy (BB = 1) +; Return PCF status in A, 0xFF for timeout +; +pcf_waitbb: + push bc ; save BC + ld a,(pcf_ctl) ; control port value + ld c,a ; ... into C + ld b,0 ; timeout counter +; +pcf_waitbb1: + in a,(c) ; get status byte + bit 0,a ; test busy bit (inverted) + jr nz,pcf_waitbb_z ; if BB=1, bus clear, return + djnz pcf_waitbb1 ; loop to keep trying + or $FF ; signal timeout +; +pcf_waitbb_z: + pop bc ; restore BC + ret ; done +; +; Wait for PIN (PIN = 0) +; Return PCF status in A, 0xFF for timeout +; +pcf_waitpin: + push bc ; save BC + ld a,(pcf_ctl) ; control port value + ld c,a ; ... into C + ld b,0 ; timeout counter +; +pcf_waitpin1: + ; Wait till done with send/receive (PIN=0) + in a,(c) ; get status byte + bit 7,a ; test PIN bit + jr z,pcf_waitpin_z ; if 0, done + djnz pcf_waitpin1 ; loop till timeout + or $FF ; signal timeout +; +pcf_waitpin_z: + pop bc ; restore BC + ret ; done +; +; Wait for slave (PIN = 0) and check for acknowledge (LRB = 0) +; Return error code +; +pcf_waitack: + call pcf_waitpin ; wait for PIN + cp $FF ; timeout? + jp z,err_timeout ; handle it + ; Evaluate response + and pcf_st_lrb ; isolate LRB bit + jp nz,err_nak ; handle NAK error + xor a ; set status + ret +; +; Error Handlers +; +err_bio: + ld a,ec_bio + jr err_ret +; +err_plt: + ld a,ec_plt + jr err_ret +; +err_usage: + ld a,ec_usage + jr err_ret +; +err_init: + ld a,ec_init + jr err_ret +; +err_timeout: + ld a,ec_timeout + jr err_ret +; +err_nak: + ld a,ec_nak + jr err_ret +; +err_fopen: + ld a,ec_fopen + jr err_ret +; +err_fio: + ld a,ec_fio + jr err_ret +; +err_exists: + ld a,ec_exists + jr err_ret +; +err_verify: + ld a,ec_verify + jr err_ret +; +err_ret: + or a ; set flags + ret +; +; +; +prterr: + push de + push hl + neg + rlca + ld hl,str_err_table + call addhla + ld e,(hl) + inc hl + ld d,(hl) + call crlf2 + call prtstr + pop hl + pop de + ret +; +;======================================================================= +; Utility Routines +;======================================================================= +; +; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 +; +idbio: +; + ; Check for UNA (UBIOS) + ld a,($FFFD) ; fixed location of UNA API vector + cp $C3 ; jp instruction? + jr nz,idbio1 ; 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,idbio1 ; 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,idbio1 ; if not, not UNA, check others +; + ld bc,$04FA ; UNA: get BIOS date and version + rst 08 ; DE := ver, HL := date +; + ld a,2 ; UNA BIOS id = 2 + ret ; and done +; +idbio1: + ; Check for RomWBW (HBIOS) + ld hl,($FFFE) ; HL := HBIOS ident location + ld a,'W' ; First byte of ident + cp (hl) ; Compare + jr nz,idbio2 ; Not HBIOS + inc hl ; Next byte of ident + ld a,~'W' ; Second byte of ident + cp (hl) ; Compare + jr nz,idbio2 ; Not HBIOS +; + ld b,bf_sysver ; HBIOS: VER function + ld c,0 ; required reserved value + rst 08 ; DE := version, L := platform id +; + ld a,1 ; HBIOS BIOS id = 1 + ret ; and done +; +idbio2: + ; No idea what this is + xor a ; Setup return value of 0 + ret ; and done + +; +; Print character in A without destroying any registers +; +prtchr: + push af ; save registers + push bc + push de + push hl + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it + pop hl ; restore registers + pop de + pop bc + pop af + ret +; +prtsp3: + call prtsp +prtsp2: + call prtsp +prtsp: +; + ; shortcut to print a space character preserving all regs + push af ; save af + ld a,' ' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +prtdot: +; + ; shortcut to print a dot character preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Uppercase character in A +; +upcase: + cp 'a' ; below 'a'? + ret c ; if so, nothing to do + cp 'z'+1 ; above 'z'? + ret nc ; if so, nothing to do + and ~$20 ; convert character to lower + ret ; done +; +; Print a zero terminated string at (de) without destroying any registers +; +prtstr: + push af + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + pop af + ret +; +; Print a hex value prefix "0x" +; +prthexpre: + push af + ld a,'0' + call prtchr + ld a,'x' + call prtchr + pop af + ret +; +; Print the value in A in hex without destroying any registers +; +prthex: + call prthexpre +prthex1: + push af ; save AF + push de ; save DE + call hexascii ; convert value in A to hex chars in DE + ld a,d ; get the high order hex char + call prtchr ; print it + ld a,e ; get the low order hex char + call prtchr ; print it + pop de ; restore DE + pop af ; restore AF + ret ; done +; +; print the hex word value in hl +; +prthexword: + call prthexpre +prthexword1: + push af + ld a,h + call prthex1 + ld a,l + call prthex1 + pop af + ret +; +; print the hex dword value in de:hl +; +prthex32: + call prthexpre + push bc + push de + pop bc + call prthexword1 + push hl + pop bc + call prthexword1 + pop bc + ret +; +; Convert binary value in A to ascii hex characters in DE +; +hexascii: + ld d,a ; save A in D + call hexconv ; convert low nibble of A to hex + ld e,a ; save it in E + ld a,d ; get original value back + rlca ; rotate high order nibble to low bits + rlca + rlca + rlca + call hexconv ; convert nibble + ld d,a ; save it in D + ret ; done +; +; Convert low nibble of A to ascii hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Dump a buffer in hex and ascii +; +; HL=buffer address +; C=buffer length, 0 for 256 bytes +; Uses AF, BC, DE, HL +; + +dumpbuf: + ld de,0 ; init buffer offset +dumpbuf1: + call dumpline + ld a,d + inc a + ret z + jr dumpbuf1 +; +dumpline: + ; HL=buf ptr, DE=buf offset, C=bytes left to print + call crlf ; start line + ex de,hl ; offset in HL + call prthexword1 ; print in hex + ld a,16 ; increment + call addhla ; ... for next time + ex de,hl ; restore DE/HL + ld a,':' + call prtchr +; + ; hex byte loop, C=bytes to print + ld b,16 ; bytes per row + push bc + push hl +dumpline1: + ld a,b + cp 8 + jr nz,dumpline2 + call prtsp + ld a,'-' + call prtchr +; +dumpline2: + call prtsp + ld a,d + inc a + jr z,dumpline3 + ld a,(hl) ; get byte + inc hl ; bump position + call prthex1 ; print it + dec c + jr nz,dumpline4 + ld d,$FF ; flag end of buf + jr dumpline4 +dumpline3: + call prtsp + call prtsp +dumpline4: + djnz dumpline1 +; + call prtsp + call prtsp + ld a,'|' + call prtchr +; + ; ascii byte loop, C=bytes to print + pop hl + pop bc +dumpline5: + ld a,(hl) ; get real byte + inc hl + call dumpchar + dec c + jr z,dumpline6 ; if done, just exit loop + djnz dumpline5 +dumpline6: + ld a,'|' + call prtchr + ret +; +dumpchar: + ; Print character. Replace non-printable with '.' + cp ' ' + jr c,dumpchar1 ; first printable char is ' ' + cp '~' + 1 + jr nc,dumpchar1 ; last printable char is '~' + jp prtchr ; print and return +dumpchar1: + ld a,'.' ; replace with '.' + jp prtchr ; print and return +; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret +; +; +; +delay: + push af + push hl + ld hl,0 +delay1: + ld a,h + or l + jr nz,delay1 + pop hl + pop af + ret +; +;======================================================================= +; String Data +;======================================================================= +; +str_banner .db "I2C Serial ROM Utility v0.1, 26-Aug-2023",0 +str_hwmsg1 .db "PCF8584 Data port=",0 +str_hwmsg2 .db ", Control/Status port=",0 +str_hwmsg3 .db "",0 +str_inforead .db "Reading",0 +str_infowrite .db "Writing",0 +str_infotest .db "Testing",0 +str_infodump .db "Dumping",0 +str_infodump2 .db ", Page #",0 +str_info1 .db " Serial ROM #",0 +str_info2 .db " (I2C address ",0 +str_info3 .db ")",0 +str_exit .db "Done, Thank you for using I2C Serial ROM Utility!",0 +str_confirm .db "Serial ROM will be overwritten, continue (y/N)?",0 +str_err_ok .db "Successful completion",0 +str_err_bio .db "RomWBW BIOS required, but not present!",0 +str_err_plt .db "Hardware platform not currently supported!",0 +str_err_usage .db "Usage:", cr, lf + .db " SROM Tn Test SROM", cr, lf + .db " SROM Dn Dump SROM n (0-511)", cr, lf + .db " SROM Rn Read SROM n into ", cr, lf + .db " SROM Wn Write SROM n from ", cr, lf + .db "", cr, lf + .db " n=SROM Id (0-7)", 0 +str_err_init .db "PCF8584 failed during initialization!",0 +str_err_timeout .db "I2C protocol timeout!",0 +str_err_nak .db "Slave negative acknowledge!",0 +str_err_fopen .db "Failed to open specified file!",0 +str_err_fio .db "File input/output error!",0 +str_err_exists .db "Output file already exists!",0 +str_err_verify .db "Data mismatch during verification!",0 +str_start .db "I2C Start...",0 +str_repstart .db "I2C Repeat Start...",0 +str_stop .db "I2C Stop...",0 +str_read .db "I2C Read...",0 +str_write .db "I2C Write...",0 +str_readpage .db "Reading ROM page ",0 +str_writepage .db "Writing ROM page ",0 +str_writepage2 .db " with Data=",0 +; +str_err_table: + .dw str_err_ok + .dw str_err_bio + .dw str_err_plt + .dw str_err_usage + .dw str_err_init + .dw str_err_timeout + .dw str_err_nak + .dw str_err_fopen + .dw str_err_fio + .dw str_err_exists + .dw str_err_verify +; +;======================================================================= +; Working Data +;======================================================================= +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +pcf_dat .db 0 ; PCF8584 data port +pcf_ctl .db 0 ; PCF8584 control/status port +; +func .db 0 ; Function requested: T/D/R/W +romadr .db 0 ; ROM device I2C address +page .dw 0 ; Page requested for dump +; +confirm_buf .db 3 ; 3 bytes in buffer + .db 0 ; bytes filled by BDOS + .fill 3,0 ; actual character buffer +; +fcb .fill 36,0 ; FCB +; +adrbuf .fill 2,0 ; ROM address buffer (big endian!!!) +pagebuf .fill rom_pgsiz,$55 ; ROM page buffer +; +;======================================================================= +; + .end diff --git a/Source/Apps/Tune/hbios.inc b/Source/Apps/Tune/hbios.inc index e56a67c8..73a7390a 100644 --- a/Source/Apps/Tune/hbios.inc +++ b/Source/Apps/Tune/hbios.inc @@ -1,4 +1,4 @@ -IDENT .EQU $FFFE ; loc of RomWBW HBIOS ident ptr +IDENT .EQU $FFFC ; loc of RomWBW HBIOS ident ptr ; BF_SYSVER .EQU $F1 ; BIOS: VER function BF_SYSGET .EQU $F8 ; HBIOS: SYSGET function diff --git a/Source/Apps/Tune/tune.asm b/Source/Apps/Tune/tune.asm index 41abfe92..1c3da63b 100644 --- a/Source/Apps/Tune/tune.asm +++ b/Source/Apps/Tune/tune.asm @@ -446,7 +446,7 @@ IDBIO: ; IDBIO1: ; Check for RomWBW (HBIOS) - LD HL,($FFFE) ; HL := HBIOS ident location + LD HL,($FFFC) ; HL := HBIOS ident location LD A,'W' ; First byte of ident CP (HL) ; Compare JR NZ,IDBIO2 ; Not HBIOS diff --git a/Source/Apps/XM/xmhb.z80 b/Source/Apps/XM/xmhb.z80 index 98bc806e..a66ad1ea 100644 --- a/Source/Apps/XM/xmhb.z80 +++ b/Source/Apps/XM/xmhb.z80 @@ -239,7 +239,7 @@ IDBIO: ; IDBIO1: ; Check for RomWBW (HBIOS) - LD HL,(0FFFEH) ; HL := HBIOS ident location + LD HL,(0FFFCH) ; HL := HBIOS ident location LD A,'W' ; First byte of ident CP (HL) ; Compare JR NZ,IDBIO2 ; Not HBIOS diff --git a/Source/Apps/XM/xmhb_old.z80 b/Source/Apps/XM/xmhb_old.z80 index 9405d3cf..2aba8ecd 100644 --- a/Source/Apps/XM/xmhb_old.z80 +++ b/Source/Apps/XM/xmhb_old.z80 @@ -180,7 +180,7 @@ IDBIO: ; IDBIO1: ; Check for RomWBW (HBIOS) - LD HL,(0FFFEH) ; HL := HBIOS ident location + LD HL,(0FFFCH) ; HL := HBIOS ident location LD A,'W' ; First byte of ident CP (HL) ; Compare JR NZ,IDBIO2 ; Not HBIOS diff --git a/Source/Apps/XM/xmuf.z80 b/Source/Apps/XM/xmuf.z80 index 53b52d86..0d69a78d 100644 --- a/Source/Apps/XM/xmuf.z80 +++ b/Source/Apps/XM/xmuf.z80 @@ -175,7 +175,7 @@ IDBIO: ; IDBIO1: ; Check for RomWBW (HBIOS) - LD HL,(0FFFEH) ; HL := HBIOS ident location + LD HL,(0FFFCH) ; HL := HBIOS ident location LD A,'W' ; First byte of ident CP (HL) ; Compare JR NZ,IDBIO2 ; Not HBIOS diff --git a/Source/Apps/ZMD/zmdhb.z80 b/Source/Apps/ZMD/zmdhb.z80 index 30529832..1bb1b192 100644 --- a/Source/Apps/ZMD/zmdhb.z80 +++ b/Source/Apps/ZMD/zmdhb.z80 @@ -273,7 +273,7 @@ IDBIO: ; IDBIO1: ; Check for RomWBW (HBIOS) - LD HL,(0FFFEH) ; HL := HBIOS ident location + LD HL,(0FFFCH) ; HL := HBIOS ident location LD A,'W' ; First byte of ident CP (HL) ; Compare JR NZ,IDBIO2 ; Not HBIOS diff --git a/Source/Apps/assign/assign.asm b/Source/Apps/assign/assign.asm index a3d1418b..b16d8d84 100644 --- a/Source/Apps/assign/assign.asm +++ b/Source/Apps/assign/assign.asm @@ -190,7 +190,7 @@ init: ldir ; do the copy ; ; determine end of CBIOS (assume HBIOS for now) - ld hl,($FFFE) ; get proxy start address + ld hl,($FFFC) ; get proxy start address ld (bioend),hl ; save as CBIOS end address ; ; check for UNA (UBIOS) diff --git a/Source/Apps/cpuspd/cpuspd.asm b/Source/Apps/cpuspd/cpuspd.asm index 4fef256c..9bf691a4 100644 --- a/Source/Apps/cpuspd/cpuspd.asm +++ b/Source/Apps/cpuspd/cpuspd.asm @@ -29,7 +29,7 @@ bf_sysres_int .equ $00 ; reset hbios internal bf_sysres_warm .equ $01 ; warm start (restart boot loader) bf_sysres_cold .equ $02 ; cold start ; -ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr +ident .equ $FFFC ; loc of RomWBW HBIOS ident ptr ; ;======================================================================= ; diff --git a/Source/Apps/mode/mode.asm b/Source/Apps/mode/mode.asm index 45f3a91f..dafb9f75 100644 --- a/Source/Apps/mode/mode.asm +++ b/Source/Apps/mode/mode.asm @@ -1,1039 +1,1039 @@ -;=============================================================================== -; MODE - Display and/or modify device configuration -; -;=============================================================================== -; -; Author: Wayne Warthen (wwarthen@gmail.com) -;_______________________________________________________________________________ -; -; Usage: -; MODE /? -; MODE COM: [[,[,[,]]]] [/P] -; -; is numerical baudrate -; is (N)one, (O)dd, (E)ven, (M)ark, or (S)pace -; is number of data bits, typically 7 or 8 -; is number of stop bits, typically 1 or 2 -; /P prompts user prior to setting new configuration -; -; Examples: -; MODE /? (display command usage) -; MODE (display configuration of all serial ports) -; MODE COM0: (display configuration of serial unit 0) -; MODE COM1: 9600,N,8,1 (set serial unit 1 configuration) -; -; Notes: -; - Parameters not provided will remain unchanged -; - Device must support specified configuration -;_______________________________________________________________________________ -; -; Change Log: -; 2017-08-16 [WBW] Initial release -; 2017-08-28 [WBW] Handle UNACPM -; 2018-07-24 [WBW] Fixed bug in getnum23 routine (credit Phil Summers) -;_______________________________________________________________________________ -; -; ToDo: -; 1) Implement flow control settings -;_______________________________________________________________________________ -; -#include "../../ver.inc" -; -;=============================================================================== -; Definitions -;=============================================================================== -; -stksiz .equ $40 ; Working stack size -; -restart .equ $0000 ; CP/M restart vector -bdos .equ $0005 ; BDOS invocation vector -; -ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr -; -bf_cioinit .equ $04 ; HBIOS: CIOINIT function -bf_cioquery .equ $05 ; HBIOS: CIOQUERY function -bf_ciodevice .equ $06 ; HBIOS: CIODEVICE function -bf_sysget .equ $F8 ; HBIOS: SYSGET function -; -;=============================================================================== -; Code Section -;=============================================================================== -; - .org $100 -; - ; setup stack (save old value) - ld (stksav),sp ; save stack - ld sp,stack ; set new stack -; - ; initialization - call init ; initialize - jr nz,exit ; abort if init fails -; - ; get the target device - call getdev ; parse device/id from command line - jr nz,exit ; abort on error -; - ; process the configuration request - call process ; parse device/id from command line - jr nz,exit ; abort on error -; -exit: ; clean up and return to command processor - call crlf ; formatting - ld sp,(stksav) ; restore stack - jp restart ; return to CP/M via restart - ret ; return to CP/M w/o restart -; -; Initialization -; -init: - ; locate start of cbios (function jump table) - ld hl,(restart+1) ; load address of CP/M restart vector - ld de,-3 ; adjustment for start of table - add hl,de ; HL now has start of table - ld (bioloc),hl ; save it -; - ; check for UNA (UBIOS) - ld a,($FFFD) ; fixed location of UNA API vector - cp $C3 ; jp instruction? - jr nz,initwbw ; 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,initwbw ; 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,initwbw ; if not, not UNA -; - ; UNA initialization - ld hl,unamod ; point to UNA mode flag - ld (hl),$FF ; set UNA mode flag - ld a,$FF ; assume max units for UNA - ld (comcnt),a ; ... and save it - jr initx ; UNA init done -; -initwbw: - ; get location of config data and verify integrity - ld hl,(ident) ; HL := adr or RomWBW HBIOS ident - ld a,(hl) ; get first byte of RomWBW marker - cp 'W' ; match? - jp nz,errinv ; abort with invalid config block - inc hl ; next byte (marker byte 2) - ld a,(hl) ; load it - cp ~'W' ; match? - jp nz,errinv ; abort with invalid config block - inc hl ; next byte (major/minor version) - ld a,(hl) ; load it - cp rmj << 4 | rmn ; match? - jp nz,errver ; abort with invalid os version -; - ; RomWBW initialization - ld b,bf_sysget ; BIOS SYSGET function - ld c,$00 ; CIOCNT subfunction - rst 08 ; E := serial device unit count - ld a,e ; count to A - ld (comcnt),a ; save it -; -initx - ; initialization complete - xor a ; signal success - ret ; return -; -; Get target device specification (e.g., "COM1:") and save -; as devicetype/id. -; -getdev: - ; skip to start of first parm - ld ix,$81 ; point to start of parm area (past len byte) - call nonblank ; skip to next non-blank char - jp z,prtcomall ; no parms, show all active ports -; -getdev1: - ; process options (if any) - cp '/' ; option prefix? - jr nz,getdev2 ; not an option, continue - call option ; process option - ret nz ; some options mean we are done (e.g., "/?") - inc ix ; skip option character - call nonblank ; skip whitespace - jr getdev1 ; continue option checking -; -getdev2: - ; parse device mnemonic (e.g., "COM1") into tmpstr - call getalpha ; extract alpha portion (e.g., "COM") - call getnum ; extract numeric portion - jp c,errunt ; handle overflow as invalid unit - ld (unit),a ; save as unit number -; - ; skip terminating ':' in device spec - ld a,(ix) ; get current char - cp ':' ; colon? - jr nz,getdev3 ; done if no colon - inc ix ; otherwise, skip the colon -; -getdev3: - call nonblank ; gobble any remaining whitespace - xor a ; indicate success - ret ; and return -; -; Process device -; -process: - ; match and branch according to device mnemonic - ld hl,tmpstr ; point to start of extracted string - ld de,strcom ; point to "COM" string - call strcmp ; and compare - jp z,comset ; handle COM port configuration - jp errdev ; abort if bad device name -; -; Display or change serial port configuration -; -comset: - ; check for valid unit number - ld hl,comcnt ; point to com device unit count - ld a,(unit) ; get com device unit count - cp (hl) ; compare to count (still in E) - jr c,comset1 ; unit < count, continue - jp errunt ; handle unit number error -; -comset1: - call ldcom ; load config for port -; - ld a,(comatr) ; get attributes - bit 7,a ; terminal? - jp nz,prtcom ; terminal not configurable -; - ld a,(ix) ; get current char - cp 0 ; nothing more? - jp z,prtcom ; no config parms, print current device config -; - ; parse and update baudrate - ld a,(ix) ; get current byte - cp '0' ; check for - jr c,comset1a ; ... valid digit - cp '9'+1 ; ... else jump ahead - jr nc,comset1a ; ... to handle empty -; - call getnum32 ; get baud rate into DE:HL - jp c,errcfg ; Handle overflow error - ld c,75 ; Constant for baud rate encode - call encode ; encode into C:4-0 - jp nz,errcfg ; Error if encode fails - ld a,(comcfg+1) ; Get high byte of config - and %11100000 ; strip out old baud rate bits - or c ; insert new baud rate bits - ld (comcfg+1),a ; save it -; -comset1a: - ; parse and update parity - call nonblank ; skip blanks - jp z,comset9 ; end of parms - cp ',' ; comma, as expected? - jp nz,comset8 ; check for trailing options - inc ix ; skip comma - call nonblank ; skip possible blanks - call ucase - ; lookup parity value - ld c,0 - cp 'N' - jr z,comset2 - ld c,1 - cp 'O' - jr z,comset2 - ld c,3 - cp 'E' - jr z,comset2 - ld c,5 - cp 'M' - jr z,comset2 - ld c,7 - cp 'S' - jr z,comset2 - jr comset3 ; unexpected parity char, possibly empty -; -comset2: - ; update parity value - ld a,c ; new parity value to A - rlca ; rotate to bits 5-3 - rlca ; - rlca ; - ld c,a ; and back to C - ld a,(comcfg) ; parity is in comcfg:5-3 - and %11000111 ; strip old value - or c ; apply new value - ld (comcfg),a ; and save it - inc ix ; bump past parity char -; -comset3: - ; parse & update data bits - call nonblank ; skip blanks - jr z,comset9 ; end of parms - cp ',' ; comma, as expected? - jr nz,comset8 ; check for trailing options - inc ix ; skip comma - call nonblank ; skip possible blanks - sub '5' ; normalize value - cp 4 ; value should now be 0-3 - jr nc,comset4 ; unexpected, possibly empty - ld c,a ; move new value to C - ld a,(comcfg) ; data bits is in comcfg:1-0 - and %11111100 ; strip old value - or c ; apply new value - ld (comcfg),a ; and save it - inc ix ; bump past data bits char -; -comset4: - ; parse & update stop bits - call nonblank ; skip blanks - jr z,comset9 ; end of parms - cp ',' ; comma, as expected? - jr nz,comset8 ; check for trailing options - inc ix ; skip comma - call nonblank ; skip possible blanks - sub '1' ; normalize value - cp 2 ; value should now be 0-1 - jr nc,comset8 ; unexpected, possibly empty - rlca ; rotate to bit 2 - rlca - ld c,a ; move new value to C - ld a,(comcfg) ; stop bit is in comcfg:2 - and %11111011 ; strip old value - or c ; apply new value - ld (comcfg),a ; and save it - inc ix ; bump past stop bits char -; -comset8: - ; trailing options - call nonblank ; skip blanks - jr z,comset9 ; end of parms - cp '/' ; option introducer? - jp nz,errprm ; parameter error - inc ix ; bump part '/' - ld a,(ix) ; get character - call ucase ; make upper case - cp 'P' ; only valid option - jp nz,errprm ; parameter error - ld a,$FF ; set prompt value on - ld (pflag),a ; save it - inc ix ; bump past character - jr comset8 ; process more parms -; -comset9: - ; display new config - ld de,(comcfg) ; get new config - call prtcom ; print it - ld a,(pflag) ; get prompt flag - or a ; set flags - jr z,comset9b ; bypass if not requested - call crlf2 ; spacing - ld de,indent ; indent - call prtstr ; do it - ld de,msgpmt ; point to prmopt message - call prtstr ; print it -; - ld b,64 -comset9a: - xor a - call prtchr - djnz comset9a -; -comset9b: - ; check for UNA - ld a,(unamod) ; get UNA flag - or a ; set flags - jr nz,comsetu ; go to UNA variant -; - ; implement new config - ld de,(comcfg) ; get new config value to DE - ld b,bf_cioinit ; BIOS serial init - ld a,(unit) ; get serial device unit - ld c,a ; ... into C - rst 08 ; call HBIOS - jp nz,errcfg ; handle error - jr comsetx ; common exit -; -comsetu: - ; implement new config under UNA - ld de,(comcfg) ; get new config value to DE - ld c,$10 ; UNA INIT function - ld a,(unit) ; get serial device unit - ld b,a ; ... into B - rst 08 ; call HBIOS - jp nz,errcfg ; handle error - jr comsetx ; common exit -; -comsetx: - ld a,(pflag) ; get prompt flag - or a ; set flags - jr z,comsetx2 ; bypass if not requested -comsetx1: - ld c,$01 ; console read - call bdos ; do it - cp $0D ; CR? - jr nz,comsetx1 ; loop as needed -; -comsetx2: - xor a - ret -; -; Print configuration of all serial ports -; -prtcomall: - ld a,(comcnt) ; get com device unit count - ld b,a ; init B as loop counter - ld c,0 ; init C as unit index -; -prtcomall1: - push bc ; save loop control -; - ; get port info - ld a,c ; put unit number - ld (unit),a ; ... into unit - call ldcom ; get config - jr z,prtcomall2 ; no error, continue - pop bc ; unwind stack - ret ; and return with NZ -; -prtcomall2: - ; print config for port - call prtcom ; print line for this port -; - ; loop as needed - pop bc ; restore loop control - inc c ; next unit index - djnz prtcomall1 ; loop till done -; - or $FF ; indicate nothing more to do - ret ; finished -; -; Print configuration of serial port -; -prtcom: - ; print leader (e.g., "COM0: ") - call crlf - ld de,indent - call prtstr - ld de,strcom - call prtstr - ld a,(unit) - call prtdecb - ld a,':' - call prtchr - ld a,' ' - call prtchr -; - ld a,(comatr) ; get attribute byte - bit 7,a ; 0=RS232, 1=terminal - jr z,prtcom1 ; handle serial port configuration -; - ; this is a terminal, just say so - ld de,strterm ; point to string - call prtstr ; print it - ret ; and return -; -prtcom1: - ld de,(comcfg) ; load config to DE -; - ; print baud rate - push de ; save it - ld a,d ; baud rate is in D - and $1F ; ... bits 4-0 - ld l,a ; move to L - ld h,0 ; setup H for decode routine - ld de,75 ; set DE to baud rate decode constant - call decode ; decode baud rate, DE:HL := baud rate - ld bc,bcdtmp ; point to temp bcd buffer - call bin2bcd ; convert baud to BCD - call prtbcd ; and print in decimal - pop de ; restore line characteristics -; - ; print parity - ld a,',' ; A := comma - call prtchr ; ... print it - ld a,e ; E has parity config - rrca ; isolate bits 5-3 - rrca ; ... - rrca ; ... - and $07 ; ... - ld hl,parmap ; HL := start of parity char table - call addhl ; index into table - ld a,(hl) ; get resulting parity char - call prtchr ; and print -; - ; print data bits - ld a,',' ; A := comma - call prtchr ; ... print it - ld a,e ; E has data bits config - and $03 ; isloate bits 1-0 - add A,'5' ; convert to printable char - call prtchr ; and print it -; - ; print stop bits - ld a,',' ; A := comma - call prtchr ; ... print it - ld a,e ; E has stop bits config - rrca ; isolate bit 2 - rrca ; ... - and $01 ; ... - add A,'1' ; convert to printable char - call prtchr ; and print it -; - ret -; -; Load serial device info for specific unit -; -ldcom: - ld a,(unamod) ; get UNA flag - or a ; set flags - jr nz,ldcomu ; go to UNA variant -; - ; get device type info - ld a,(unit) ; get unit - ld b,bf_ciodevice ; BIOS device call - ld c,a ; ... and put in C - rst 08 ; call HBIOS, C := attributes - ret nz ; return on error - ld a,c ; attributes to A - ld (comatr),a ; save it -; - ; get serial port config - ld b,bf_cioquery ; BIOS serial device query - ld a,(unit) ; get device unit num - ld c,a ; ... and put in C - rst 08 ; call H/UBIOS, DE := line characteristics - ret nz ; abort on error - ld (comcfg),de ; save config -; - xor a ; success - ret -; -ldcomu: ; UNA variant - xor a ; assume attribtues zero - ld (comatr),a ; save it - ; get device info - ld a,(unit) ; get unit - ld b,a ; put unit in B - ld c,$18 ; UNA Get line/driver info func - rst 08 ; call H/UBIOS, DE := line characteristics - ld a,c - or a - jr z,ldcomu1 - cp $43 ; $43 is OK for now (tell John about this) - jr z,ldcomu1 - ret ; return w/ NZ indicating error -; -ldcomu1: - ld (comcfg),de ; save config -; - xor a ; success - ret - -; -; Handle special options -; -option: -; - inc ix ; next char - ld a,(ix) ; get it - cp '?' ; is it a '?' as expected? - jp z,usage ; yes, display usage -; cp 'L' ; is it a 'L', display device list? -; jp z,devlist ; yes, display device list - jp errprm ; anything else is an error -; -; Display usage -; -usage: -; - call crlf ; formatting - ld de,msgban1 ; point to version message part 1 - call prtstr ; print it - ld a,(unamod) ; get UNA flag - or a ; set flags - ld de,msghb ; point to HBIOS mode message - call z,prtstr ; if not UNA, say so - ld de,msgub ; point to UBIOS mode message - call nz,prtstr ; if UNA, say so - call crlf ; formatting - ld de,msgban2 ; point to version message part 2 - call prtstr ; print it - call crlf2 ; blank line - ld de,msguse ; point to usage message - call prtstr ; print it - or $FF ; signal no action performed - ret ; and return -; -; Print character in A without destroying any registers -; -prtchr: - push bc ; save registers - push de - push hl - ld e,a ; character to print in E - ld c,$02 ; BDOS function to output a character - call bdos ; do it - pop hl ; restore registers - pop de - pop bc - ret -; -prtdot: -; - ; shortcut to print a dot preserving all regs - push af ; save af - ld a,'.' ; load dot char - call prtchr ; print it - pop af ; restore af - ret ; done -; -; Print a zero terminated string at (DE) without destroying any registers -; -prtstr: - push de -; -prtstr1: - ld a,(de) ; get next char - or a - jr z,prtstr2 - call prtchr - inc de - jr prtstr1 -; -prtstr2: - pop de ; restore registers - ret -; -; Print the value in A in hex without destroying any registers -; -prthex: - push af ; save AF - push de ; save DE - call hexascii ; convert value in A to hex chars in DE - ld a,d ; get the high order hex char - call prtchr ; print it - ld a,e ; get the low order hex char - call prtchr ; print it - pop de ; restore DE - pop af ; restore AF - ret ; done -; -; print the hex word value in bc -; -prthexword: - push af - ld a,b - call prthex - ld a,c - call prthex - pop af - ret -; -; print the hex dword value in de:hl -; -prthex32: - push bc - push de - pop bc - call prthexword - push hl - pop bc - call prthexword - pop bc - ret -; -; Convert binary value in A to ascii hex characters in DE -; -hexascii: - ld d,a ; save A in D - call hexconv ; convert low nibble of A to hex - ld e,a ; save it in E - ld a,d ; get original value back - rlca ; rotate high order nibble to low bits - rlca - rlca - rlca - call hexconv ; convert nibble - ld d,a ; save it in D - ret ; done -; -; Convert low nibble of A to ascii hex -; -hexconv: - and $0F ; low nibble only - add a,$90 - daa - adc a,$40 - daa - ret -; -; Print value of A or HL in decimal with leading zero suppression -; Use prtdecb for A or prtdecw for HL -; -prtdecb: - push hl - ld h,0 - ld l,a - call prtdecw ; print it - pop hl - ret -; -prtdecw: - push af - push bc - push de - push hl - call prtdec0 - pop hl - pop de - pop bc - pop af - ret -; -prtdec0: - ld e,'0' - ld bc,-10000 - call prtdec1 - ld bc,-1000 - call prtdec1 - ld bc,-100 - call prtdec1 - ld c,-10 - call prtdec1 - ld e,0 - ld c,-1 -prtdec1: - ld a,'0' - 1 -prtdec2: - inc a - add hl,bc - jr c,prtdec2 - sbc hl,bc - cp e - ret z - ld e,0 - call prtchr - ret -; -; Start a new line -; -crlf2: - call crlf ; two of them -crlf: - push af ; preserve AF - ld a,13 ; - call prtchr ; print it - ld a,10 ; - call prtchr ; print it - pop af ; restore AF - ret -; -; Get the next non-blank character from (HL). -; -nonblank: - ld a,(ix) ; load next character - or a ; string ends with a null - ret z ; if null, return pointing to null - cp ' ' ; check for blank - ret nz ; return if not blank - inc ix ; if blank, increment character pointer - jr nonblank ; and loop -; -; Get alpha chars and save in tmpstr -; Length of string returned in A -; -getalpha: -; - ld hl,tmpstr ; location to save chars - ld b,8 ; length counter (tmpstr max chars) - ld c,0 ; init character counter -; -getalpha1: - ld a,(ix) ; get active char - call ucase ; lower case -> uppper case, if needed - cp 'A' ; check for start of alpha range - jr c,getalpha2 ; not alpha, get out - cp 'Z' + 1 ; check for end of alpha range - jr nc,getalpha2 ; not alpha, get out - ; handle alpha char - ld (hl),a ; save it - inc c ; bump char count - inc hl ; inc string pointer - inc ix ; increment buffer ptr - djnz getalpha1 ; if space, loop for more chars -; -getalpha2: ; non-alpha, clean up and return - ld (hl),0 ; terminate string - ld a,c ; string length to A - or a ; set flags - ret ; and return -; -; Get numeric chars and convert to number returned in A -; Carry flag set on overflow -; -getnum: - ld c,0 ; C is working register -getnum1: - ld a,(ix) ; get the active char - cp '0' ; compare to ascii '0' - jr c,getnum2 ; abort if below - cp '9' + 1 ; compare to ascii '9' - jr nc,getnum2 ; abort if above -; - ; valid digit, add new digit to C - ld a,c ; get working value to A - rlca ; multiply by 10 - ret c ; overflow, return with carry set - rlca ; ... - ret c ; overflow, return with carry set - add a,c ; ... - ret c ; overflow, return with carry set - rlca ; ... - ret c ; overflow, return with carry set - ld c,a ; back to C - ld a,(ix) ; get new digit - sub '0' ; make binary - add a,c ; add in working value - ret c ; overflow, return with carry set - ld c,a ; back to C -; - inc ix ; bump to next char - jr getnum1 ; loop -; -getnum2: ; return result - ld a,c ; return result in A - or a ; with flags set, CF is cleared - ret -; -; Get numeric chars and convert to 32-bit number returned in DE:HL -; Carry flag set on overflow -; -getnum32: - ld de,0 ; Initialize DE:HL - ld hl,0 ; ... to zero -getnum32a: - ld a,(ix) ; get the active char - cp '0' ; compare to ascii '0' - jr c,getnum32c ; abort if below - cp '9' + 1 ; compare to ascii '9' - jr nc,getnum32c ; abort if above -; - ; valid digit, multiply DE:HL by 10 - ; X * 10 = (((x * 2 * 2) + x)) * 2 - push de - push hl -; - call getnum32e ; DE:HL *= 2 - jr c,getnum32d ; if overflow, ret w/ CF & stack pop -; - call getnum32e ; DE:HL *= 2 - jr c,getnum32d ; if overflow, ret w/ CF & stack pop -; - pop bc ; DE:HL += X - add hl,bc - ex de,hl - pop bc - adc hl,bc - ex de,hl - ret c ; if overflow, ret w/ CF -; - call getnum32e ; DE:HL *= 2 - ret c ; if overflow, ret w/ CF -; - ; now add in new digit - ld a,(ix) ; get the active char - sub '0' ; make it binary - add a,l ; add to L, CF updated - ld l,a ; back to L - jr nc,getnum32b ; if no carry, done - inc h ; otherwise, bump H - jr nz,getnum32b ; if no overflow, done - inc e ; otherwise, bump E - jr nz,getnum32b ; if no overflow, done - inc d ; otherwise, bump D - jr nz,getnum32b ; if no overflow, done - scf ; set carry flag to indicate overflow - ret ; and return -; -getnum32b: - inc ix ; bump to next char - jr getnum32a ; loop -; -getnum32c: - ; successful completion - xor a ; clear flags - ret ; and return -; -getnum32d: - ; special overflow exit with stack fixup - pop hl ; burn 2 - pop hl ; ... stack entries - ret ; and return -; -getnum32e: - ; DE:HL := DE:HL * 2 - sla l - rl h - rl e - rl d - ret -; -; Compare null terminated strings at HL & DE -; If equal return with Z set, else NZ -; -strcmp: - ld a,(de) ; get current source char - cp (hl) ; compare to current dest char - ret nz ; compare failed, return with NZ - or a ; set flags - ret z ; end of string, match, return with Z set - inc de ; point to next char in source - inc hl ; point to next char in dest - jr strcmp ; loop till done -; -; Convert character in A to uppercase -; -ucase: - cp 'a' ; if below 'a' - ret c ; ... do nothing and return - cp 'z' + 1 ; if above 'z' - ret nc ; ... do nothing and return - res 5,a ; clear bit 5 to make lower case -> upper case - ret ; and return -; -; Add the value in A to HL (HL := HL + A) -; -addhl: - add a,l ; A := A + L - ld l,a ; Put result back in L - ret nc ; if no carry, we are done - inc h ; if carry, increment H - ret ; and return -; -; Integer divide DE:HL by C -; result in DE:HL, remainder in A -; clobbers F, B -; -div32x8: - xor a - ld b,32 -div32x8a: - add hl,hl - rl e - rl d - rla - cp c - jr c,div32x8b - sub c - inc l -div32x8b: - djnz div32x8a - ret -; -; Jump indirect to address in HL -; -jphl: - jp (hl) -; -; Errors -; -erruse: ; command usage error (syntax) - ld de,msguse - jr err -; -errprm: ; command parameter error (syntax) - ld de,msgprm - jr err -; -errinv: ; invalid HBIOS, signature not found - ld de,msginv - jr err -; -errver: ; unsupported HBIOS version - ld de,msgver - jr err -; -errdev: ; invalid device name - ld de,msgdev - jr err -; -errnum: ; invalid number parsed, overflow - ld de,msgnum - jr err -; -errunt: ; Invalid device unit specified - ld de,msgunt - jr err -; -errcfg: ; Invalid device configuration specified - ld de,msgcfg - jr err -; -err: ; print error string and return error signal - call crlf2 ; print newline -; -err1: ; without the leading crlf - call prtstr ; print error string -; -err2: ; without the string -; call crlf ; print newline - or $FF ; signal error - ret ; done -; -;=============================================================================== -; Utility modules -;=============================================================================== -; -#include "encode.asm" -#include "decode.asm" -#include "bcd.asm" -; -;=============================================================================== -; Storage Section -;=============================================================================== -; -; -bioloc .dw 0 ; CBIOS starting address -unit .db 0 ; source unit -; -unamod .db 0 ; $FF indicates UNA UBIOS active -; -tmpstr .fill 9,0 ; temporary string of up to 8 chars, zero term -bcdtmp .fill 5,0 ; temporary bcd number storage -; -comcnt .db 0 ; count of com ports -comatr .db 0 ; com port attributes -comcfg .dw 0 ; com port configuration -; -parmap .db "NONENMNS" ; parity character lookup table -; -pflag .db 0 ; $FF indicates prompt option set -; -strcom .db "COM",0 ; serial device name string -strterm .db "VDU",0 ; terminal device string -; -stksav .dw 0 ; stack pointer saved at start - .fill stksiz,0 ; stack -stack .equ $ ; stack top -; -; Messages -; -indent .db " ",0 -msgban1 .db "MODE v1.2, 24-Jul-2018",0 -msghb .db " [HBIOS]",0 -msgub .db " [UBIOS]",0 -msgban2 .db "Copyright (C) 2017, Wayne Warthen, GNU GPL v3",0 -msguse .db "Usage: MODE COM: [[,[,[,]]]] [/P]",13,10 - .db " ex. MODE /? (display version and usage)",13,10 - .db " MODE (display config of all serial ports)",13,10 - .db " MODE COM0: (display serial unit 0 config)",13,10 - .db " MODE COM1: 9600,N,8,1 (set serial unit 1 config)",0 -msgprm .db "Parameter error (MODE /? for usage)",0 -msginv .db "Invalid BIOS (signature missing)",0 -msgver .db "Unexpected HBIOS version",0 -msgdev .db "Invalid device name",0 -msgnum .db "Unit or slice number invalid",0 -msgunt .db "Invalid device unit number specified",0 -msgcfg .db "Invalid device configuration specified",0 -msgpmt .db "Prepare line then press ",0 -; - .end +;=============================================================================== +; MODE - Display and/or modify device configuration +; +;=============================================================================== +; +; Author: Wayne Warthen (wwarthen@gmail.com) +;_______________________________________________________________________________ +; +; Usage: +; MODE /? +; MODE COM: [[,[,[,]]]] [/P] +; +; is numerical baudrate +; is (N)one, (O)dd, (E)ven, (M)ark, or (S)pace +; is number of data bits, typically 7 or 8 +; is number of stop bits, typically 1 or 2 +; /P prompts user prior to setting new configuration +; +; Examples: +; MODE /? (display command usage) +; MODE (display configuration of all serial ports) +; MODE COM0: (display configuration of serial unit 0) +; MODE COM1: 9600,N,8,1 (set serial unit 1 configuration) +; +; Notes: +; - Parameters not provided will remain unchanged +; - Device must support specified configuration +;_______________________________________________________________________________ +; +; Change Log: +; 2017-08-16 [WBW] Initial release +; 2017-08-28 [WBW] Handle UNACPM +; 2018-07-24 [WBW] Fixed bug in getnum23 routine (credit Phil Summers) +;_______________________________________________________________________________ +; +; ToDo: +; 1) Implement flow control settings +;_______________________________________________________________________________ +; +#include "../../ver.inc" +; +;=============================================================================== +; Definitions +;=============================================================================== +; +stksiz .equ $40 ; Working stack size +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +ident .equ $FFFC ; loc of RomWBW HBIOS ident ptr +; +bf_cioinit .equ $04 ; HBIOS: CIOINIT function +bf_cioquery .equ $05 ; HBIOS: CIOQUERY function +bf_ciodevice .equ $06 ; HBIOS: CIODEVICE function +bf_sysget .equ $F8 ; HBIOS: SYSGET function +; +;=============================================================================== +; Code Section +;=============================================================================== +; + .org $100 +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +; + ; get the target device + call getdev ; parse device/id from command line + jr nz,exit ; abort on error +; + ; process the configuration request + call process ; parse device/id from command line + jr nz,exit ; abort on error +; +exit: ; clean up and return to command processor + call crlf ; formatting + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart + ret ; return to CP/M w/o restart +; +; Initialization +; +init: + ; locate start of cbios (function jump table) + ld hl,(restart+1) ; load address of CP/M restart vector + ld de,-3 ; adjustment for start of table + add hl,de ; HL now has start of table + ld (bioloc),hl ; save it +; + ; check for UNA (UBIOS) + ld a,($FFFD) ; fixed location of UNA API vector + cp $C3 ; jp instruction? + jr nz,initwbw ; 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,initwbw ; 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,initwbw ; if not, not UNA +; + ; UNA initialization + ld hl,unamod ; point to UNA mode flag + ld (hl),$FF ; set UNA mode flag + ld a,$FF ; assume max units for UNA + ld (comcnt),a ; ... and save it + jr initx ; UNA init done +; +initwbw: + ; get location of config data and verify integrity + ld hl,(ident) ; HL := adr or RomWBW HBIOS ident + ld a,(hl) ; get first byte of RomWBW marker + cp 'W' ; match? + jp nz,errinv ; abort with invalid config block + inc hl ; next byte (marker byte 2) + ld a,(hl) ; load it + cp ~'W' ; match? + jp nz,errinv ; abort with invalid config block + inc hl ; next byte (major/minor version) + ld a,(hl) ; load it + cp rmj << 4 | rmn ; match? + jp nz,errver ; abort with invalid os version +; + ; RomWBW initialization + ld b,bf_sysget ; BIOS SYSGET function + ld c,$00 ; CIOCNT subfunction + rst 08 ; E := serial device unit count + ld a,e ; count to A + ld (comcnt),a ; save it +; +initx + ; initialization complete + xor a ; signal success + ret ; return +; +; Get target device specification (e.g., "COM1:") and save +; as devicetype/id. +; +getdev: + ; skip to start of first parm + ld ix,$81 ; point to start of parm area (past len byte) + call nonblank ; skip to next non-blank char + jp z,prtcomall ; no parms, show all active ports +; +getdev1: + ; process options (if any) + cp '/' ; option prefix? + jr nz,getdev2 ; not an option, continue + call option ; process option + ret nz ; some options mean we are done (e.g., "/?") + inc ix ; skip option character + call nonblank ; skip whitespace + jr getdev1 ; continue option checking +; +getdev2: + ; parse device mnemonic (e.g., "COM1") into tmpstr + call getalpha ; extract alpha portion (e.g., "COM") + call getnum ; extract numeric portion + jp c,errunt ; handle overflow as invalid unit + ld (unit),a ; save as unit number +; + ; skip terminating ':' in device spec + ld a,(ix) ; get current char + cp ':' ; colon? + jr nz,getdev3 ; done if no colon + inc ix ; otherwise, skip the colon +; +getdev3: + call nonblank ; gobble any remaining whitespace + xor a ; indicate success + ret ; and return +; +; Process device +; +process: + ; match and branch according to device mnemonic + ld hl,tmpstr ; point to start of extracted string + ld de,strcom ; point to "COM" string + call strcmp ; and compare + jp z,comset ; handle COM port configuration + jp errdev ; abort if bad device name +; +; Display or change serial port configuration +; +comset: + ; check for valid unit number + ld hl,comcnt ; point to com device unit count + ld a,(unit) ; get com device unit count + cp (hl) ; compare to count (still in E) + jr c,comset1 ; unit < count, continue + jp errunt ; handle unit number error +; +comset1: + call ldcom ; load config for port +; + ld a,(comatr) ; get attributes + bit 7,a ; terminal? + jp nz,prtcom ; terminal not configurable +; + ld a,(ix) ; get current char + cp 0 ; nothing more? + jp z,prtcom ; no config parms, print current device config +; + ; parse and update baudrate + ld a,(ix) ; get current byte + cp '0' ; check for + jr c,comset1a ; ... valid digit + cp '9'+1 ; ... else jump ahead + jr nc,comset1a ; ... to handle empty +; + call getnum32 ; get baud rate into DE:HL + jp c,errcfg ; Handle overflow error + ld c,75 ; Constant for baud rate encode + call encode ; encode into C:4-0 + jp nz,errcfg ; Error if encode fails + ld a,(comcfg+1) ; Get high byte of config + and %11100000 ; strip out old baud rate bits + or c ; insert new baud rate bits + ld (comcfg+1),a ; save it +; +comset1a: + ; parse and update parity + call nonblank ; skip blanks + jp z,comset9 ; end of parms + cp ',' ; comma, as expected? + jp nz,comset8 ; check for trailing options + inc ix ; skip comma + call nonblank ; skip possible blanks + call ucase + ; lookup parity value + ld c,0 + cp 'N' + jr z,comset2 + ld c,1 + cp 'O' + jr z,comset2 + ld c,3 + cp 'E' + jr z,comset2 + ld c,5 + cp 'M' + jr z,comset2 + ld c,7 + cp 'S' + jr z,comset2 + jr comset3 ; unexpected parity char, possibly empty +; +comset2: + ; update parity value + ld a,c ; new parity value to A + rlca ; rotate to bits 5-3 + rlca ; + rlca ; + ld c,a ; and back to C + ld a,(comcfg) ; parity is in comcfg:5-3 + and %11000111 ; strip old value + or c ; apply new value + ld (comcfg),a ; and save it + inc ix ; bump past parity char +; +comset3: + ; parse & update data bits + call nonblank ; skip blanks + jr z,comset9 ; end of parms + cp ',' ; comma, as expected? + jr nz,comset8 ; check for trailing options + inc ix ; skip comma + call nonblank ; skip possible blanks + sub '5' ; normalize value + cp 4 ; value should now be 0-3 + jr nc,comset4 ; unexpected, possibly empty + ld c,a ; move new value to C + ld a,(comcfg) ; data bits is in comcfg:1-0 + and %11111100 ; strip old value + or c ; apply new value + ld (comcfg),a ; and save it + inc ix ; bump past data bits char +; +comset4: + ; parse & update stop bits + call nonblank ; skip blanks + jr z,comset9 ; end of parms + cp ',' ; comma, as expected? + jr nz,comset8 ; check for trailing options + inc ix ; skip comma + call nonblank ; skip possible blanks + sub '1' ; normalize value + cp 2 ; value should now be 0-1 + jr nc,comset8 ; unexpected, possibly empty + rlca ; rotate to bit 2 + rlca + ld c,a ; move new value to C + ld a,(comcfg) ; stop bit is in comcfg:2 + and %11111011 ; strip old value + or c ; apply new value + ld (comcfg),a ; and save it + inc ix ; bump past stop bits char +; +comset8: + ; trailing options + call nonblank ; skip blanks + jr z,comset9 ; end of parms + cp '/' ; option introducer? + jp nz,errprm ; parameter error + inc ix ; bump part '/' + ld a,(ix) ; get character + call ucase ; make upper case + cp 'P' ; only valid option + jp nz,errprm ; parameter error + ld a,$FF ; set prompt value on + ld (pflag),a ; save it + inc ix ; bump past character + jr comset8 ; process more parms +; +comset9: + ; display new config + ld de,(comcfg) ; get new config + call prtcom ; print it + ld a,(pflag) ; get prompt flag + or a ; set flags + jr z,comset9b ; bypass if not requested + call crlf2 ; spacing + ld de,indent ; indent + call prtstr ; do it + ld de,msgpmt ; point to prmopt message + call prtstr ; print it +; + ld b,64 +comset9a: + xor a + call prtchr + djnz comset9a +; +comset9b: + ; check for UNA + ld a,(unamod) ; get UNA flag + or a ; set flags + jr nz,comsetu ; go to UNA variant +; + ; implement new config + ld de,(comcfg) ; get new config value to DE + ld b,bf_cioinit ; BIOS serial init + ld a,(unit) ; get serial device unit + ld c,a ; ... into C + rst 08 ; call HBIOS + jp nz,errcfg ; handle error + jr comsetx ; common exit +; +comsetu: + ; implement new config under UNA + ld de,(comcfg) ; get new config value to DE + ld c,$10 ; UNA INIT function + ld a,(unit) ; get serial device unit + ld b,a ; ... into B + rst 08 ; call HBIOS + jp nz,errcfg ; handle error + jr comsetx ; common exit +; +comsetx: + ld a,(pflag) ; get prompt flag + or a ; set flags + jr z,comsetx2 ; bypass if not requested +comsetx1: + ld c,$01 ; console read + call bdos ; do it + cp $0D ; CR? + jr nz,comsetx1 ; loop as needed +; +comsetx2: + xor a + ret +; +; Print configuration of all serial ports +; +prtcomall: + ld a,(comcnt) ; get com device unit count + ld b,a ; init B as loop counter + ld c,0 ; init C as unit index +; +prtcomall1: + push bc ; save loop control +; + ; get port info + ld a,c ; put unit number + ld (unit),a ; ... into unit + call ldcom ; get config + jr z,prtcomall2 ; no error, continue + pop bc ; unwind stack + ret ; and return with NZ +; +prtcomall2: + ; print config for port + call prtcom ; print line for this port +; + ; loop as needed + pop bc ; restore loop control + inc c ; next unit index + djnz prtcomall1 ; loop till done +; + or $FF ; indicate nothing more to do + ret ; finished +; +; Print configuration of serial port +; +prtcom: + ; print leader (e.g., "COM0: ") + call crlf + ld de,indent + call prtstr + ld de,strcom + call prtstr + ld a,(unit) + call prtdecb + ld a,':' + call prtchr + ld a,' ' + call prtchr +; + ld a,(comatr) ; get attribute byte + bit 7,a ; 0=RS232, 1=terminal + jr z,prtcom1 ; handle serial port configuration +; + ; this is a terminal, just say so + ld de,strterm ; point to string + call prtstr ; print it + ret ; and return +; +prtcom1: + ld de,(comcfg) ; load config to DE +; + ; print baud rate + push de ; save it + ld a,d ; baud rate is in D + and $1F ; ... bits 4-0 + ld l,a ; move to L + ld h,0 ; setup H for decode routine + ld de,75 ; set DE to baud rate decode constant + call decode ; decode baud rate, DE:HL := baud rate + ld bc,bcdtmp ; point to temp bcd buffer + call bin2bcd ; convert baud to BCD + call prtbcd ; and print in decimal + pop de ; restore line characteristics +; + ; print parity + ld a,',' ; A := comma + call prtchr ; ... print it + ld a,e ; E has parity config + rrca ; isolate bits 5-3 + rrca ; ... + rrca ; ... + and $07 ; ... + ld hl,parmap ; HL := start of parity char table + call addhl ; index into table + ld a,(hl) ; get resulting parity char + call prtchr ; and print +; + ; print data bits + ld a,',' ; A := comma + call prtchr ; ... print it + ld a,e ; E has data bits config + and $03 ; isloate bits 1-0 + add A,'5' ; convert to printable char + call prtchr ; and print it +; + ; print stop bits + ld a,',' ; A := comma + call prtchr ; ... print it + ld a,e ; E has stop bits config + rrca ; isolate bit 2 + rrca ; ... + and $01 ; ... + add A,'1' ; convert to printable char + call prtchr ; and print it +; + ret +; +; Load serial device info for specific unit +; +ldcom: + ld a,(unamod) ; get UNA flag + or a ; set flags + jr nz,ldcomu ; go to UNA variant +; + ; get device type info + ld a,(unit) ; get unit + ld b,bf_ciodevice ; BIOS device call + ld c,a ; ... and put in C + rst 08 ; call HBIOS, C := attributes + ret nz ; return on error + ld a,c ; attributes to A + ld (comatr),a ; save it +; + ; get serial port config + ld b,bf_cioquery ; BIOS serial device query + ld a,(unit) ; get device unit num + ld c,a ; ... and put in C + rst 08 ; call H/UBIOS, DE := line characteristics + ret nz ; abort on error + ld (comcfg),de ; save config +; + xor a ; success + ret +; +ldcomu: ; UNA variant + xor a ; assume attribtues zero + ld (comatr),a ; save it + ; get device info + ld a,(unit) ; get unit + ld b,a ; put unit in B + ld c,$18 ; UNA Get line/driver info func + rst 08 ; call H/UBIOS, DE := line characteristics + ld a,c + or a + jr z,ldcomu1 + cp $43 ; $43 is OK for now (tell John about this) + jr z,ldcomu1 + ret ; return w/ NZ indicating error +; +ldcomu1: + ld (comcfg),de ; save config +; + xor a ; success + ret + +; +; Handle special options +; +option: +; + inc ix ; next char + ld a,(ix) ; get it + cp '?' ; is it a '?' as expected? + jp z,usage ; yes, display usage +; cp 'L' ; is it a 'L', display device list? +; jp z,devlist ; yes, display device list + jp errprm ; anything else is an error +; +; Display usage +; +usage: +; + call crlf ; formatting + ld de,msgban1 ; point to version message part 1 + call prtstr ; print it + ld a,(unamod) ; get UNA flag + or a ; set flags + ld de,msghb ; point to HBIOS mode message + call z,prtstr ; if not UNA, say so + ld de,msgub ; point to UBIOS mode message + call nz,prtstr ; if UNA, say so + call crlf ; formatting + ld de,msgban2 ; point to version message part 2 + call prtstr ; print it + call crlf2 ; blank line + ld de,msguse ; point to usage message + call prtstr ; print it + or $FF ; signal no action performed + ret ; and return +; +; Print character in A without destroying any registers +; +prtchr: + push bc ; save registers + push de + push hl + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it + pop hl ; restore registers + pop de + pop bc + ret +; +prtdot: +; + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print a zero terminated string at (DE) without destroying any registers +; +prtstr: + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + ret +; +; Print the value in A in hex without destroying any registers +; +prthex: + push af ; save AF + push de ; save DE + call hexascii ; convert value in A to hex chars in DE + ld a,d ; get the high order hex char + call prtchr ; print it + ld a,e ; get the low order hex char + call prtchr ; print it + pop de ; restore DE + pop af ; restore AF + ret ; done +; +; print the hex word value in bc +; +prthexword: + push af + ld a,b + call prthex + ld a,c + call prthex + pop af + ret +; +; print the hex dword value in de:hl +; +prthex32: + push bc + push de + pop bc + call prthexword + push hl + pop bc + call prthexword + pop bc + ret +; +; Convert binary value in A to ascii hex characters in DE +; +hexascii: + ld d,a ; save A in D + call hexconv ; convert low nibble of A to hex + ld e,a ; save it in E + ld a,d ; get original value back + rlca ; rotate high order nibble to low bits + rlca + rlca + rlca + call hexconv ; convert nibble + ld d,a ; save it in D + ret ; done +; +; Convert low nibble of A to ascii hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Get the next non-blank character from (HL). +; +nonblank: + ld a,(ix) ; load next character + or a ; string ends with a null + ret z ; if null, return pointing to null + cp ' ' ; check for blank + ret nz ; return if not blank + inc ix ; if blank, increment character pointer + jr nonblank ; and loop +; +; Get alpha chars and save in tmpstr +; Length of string returned in A +; +getalpha: +; + ld hl,tmpstr ; location to save chars + ld b,8 ; length counter (tmpstr max chars) + ld c,0 ; init character counter +; +getalpha1: + ld a,(ix) ; get active char + call ucase ; lower case -> uppper case, if needed + cp 'A' ; check for start of alpha range + jr c,getalpha2 ; not alpha, get out + cp 'Z' + 1 ; check for end of alpha range + jr nc,getalpha2 ; not alpha, get out + ; handle alpha char + ld (hl),a ; save it + inc c ; bump char count + inc hl ; inc string pointer + inc ix ; increment buffer ptr + djnz getalpha1 ; if space, loop for more chars +; +getalpha2: ; non-alpha, clean up and return + ld (hl),0 ; terminate string + ld a,c ; string length to A + or a ; set flags + ret ; and return +; +; Get numeric chars and convert to number returned in A +; Carry flag set on overflow +; +getnum: + ld c,0 ; C is working register +getnum1: + ld a,(ix) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getnum2 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getnum2 ; abort if above +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 10 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + add a,c ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(ix) ; get new digit + sub '0' ; make binary + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc ix ; bump to next char + jr getnum1 ; loop +; +getnum2: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Get numeric chars and convert to 32-bit number returned in DE:HL +; Carry flag set on overflow +; +getnum32: + ld de,0 ; Initialize DE:HL + ld hl,0 ; ... to zero +getnum32a: + ld a,(ix) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getnum32c ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getnum32c ; abort if above +; + ; valid digit, multiply DE:HL by 10 + ; X * 10 = (((x * 2 * 2) + x)) * 2 + push de + push hl +; + call getnum32e ; DE:HL *= 2 + jr c,getnum32d ; if overflow, ret w/ CF & stack pop +; + call getnum32e ; DE:HL *= 2 + jr c,getnum32d ; if overflow, ret w/ CF & stack pop +; + pop bc ; DE:HL += X + add hl,bc + ex de,hl + pop bc + adc hl,bc + ex de,hl + ret c ; if overflow, ret w/ CF +; + call getnum32e ; DE:HL *= 2 + ret c ; if overflow, ret w/ CF +; + ; now add in new digit + ld a,(ix) ; get the active char + sub '0' ; make it binary + add a,l ; add to L, CF updated + ld l,a ; back to L + jr nc,getnum32b ; if no carry, done + inc h ; otherwise, bump H + jr nz,getnum32b ; if no overflow, done + inc e ; otherwise, bump E + jr nz,getnum32b ; if no overflow, done + inc d ; otherwise, bump D + jr nz,getnum32b ; if no overflow, done + scf ; set carry flag to indicate overflow + ret ; and return +; +getnum32b: + inc ix ; bump to next char + jr getnum32a ; loop +; +getnum32c: + ; successful completion + xor a ; clear flags + ret ; and return +; +getnum32d: + ; special overflow exit with stack fixup + pop hl ; burn 2 + pop hl ; ... stack entries + ret ; and return +; +getnum32e: + ; DE:HL := DE:HL * 2 + sla l + rl h + rl e + rl d + ret +; +; Compare null terminated strings at HL & DE +; If equal return with Z set, else NZ +; +strcmp: + ld a,(de) ; get current source char + cp (hl) ; compare to current dest char + ret nz ; compare failed, return with NZ + or a ; set flags + ret z ; end of string, match, return with Z set + inc de ; point to next char in source + inc hl ; point to next char in dest + jr strcmp ; loop till done +; +; Convert character in A to uppercase +; +ucase: + cp 'a' ; if below 'a' + ret c ; ... do nothing and return + cp 'z' + 1 ; if above 'z' + ret nc ; ... do nothing and return + res 5,a ; clear bit 5 to make lower case -> upper case + ret ; and return +; +; Add the value in A to HL (HL := HL + A) +; +addhl: + add a,l ; A := A + L + ld l,a ; Put result back in L + ret nc ; if no carry, we are done + inc h ; if carry, increment H + ret ; and return +; +; Integer divide DE:HL by C +; result in DE:HL, remainder in A +; clobbers F, B +; +div32x8: + xor a + ld b,32 +div32x8a: + add hl,hl + rl e + rl d + rla + cp c + jr c,div32x8b + sub c + inc l +div32x8b: + djnz div32x8a + ret +; +; Jump indirect to address in HL +; +jphl: + jp (hl) +; +; Errors +; +erruse: ; command usage error (syntax) + ld de,msguse + jr err +; +errprm: ; command parameter error (syntax) + ld de,msgprm + jr err +; +errinv: ; invalid HBIOS, signature not found + ld de,msginv + jr err +; +errver: ; unsupported HBIOS version + ld de,msgver + jr err +; +errdev: ; invalid device name + ld de,msgdev + jr err +; +errnum: ; invalid number parsed, overflow + ld de,msgnum + jr err +; +errunt: ; Invalid device unit specified + ld de,msgunt + jr err +; +errcfg: ; Invalid device configuration specified + ld de,msgcfg + jr err +; +err: ; print error string and return error signal + call crlf2 ; print newline +; +err1: ; without the leading crlf + call prtstr ; print error string +; +err2: ; without the string +; call crlf ; print newline + or $FF ; signal error + ret ; done +; +;=============================================================================== +; Utility modules +;=============================================================================== +; +#include "encode.asm" +#include "decode.asm" +#include "bcd.asm" +; +;=============================================================================== +; Storage Section +;=============================================================================== +; +; +bioloc .dw 0 ; CBIOS starting address +unit .db 0 ; source unit +; +unamod .db 0 ; $FF indicates UNA UBIOS active +; +tmpstr .fill 9,0 ; temporary string of up to 8 chars, zero term +bcdtmp .fill 5,0 ; temporary bcd number storage +; +comcnt .db 0 ; count of com ports +comatr .db 0 ; com port attributes +comcfg .dw 0 ; com port configuration +; +parmap .db "NONENMNS" ; parity character lookup table +; +pflag .db 0 ; $FF indicates prompt option set +; +strcom .db "COM",0 ; serial device name string +strterm .db "VDU",0 ; terminal device string +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +; Messages +; +indent .db " ",0 +msgban1 .db "MODE v1.2, 24-Jul-2018",0 +msghb .db " [HBIOS]",0 +msgub .db " [UBIOS]",0 +msgban2 .db "Copyright (C) 2017, Wayne Warthen, GNU GPL v3",0 +msguse .db "Usage: MODE COM: [[,[,[,]]]] [/P]",13,10 + .db " ex. MODE /? (display version and usage)",13,10 + .db " MODE (display config of all serial ports)",13,10 + .db " MODE COM0: (display serial unit 0 config)",13,10 + .db " MODE COM1: 9600,N,8,1 (set serial unit 1 config)",0 +msgprm .db "Parameter error (MODE /? for usage)",0 +msginv .db "Invalid BIOS (signature missing)",0 +msgver .db "Unexpected HBIOS version",0 +msgdev .db "Invalid device name",0 +msgnum .db "Unit or slice number invalid",0 +msgunt .db "Invalid device unit number specified",0 +msgcfg .db "Invalid device configuration specified",0 +msgpmt .db "Prepare line then press ",0 +; + .end diff --git a/Source/Apps/reboot/reboot.asm b/Source/Apps/reboot/reboot.asm index e8dd8e79..5259272c 100644 --- a/Source/Apps/reboot/reboot.asm +++ b/Source/Apps/reboot/reboot.asm @@ -1,299 +1,299 @@ -;============================================================================== -; REBOOT - Allows the user to Cold or Warm Boot the RomWBW System -; Version 1.0 12-October-2024 -;============================================================================== -; -; Author: MartinR (October 2024) -; Based **very heavily** on code by Wayne Warthen (wwarthen@gmail.com) -;______________________________________________________________________________ -; -; Usage: -; REBOOT [/C] [/W] [/?] -; ex: REBOOT Display version and usage -; REBOOT /? Display version and usage -; REBOOT /C Cold boot RomWBW system -; REBOOT /W Warm boot RomWBW system -; -; Operation: -; Cold or warm boots a RomWBW system depending on the user option selected. -; -; This code will only execute on a Z80 CPU (or derivitive) -; -; This source code assembles with TASM V3.2 under Windows-11 using the -; following command line: -; tasm -80 -g3 -l REBOOT.ASM REBOOT.COM -; ie: Z80 CPU; output format 'binary' named .COM (rather than .OBJ) -; and includes a symbol table as part of the listing file. -;______________________________________________________________________________ -; -; Change Log: -; 2024-09-11 [WBW] Release of RomWBW CPU Speed Selector v1.0 used as the basis -; 2024-10-12 [MR ] Initial release of version 1.0 -;______________________________________________________________________________ -; -; Include Files -; -#include "../../ver.inc" ; Used for building RomWBW -#include "../../HBIOS/hbios.inc" - -;#include "ver.inc" ; Used for testing purposes.... -;#include "hbios.inc" ; ....during code development -; -;=============================================================================== -; -; General operational equates (should not requre adjustment) -; -stksiz .equ $40 ; Working stack size -; -restart .equ $0000 ; CP/M restart vector -bdos .equ $0005 ; BDOS invocation vector -; -bf_sysreset .equ $F0 ; restart system -bf_sysres_int .equ $00 ; reset hbios internal -bf_sysres_warm .equ $01 ; warm start (restart boot loader) -bf_sysres_cold .equ $02 ; cold start -; -ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr -; -;=============================================================================== -; - .org $0100 ; standard CP/M TPA executable -; - ; setup stack (save old value) - ld (stksav),sp ; save stack - ld sp,stack ; set new stack -; - call crlf - ld de,str_banner ; banner - call prtstr -; - ; initialization - call init ; initialize - jr nz,exit ; abort if init fails -; - call main ; do the real work -; -exit: - ; clean up and return to command processor - call crlf ; formatting - ld sp,(stksav) ; restore stack - jp restart ; return to CP/M via restart -; -; -;=============================================================================== -; Main Program -;=============================================================================== -; -; Initialization -; -init: - ; check for UNA (UBIOS) - ld a,($FFFD) ; fixed location of UNA API vector - cp $C3 ; jp instruction? - jr nz,initwbw ; 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,initwbw ; 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,initwbw ; if not, not UNA - jp err_una ; UNA not supported -; -initwbw: - ; get location of config data and verify integrity - ld hl,(ident) ; HL := adr or RomWBW HBIOS ident - ld a,(hl) ; get first byte of RomWBW marker - cp 'W' ; match? - jp nz,err_inv ; abort with invalid config block - inc hl ; next byte (marker byte 2) - ld a,(hl) ; load it - cp ~'W' ; match? - jp nz,err_inv ; abort with invalid config block - inc hl ; next byte (major/minor version) - ld a,(hl) ; load it - cp rmj << 4 | rmn ; match? - jp nz,err_ver ; abort with invalid os version -; -initz: - ; initialization complete - xor a ; signal success - ret ; return -; -; -; -main: - ; skip to start of first command line parameter - ld ix,$0081 ; point to start of parm area (past length byte) - call nonblank ; skip to next non-blank char - cp '/' ; option prefix? - jr nz,usage ; display help info & exit if nothing to do -; - ; process any options - inc ix ; fetch next character and process - ld a,(ix) - call upcase ; ensure it's an upper case character - cp 'C' ; if it's a 'C' then - jr z,cboot ; do a cold boot. - cp 'W' ; if it's a 'W' then - jr z,wboot ; do a warm boot. - cp '?' ; if it's a '?' then - jr z,usage ; display usage info and exit. - jr err_parm ; or not a recognised option, so report and exit. -; -; Handle Usage Information -; -usage: - call crlf2 ; display the options for this utility - ld de,str_usage - call prtstr - or $FF - ret ; exit back out to CP/M CCP -; -; Handle Warm Boot -; -wboot: - ld de,str_warmboot ; message - call prtstr ; display it - ld b,bf_sysreset ; system restart - ld c,bf_sysres_warm ; warm start - call $fff0 ; call hbios -; -; Handle Cold Boot -; -cboot: - ld de,str_coldboot ; message - call prtstr ; display it - ld b,bf_sysreset ; system restart - ld c,bf_sysres_cold ; cold start - call $fff0 ; call hbios -; -;=============================================================================== -; Error Handlers -;=============================================================================== -; -err_una: - ld de,str_err_una - jr err_ret -err_inv: - ld de,str_err_inv - jr err_ret -err_ver: - ld de,str_err_ver - jr err_ret -err_parm: - ld de,str_err_parm - jr err_ret - -; -err_ret: - call crlf2 - call prtstr - or $FF ; signal error - ret -; -;=============================================================================== -; Utility Routines -;=============================================================================== -; -; Print character in A without destroying any registers -; -prtchr: - push af - push bc ; save registers - push de - push hl - ld e,a ; character to print in E - ld c,$02 ; BDOS function to output a character - call bdos ; do it - pop hl ; restore registers - pop de - pop bc - pop af - ret -; -; Start a new line -; -crlf2: - call crlf ; two of them -crlf: - push af ; preserve AF - ld a,13 ; - call prtchr ; print it - ld a,10 ; - call prtchr ; print it - pop af ; restore AF - ret -; -; Print a zero terminated string at (de) without destroying any registers -; -prtstr: - push af - push de -; -prtstr1: - ld a,(de) ; get next char - or a - jr z,prtstr2 - call prtchr - inc de - jr prtstr1 -; -prtstr2: - pop de ; restore registers - pop af - ret -; -; Get the next non-blank character from (ix) -; -nonblank: - ld a,(ix) ; load next character - or a ; string ends with a null - ret z ; if null, return pointing to null - cp ' ' ; check for blank - ret nz ; return if not blank - inc ix ; if blank, increment character pointer - jr nonblank ; and loop -; -; Convert character in A to uppercase -; -upcase: - cp 'a' ; if below 'a' - ret c ; ... do nothing and return - cp 'z' + 1 ; if above 'z' - ret nc ; ... do nothing and return - res 5,a ; clear bit 5 to make lower case -> upper case - ret ; and return -; -;=============================================================================== -; Constants -;=============================================================================== -; -str_banner .db "RomWBW Reboot Utility, Version 1.0, 12-Oct-2024\r\n" - .db " Wayne Warthen (wwarthen@gmail.com) & MartinR",0 -; -str_warmboot .db "\r\n\r\nWarm booting...\r\n",0 -str_coldboot .db "\r\n\r\nCold booting...\r\n",0 -; -str_err_una .db " ERROR: UNA not supported by application",0 -str_err_inv .db " ERROR: Invalid BIOS (signature missing)",0 -str_err_ver .db " ERROR: Unexpected HBIOS version",0 -str_err_parm .db " ERROR: Parameter error (REBOOT /? for usage)",0 -; -str_usage .db " Usage: REBOOT /? - Display this help info.\r\n" - .db " REBOOT /W - Warm boot system\r\n" - .db " REBOOT /C - Cold boot system\r\n" - .db " Options are case insensitive.\r\n",0 -; -;=============================================================================== -; Working data -;=============================================================================== -; -stksav .dw 0 ; stack pointer saved at start - .fill stksiz,0 ; stack -stack .equ $ ; stack top -; -;=============================================================================== -; +;============================================================================== +; REBOOT - Allows the user to Cold or Warm Boot the RomWBW System +; Version 1.0 12-October-2024 +;============================================================================== +; +; Author: MartinR (October 2024) +; Based **very heavily** on code by Wayne Warthen (wwarthen@gmail.com) +;______________________________________________________________________________ +; +; Usage: +; REBOOT [/C] [/W] [/?] +; ex: REBOOT Display version and usage +; REBOOT /? Display version and usage +; REBOOT /C Cold boot RomWBW system +; REBOOT /W Warm boot RomWBW system +; +; Operation: +; Cold or warm boots a RomWBW system depending on the user option selected. +; +; This code will only execute on a Z80 CPU (or derivitive) +; +; This source code assembles with TASM V3.2 under Windows-11 using the +; following command line: +; tasm -80 -g3 -l REBOOT.ASM REBOOT.COM +; ie: Z80 CPU; output format 'binary' named .COM (rather than .OBJ) +; and includes a symbol table as part of the listing file. +;______________________________________________________________________________ +; +; Change Log: +; 2024-09-11 [WBW] Release of RomWBW CPU Speed Selector v1.0 used as the basis +; 2024-10-12 [MR ] Initial release of version 1.0 +;______________________________________________________________________________ +; +; Include Files +; +#include "../../ver.inc" ; Used for building RomWBW +#include "../../HBIOS/hbios.inc" + +;#include "ver.inc" ; Used for testing purposes.... +;#include "hbios.inc" ; ....during code development +; +;=============================================================================== +; +; General operational equates (should not requre adjustment) +; +stksiz .equ $40 ; Working stack size +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +bf_sysreset .equ $F0 ; restart system +bf_sysres_int .equ $00 ; reset hbios internal +bf_sysres_warm .equ $01 ; warm start (restart boot loader) +bf_sysres_cold .equ $02 ; cold start +; +ident .equ $FFFC ; loc of RomWBW HBIOS ident ptr +; +;=============================================================================== +; + .org $0100 ; standard CP/M TPA executable +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + call crlf + ld de,str_banner ; banner + call prtstr +; + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +; + call main ; do the real work +; +exit: + ; clean up and return to command processor + call crlf ; formatting + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart +; +; +;=============================================================================== +; Main Program +;=============================================================================== +; +; Initialization +; +init: + ; check for UNA (UBIOS) + ld a,($FFFD) ; fixed location of UNA API vector + cp $C3 ; jp instruction? + jr nz,initwbw ; 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,initwbw ; 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,initwbw ; if not, not UNA + jp err_una ; UNA not supported +; +initwbw: + ; get location of config data and verify integrity + ld hl,(ident) ; HL := adr or RomWBW HBIOS ident + ld a,(hl) ; get first byte of RomWBW marker + cp 'W' ; match? + jp nz,err_inv ; abort with invalid config block + inc hl ; next byte (marker byte 2) + ld a,(hl) ; load it + cp ~'W' ; match? + jp nz,err_inv ; abort with invalid config block + inc hl ; next byte (major/minor version) + ld a,(hl) ; load it + cp rmj << 4 | rmn ; match? + jp nz,err_ver ; abort with invalid os version +; +initz: + ; initialization complete + xor a ; signal success + ret ; return +; +; +; +main: + ; skip to start of first command line parameter + ld ix,$0081 ; point to start of parm area (past length byte) + call nonblank ; skip to next non-blank char + cp '/' ; option prefix? + jr nz,usage ; display help info & exit if nothing to do +; + ; process any options + inc ix ; fetch next character and process + ld a,(ix) + call upcase ; ensure it's an upper case character + cp 'C' ; if it's a 'C' then + jr z,cboot ; do a cold boot. + cp 'W' ; if it's a 'W' then + jr z,wboot ; do a warm boot. + cp '?' ; if it's a '?' then + jr z,usage ; display usage info and exit. + jr err_parm ; or not a recognised option, so report and exit. +; +; Handle Usage Information +; +usage: + call crlf2 ; display the options for this utility + ld de,str_usage + call prtstr + or $FF + ret ; exit back out to CP/M CCP +; +; Handle Warm Boot +; +wboot: + ld de,str_warmboot ; message + call prtstr ; display it + ld b,bf_sysreset ; system restart + ld c,bf_sysres_warm ; warm start + call $fff0 ; call hbios +; +; Handle Cold Boot +; +cboot: + ld de,str_coldboot ; message + call prtstr ; display it + ld b,bf_sysreset ; system restart + ld c,bf_sysres_cold ; cold start + call $fff0 ; call hbios +; +;=============================================================================== +; Error Handlers +;=============================================================================== +; +err_una: + ld de,str_err_una + jr err_ret +err_inv: + ld de,str_err_inv + jr err_ret +err_ver: + ld de,str_err_ver + jr err_ret +err_parm: + ld de,str_err_parm + jr err_ret + +; +err_ret: + call crlf2 + call prtstr + or $FF ; signal error + ret +; +;=============================================================================== +; Utility Routines +;=============================================================================== +; +; Print character in A without destroying any registers +; +prtchr: + push af + push bc ; save registers + push de + push hl + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it + pop hl ; restore registers + pop de + pop bc + pop af + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Print a zero terminated string at (de) without destroying any registers +; +prtstr: + push af + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + pop af + ret +; +; Get the next non-blank character from (ix) +; +nonblank: + ld a,(ix) ; load next character + or a ; string ends with a null + ret z ; if null, return pointing to null + cp ' ' ; check for blank + ret nz ; return if not blank + inc ix ; if blank, increment character pointer + jr nonblank ; and loop +; +; Convert character in A to uppercase +; +upcase: + cp 'a' ; if below 'a' + ret c ; ... do nothing and return + cp 'z' + 1 ; if above 'z' + ret nc ; ... do nothing and return + res 5,a ; clear bit 5 to make lower case -> upper case + ret ; and return +; +;=============================================================================== +; Constants +;=============================================================================== +; +str_banner .db "RomWBW Reboot Utility, Version 1.0, 12-Oct-2024\r\n" + .db " Wayne Warthen (wwarthen@gmail.com) & MartinR",0 +; +str_warmboot .db "\r\n\r\nWarm booting...\r\n",0 +str_coldboot .db "\r\n\r\nCold booting...\r\n",0 +; +str_err_una .db " ERROR: UNA not supported by application",0 +str_err_inv .db " ERROR: Invalid BIOS (signature missing)",0 +str_err_ver .db " ERROR: Unexpected HBIOS version",0 +str_err_parm .db " ERROR: Parameter error (REBOOT /? for usage)",0 +; +str_usage .db " Usage: REBOOT /? - Display this help info.\r\n" + .db " REBOOT /W - Warm boot system\r\n" + .db " REBOOT /C - Cold boot system\r\n" + .db " Options are case insensitive.\r\n",0 +; +;=============================================================================== +; Working data +;=============================================================================== +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +;=============================================================================== +; .end \ No newline at end of file diff --git a/Source/Apps/rtc/rtc.asm b/Source/Apps/rtc/rtc.asm index 7d456da7..f0d95636 100644 --- a/Source/Apps/rtc/rtc.asm +++ b/Source/Apps/rtc/rtc.asm @@ -1,1808 +1,1808 @@ - .Title "RTC" -; -; Program: rtc.asm -; Author: Andrew Lynch -; Date: 22 Feb 2007 -; Enviroment: TASM MS-DOS Z80 Cross Assembler source for CP/M -; -;[2011/8/11] VK5DG modified for N8 -; Changed base address to $88 -; Changed trickle charger value to 2k+2 diodes for DS1210s -; -;[2012/2/7] WBW modified to build for either -; traditional N8VEM/Zeta or N8 via conditionals -; -;[2013/12/29] WBW modified to build for MK4 -; -;[2017/11/29] WBW modified to adjust to RTC in use dynamically -; using HBIOS platform detection -; -;[2018/11/8] v1.2 PMS Add boot option. Code optimization. -; -;[2019/06/21] v1.3 Finalized RCBus Z180 support. -; -;[2019/08/11] v1.4 Support SCZ180 platform. -; -;[2020/02/02] v1.5 PMS Basic command line support -; -;[2020/05/15] v1.6 Added Warm Start option -; -;[2021/07/10] v1.7 Support MBC (AJL) -; -;[2022/03/27] v1.8 Support RHYOPHYRE -; -;[2023/07/07] v1.9 Support DUODYNE -; -;[2024/09/02] v1.10 Support Genesis STD Z180 -; -; Constants -; -mask_data .EQU %10000000 ; RTC data line -mask_clk .EQU %01000000 ; RTC Serial Clock line -mask_rd .EQU %00100000 ; Enable data read from RTC -mask_rst .EQU %00010000 ; De-activate RTC reset line - -PORT_SBC .EQU $70 ; RTC port for SBC/ZETA -PORT_N8 .EQU $88 ; RTC port for N8 -PORT_MK4 .EQU $8A ; RTC port for MK4 -PORT_RCZ80 .EQU $C0 ; RTC port for RCBus -PORT_RCZ180 .EQU $0C ; RTC port for RCBus -PORT_EZZ80 .EQU $C0 ; RTC port for EZZ80 (actually does not have one!!!) -PORT_SCZ180 .EQU $0C ; RTC port for SCZ180 -PORT_DYNO .EQU $0C ; RTC port for DYNO -PORT_RCZ280 .EQU $C0 ; RTC port for RCZ280 -PORT_MBC .EQU $70 ; RTC port for MBC -PORT_RPH .EQU $84 ; RTC port for RHYOPHYRE -PORT_DUO .EQU $94 ; RTC port for DUODYNE -PORT_STDZ180 .EQU $84 ; RTC Port for STD Bus Z180 board - - -BDOS .EQU 5 ; BDOS invocation vector -FCB .EQU 05CH ; Start of command line - -;BID_BOOT .EQU $00 -;HB_BNKCALL .EQU $FFF9 - -BF_SYSRESET .EQU $F0 ; RESTART SYSTEM - -BF_SYSRES_INT .EQU $00 ; RESET HBIOS INTERNAL -BF_SYSRES_WARM .EQU $01 ; WARM START (RESTART BOOT LOADER) -BF_SYSRES_COLD .EQU $02 ; COLD START - -; -; Program -; - .ORG 0100H - -LOOP: - LD DE,MSG - LD C,09H ; CP/M write string to console call - CALL 0005H - -; program starts here - - CALL RTC_INIT ; Program initialization - - CALL RTC_TOP_LOOP - - LD C,00H ; CP/M system reset call - shut down - CALL 0005H - - HALT ; This code is never reached - - -; function HEXSTR -; input number in A -; output upper nibble of number in ASCII in H -; output lower nibble of number in ASCII in L -; uses BC -; -; based on following algorithm: -; -; const -; hextab : string = ('0','1','2','3','4','5','6','7','8', -; '9','A','B','C','D','E','F'); -; -; PROCEDURE hexstr(n: int): ^string; -; BEGIN -; n := n and 255; -; tmpstr[1] := hextab[n / 16]; -; tmpstr[2] := hextab[n and 15]; -; tmpstr[0] := #2; -; return @tmpstr; -; END; - - -HEXSTR: - PUSH BC ;SAVE BC - LD B,A - RLC A ;DO HIGH NIBBLE FIRST - RLC A - RLC A - RLC A - AND 0FH ;ONLY THIS NOW - ADD A,30H ;TRY A NUMBER - CP 3AH ;TEST IT - JR C,HEXSTR1 ;IF CY SET SAVE 'NUMBER' in H - ADD A,07H ;MAKE IT AN ALPHA -HEXSTR1: - LD H,A ;SAVE 'ALPHA' in H - LD A,B ;NEXT NIBBLE - AND 0FH ;JUST THIS - ADD A,30H ;TRY A NUMBER - CP 3AH ;TEST IT - JR C,HEXSTR2 ;IF CY SET SAVE 'NUMBER' in L - ADD A,07H ;MAKE IT ALPHA - -HEXSTR2: - LD L,A ;SAVE 'ALPHA' in L - POP BC ;RESTORE BC - RET - - -;***************************************************** -;* GET K.B. DATA & MAKE IT 'HEX' -;***************************************************** - -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 - PUSH BC - - CALL NIBL ;DO NEXT NIBBLE - POP BC - ADD A,B ;COMBINE NIBBLES IN ACC. - POP BC ;RESTORE BC - RET ;DONE -NIBL: - LD C,01H ; CP/M console input call - CALL 0005H ;GET K.B. DATA - 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 - -; function RTC_IN -; -; read a byte from RTC port, return in A -; NOTE: port address is dynamically set in RTC_INIT - -RTC_IN: -INP .EQU $ + 1 - IN A,($FF) - RET - -; function RTC_OUT -; -; write a byte to RTC port, value in A -; NOTE: port address is dynamically set in RTC_INIT - -RTC_OUT: -OUTP .EQU $ + 1 - OUT ($FF),A - RET - -; function RTC_BIT_DELAY -; -; based on following algorithm: -; -; { Make a short delay } -; PROCEDURE rtc_bit_delay; -; var -; x : int; -; BEGIN -; x := 3; -; END; - -RTC_BIT_DELAY: ; purpose is to delay ~36 uS or 144 t-states at 4MHz - PUSH AF ; 11 t-states - LD A,07H ; 7 t-states ADJUST THE TIME 13h IS FOR 4 MHZ -RTC_BIT_DELAY1: - DEC A ; 4 t-states DEC COUNTER. 4 T-states = 1 uS. - JP NZ,RTC_BIT_DELAY1 ; 10 t-states JUMP TO PAUSELOOP2 IF A <> 0. - - NOP ; 4 t-states - NOP ; 4 t-states - POP AF ; 10 t-states - RET ; 10 t-states (144 t-states total) - - -; function RTC_RESET -; -; based on following algorithm: -; -; { Output a RTC reset signal } -; PROCEDURE rtc_reset; -; BEGIN -; out(rtc_base,mask_data + mask_rd); -; rtc_bit_delay(); -; rtc_bit_delay(); -; out(rtc_base,mask_data + mask_rd + mask_rst); -; rtc_bit_delay(); -; rtc_bit_delay(); -; END; -; -RTC_RESET: - LD A,mask_data + mask_rd - ;OUT (RTC),A - CALL RTC_OUT - CALL RTC_BIT_DELAY - CALL RTC_BIT_DELAY - LD A,mask_data + mask_rd + mask_rst - ;OUT (RTC),A - CALL RTC_OUT - CALL RTC_BIT_DELAY - CALL RTC_BIT_DELAY - RET - - -; function RTC_RESET_ON -; -; based on following algorithm: -; -; { Assert RTC reset signal } -; PROCEDURE rtc_reset_on; -; BEGIN -; out(rtc_base,mask_data + mask_rd); -; rtc_bit_delay(); -; rtc_bit_delay(); -; END; - -RTC_RESET_ON: - LD A,mask_data + mask_rd - ;OUT (RTC),A - CALL RTC_OUT - CALL RTC_BIT_DELAY - CALL RTC_BIT_DELAY - RET - -; function RTC_RESET_OFF -; -; based on following algorithm: -; -; { De-assert RTC reset signal } -; PROCEDURE rtc_reset_off; -; BEGIN -; out(rtc_base,mask_data + mask_rd + mask_rst); -; rtc_bit_delay(); -; rtc_bit_delay(); -; END; - -RTC_RESET_OFF: - LD A,mask_data + mask_rd + mask_rst - ;OUT (RTC),A - CALL RTC_OUT - CALL RTC_BIT_DELAY - CALL RTC_BIT_DELAY - RET - -; function RTC_WR -; input value in C -; uses A -; -; PROCEDURE rtc_wr(n : int); -; var -; i : int; -; BEGIN -; for i := 0 while i < 8 do inc(i) loop -; if (n and 1) <> 0 then -; out(rtc_base,mask_rst + mask_data); -; rtc_bit_delay(); -; out(rtc_base,mask_rst + mask_clk + mask_data); -; else -; out(rtc_base,mask_rst); -; rtc_bit_delay(); -; out(rtc_base,mask_rst + mask_clk); -; end; -; rtc_bit_delay(); -; n := shr(n,1); -; end loop; -; END; - -RTC_WR: - XOR A ; set A=0 index counter of FOR loop - -RTC_WR1: - PUSH AF ; save accumulator as it is the index counter in FOR loop - LD A,C ; get the value to be written in A from C (passed value to write in C) - BIT 0,A ; is LSB a 0 or 1? - JP Z,RTC_WR2 ; if it's a 0, handle it at RTC_WR2. - ; LSB is a 1, handle it below - ; setup RTC latch with RST and DATA high, SCLK low - LD A,mask_rst + mask_data - ;OUT (RTC),A ; output to RTC latch - CALL RTC_OUT - CALL RTC_BIT_DELAY ; let it settle a while - ; setup RTC with RST, DATA, and SCLK high - LD A,mask_rst + mask_clk + mask_data - ;OUT (RTC),A ; output to RTC latch - CALL RTC_OUT - JP RTC_WR3 ; exit FOR loop - -RTC_WR2: - ; LSB is a 0, handle it below - LD A,mask_rst ; setup RTC latch with RST high, SCLK and DATA low - ;OUT (RTC),A ; output to RTC latch - CALL RTC_OUT - CALL RTC_BIT_DELAY ; let it settle a while - ; setup RTC with RST and SCLK high, DATA low - LD A,mask_rst + mask_clk - ;OUT (RTC),A ; output to RTC latch - CALL RTC_OUT - -RTC_WR3: - CALL RTC_BIT_DELAY ; let it settle a while - RRC C ; move next bit into LSB position for processing to RTC - POP AF ; recover accumulator as it is the index counter in FOR loop - INC A ; increment A in FOR loop (A=A+1) - CP $08 ; is A < $08 ? - JP NZ,RTC_WR1 ; No, do FOR loop again - RET ; Yes, end function and return - - -; function RTC_RD -; output value in C -; uses A -; -; function RTC_RD -; -; PROCEDURE rtc_rd(): int ; -; var -; i,n,mask : int; -; BEGIN -; n := 0; -; mask := 1; -; for i := 0 while i < 8 do inc(i) loop -; out(rtc_base,mask_rst + mask_rd); -; rtc_bit_delay(); -; if (in(rtc_base) and #1) <> #0 then -; { Data = 1 } -; n := n + mask; -; else -; { Data = 0 } -; end; -; mask := shl(mask,1); -; out(rtc_base,mask_rst + mask_clk + mask_rd); -; rtc_bit_delay(); -; end loop; -; return n; -; END; - -RTC_RD: - XOR A ; set A=0 index counter of FOR loop - LD C,$00 ; set C=0 output of RTC_RD is passed in C - LD B,$01 ; B is mask value - -RTC_RD1: - PUSH AF ; save accumulator as it is the index counter in FOR loop - ; setup RTC with RST and RD high, SCLK low - LD A,mask_rst + mask_rd - ;OUT (RTC),A ; output to RTC latch - CALL RTC_OUT - CALL RTC_BIT_DELAY ; let it settle a while - ;IN A,(RTC) ; input from RTC latch - CALL RTC_IN ; input from RTC latch - BIT 0,A ; is LSB a 0 or 1? - JP Z,RTC_RD2 ; if LSB is a 1, handle it below - LD A,C - ADD A,B - LD C,A -; INC C - ; if LSB is a 0, skip it (C=C+0) -RTC_RD2: - RLC B ; move input bit out of LSB position to save it in C - ; setup RTC with RST, SCLK high, and RD high - LD A,mask_rst + mask_clk + mask_rd - ;OUT (RTC),A ; output to RTC latch - CALL RTC_OUT - CALL RTC_BIT_DELAY ; let it settle - POP AF ; recover accumulator as it is the index counter in FOR loop - INC A ; increment A in FOR loop (A=A+1) - CP $08 ; is A < $08 ? - JP NZ,RTC_RD1 ; No, do FOR loop again - RET ; Yes, end function and return. Read RTC value is in C - -; function RTC_WRITE -; input address in D -; input value in E -; uses A -; -; based on following algorithm: -; -; PROCEDURE rtc_write(address, value: int); -; BEGIN -; lock(); -; rtc_reset_off(); -; { Write command } -; rtc_wr(128 + shl(address and $3f,1)); -; { Write data } -; rtc_wr(value and $ff); -; rtc_reset_on(); -; unlock(); -; END; - -RTC_WRITE: - DI ; disable interrupts during critical section - CALL RTC_RESET_OFF ; turn off RTC reset - LD A,D ; bring into A the address from D -; AND $3F ; keep only bits 6 LSBs, discard 2 MSBs - AND %00111111 ; keep only bits 6 LSBs, discard 2 MSBs - RLC A ; rotate address bits to the left -; ADD A,$80 ; set MSB to one for DS1302 COMMAND BYTE (WRITE) - ADD A,%10000000 ; set MSB to one for DS1302 COMMAND BYTE (WRITE) - LD C,A ; RTC_WR expects write data (address) in reg C - CALL RTC_WR ; write address to DS1302 - LD A,E ; start processing value - AND $FF ; seems unnecessary, probably delete since all values are 8-bit - LD C,A ; RTC_WR expects write data (value) in reg C - CALL RTC_WR ; write address to DS1302 - CALL RTC_RESET_ON ; turn on RTC reset - EI - RET - - -; function RTC_READ -; input address in D -; output value in C -; uses A -; -; based on following algorithm -; -; PROCEDURE rtc_read(address: int): int; -; var -; n : int; -; BEGIN -; lock(); -; rtc_reset_off(); -; { Write command } -; rtc_wr(128 + shl(address and $3f,1) + 1); -; { Read data } -; n := rtc_rd(); -; rtc_reset_on(); -; unlock(); -; return n; -; END; - -RTC_READ: - DI ; disable interrupts during critical section - CALL RTC_RESET_OFF ; turn off RTC reset - LD A,D ; bring into A the address from D - AND $3F ; keep only bits 6 LSBs, discard 2 MSBs - RLC A ; rotate address bits to the left - ADD A,$81 ; set MSB to one for DS1302 COMMAND BYTE (READ) - LD C,A ; RTC_WR expects write data (address) in reg C - CALL RTC_WR ; write address to DS1302 - CALL RTC_RD ; read value from DS1302 (value is in reg C) - CALL RTC_RESET_ON ; turn on RTC reset - EI - RET - - -; function RTC_WR_PROTECT -; input D (address) $07 -; input E (value) $80 -; uses A -; -; based on following algorithm -; -; PROCEDURE rtc_wr_protect; -; BEGIN -; rtc_write(7,128); -; END; - -RTC_WR_PROTECT: -; LD D,$07 - LD D,%00000111 -; LD E,$80 - LD E,%10000000 - CALL RTC_WRITE - RET - - -; function RTC_WR_UNPROTECT -; input D (address) $07 -; input E (value) $00 -; uses A -; -; based on following algorithm -; -; PROCEDURE rtc_wr_unprotect; -; BEGIN -; rtc_write(7,0); -; END; - -RTC_WR_UNPROTECT: -; LD D,$07 - LD D,%00000111 -; LD E,$00 - LD E,%00000000 - CALL RTC_WRITE - RET - - -; function RTC_GET_TIME -; input HL (memory address of buffer) -; uses A,C,D,E -; -; based on following algorithm -; -; PROCEDURE rtc_get_time(var buf: string); -; var -; n : int; -; BEGIN -; lock(); -; rtc_reset_off(); -; { Write command, burst read } -; rtc_wr(255 - 64); -; { Read seconds } -; n := rtc_rd(); 0 -; buf[16] := char(((n / 16) and $07)) + '0'; -; buf[17] := char((n and $0f)) + '0'; -; { Read minutes } -; n := rtc_rd(); 1 -; buf[13] := char(((n / 16) and $07)) + '0'; -; buf[14] := char((n and $0f)) + '0'; -; buf[15] := ':'; -; { Read hours } -; n := rtc_rd(); 2 -; buf[10] := char(((n / 16) and $03)) + '0'; -; buf[11] := char((n and $0f)) + '0'; -; buf[12] := ':'; -; { Read date } -; n := rtc_rd(); 3 -; buf[7] := char(((n / 16) and $03)) + '0'; -; buf[8] := char((n and $0f)) + '0'; -; buf[9] := ' '; -; { Read month } -; n := rtc_rd(); 4 -; buf[4] := char(((n / 16) and $03)) + '0'; -; buf[5] := char((n and $0f)) + '0'; -; buf[6] := '-'; -; { Read day } -; n := rtc_rd(); 5 -; { -; buf[4] := char(((n / 16) and $03)) + '0'; -; buf[4] := char((n and $0f)) + '0'; -; } -; { Read year } -; n := rtc_rd(); 6 -; buf[1] := char(((n / 16) and $0f)) + '0'; -; buf[2] := char((n and $0f)) + '0'; -; buf[3] := '-'; -; length(buf) := 17; -; rtc_reset_on(); -; unlock(); -; END rtc_get_time; - -RTC_GET_TIME: - DI ; disable interrupts during DS1302 read - CALL RTC_RESET_OFF ; turn of RTC reset - ; { Write command, burst read } - LD C,%10111111 ; (255 - 64) - CALL RTC_WR ; send COMMAND BYTE (BURST READ) to DS1302 - -; { Read seconds } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 16 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $07 - ADD A,'0' - LD (RTC_PRINT_BUFFER+15),A - - ; digit 17 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+16),A - -; { Read minutes } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 13 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $07 - ADD A,'0' - LD (RTC_PRINT_BUFFER+12),A - - ; digit 14 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+13),A - - ; digit 15 - LD A,':' - LD (RTC_PRINT_BUFFER+14),A - -; { Read hours } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 10 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $03 - ADD A,'0' - LD (RTC_PRINT_BUFFER+09),A - - ; digit 11 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+10),A - - ; digit 12 - LD A,':' - LD (RTC_PRINT_BUFFER+11),A - -; { Read date } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 07 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $03 - ADD A,'0' - LD (RTC_PRINT_BUFFER+06),A - - ; digit 08 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+07),A - - ; digit 09 - LD A,' ' - LD (RTC_PRINT_BUFFER+08),A - -; { Read month } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 04 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $03 - ADD A,'0' - LD (RTC_PRINT_BUFFER+03),A - - ; digit 05 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+04),A - - ; digit 06 - LD A,'-' - LD (RTC_PRINT_BUFFER+05),A - -; { Read day } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 04 -; LD A,C ; put value output in Reg C into accumulator -; RLC A -; RLC A -; RLC A -; RLC A -; AND $03 -; ADD A,'0' -; LD (RTC_PRINT_BUFFER+03),A - - ; digit 04 -; LD A,C ; put value output in Reg C into accumulator -; AND $0F -; ADD A,'0' -; LD (RTC_PRINT_BUFFER+03),A - -; add special code to put "DAY" value at end of string until better solution known - - ; digit 18 - LD A,'-' - LD (RTC_PRINT_BUFFER+17),A - - ; digit 19 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+18),A - - ; digit 20 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+19),A - -; { Read year } - - CALL RTC_RD ; read value from DS1302, value is in Reg C - - ; digit 01 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+00),A - - ; digit 02 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+01),A - - ; digit 03 - LD A,'-' - LD (RTC_PRINT_BUFFER+02),A - - CALL RTC_RESET_ON ; turn RTC reset back on - EI ; re-enable interrupts - - RET ; Yes, end function and return - - -; function RTC_SET_NOW -; uses A, D, E -; -; based on following algorithm -; -; { Set time to 96-02-18 19:43:00 } -; PROCEDURE rtc_set_now; -; BEGIN -; rtc_wr_unprotect(); -; { Set seconds } -; rtc_write(0,0); -; { Set minutes } -; rtc_write(1,$43); -; { Set hours } -; rtc_write(2,$19); -; { Set date } -; rtc_write(3,$18); -; { Set month } -; rtc_write(4,$02); -; { Set day } -; rtc_write(5,$07); -; { Set year } -; rtc_write(6,$96); -; rtc_wr_protect(); -; END; - -RTC_SET_NOW: -; set time to 07-02-23 19:45:00-05 <-Friday - CALL RTC_WR_UNPROTECT -; seconds - LD D,$00 - LD A,(SECONDS) - LD E,A - CALL RTC_WRITE - -; minutes - LD D,$01 - LD A,(MINUTES) - LD E,A - CALL RTC_WRITE - -; hours - LD D,$02 - LD A,(HOURS) - LD E,A - CALL RTC_WRITE - -; date - LD D,$03 - LD A,(DATE) - LD E,A - CALL RTC_WRITE - -; month - LD D,$04 - LD A,(MONTH) - LD E,A - CALL RTC_WRITE - -; day - LD D,$05 - LD A,(DAY) - LD E,A - CALL RTC_WRITE - -; year - LD D,$06 - LD A,(YEAR) - LD E,A - CALL RTC_WRITE - - CALL RTC_WR_PROTECT - RET - -RTC_INIT_NOW: -; set time to Current Time - -; year - LD DE,RTC_TOP_LOOP1_INIT_YEAR - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (YEAR),A - -; month - LD DE,RTC_TOP_LOOP1_INIT_MONTH - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (MONTH),A - -; date - LD DE,RTC_TOP_LOOP1_INIT_DATE - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (DATE),A - -; hours - LD DE,RTC_TOP_LOOP1_INIT_HOURS - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (HOURS),A - -; minutes - LD DE,RTC_TOP_LOOP1_INIT_MINUTES - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (MINUTES),A - -; seconds - LD DE,RTC_TOP_LOOP1_INIT_SECONDS - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (SECONDS),A - -; day - LD DE,RTC_TOP_LOOP1_INIT_DAY - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL HEXIN - LD (DAY),A - - RET - - -; function RTC_RESTART -; -; uses A, D, E, -; -; based on the following algorithm -; -; { Restart clock, set seconds to 00 } -; PROCEDURE rtc_restart; -; BEGIN -; rtc_wr_unprotect(); -; { Set seconds } -; rtc_write(0,0); -; rtc_wr_protect(); -; END; - -RTC_RESTART: - CALL RTC_WR_UNPROTECT - LD D,$00 - LD E,$00 - CALL RTC_WRITE - CALL RTC_WR_PROTECT - RET - - -; function RTC_CHARGE_ENABLE -; -; uses A, D, E -; -; based on following algorithm -; -; PROCEDURE rtc_charge_enable; -; BEGIN -; rtc_wr_unprotect(); -; { Enable trickle charger, 2kohm, 1 diode } -; rtc_write(8,$A5); -; rtc_wr_protect(); -; END; -; -; Trickle Charge Current: -; -; Imax = (5.0V - (0.7 * Ndiode)) / R -; (5.0 - (0.7 * 1)) / 2000 = .00215A = 2.15 milliamps -; (5.0 - (0.7 * 1)) / 8000 = 0.0005375A = .537 milliamps -; - -RTC_CHARGE_ENABLE - CALL RTC_WR_UNPROTECT - LD D,$08 - LD E,$A5 - CALL RTC_WRITE - CALL RTC_WR_PROTECT - RET - - -; function RTC_CHARGE_DISABLE -; -; uses A, D, E -; -; based on following algorithm -; -; PROCEDURE rtc_charge_disable; -; BEGIN -; rtc_wr_unprotect(); -; { Disable trickle charger} -; rtc_write(8,$00); -; rtc_wr_protect(); -; END; - -RTC_CHARGE_DISABLE - CALL RTC_WR_UNPROTECT - LD D,$08 - LD E,$00 - CALL RTC_WRITE - CALL RTC_WR_PROTECT - RET - - -; function TEST_BIT_DELAY -; -; based on the following algorithm -; -; -; PROCEDURE test_bit_delay(); -; var -; i,t0,t1 : int; -; BEGIN -; putln("Testing bit delay..."); -; t0 := sys_time(); -; for i := 0 while i < 1000 do inc(i) loop -; rtc_bit_delay(); -; end loop; -; t1 := sys_time(); -; putln(i," rtc_bit_delay calls took ",t1-t0," ms."); -; END; - -RTC_TEST_BIT_DELAY - LD DE,TESTING_BIT_DELAY_MSG - LD C,09H ; CP/M write string to console call - CALL 0005H - LD C,01H ; CP/M console input call - CALL 0005H - - ; test should take approximately 43 seconds based on the following code analysis - ; of Z80 T-states on a 4 MHz processor - ; =(4+15*(7+255*(7+255*(17+144+4+10)+4+10)+10)+7)/4/1000000 - - LD B,$0F -PAUSE: - LD C,$FF -PAUSE1: - LD A,$FF ; ADJUST THE TIME 13h IS FOR 4 MHZ -PAUSE2: - CALL RTC_BIT_DELAY ; CAUSE 36uS DELAY - DEC A ; DEC COUNTER. - JP NZ,PAUSE2 ; JUMP TO PAUSE2 IF A <> 0. - DEC C ; DEC COUNTER - JP NZ,PAUSE1 ; JUMP TO PAUSE1 IF C <> 0. - DJNZ PAUSE ; JUMP TO PAUSE IF B <> 0. - - LD DE,TESTING_BIT_DELAY_OVER - LD C,09H ; CP/M write string to console call - CALL 0005H - RET - - -; function RTC_HELP -; -; based on following algorithm -; -; PROCEDURE help(); -; BEGIN -; putln(); -; putln("rtc: ",version); -; putln("rtc: Commands: (E)xit (T)ime st(A)rt (S)et (R)aw (L)oop (C)harge (N)ocharge (H)elp"); -; END; - -RTC_HELP - LD DE,RTC_HELP_MSG - LD C,09H ; CP/M write string to console call - CALL 0005H - RET - -; function RTC_INIT -; -; Determine RTC port based on hardware platform -; and record it dynamically in code (see RTC_IN and RTC_OUT). -; - -RTC_INIT: - CALL IDBIO ; Id BIOS, 1=HBIOS, 2=UBIOS - DEC A ; Test for HBIOS - JP Z,HINIT ; Do HBIOS setup - DEC A ; Test for UBIOS - JP Z,UINIT ; Do UBIOS setup -; - ; Neither UNA nor RomWBW - LD DE,BIOERR ; BIOS error message - LD C,9 ; BDOS string display function - CALL BDOS ; Do it - JP 0 ; Bail out! -; -HINIT: -; - ; Display RomWBW notification string - LD DE,HBTAG ; BIOS notification string - LD C,9 ; BDOS string display function - CALL BDOS ; Do it -; - ; Get platform id from RomWBW HBIOS - LD B,0F1H ; HBIOS VER function 0xF1 - LD C,0 ; Required reserved value - RST 08 ; Do it, L := Platform ID - LD A,L ; Move to A -; - ; Assign correct port to C - LD C,PORT_SBC - LD DE,PLT_SBC - CP $01 ; SBC - JP Z,RTC_INIT2 - CP $02 ; ZETA - JP Z,RTC_INIT2 - CP $03 ; ZETA 2 - JP Z,RTC_INIT2 -; - LD C,PORT_N8 - LD DE,PLT_N8 - CP $04 ; N8 - JP Z,RTC_INIT2 -; - LD C,PORT_MK4 - LD DE,PLT_MK4 - CP $05 ; Mark IV - JP Z,RTC_INIT2 -; - LD C,PORT_RCZ80 - LD DE,PLT_RCZ80 - CP $07 ; RCBus w/ Z80 - JP Z,RTC_INIT2 -; - LD C,PORT_RCZ180 - LD DE,PLT_RCZ180 - CP $08 ; RCBus w/ Z180 - JP Z,RTC_INIT2 -; - LD C,PORT_EZZ80 - LD DE,PLT_EZZ80 - CP $09 ; Easy Z80 - JP Z,RTC_INIT2 -; - LD C,PORT_SCZ180 - LD DE,PLT_SCZ180 - CP $0A ; SCZ180 - JP Z,RTC_INIT2 -; - LD C,PORT_DYNO - LD DE,PLT_DYNO - CP 11 ; DYNO - JP Z,RTC_INIT2 -; - LD C,PORT_RCZ280 - LD DE,PLT_RCZ280 - CP 12 ; RCZ280 - JP Z,RTC_INIT2 -; - LD C,PORT_MBC - LD DE,PLT_MBC - CP 13 ; MBC - JP Z,RTC_INIT2 -; - LD C,PORT_RPH - LD DE,PLT_RPH - CP 14 ; RHYOPHYRE - JP Z,RTC_INIT2 -; - LD C,PORT_DUO - LD DE,PLT_DUO - CP 17 ; DUODYNE - JP Z,RTC_INIT2 -; - LD C,PORT_STDZ180 - LD DE,PLT_STDZ180 - CP 21 ; STD Z180 - JP Z,RTC_INIT2 -; - -; Unknown platform - LD DE,PLTERR ; BIOS error message - LD C,9 ; BDOS string display function - CALL BDOS ; Do it - JP 0 ; Bail out! -; -UINIT: - ;; Display UNA notification string - ;LD DE,UBTAG ; BIOS notification string - ;LD C,9 ; BDOS string display function - ;CALL BDOS ; Do it -; - ; Notify UNA not supported at present - LD DE,UBERR ; BIOS not support message - LD C,9 ; BDOS string display function - CALL BDOS ; Do it - JP 0 ; Bail out! - -RTC_INIT2: - ; Record port number in code routines - LD A,C - LD (INP),A - LD (OUTP),A -; - ; Display platform - LD C,9 ; BDOS string display function - CALL BDOS ; Do it - RET - -; -; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 -; -IDBIO: -; - ; Check for UNA (UBIOS) - LD A,(0FFFDH) ; fixed location of UNA API vector - CP 0C3H ; jp instruction? - JR NZ,IDBIO1 ; if not, not UNA - LD HL,(0FFFEH) ; get jp address - LD A,(HL) ; get byte at target address - CP 0FDH ; first byte of UNA push ix instruction - JR NZ,IDBIO1 ; if not, not UNA - INC HL ; point to next byte - LD A,(HL) ; get next byte - CP 0E5H ; second byte of UNA push ix instruction - JR NZ,IDBIO1 ; if not, not UNA, check others - LD A,2 ; UNA BIOS id = 2 - RET ; and done -; -IDBIO1: - ; Check for RomWBW (HBIOS) - LD HL,(0FFFEH) ; HL := HBIOS ident location - LD A,'W' ; First byte of ident - CP (HL) ; Compare - JR NZ,IDBIO2 ; Not HBIOS - INC HL ; Next byte of ident - LD A,~'W' ; Second byte of ident - CP (HL) ; Compare - JR NZ,IDBIO2 ; Not HBIOS - LD A,1 ; HBIOS BIOS id = 1 - RET ; and done -; -IDBIO2: - ; No idea what this is - XOR A ; Setup return value of 0 - RET ; and done - - -; function RTC_TOP_LOOP -; -; based on following algorithm -; -; PROCEDURE toploop(); -; var -; err,i,n,fd : int; -; BEGIN -; putln(); -; help(); -; rtc_reset_on(); -; hold(100); -; test_bit_delay(); -; rtc_charge_disable(); -; putln("rtc: trickle charger disabled."); -; loop -; put("rtc>"); -; gets(line); -; if line = "exit" then -; putln("Bye."); -; exit(0); -; elsif line = "charge" then -; putln("Trickle charger enabled."); -; rtc_charge_enable(); -; elsif line = "nocharge" then -; putln("Trickle charger disabled."); -; rtc_charge_disable(); -; elsif line = "start" then -; rtc_restart(); -; putln("Restarting RTC"); -; elsif line = "t" then -; rtc_get_time(line); -; putln("Current time: ",line); -; elsif line = "raw" then -; putln(); -; putln("Raw read loop, hit any key to stop..."); -; while read(0,@n,1 + RD_NOWAIT) = 0 loop -; put(#13,"sec=",hexstr(rtc_read(0))^); -; put(" min=",hexstr(rtc_read(1))^); -; hold(500); -; end loop; -; elsif line = "loop" then -; putln(); -; putln("Clock loop, hit any key to stop..."); -; while read(0,@n,1 + RD_NOWAIT) = 0 loop -; rtc_get_time(line); -; put(#13,line); -; hold(200); -; end loop; -; elsif line = "set" then -; putln("Setting RTC time to 96-02-18 19:43:00"); -; rtc_set_now(); -; elsif (line = "help") or (line = "?") then -; help(); -; elsif length(line) <> 0 then -; putln("You typed: """,line,""""); -; end; -; end loop; -; END toploop; -; Note:above code is not fully in sync with current menu code - -RTC_TOP_LOOP: - CALL RTC_RESET_ON - CALL RTC_BIT_DELAY - CALL RTC_BIT_DELAY - CALL RTC_BIT_DELAY - - LD A,(FCB+1) ; If there a command line tail - CP '/' ; get the command and feed it - LD A,(FCB+2) ; into the input stream - JR Z,RTC_UCL - - LD DE,CRLF_MSG - LD C,09H ; CP/M write string to console call - CALL 0005H - - CALL RTC_HELP - -RTC_TOP_LOOP_1: - LD DE,RTC_TOP_LOOP1_PROMPT - LD C,09H ; CP/M write string to console call - CALL 0005H - - LD C,01H ; CP/M console input call - CALL 0005H -RTC_UCL: - AND %01011111 ; handle lower case responses to menu - - CP 'L' - JP Z,RTC_TOP_LOOP_LOOP - - CP 'R' - JP Z,RTC_TOP_LOOP_RAW - - CP 'G' - JP Z,RTC_TOP_LOOP_GET - - CP 'P' - JP Z,RTC_TOP_LOOP_PUT - - CP 'E' -; JP Z,RTC_TOP_LOOP_EXIT - RET Z - - CP 'H' - JP Z,RTC_TOP_LOOP_HELP - - CP 'D' - JP Z,RTC_TOP_LOOP_DELAY - - CP 'B' - JP Z,RTC_TOP_LOOP_BOOT - - CP 'W' - JP Z,RTC_TOP_LOOP_WARMSTART - - CP 'C' - JP Z,RTC_TOP_LOOP_CHARGE - - CP 'N' - JP Z,RTC_TOP_LOOP_NOCHARGE - - CP 'A' - JP Z,RTC_TOP_LOOP_START - - CP 'S' - JP Z,RTC_TOP_LOOP_SET - - CP 'I' - JP Z,RTC_TOP_LOOP_INIT - - CP 'T' - JP Z,RTC_TOP_LOOP_TIME - - LD DE,CRLF_MSG - LD C,09H ; CP/M write string to console call - CALL 0005H - - JR RTC_TOP_LOOP_1 - -;RTC_TOP_LOOP_EXIT: -; RET - -RTC_TOP_LOOP_HELP: - CALL RTC_HELP - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_DELAY: - CALL RTC_TEST_BIT_DELAY - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_BOOT: - LD DE,BOOTMSG ; BOOT message - LD C,9 ; BDOS string display function - CALL BDOS ; Do it - ; WAIT FOR MESSAGE TO BE DISPLAYED - LD HL,10000 -DELAY_LOOP: ; LOOP IS 26TS - DEC HL ; 6TS - LD A,H ; 4TS - OR L ; 4TS - JR NZ,DELAY_LOOP ; 12TS - ; RESTART SYSTEM FROM ROM BANK 0, ADDRESS $0000 - LD B,BF_SYSRESET ; SYSTEM RESTART - LD C,BF_SYSRES_COLD ; COLD START - CALL $FFF0 ; CALL HBIOS - - -RTC_TOP_LOOP_WARMSTART: - LD B,BF_SYSRESET ; SYSTEM RESTART - LD C,BF_SYSRES_WARM ; WARM START - CALL $FFF0 ; CALL HBIOS - -RTC_TOP_LOOP_CHARGE: - LD DE,RTC_TOP_LOOP1_CHARGE - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL RTC_CHARGE_ENABLE - LD A,(FCB+1) ; If we came from the - CP '/' ; command line - RET Z ; exit back to CP/M - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_NOCHARGE: - LD DE,RTC_TOP_LOOP1_NOCHARGE - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL RTC_CHARGE_DISABLE - LD A,(FCB+1) ; If we came from the - CP '/' ; command line - RET Z ; exit back to CP/M - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_START: - LD DE,RTC_TOP_LOOP1_START - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL RTC_RESTART - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_SET: - LD DE,RTC_TOP_LOOP1_SET - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL RTC_SET_NOW - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_INIT: - LD DE,RTC_TOP_LOOP1_INIT - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL RTC_INIT_NOW - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_TIME: - LD DE,RTC_TOP_LOOP1_TIME - LD C,09H ; CP/M write string to console call - CALL 0005H - CALL RTC_GET_TIME - LD DE,RTC_PRINT_BUFFER - LD C,09H ; CP/M write string to console call - CALL 0005H - LD A,(FCB+1) ; If we came from the - CP '/' ; command line - RET Z ; exit back to CP/M - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_RAW: - LD DE,RTC_TOP_LOOP1_RAW - LD C,09H ; CP/M write string to console call - CALL 0005H -RTC_TOP_LOOP_RAW1: - -; { Read seconds } - LD D,$00 ; seconds register in DS1302 - CALL RTC_READ ; read value from DS1302, value is in Reg C - - ; digit 16 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $07 - ADD A,'0' - LD (RTC_PRINT_BUFFER+15),A - - ; digit 17 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+16),A - -; { Read minutes } - - LD D,$01 ; minutes register in DS1302 - CALL RTC_READ ; read value from DS1302, value is in Reg C - - ; digit 13 - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $07 - ADD A,'0' - LD (RTC_PRINT_BUFFER+12),A - - ; digit 14 - LD A,C ; put value output in Reg C into accumulator - AND $0F - ADD A,'0' - LD (RTC_PRINT_BUFFER+13),A - - ; digit 15 - LD A,':' - LD (RTC_PRINT_BUFFER+14),A - - ; digits 1-12 and 18-20 are spaces - LD A,' ' ; space - LD (RTC_PRINT_BUFFER+19),A - LD (RTC_PRINT_BUFFER+18),A - LD (RTC_PRINT_BUFFER+17),A - LD (RTC_PRINT_BUFFER+11),A - LD (RTC_PRINT_BUFFER+10),A - LD (RTC_PRINT_BUFFER+09),A - LD (RTC_PRINT_BUFFER+08),A - LD (RTC_PRINT_BUFFER+07),A - LD (RTC_PRINT_BUFFER+06),A - LD (RTC_PRINT_BUFFER+05),A - LD (RTC_PRINT_BUFFER+04),A - LD (RTC_PRINT_BUFFER+03),A - LD (RTC_PRINT_BUFFER+02),A - LD (RTC_PRINT_BUFFER+01),A - LD (RTC_PRINT_BUFFER+00),A - - LD DE,RTC_PRINT_BUFFER - LD C,09H ; CP/M write string to console call - CALL 0005H - - LD C,01H ; CP/M console input call - CALL 0005H - - CP ' ' ; space - JP Z,RTC_TOP_LOOP_RAW1 - - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_LOOP: - LD DE,RTC_TOP_LOOP1_LOOP - LD C,09H ; CP/M write string to console call - CALL 0005H - -RTC_TOP_LOOP_LOOP1: - CALL RTC_GET_TIME - - LD DE,RTC_PRINT_BUFFER - LD C,09H ; CP/M write string to console call - CALL 0005H - - LD C,01H ; CP/M console input call - CALL 0005H - - CP ' ' - JP Z,RTC_TOP_LOOP_LOOP1 - - JP RTC_TOP_LOOP_1 - -RTC_TOP_LOOP_PUT: - LD A,$01 ; set PUT as true - LD (GET_PUT),A -RTC_TOP_LOOP_GET: - LD DE,RTC_TOP_LOOP1_GET - LD C,09H ; CP/M write string to console call - CALL 0005H - - CALL HEXIN ; read NVRAM address - LD (PUT_ADR),A ; store for possible PUT later - -; { Read NVRAM address } - LD D,A ; seconds register in DS1302 - CALL RTC_READ ; read value from DS1302, value is in Reg C - - ; first digit - LD A,C ; put value output in Reg C into accumulator - RLC A - RLC A - RLC A - RLC A - AND $0F - CP 0AH ;TEST FOR NUMERIC & convert to ASCII - JR C,NUM1 ;if not ALPHA, its numeric and skip - ADD A,$07 - -NUM1: ADD A,'0' - LD (RTC_GET_BUFFER),A - - ; second digit - LD A,C ; put value output in Reg C into accumulator - AND $0F - CP 0AH ;TEST FOR NUMERIC & convert to ASCII - JR C,NUM2 ;if not ALPHA, its numeric and skip - ADD A,$07 - -NUM2: ADD A,'0' - LD (RTC_GET_BUFFER+1),A - - LD DE,CRLF_MSG - LD C,09H ; CP/M write string to console call - CALL 0005H - - LD DE,RTC_GET_BUFFER - LD C,09H ; CP/M write string to console call - CALL 0005H - - LD A,(GET_PUT) ; check if GET or PUT mode - CP $00 - JP Z,RTC_GET_PUT_EXIT ; if GET mode, exit - - LD DE,RTC_TOP_LOOP1_PUT - LD C,09H ; CP/M write string to console call - CALL 0005H - -; { Write NVRAM address } - - CALL RTC_WR_UNPROTECT - - CALL HEXIN ; read NVRAM address - LD E,A ; new data for NVRAM register in DS1302 - LD A,(PUT_ADR) - LD D,A ; load address from before - - CALL RTC_WRITE ; read value from DS1302, value is in Reg C - - CALL RTC_WR_PROTECT - -RTC_GET_PUT_EXIT: - LD A,$00 ; reset GET mode - LD (GET_PUT),A - JP RTC_TOP_LOOP_1 - -; -; Text Strings -; - -MSG: - .TEXT "Start RTC Program" -CRLF_MSG: - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -TESTING_BIT_DELAY_MSG: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Testing bit delay. Successful test is ~43 sec." - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Start clock and press space bar." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -TESTING_BIT_DELAY_OVER: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Test complete. Stop clock." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_HELP_MSG: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "RTC: Version 1.9" - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Commands: E)xit T)ime st(A)rt S)et R)aw L)oop C)harge N)ocharge D)elay I)nit G)et P)ut B)oot W)arm-start H)elp" - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_PROMPT: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "RTC>" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_CHARGE: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Trickle charger enabled." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_NOCHARGE: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Trickle charger disabled." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_START: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Restart RTC." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_TIME: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Current time: " - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_RAW: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Raw read Loop. Press SPACE BAR for next." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_LOOP: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Clock Loop. Press SPACE BAR for next." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_SET: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Set RTC time." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Init date/time." - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_GET: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "Get NVRAM addr:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_PUT: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "NVRAM data:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_SECONDS: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "SECONDS:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_MINUTES: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "MINUTES:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_HOURS: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "HOURS:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_DATE: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "DATE:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_MONTH: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "MONTH:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_DAY: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "DAY:" - .DB "$" ; Line terminator - -RTC_TOP_LOOP1_INIT_YEAR: - .DB 0Ah, 0Dh ; line feed and carriage return - .TEXT "YEAR:" - .DB "$" ; Line terminator - -RTC_PRINT_BUFFER: - .FILL 20,0 ; Buffer for formatted date & time to print - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; line terminator - -RTC_GET_BUFFER: - .FILL 2,0 ; Buffer for formatted NVRAM data to print - .DB 0Ah, 0Dh ; line feed and carriage return - .DB "$" ; line terminator - -BIOERR .TEXT "\r\nUnknown BIOS, aborting...\r\n$" -PLTERR .TEXT "\r\n\r\nUnknown/unsupported hardware platform, aborting...\r\n$" -UBERR .TEXT "\r\nUNA UBIOS is not currently supported, aborting...\r\n$" -HBTAG .TEXT "RomWBW HBIOS$" -UBTAG .TEXT "UNA UBIOS" -BOOTMSG .TEXT "\r\n\r\nRebooting...$" -PLT_SBC .TEXT ", SBC/Zeta RTC Latch Port 0x70\r\n$" -PLT_N8 .TEXT ", N8 RTC Latch Port 0x88\r\n$" -PLT_MK4 .TEXT ", Mark 4 RTC Latch Port 0x8A\r\n$" -PLT_RCZ80 .TEXT ", RCBus Z80 RTC Module Latch Port 0xC0\r\n$" -PLT_RCZ180 .TEXT ", RCBus Z180 RTC Module Latch Port 0x0C\r\n$" -PLT_EZZ80 .TEXT ", Easy Z80 RTC Module Latch Port 0xC0\r\n$" -PLT_SCZ180 .TEXT ", SC Z180 RTC Module Latch Port 0x0C\r\n$" -PLT_DYNO .TEXT ", DYNO RTC Module Latch Port 0x0C\r\n$" -PLT_RCZ280 .TEXT ", RCBus Z280 RTC Module Latch Port 0xC0\r\n$" -PLT_MBC .TEXT ", MBC RTC Latch Port 0x70\r\n$" -PLT_RPH .TEXT ", RHYOPHYRE RTC Latch Port 0x84\r\n$" -PLT_DUO .TEXT ", DUODYNE RTC Latch Port 0x70\r\n$" -PLT_STDZ180 .TEXT ", STD Z180 RTC Module latch port 0x84\r\n$" - -; -; Generic FOR-NEXT loop algorithm -; -; LD A,$00 ; set A=0 index counter of FOR loop -;FOR_LOOP: -; PUSH AF ; save accumulator as it is the index counter in FOR loop -; { contents of FOR loop here } ; setup RTC with RST and RD high, SCLK low -; POP AF ; recover accumulator as it is the index counter in FOR loop -; INC A ; increment A in FOR loop (A=A+1) -; CP $08 ; is A < $08 ? -; JP NZ,FOR_LOOP ; No, do FOR loop again -; RET ; Yes, end function and return. Read RTC value is in C - -YEAR .DB $18 -MONTH .DB $11 -DATE .DB $08 -HOURS .DB $00 -MINUTES .DB $00 -SECONDS .DB $00 -DAY .DB $05 -GET_PUT .DB $00 - -PUT_ADR .DB 0 - - .END - + .Title "RTC" +; +; Program: rtc.asm +; Author: Andrew Lynch +; Date: 22 Feb 2007 +; Enviroment: TASM MS-DOS Z80 Cross Assembler source for CP/M +; +;[2011/8/11] VK5DG modified for N8 +; Changed base address to $88 +; Changed trickle charger value to 2k+2 diodes for DS1210s +; +;[2012/2/7] WBW modified to build for either +; traditional N8VEM/Zeta or N8 via conditionals +; +;[2013/12/29] WBW modified to build for MK4 +; +;[2017/11/29] WBW modified to adjust to RTC in use dynamically +; using HBIOS platform detection +; +;[2018/11/8] v1.2 PMS Add boot option. Code optimization. +; +;[2019/06/21] v1.3 Finalized RCBus Z180 support. +; +;[2019/08/11] v1.4 Support SCZ180 platform. +; +;[2020/02/02] v1.5 PMS Basic command line support +; +;[2020/05/15] v1.6 Added Warm Start option +; +;[2021/07/10] v1.7 Support MBC (AJL) +; +;[2022/03/27] v1.8 Support RHYOPHYRE +; +;[2023/07/07] v1.9 Support DUODYNE +; +;[2024/09/02] v1.10 Support Genesis STD Z180 +; +; Constants +; +mask_data .EQU %10000000 ; RTC data line +mask_clk .EQU %01000000 ; RTC Serial Clock line +mask_rd .EQU %00100000 ; Enable data read from RTC +mask_rst .EQU %00010000 ; De-activate RTC reset line + +PORT_SBC .EQU $70 ; RTC port for SBC/ZETA +PORT_N8 .EQU $88 ; RTC port for N8 +PORT_MK4 .EQU $8A ; RTC port for MK4 +PORT_RCZ80 .EQU $C0 ; RTC port for RCBus +PORT_RCZ180 .EQU $0C ; RTC port for RCBus +PORT_EZZ80 .EQU $C0 ; RTC port for EZZ80 (actually does not have one!!!) +PORT_SCZ180 .EQU $0C ; RTC port for SCZ180 +PORT_DYNO .EQU $0C ; RTC port for DYNO +PORT_RCZ280 .EQU $C0 ; RTC port for RCZ280 +PORT_MBC .EQU $70 ; RTC port for MBC +PORT_RPH .EQU $84 ; RTC port for RHYOPHYRE +PORT_DUO .EQU $94 ; RTC port for DUODYNE +PORT_STDZ180 .EQU $84 ; RTC Port for STD Bus Z180 board + + +BDOS .EQU 5 ; BDOS invocation vector +FCB .EQU 05CH ; Start of command line + +;BID_BOOT .EQU $00 +;HB_BNKCALL .EQU $FFF9 + +BF_SYSRESET .EQU $F0 ; RESTART SYSTEM + +BF_SYSRES_INT .EQU $00 ; RESET HBIOS INTERNAL +BF_SYSRES_WARM .EQU $01 ; WARM START (RESTART BOOT LOADER) +BF_SYSRES_COLD .EQU $02 ; COLD START + +; +; Program +; + .ORG 0100H + +LOOP: + LD DE,MSG + LD C,09H ; CP/M write string to console call + CALL 0005H + +; program starts here + + CALL RTC_INIT ; Program initialization + + CALL RTC_TOP_LOOP + + LD C,00H ; CP/M system reset call - shut down + CALL 0005H + + HALT ; This code is never reached + + +; function HEXSTR +; input number in A +; output upper nibble of number in ASCII in H +; output lower nibble of number in ASCII in L +; uses BC +; +; based on following algorithm: +; +; const +; hextab : string = ('0','1','2','3','4','5','6','7','8', +; '9','A','B','C','D','E','F'); +; +; PROCEDURE hexstr(n: int): ^string; +; BEGIN +; n := n and 255; +; tmpstr[1] := hextab[n / 16]; +; tmpstr[2] := hextab[n and 15]; +; tmpstr[0] := #2; +; return @tmpstr; +; END; + + +HEXSTR: + PUSH BC ;SAVE BC + LD B,A + RLC A ;DO HIGH NIBBLE FIRST + RLC A + RLC A + RLC A + AND 0FH ;ONLY THIS NOW + ADD A,30H ;TRY A NUMBER + CP 3AH ;TEST IT + JR C,HEXSTR1 ;IF CY SET SAVE 'NUMBER' in H + ADD A,07H ;MAKE IT AN ALPHA +HEXSTR1: + LD H,A ;SAVE 'ALPHA' in H + LD A,B ;NEXT NIBBLE + AND 0FH ;JUST THIS + ADD A,30H ;TRY A NUMBER + CP 3AH ;TEST IT + JR C,HEXSTR2 ;IF CY SET SAVE 'NUMBER' in L + ADD A,07H ;MAKE IT ALPHA + +HEXSTR2: + LD L,A ;SAVE 'ALPHA' in L + POP BC ;RESTORE BC + RET + + +;***************************************************** +;* GET K.B. DATA & MAKE IT 'HEX' +;***************************************************** + +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 + PUSH BC + + CALL NIBL ;DO NEXT NIBBLE + POP BC + ADD A,B ;COMBINE NIBBLES IN ACC. + POP BC ;RESTORE BC + RET ;DONE +NIBL: + LD C,01H ; CP/M console input call + CALL 0005H ;GET K.B. DATA + 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 + +; function RTC_IN +; +; read a byte from RTC port, return in A +; NOTE: port address is dynamically set in RTC_INIT + +RTC_IN: +INP .EQU $ + 1 + IN A,($FF) + RET + +; function RTC_OUT +; +; write a byte to RTC port, value in A +; NOTE: port address is dynamically set in RTC_INIT + +RTC_OUT: +OUTP .EQU $ + 1 + OUT ($FF),A + RET + +; function RTC_BIT_DELAY +; +; based on following algorithm: +; +; { Make a short delay } +; PROCEDURE rtc_bit_delay; +; var +; x : int; +; BEGIN +; x := 3; +; END; + +RTC_BIT_DELAY: ; purpose is to delay ~36 uS or 144 t-states at 4MHz + PUSH AF ; 11 t-states + LD A,07H ; 7 t-states ADJUST THE TIME 13h IS FOR 4 MHZ +RTC_BIT_DELAY1: + DEC A ; 4 t-states DEC COUNTER. 4 T-states = 1 uS. + JP NZ,RTC_BIT_DELAY1 ; 10 t-states JUMP TO PAUSELOOP2 IF A <> 0. + + NOP ; 4 t-states + NOP ; 4 t-states + POP AF ; 10 t-states + RET ; 10 t-states (144 t-states total) + + +; function RTC_RESET +; +; based on following algorithm: +; +; { Output a RTC reset signal } +; PROCEDURE rtc_reset; +; BEGIN +; out(rtc_base,mask_data + mask_rd); +; rtc_bit_delay(); +; rtc_bit_delay(); +; out(rtc_base,mask_data + mask_rd + mask_rst); +; rtc_bit_delay(); +; rtc_bit_delay(); +; END; +; +RTC_RESET: + LD A,mask_data + mask_rd + ;OUT (RTC),A + CALL RTC_OUT + CALL RTC_BIT_DELAY + CALL RTC_BIT_DELAY + LD A,mask_data + mask_rd + mask_rst + ;OUT (RTC),A + CALL RTC_OUT + CALL RTC_BIT_DELAY + CALL RTC_BIT_DELAY + RET + + +; function RTC_RESET_ON +; +; based on following algorithm: +; +; { Assert RTC reset signal } +; PROCEDURE rtc_reset_on; +; BEGIN +; out(rtc_base,mask_data + mask_rd); +; rtc_bit_delay(); +; rtc_bit_delay(); +; END; + +RTC_RESET_ON: + LD A,mask_data + mask_rd + ;OUT (RTC),A + CALL RTC_OUT + CALL RTC_BIT_DELAY + CALL RTC_BIT_DELAY + RET + +; function RTC_RESET_OFF +; +; based on following algorithm: +; +; { De-assert RTC reset signal } +; PROCEDURE rtc_reset_off; +; BEGIN +; out(rtc_base,mask_data + mask_rd + mask_rst); +; rtc_bit_delay(); +; rtc_bit_delay(); +; END; + +RTC_RESET_OFF: + LD A,mask_data + mask_rd + mask_rst + ;OUT (RTC),A + CALL RTC_OUT + CALL RTC_BIT_DELAY + CALL RTC_BIT_DELAY + RET + +; function RTC_WR +; input value in C +; uses A +; +; PROCEDURE rtc_wr(n : int); +; var +; i : int; +; BEGIN +; for i := 0 while i < 8 do inc(i) loop +; if (n and 1) <> 0 then +; out(rtc_base,mask_rst + mask_data); +; rtc_bit_delay(); +; out(rtc_base,mask_rst + mask_clk + mask_data); +; else +; out(rtc_base,mask_rst); +; rtc_bit_delay(); +; out(rtc_base,mask_rst + mask_clk); +; end; +; rtc_bit_delay(); +; n := shr(n,1); +; end loop; +; END; + +RTC_WR: + XOR A ; set A=0 index counter of FOR loop + +RTC_WR1: + PUSH AF ; save accumulator as it is the index counter in FOR loop + LD A,C ; get the value to be written in A from C (passed value to write in C) + BIT 0,A ; is LSB a 0 or 1? + JP Z,RTC_WR2 ; if it's a 0, handle it at RTC_WR2. + ; LSB is a 1, handle it below + ; setup RTC latch with RST and DATA high, SCLK low + LD A,mask_rst + mask_data + ;OUT (RTC),A ; output to RTC latch + CALL RTC_OUT + CALL RTC_BIT_DELAY ; let it settle a while + ; setup RTC with RST, DATA, and SCLK high + LD A,mask_rst + mask_clk + mask_data + ;OUT (RTC),A ; output to RTC latch + CALL RTC_OUT + JP RTC_WR3 ; exit FOR loop + +RTC_WR2: + ; LSB is a 0, handle it below + LD A,mask_rst ; setup RTC latch with RST high, SCLK and DATA low + ;OUT (RTC),A ; output to RTC latch + CALL RTC_OUT + CALL RTC_BIT_DELAY ; let it settle a while + ; setup RTC with RST and SCLK high, DATA low + LD A,mask_rst + mask_clk + ;OUT (RTC),A ; output to RTC latch + CALL RTC_OUT + +RTC_WR3: + CALL RTC_BIT_DELAY ; let it settle a while + RRC C ; move next bit into LSB position for processing to RTC + POP AF ; recover accumulator as it is the index counter in FOR loop + INC A ; increment A in FOR loop (A=A+1) + CP $08 ; is A < $08 ? + JP NZ,RTC_WR1 ; No, do FOR loop again + RET ; Yes, end function and return + + +; function RTC_RD +; output value in C +; uses A +; +; function RTC_RD +; +; PROCEDURE rtc_rd(): int ; +; var +; i,n,mask : int; +; BEGIN +; n := 0; +; mask := 1; +; for i := 0 while i < 8 do inc(i) loop +; out(rtc_base,mask_rst + mask_rd); +; rtc_bit_delay(); +; if (in(rtc_base) and #1) <> #0 then +; { Data = 1 } +; n := n + mask; +; else +; { Data = 0 } +; end; +; mask := shl(mask,1); +; out(rtc_base,mask_rst + mask_clk + mask_rd); +; rtc_bit_delay(); +; end loop; +; return n; +; END; + +RTC_RD: + XOR A ; set A=0 index counter of FOR loop + LD C,$00 ; set C=0 output of RTC_RD is passed in C + LD B,$01 ; B is mask value + +RTC_RD1: + PUSH AF ; save accumulator as it is the index counter in FOR loop + ; setup RTC with RST and RD high, SCLK low + LD A,mask_rst + mask_rd + ;OUT (RTC),A ; output to RTC latch + CALL RTC_OUT + CALL RTC_BIT_DELAY ; let it settle a while + ;IN A,(RTC) ; input from RTC latch + CALL RTC_IN ; input from RTC latch + BIT 0,A ; is LSB a 0 or 1? + JP Z,RTC_RD2 ; if LSB is a 1, handle it below + LD A,C + ADD A,B + LD C,A +; INC C + ; if LSB is a 0, skip it (C=C+0) +RTC_RD2: + RLC B ; move input bit out of LSB position to save it in C + ; setup RTC with RST, SCLK high, and RD high + LD A,mask_rst + mask_clk + mask_rd + ;OUT (RTC),A ; output to RTC latch + CALL RTC_OUT + CALL RTC_BIT_DELAY ; let it settle + POP AF ; recover accumulator as it is the index counter in FOR loop + INC A ; increment A in FOR loop (A=A+1) + CP $08 ; is A < $08 ? + JP NZ,RTC_RD1 ; No, do FOR loop again + RET ; Yes, end function and return. Read RTC value is in C + +; function RTC_WRITE +; input address in D +; input value in E +; uses A +; +; based on following algorithm: +; +; PROCEDURE rtc_write(address, value: int); +; BEGIN +; lock(); +; rtc_reset_off(); +; { Write command } +; rtc_wr(128 + shl(address and $3f,1)); +; { Write data } +; rtc_wr(value and $ff); +; rtc_reset_on(); +; unlock(); +; END; + +RTC_WRITE: + DI ; disable interrupts during critical section + CALL RTC_RESET_OFF ; turn off RTC reset + LD A,D ; bring into A the address from D +; AND $3F ; keep only bits 6 LSBs, discard 2 MSBs + AND %00111111 ; keep only bits 6 LSBs, discard 2 MSBs + RLC A ; rotate address bits to the left +; ADD A,$80 ; set MSB to one for DS1302 COMMAND BYTE (WRITE) + ADD A,%10000000 ; set MSB to one for DS1302 COMMAND BYTE (WRITE) + LD C,A ; RTC_WR expects write data (address) in reg C + CALL RTC_WR ; write address to DS1302 + LD A,E ; start processing value + AND $FF ; seems unnecessary, probably delete since all values are 8-bit + LD C,A ; RTC_WR expects write data (value) in reg C + CALL RTC_WR ; write address to DS1302 + CALL RTC_RESET_ON ; turn on RTC reset + EI + RET + + +; function RTC_READ +; input address in D +; output value in C +; uses A +; +; based on following algorithm +; +; PROCEDURE rtc_read(address: int): int; +; var +; n : int; +; BEGIN +; lock(); +; rtc_reset_off(); +; { Write command } +; rtc_wr(128 + shl(address and $3f,1) + 1); +; { Read data } +; n := rtc_rd(); +; rtc_reset_on(); +; unlock(); +; return n; +; END; + +RTC_READ: + DI ; disable interrupts during critical section + CALL RTC_RESET_OFF ; turn off RTC reset + LD A,D ; bring into A the address from D + AND $3F ; keep only bits 6 LSBs, discard 2 MSBs + RLC A ; rotate address bits to the left + ADD A,$81 ; set MSB to one for DS1302 COMMAND BYTE (READ) + LD C,A ; RTC_WR expects write data (address) in reg C + CALL RTC_WR ; write address to DS1302 + CALL RTC_RD ; read value from DS1302 (value is in reg C) + CALL RTC_RESET_ON ; turn on RTC reset + EI + RET + + +; function RTC_WR_PROTECT +; input D (address) $07 +; input E (value) $80 +; uses A +; +; based on following algorithm +; +; PROCEDURE rtc_wr_protect; +; BEGIN +; rtc_write(7,128); +; END; + +RTC_WR_PROTECT: +; LD D,$07 + LD D,%00000111 +; LD E,$80 + LD E,%10000000 + CALL RTC_WRITE + RET + + +; function RTC_WR_UNPROTECT +; input D (address) $07 +; input E (value) $00 +; uses A +; +; based on following algorithm +; +; PROCEDURE rtc_wr_unprotect; +; BEGIN +; rtc_write(7,0); +; END; + +RTC_WR_UNPROTECT: +; LD D,$07 + LD D,%00000111 +; LD E,$00 + LD E,%00000000 + CALL RTC_WRITE + RET + + +; function RTC_GET_TIME +; input HL (memory address of buffer) +; uses A,C,D,E +; +; based on following algorithm +; +; PROCEDURE rtc_get_time(var buf: string); +; var +; n : int; +; BEGIN +; lock(); +; rtc_reset_off(); +; { Write command, burst read } +; rtc_wr(255 - 64); +; { Read seconds } +; n := rtc_rd(); 0 +; buf[16] := char(((n / 16) and $07)) + '0'; +; buf[17] := char((n and $0f)) + '0'; +; { Read minutes } +; n := rtc_rd(); 1 +; buf[13] := char(((n / 16) and $07)) + '0'; +; buf[14] := char((n and $0f)) + '0'; +; buf[15] := ':'; +; { Read hours } +; n := rtc_rd(); 2 +; buf[10] := char(((n / 16) and $03)) + '0'; +; buf[11] := char((n and $0f)) + '0'; +; buf[12] := ':'; +; { Read date } +; n := rtc_rd(); 3 +; buf[7] := char(((n / 16) and $03)) + '0'; +; buf[8] := char((n and $0f)) + '0'; +; buf[9] := ' '; +; { Read month } +; n := rtc_rd(); 4 +; buf[4] := char(((n / 16) and $03)) + '0'; +; buf[5] := char((n and $0f)) + '0'; +; buf[6] := '-'; +; { Read day } +; n := rtc_rd(); 5 +; { +; buf[4] := char(((n / 16) and $03)) + '0'; +; buf[4] := char((n and $0f)) + '0'; +; } +; { Read year } +; n := rtc_rd(); 6 +; buf[1] := char(((n / 16) and $0f)) + '0'; +; buf[2] := char((n and $0f)) + '0'; +; buf[3] := '-'; +; length(buf) := 17; +; rtc_reset_on(); +; unlock(); +; END rtc_get_time; + +RTC_GET_TIME: + DI ; disable interrupts during DS1302 read + CALL RTC_RESET_OFF ; turn of RTC reset + ; { Write command, burst read } + LD C,%10111111 ; (255 - 64) + CALL RTC_WR ; send COMMAND BYTE (BURST READ) to DS1302 + +; { Read seconds } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 16 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $07 + ADD A,'0' + LD (RTC_PRINT_BUFFER+15),A + + ; digit 17 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+16),A + +; { Read minutes } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 13 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $07 + ADD A,'0' + LD (RTC_PRINT_BUFFER+12),A + + ; digit 14 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+13),A + + ; digit 15 + LD A,':' + LD (RTC_PRINT_BUFFER+14),A + +; { Read hours } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 10 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $03 + ADD A,'0' + LD (RTC_PRINT_BUFFER+09),A + + ; digit 11 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+10),A + + ; digit 12 + LD A,':' + LD (RTC_PRINT_BUFFER+11),A + +; { Read date } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 07 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $03 + ADD A,'0' + LD (RTC_PRINT_BUFFER+06),A + + ; digit 08 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+07),A + + ; digit 09 + LD A,' ' + LD (RTC_PRINT_BUFFER+08),A + +; { Read month } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 04 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $03 + ADD A,'0' + LD (RTC_PRINT_BUFFER+03),A + + ; digit 05 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+04),A + + ; digit 06 + LD A,'-' + LD (RTC_PRINT_BUFFER+05),A + +; { Read day } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 04 +; LD A,C ; put value output in Reg C into accumulator +; RLC A +; RLC A +; RLC A +; RLC A +; AND $03 +; ADD A,'0' +; LD (RTC_PRINT_BUFFER+03),A + + ; digit 04 +; LD A,C ; put value output in Reg C into accumulator +; AND $0F +; ADD A,'0' +; LD (RTC_PRINT_BUFFER+03),A + +; add special code to put "DAY" value at end of string until better solution known + + ; digit 18 + LD A,'-' + LD (RTC_PRINT_BUFFER+17),A + + ; digit 19 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+18),A + + ; digit 20 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+19),A + +; { Read year } + + CALL RTC_RD ; read value from DS1302, value is in Reg C + + ; digit 01 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+00),A + + ; digit 02 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+01),A + + ; digit 03 + LD A,'-' + LD (RTC_PRINT_BUFFER+02),A + + CALL RTC_RESET_ON ; turn RTC reset back on + EI ; re-enable interrupts + + RET ; Yes, end function and return + + +; function RTC_SET_NOW +; uses A, D, E +; +; based on following algorithm +; +; { Set time to 96-02-18 19:43:00 } +; PROCEDURE rtc_set_now; +; BEGIN +; rtc_wr_unprotect(); +; { Set seconds } +; rtc_write(0,0); +; { Set minutes } +; rtc_write(1,$43); +; { Set hours } +; rtc_write(2,$19); +; { Set date } +; rtc_write(3,$18); +; { Set month } +; rtc_write(4,$02); +; { Set day } +; rtc_write(5,$07); +; { Set year } +; rtc_write(6,$96); +; rtc_wr_protect(); +; END; + +RTC_SET_NOW: +; set time to 07-02-23 19:45:00-05 <-Friday + CALL RTC_WR_UNPROTECT +; seconds + LD D,$00 + LD A,(SECONDS) + LD E,A + CALL RTC_WRITE + +; minutes + LD D,$01 + LD A,(MINUTES) + LD E,A + CALL RTC_WRITE + +; hours + LD D,$02 + LD A,(HOURS) + LD E,A + CALL RTC_WRITE + +; date + LD D,$03 + LD A,(DATE) + LD E,A + CALL RTC_WRITE + +; month + LD D,$04 + LD A,(MONTH) + LD E,A + CALL RTC_WRITE + +; day + LD D,$05 + LD A,(DAY) + LD E,A + CALL RTC_WRITE + +; year + LD D,$06 + LD A,(YEAR) + LD E,A + CALL RTC_WRITE + + CALL RTC_WR_PROTECT + RET + +RTC_INIT_NOW: +; set time to Current Time + +; year + LD DE,RTC_TOP_LOOP1_INIT_YEAR + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (YEAR),A + +; month + LD DE,RTC_TOP_LOOP1_INIT_MONTH + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (MONTH),A + +; date + LD DE,RTC_TOP_LOOP1_INIT_DATE + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (DATE),A + +; hours + LD DE,RTC_TOP_LOOP1_INIT_HOURS + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (HOURS),A + +; minutes + LD DE,RTC_TOP_LOOP1_INIT_MINUTES + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (MINUTES),A + +; seconds + LD DE,RTC_TOP_LOOP1_INIT_SECONDS + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (SECONDS),A + +; day + LD DE,RTC_TOP_LOOP1_INIT_DAY + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL HEXIN + LD (DAY),A + + RET + + +; function RTC_RESTART +; +; uses A, D, E, +; +; based on the following algorithm +; +; { Restart clock, set seconds to 00 } +; PROCEDURE rtc_restart; +; BEGIN +; rtc_wr_unprotect(); +; { Set seconds } +; rtc_write(0,0); +; rtc_wr_protect(); +; END; + +RTC_RESTART: + CALL RTC_WR_UNPROTECT + LD D,$00 + LD E,$00 + CALL RTC_WRITE + CALL RTC_WR_PROTECT + RET + + +; function RTC_CHARGE_ENABLE +; +; uses A, D, E +; +; based on following algorithm +; +; PROCEDURE rtc_charge_enable; +; BEGIN +; rtc_wr_unprotect(); +; { Enable trickle charger, 2kohm, 1 diode } +; rtc_write(8,$A5); +; rtc_wr_protect(); +; END; +; +; Trickle Charge Current: +; +; Imax = (5.0V - (0.7 * Ndiode)) / R +; (5.0 - (0.7 * 1)) / 2000 = .00215A = 2.15 milliamps +; (5.0 - (0.7 * 1)) / 8000 = 0.0005375A = .537 milliamps +; + +RTC_CHARGE_ENABLE + CALL RTC_WR_UNPROTECT + LD D,$08 + LD E,$A5 + CALL RTC_WRITE + CALL RTC_WR_PROTECT + RET + + +; function RTC_CHARGE_DISABLE +; +; uses A, D, E +; +; based on following algorithm +; +; PROCEDURE rtc_charge_disable; +; BEGIN +; rtc_wr_unprotect(); +; { Disable trickle charger} +; rtc_write(8,$00); +; rtc_wr_protect(); +; END; + +RTC_CHARGE_DISABLE + CALL RTC_WR_UNPROTECT + LD D,$08 + LD E,$00 + CALL RTC_WRITE + CALL RTC_WR_PROTECT + RET + + +; function TEST_BIT_DELAY +; +; based on the following algorithm +; +; +; PROCEDURE test_bit_delay(); +; var +; i,t0,t1 : int; +; BEGIN +; putln("Testing bit delay..."); +; t0 := sys_time(); +; for i := 0 while i < 1000 do inc(i) loop +; rtc_bit_delay(); +; end loop; +; t1 := sys_time(); +; putln(i," rtc_bit_delay calls took ",t1-t0," ms."); +; END; + +RTC_TEST_BIT_DELAY + LD DE,TESTING_BIT_DELAY_MSG + LD C,09H ; CP/M write string to console call + CALL 0005H + LD C,01H ; CP/M console input call + CALL 0005H + + ; test should take approximately 43 seconds based on the following code analysis + ; of Z80 T-states on a 4 MHz processor + ; =(4+15*(7+255*(7+255*(17+144+4+10)+4+10)+10)+7)/4/1000000 + + LD B,$0F +PAUSE: + LD C,$FF +PAUSE1: + LD A,$FF ; ADJUST THE TIME 13h IS FOR 4 MHZ +PAUSE2: + CALL RTC_BIT_DELAY ; CAUSE 36uS DELAY + DEC A ; DEC COUNTER. + JP NZ,PAUSE2 ; JUMP TO PAUSE2 IF A <> 0. + DEC C ; DEC COUNTER + JP NZ,PAUSE1 ; JUMP TO PAUSE1 IF C <> 0. + DJNZ PAUSE ; JUMP TO PAUSE IF B <> 0. + + LD DE,TESTING_BIT_DELAY_OVER + LD C,09H ; CP/M write string to console call + CALL 0005H + RET + + +; function RTC_HELP +; +; based on following algorithm +; +; PROCEDURE help(); +; BEGIN +; putln(); +; putln("rtc: ",version); +; putln("rtc: Commands: (E)xit (T)ime st(A)rt (S)et (R)aw (L)oop (C)harge (N)ocharge (H)elp"); +; END; + +RTC_HELP + LD DE,RTC_HELP_MSG + LD C,09H ; CP/M write string to console call + CALL 0005H + RET + +; function RTC_INIT +; +; Determine RTC port based on hardware platform +; and record it dynamically in code (see RTC_IN and RTC_OUT). +; + +RTC_INIT: + CALL IDBIO ; Id BIOS, 1=HBIOS, 2=UBIOS + DEC A ; Test for HBIOS + JP Z,HINIT ; Do HBIOS setup + DEC A ; Test for UBIOS + JP Z,UINIT ; Do UBIOS setup +; + ; Neither UNA nor RomWBW + LD DE,BIOERR ; BIOS error message + LD C,9 ; BDOS string display function + CALL BDOS ; Do it + JP 0 ; Bail out! +; +HINIT: +; + ; Display RomWBW notification string + LD DE,HBTAG ; BIOS notification string + LD C,9 ; BDOS string display function + CALL BDOS ; Do it +; + ; Get platform id from RomWBW HBIOS + LD B,0F1H ; HBIOS VER function 0xF1 + LD C,0 ; Required reserved value + RST 08 ; Do it, L := Platform ID + LD A,L ; Move to A +; + ; Assign correct port to C + LD C,PORT_SBC + LD DE,PLT_SBC + CP $01 ; SBC + JP Z,RTC_INIT2 + CP $02 ; ZETA + JP Z,RTC_INIT2 + CP $03 ; ZETA 2 + JP Z,RTC_INIT2 +; + LD C,PORT_N8 + LD DE,PLT_N8 + CP $04 ; N8 + JP Z,RTC_INIT2 +; + LD C,PORT_MK4 + LD DE,PLT_MK4 + CP $05 ; Mark IV + JP Z,RTC_INIT2 +; + LD C,PORT_RCZ80 + LD DE,PLT_RCZ80 + CP $07 ; RCBus w/ Z80 + JP Z,RTC_INIT2 +; + LD C,PORT_RCZ180 + LD DE,PLT_RCZ180 + CP $08 ; RCBus w/ Z180 + JP Z,RTC_INIT2 +; + LD C,PORT_EZZ80 + LD DE,PLT_EZZ80 + CP $09 ; Easy Z80 + JP Z,RTC_INIT2 +; + LD C,PORT_SCZ180 + LD DE,PLT_SCZ180 + CP $0A ; SCZ180 + JP Z,RTC_INIT2 +; + LD C,PORT_DYNO + LD DE,PLT_DYNO + CP 11 ; DYNO + JP Z,RTC_INIT2 +; + LD C,PORT_RCZ280 + LD DE,PLT_RCZ280 + CP 12 ; RCZ280 + JP Z,RTC_INIT2 +; + LD C,PORT_MBC + LD DE,PLT_MBC + CP 13 ; MBC + JP Z,RTC_INIT2 +; + LD C,PORT_RPH + LD DE,PLT_RPH + CP 14 ; RHYOPHYRE + JP Z,RTC_INIT2 +; + LD C,PORT_DUO + LD DE,PLT_DUO + CP 17 ; DUODYNE + JP Z,RTC_INIT2 +; + LD C,PORT_STDZ180 + LD DE,PLT_STDZ180 + CP 21 ; STD Z180 + JP Z,RTC_INIT2 +; + +; Unknown platform + LD DE,PLTERR ; BIOS error message + LD C,9 ; BDOS string display function + CALL BDOS ; Do it + JP 0 ; Bail out! +; +UINIT: + ;; Display UNA notification string + ;LD DE,UBTAG ; BIOS notification string + ;LD C,9 ; BDOS string display function + ;CALL BDOS ; Do it +; + ; Notify UNA not supported at present + LD DE,UBERR ; BIOS not support message + LD C,9 ; BDOS string display function + CALL BDOS ; Do it + JP 0 ; Bail out! + +RTC_INIT2: + ; Record port number in code routines + LD A,C + LD (INP),A + LD (OUTP),A +; + ; Display platform + LD C,9 ; BDOS string display function + CALL BDOS ; Do it + RET + +; +; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 +; +IDBIO: +; + ; Check for UNA (UBIOS) + LD A,(0FFFDH) ; fixed location of UNA API vector + CP 0C3H ; jp instruction? + JR NZ,IDBIO1 ; if not, not UNA + LD HL,(0FFFEH) ; get jp address + LD A,(HL) ; get byte at target address + CP 0FDH ; first byte of UNA push ix instruction + JR NZ,IDBIO1 ; if not, not UNA + INC HL ; point to next byte + LD A,(HL) ; get next byte + CP 0E5H ; second byte of UNA push ix instruction + JR NZ,IDBIO1 ; if not, not UNA, check others + LD A,2 ; UNA BIOS id = 2 + RET ; and done +; +IDBIO1: + ; Check for RomWBW (HBIOS) + LD HL,(0FFFCH) ; HL := HBIOS ident location + LD A,'W' ; First byte of ident + CP (HL) ; Compare + JR NZ,IDBIO2 ; Not HBIOS + INC HL ; Next byte of ident + LD A,~'W' ; Second byte of ident + CP (HL) ; Compare + JR NZ,IDBIO2 ; Not HBIOS + LD A,1 ; HBIOS BIOS id = 1 + RET ; and done +; +IDBIO2: + ; No idea what this is + XOR A ; Setup return value of 0 + RET ; and done + + +; function RTC_TOP_LOOP +; +; based on following algorithm +; +; PROCEDURE toploop(); +; var +; err,i,n,fd : int; +; BEGIN +; putln(); +; help(); +; rtc_reset_on(); +; hold(100); +; test_bit_delay(); +; rtc_charge_disable(); +; putln("rtc: trickle charger disabled."); +; loop +; put("rtc>"); +; gets(line); +; if line = "exit" then +; putln("Bye."); +; exit(0); +; elsif line = "charge" then +; putln("Trickle charger enabled."); +; rtc_charge_enable(); +; elsif line = "nocharge" then +; putln("Trickle charger disabled."); +; rtc_charge_disable(); +; elsif line = "start" then +; rtc_restart(); +; putln("Restarting RTC"); +; elsif line = "t" then +; rtc_get_time(line); +; putln("Current time: ",line); +; elsif line = "raw" then +; putln(); +; putln("Raw read loop, hit any key to stop..."); +; while read(0,@n,1 + RD_NOWAIT) = 0 loop +; put(#13,"sec=",hexstr(rtc_read(0))^); +; put(" min=",hexstr(rtc_read(1))^); +; hold(500); +; end loop; +; elsif line = "loop" then +; putln(); +; putln("Clock loop, hit any key to stop..."); +; while read(0,@n,1 + RD_NOWAIT) = 0 loop +; rtc_get_time(line); +; put(#13,line); +; hold(200); +; end loop; +; elsif line = "set" then +; putln("Setting RTC time to 96-02-18 19:43:00"); +; rtc_set_now(); +; elsif (line = "help") or (line = "?") then +; help(); +; elsif length(line) <> 0 then +; putln("You typed: """,line,""""); +; end; +; end loop; +; END toploop; +; Note:above code is not fully in sync with current menu code + +RTC_TOP_LOOP: + CALL RTC_RESET_ON + CALL RTC_BIT_DELAY + CALL RTC_BIT_DELAY + CALL RTC_BIT_DELAY + + LD A,(FCB+1) ; If there a command line tail + CP '/' ; get the command and feed it + LD A,(FCB+2) ; into the input stream + JR Z,RTC_UCL + + LD DE,CRLF_MSG + LD C,09H ; CP/M write string to console call + CALL 0005H + + CALL RTC_HELP + +RTC_TOP_LOOP_1: + LD DE,RTC_TOP_LOOP1_PROMPT + LD C,09H ; CP/M write string to console call + CALL 0005H + + LD C,01H ; CP/M console input call + CALL 0005H +RTC_UCL: + AND %01011111 ; handle lower case responses to menu + + CP 'L' + JP Z,RTC_TOP_LOOP_LOOP + + CP 'R' + JP Z,RTC_TOP_LOOP_RAW + + CP 'G' + JP Z,RTC_TOP_LOOP_GET + + CP 'P' + JP Z,RTC_TOP_LOOP_PUT + + CP 'E' +; JP Z,RTC_TOP_LOOP_EXIT + RET Z + + CP 'H' + JP Z,RTC_TOP_LOOP_HELP + + CP 'D' + JP Z,RTC_TOP_LOOP_DELAY + + CP 'B' + JP Z,RTC_TOP_LOOP_BOOT + + CP 'W' + JP Z,RTC_TOP_LOOP_WARMSTART + + CP 'C' + JP Z,RTC_TOP_LOOP_CHARGE + + CP 'N' + JP Z,RTC_TOP_LOOP_NOCHARGE + + CP 'A' + JP Z,RTC_TOP_LOOP_START + + CP 'S' + JP Z,RTC_TOP_LOOP_SET + + CP 'I' + JP Z,RTC_TOP_LOOP_INIT + + CP 'T' + JP Z,RTC_TOP_LOOP_TIME + + LD DE,CRLF_MSG + LD C,09H ; CP/M write string to console call + CALL 0005H + + JR RTC_TOP_LOOP_1 + +;RTC_TOP_LOOP_EXIT: +; RET + +RTC_TOP_LOOP_HELP: + CALL RTC_HELP + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_DELAY: + CALL RTC_TEST_BIT_DELAY + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_BOOT: + LD DE,BOOTMSG ; BOOT message + LD C,9 ; BDOS string display function + CALL BDOS ; Do it + ; WAIT FOR MESSAGE TO BE DISPLAYED + LD HL,10000 +DELAY_LOOP: ; LOOP IS 26TS + DEC HL ; 6TS + LD A,H ; 4TS + OR L ; 4TS + JR NZ,DELAY_LOOP ; 12TS + ; RESTART SYSTEM FROM ROM BANK 0, ADDRESS $0000 + LD B,BF_SYSRESET ; SYSTEM RESTART + LD C,BF_SYSRES_COLD ; COLD START + CALL $FFF0 ; CALL HBIOS + + +RTC_TOP_LOOP_WARMSTART: + LD B,BF_SYSRESET ; SYSTEM RESTART + LD C,BF_SYSRES_WARM ; WARM START + CALL $FFF0 ; CALL HBIOS + +RTC_TOP_LOOP_CHARGE: + LD DE,RTC_TOP_LOOP1_CHARGE + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL RTC_CHARGE_ENABLE + LD A,(FCB+1) ; If we came from the + CP '/' ; command line + RET Z ; exit back to CP/M + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_NOCHARGE: + LD DE,RTC_TOP_LOOP1_NOCHARGE + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL RTC_CHARGE_DISABLE + LD A,(FCB+1) ; If we came from the + CP '/' ; command line + RET Z ; exit back to CP/M + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_START: + LD DE,RTC_TOP_LOOP1_START + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL RTC_RESTART + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_SET: + LD DE,RTC_TOP_LOOP1_SET + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL RTC_SET_NOW + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_INIT: + LD DE,RTC_TOP_LOOP1_INIT + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL RTC_INIT_NOW + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_TIME: + LD DE,RTC_TOP_LOOP1_TIME + LD C,09H ; CP/M write string to console call + CALL 0005H + CALL RTC_GET_TIME + LD DE,RTC_PRINT_BUFFER + LD C,09H ; CP/M write string to console call + CALL 0005H + LD A,(FCB+1) ; If we came from the + CP '/' ; command line + RET Z ; exit back to CP/M + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_RAW: + LD DE,RTC_TOP_LOOP1_RAW + LD C,09H ; CP/M write string to console call + CALL 0005H +RTC_TOP_LOOP_RAW1: + +; { Read seconds } + LD D,$00 ; seconds register in DS1302 + CALL RTC_READ ; read value from DS1302, value is in Reg C + + ; digit 16 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $07 + ADD A,'0' + LD (RTC_PRINT_BUFFER+15),A + + ; digit 17 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+16),A + +; { Read minutes } + + LD D,$01 ; minutes register in DS1302 + CALL RTC_READ ; read value from DS1302, value is in Reg C + + ; digit 13 + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $07 + ADD A,'0' + LD (RTC_PRINT_BUFFER+12),A + + ; digit 14 + LD A,C ; put value output in Reg C into accumulator + AND $0F + ADD A,'0' + LD (RTC_PRINT_BUFFER+13),A + + ; digit 15 + LD A,':' + LD (RTC_PRINT_BUFFER+14),A + + ; digits 1-12 and 18-20 are spaces + LD A,' ' ; space + LD (RTC_PRINT_BUFFER+19),A + LD (RTC_PRINT_BUFFER+18),A + LD (RTC_PRINT_BUFFER+17),A + LD (RTC_PRINT_BUFFER+11),A + LD (RTC_PRINT_BUFFER+10),A + LD (RTC_PRINT_BUFFER+09),A + LD (RTC_PRINT_BUFFER+08),A + LD (RTC_PRINT_BUFFER+07),A + LD (RTC_PRINT_BUFFER+06),A + LD (RTC_PRINT_BUFFER+05),A + LD (RTC_PRINT_BUFFER+04),A + LD (RTC_PRINT_BUFFER+03),A + LD (RTC_PRINT_BUFFER+02),A + LD (RTC_PRINT_BUFFER+01),A + LD (RTC_PRINT_BUFFER+00),A + + LD DE,RTC_PRINT_BUFFER + LD C,09H ; CP/M write string to console call + CALL 0005H + + LD C,01H ; CP/M console input call + CALL 0005H + + CP ' ' ; space + JP Z,RTC_TOP_LOOP_RAW1 + + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_LOOP: + LD DE,RTC_TOP_LOOP1_LOOP + LD C,09H ; CP/M write string to console call + CALL 0005H + +RTC_TOP_LOOP_LOOP1: + CALL RTC_GET_TIME + + LD DE,RTC_PRINT_BUFFER + LD C,09H ; CP/M write string to console call + CALL 0005H + + LD C,01H ; CP/M console input call + CALL 0005H + + CP ' ' + JP Z,RTC_TOP_LOOP_LOOP1 + + JP RTC_TOP_LOOP_1 + +RTC_TOP_LOOP_PUT: + LD A,$01 ; set PUT as true + LD (GET_PUT),A +RTC_TOP_LOOP_GET: + LD DE,RTC_TOP_LOOP1_GET + LD C,09H ; CP/M write string to console call + CALL 0005H + + CALL HEXIN ; read NVRAM address + LD (PUT_ADR),A ; store for possible PUT later + +; { Read NVRAM address } + LD D,A ; seconds register in DS1302 + CALL RTC_READ ; read value from DS1302, value is in Reg C + + ; first digit + LD A,C ; put value output in Reg C into accumulator + RLC A + RLC A + RLC A + RLC A + AND $0F + CP 0AH ;TEST FOR NUMERIC & convert to ASCII + JR C,NUM1 ;if not ALPHA, its numeric and skip + ADD A,$07 + +NUM1: ADD A,'0' + LD (RTC_GET_BUFFER),A + + ; second digit + LD A,C ; put value output in Reg C into accumulator + AND $0F + CP 0AH ;TEST FOR NUMERIC & convert to ASCII + JR C,NUM2 ;if not ALPHA, its numeric and skip + ADD A,$07 + +NUM2: ADD A,'0' + LD (RTC_GET_BUFFER+1),A + + LD DE,CRLF_MSG + LD C,09H ; CP/M write string to console call + CALL 0005H + + LD DE,RTC_GET_BUFFER + LD C,09H ; CP/M write string to console call + CALL 0005H + + LD A,(GET_PUT) ; check if GET or PUT mode + CP $00 + JP Z,RTC_GET_PUT_EXIT ; if GET mode, exit + + LD DE,RTC_TOP_LOOP1_PUT + LD C,09H ; CP/M write string to console call + CALL 0005H + +; { Write NVRAM address } + + CALL RTC_WR_UNPROTECT + + CALL HEXIN ; read NVRAM address + LD E,A ; new data for NVRAM register in DS1302 + LD A,(PUT_ADR) + LD D,A ; load address from before + + CALL RTC_WRITE ; read value from DS1302, value is in Reg C + + CALL RTC_WR_PROTECT + +RTC_GET_PUT_EXIT: + LD A,$00 ; reset GET mode + LD (GET_PUT),A + JP RTC_TOP_LOOP_1 + +; +; Text Strings +; + +MSG: + .TEXT "Start RTC Program" +CRLF_MSG: + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +TESTING_BIT_DELAY_MSG: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Testing bit delay. Successful test is ~43 sec." + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Start clock and press space bar." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +TESTING_BIT_DELAY_OVER: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Test complete. Stop clock." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_HELP_MSG: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "RTC: Version 1.9" + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Commands: E)xit T)ime st(A)rt S)et R)aw L)oop C)harge N)ocharge D)elay I)nit G)et P)ut B)oot W)arm-start H)elp" + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_PROMPT: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "RTC>" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_CHARGE: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Trickle charger enabled." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_NOCHARGE: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Trickle charger disabled." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_START: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Restart RTC." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_TIME: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Current time: " + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_RAW: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Raw read Loop. Press SPACE BAR for next." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_LOOP: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Clock Loop. Press SPACE BAR for next." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_SET: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Set RTC time." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Init date/time." + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_GET: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "Get NVRAM addr:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_PUT: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "NVRAM data:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_SECONDS: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "SECONDS:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_MINUTES: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "MINUTES:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_HOURS: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "HOURS:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_DATE: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "DATE:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_MONTH: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "MONTH:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_DAY: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "DAY:" + .DB "$" ; Line terminator + +RTC_TOP_LOOP1_INIT_YEAR: + .DB 0Ah, 0Dh ; line feed and carriage return + .TEXT "YEAR:" + .DB "$" ; Line terminator + +RTC_PRINT_BUFFER: + .FILL 20,0 ; Buffer for formatted date & time to print + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; line terminator + +RTC_GET_BUFFER: + .FILL 2,0 ; Buffer for formatted NVRAM data to print + .DB 0Ah, 0Dh ; line feed and carriage return + .DB "$" ; line terminator + +BIOERR .TEXT "\r\nUnknown BIOS, aborting...\r\n$" +PLTERR .TEXT "\r\n\r\nUnknown/unsupported hardware platform, aborting...\r\n$" +UBERR .TEXT "\r\nUNA UBIOS is not currently supported, aborting...\r\n$" +HBTAG .TEXT "RomWBW HBIOS$" +UBTAG .TEXT "UNA UBIOS" +BOOTMSG .TEXT "\r\n\r\nRebooting...$" +PLT_SBC .TEXT ", SBC/Zeta RTC Latch Port 0x70\r\n$" +PLT_N8 .TEXT ", N8 RTC Latch Port 0x88\r\n$" +PLT_MK4 .TEXT ", Mark 4 RTC Latch Port 0x8A\r\n$" +PLT_RCZ80 .TEXT ", RCBus Z80 RTC Module Latch Port 0xC0\r\n$" +PLT_RCZ180 .TEXT ", RCBus Z180 RTC Module Latch Port 0x0C\r\n$" +PLT_EZZ80 .TEXT ", Easy Z80 RTC Module Latch Port 0xC0\r\n$" +PLT_SCZ180 .TEXT ", SC Z180 RTC Module Latch Port 0x0C\r\n$" +PLT_DYNO .TEXT ", DYNO RTC Module Latch Port 0x0C\r\n$" +PLT_RCZ280 .TEXT ", RCBus Z280 RTC Module Latch Port 0xC0\r\n$" +PLT_MBC .TEXT ", MBC RTC Latch Port 0x70\r\n$" +PLT_RPH .TEXT ", RHYOPHYRE RTC Latch Port 0x84\r\n$" +PLT_DUO .TEXT ", DUODYNE RTC Latch Port 0x70\r\n$" +PLT_STDZ180 .TEXT ", STD Z180 RTC Module latch port 0x84\r\n$" + +; +; Generic FOR-NEXT loop algorithm +; +; LD A,$00 ; set A=0 index counter of FOR loop +;FOR_LOOP: +; PUSH AF ; save accumulator as it is the index counter in FOR loop +; { contents of FOR loop here } ; setup RTC with RST and RD high, SCLK low +; POP AF ; recover accumulator as it is the index counter in FOR loop +; INC A ; increment A in FOR loop (A=A+1) +; CP $08 ; is A < $08 ? +; JP NZ,FOR_LOOP ; No, do FOR loop again +; RET ; Yes, end function and return. Read RTC value is in C + +YEAR .DB $18 +MONTH .DB $11 +DATE .DB $08 +HOURS .DB $00 +MINUTES .DB $00 +SECONDS .DB $00 +DAY .DB $05 +GET_PUT .DB $00 + +PUT_ADR .DB 0 + + .END + diff --git a/Source/Apps/slabel/slabel.asm b/Source/Apps/slabel/slabel.asm index c17ff828..e899e894 100644 --- a/Source/Apps/slabel/slabel.asm +++ b/Source/Apps/slabel/slabel.asm @@ -68,7 +68,7 @@ bf_sysreset .equ $F0 ; restart system bf_sysres_int .equ $00 ; reset hbios internal bf_sysres_warm .equ $01 ; warm start (restart boot loader) ; -ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr +ident .equ $FFFC ; loc of RomWBW HBIOS ident ptr ; sigbyte1 .equ $A5 ; 1st sig byte boot info sector (bb_sig) sigbyte2 .equ $5A ; 2nd sig byte boot info sector (bb_sig) diff --git a/Source/Apps/startup/startup.asm b/Source/Apps/startup/startup.asm index 2e902fa6..e5416827 100644 --- a/Source/Apps/startup/startup.asm +++ b/Source/Apps/startup/startup.asm @@ -1,399 +1,399 @@ -;=============================================================================== -; STARTUP - Application run automatically at OS startup -; -;=============================================================================== -; -; Author: Wayne Warthen (wwarthen@gmail.com) -;_______________________________________________________________________________ -; -; Usage: -; MODE [/?] -; -; Operation: -; Determines if STARTUP.CMD exists on startup drive, user 0. If it is -; found, it is run via SUBMIT. -;_______________________________________________________________________________ -; -; Change Log: -; 2017-12-01 [WBW] Initial release -;_______________________________________________________________________________ -; -; ToDo: -; 1) Detect OS type (CP/M or ZSYS) and run different batch files as a result. -;_______________________________________________________________________________ -; -;=============================================================================== -; Definitions -;=============================================================================== -; -stksiz .equ $40 ; Working stack size -; -restart .equ $0000 ; CP/M restart vector -bdos .equ $0005 ; BDOS invocation vector -; -ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr -; -rmj .equ 2 ; intended CBIOS version - major -rmn .equ 9 ; intended CBIOS version - minor -; -bf_cioinit .equ $04 ; HBIOS: CIOINIT function -bf_cioquery .equ $05 ; HBIOS: CIOQUERY function -bf_ciodevice .equ $06 ; HBIOS: CIODEVICE function -bf_sysget .equ $F8 ; HBIOS: SYSGET function -; -;=============================================================================== -; Code Section -;=============================================================================== -; - .org $100 -; - ; setup stack (save old value) - ld (stksav),sp ; save stack - ld sp,stack ; set new stack -; - ; initialization - call init ; initialize - jr nz,exit ; abort if init fails -; - ; process - call process ; do main processing - jr nz,exit ; abort on error -; -exit: ; clean up and return to command processor - call crlf ; formatting - ld sp,(stksav) ; restore stack - ;jp restart ; return to CP/M via restart - ret ; return to CP/M w/o restart -; -; Initialization -; -init: -; -initx - ; initialization complete - xor a ; signal success - ret ; return -; -; Process -; -process: - ; skip to start of first parm - ld ix,$81 ; point to start of parm area (past len byte) - call nonblank ; skip to next non-blank char - jp z,runcmd ; no parms, do command processing -; -process1: - ; process options (if any) - cp '/' ; option prefix? - jp nz,erruse ; invalid option introducer - call option ; process option - ret nz ; some options mean we are done (e.g., "/?") - inc ix ; skip option character - call nonblank ; skip whitespace - jr nz,process1 ; continue option checking - jp runcmd ; end of parms, do cmd processing -; -; -; -runcmd: - call ldfil ; load executable - ret nz ; abort on error -; - xor a - ret -; -; Load file for execution -; -ldfil: - ld c,15 ; BDOS function: Open File - ld de,fcb ; pointer to FCB - call bdos ; do it - inc a ; check for err, 0xFF --> 0x00 - jp z,errfil ; handle file not found err -; - ld c,16 ; BDOS function: Close File - ld de,fcb ; pointer to FCB - call bdos ; do it - inc a ; check for err, 0xFF --> 0x00 - jp z,errfil ; handle file close err -; - xor a ; signal success - ret ; done - - -; -; Handle options -; -option: -; - inc ix ; next char - ld a,(ix) ; get it - cp '?' ; is it a '?' as expected? - jp z,usage ; yes, display usage - jp errprm ; anything else is an error -; -; Display usage -; -usage: -; - call crlf ; formatting - ld de,msgban ; point to version message part 1 - call prtstr ; print it - call crlf2 ; blank line - ld de,msguse ; point to usage message - call prtstr ; print it - or $FF ; signal no action performed - ret ; and return -; -; Print character in A without destroying any registers -; -prtchr: - push bc ; save registers - push de - push hl - ld e,a ; character to print in E - ld c,$02 ; BDOS function to output a character - call bdos ; do it - pop hl ; restore registers - pop de - pop bc - ret -; -prtdot: -; - ; shortcut to print a dot preserving all regs - push af ; save af - ld a,'.' ; load dot char - call prtchr ; print it - pop af ; restore af - ret ; done -; -; Print a zero terminated string at (DE) without destroying any registers -; -prtstr: - push de -; -prtstr1: - ld a,(de) ; get next char - or a - jr z,prtstr2 - call prtchr - inc de - jr prtstr1 -; -prtstr2: - pop de ; restore registers - ret -; -; Print the value in A in hex without destroying any registers -; -prthex: - push af ; save AF - push de ; save DE - call hexascii ; convert value in A to hex chars in DE - ld a,d ; get the high order hex char - call prtchr ; print it - ld a,e ; get the low order hex char - call prtchr ; print it - pop de ; restore DE - pop af ; restore AF - ret ; done -; -; print the hex word value in bc -; -prthexword: - push af - ld a,b - call prthex - ld a,c - call prthex - pop af - ret -; -; print the hex dword value in de:hl -; -prthex32: - push bc - push de - pop bc - call prthexword - push hl - pop bc - call prthexword - pop bc - ret -; -; Convert binary value in A to ascii hex characters in DE -; -hexascii: - ld d,a ; save A in D - call hexconv ; convert low nibble of A to hex - ld e,a ; save it in E - ld a,d ; get original value back - rlca ; rotate high order nibble to low bits - rlca - rlca - rlca - call hexconv ; convert nibble - ld d,a ; save it in D - ret ; done -; -; Convert low nibble of A to ascii hex -; -hexconv: - and $0F ; low nibble only - add a,$90 - daa - adc a,$40 - daa - ret -; -; Print value of A or HL in decimal with leading zero suppression -; Use prtdecb for A or prtdecw for HL -; -prtdecb: - push hl - ld h,0 - ld l,a - call prtdecw ; print it - pop hl - ret -; -prtdecw: - push af - push bc - push de - push hl - call prtdec0 - pop hl - pop de - pop bc - pop af - ret -; -prtdec0: - ld e,'0' - ld bc,-10000 - call prtdec1 - ld bc,-1000 - call prtdec1 - ld bc,-100 - call prtdec1 - ld c,-10 - call prtdec1 - ld e,0 - ld c,-1 -prtdec1: - ld a,'0' - 1 -prtdec2: - inc a - add hl,bc - jr c,prtdec2 - sbc hl,bc - cp e - ret z - ld e,0 - call prtchr - ret -; -; Start a new line -; -crlf2: - call crlf ; two of them -crlf: - push af ; preserve AF - ld a,13 ; - call prtchr ; print it - ld a,10 ; - call prtchr ; print it - pop af ; restore AF - ret -; -; Get the next non-blank character from (HL). -; -nonblank: - ld a,(ix) ; load next character - or a ; string ends with a null - ret z ; if null, return pointing to null - cp ' ' ; check for blank - ret nz ; return if not blank - inc ix ; if blank, increment character pointer - jr nonblank ; and loop -; -; Convert character in A to uppercase -; -ucase: - cp 'a' ; if below 'a' - ret c ; ... do nothing and return - cp 'z' + 1 ; if above 'z' - ret nc ; ... do nothing and return - res 5,a ; clear bit 5 to make lower case -> upper case - ret ; and return -; -; Add the value in A to HL (HL := HL + A) -; -addhl: - add a,l ; A := A + L - ld l,a ; Put result back in L - ret nc ; if no carry, we are done - inc h ; if carry, increment H - ret ; and return -; -; Jump indirect to address in HL -; -jphl: - jp (hl) -; -; Errors -; -erruse: ; command usage error (syntax) - ld de,msguse - jr err -; -errprm: ; command parameter error (syntax) - ld de,msgprm - jr err -; -errfil: ; STARTUP.CMD file not present - ld de,msgfil - jr err -; -err: ; print error string and return error signal - call crlf ; print newline -; -err1: ; without the leading crlf - call prtstr ; print error string -; -err2: ; without the string -; call crlf ; print newline - or $FF ; signal error - ret ; done -; -;=============================================================================== -; Storage Section -;=============================================================================== -; -fcb .db 0 ; Drive code, 0 = current drive - .db "START " ; File name, 8 chars - .db "COM" ; File type, 3 chars - .fill 36-($-fcb),0 ; zero fill remainder of fcb -; -cmdblk .db cmdlen ; length -cmdtxt .db " B:SUBMIT START" - .db 0 ; null terminator -cmdlen .equ $ - cmdtxt -cmdend .equ $ -; -stksav .dw 0 ; stack pointer saved at start - .fill stksiz,0 ; stack -stack .equ $ ; stack top -; -; Messages -; -msgban .db "STARTUP v1.0, 01-Dec-2017",13,10 - .db "Copyright (C) 2017, Wayne Warthen, GNU GPL v3",0 -msguse .db "Usage: STARTUP [/?]",0 -msgprm .db "Parameter error (STARTUP /? for usage)",0 -msgfil .db "STARTUP.CMD file missing",0 -; - .end +;=============================================================================== +; STARTUP - Application run automatically at OS startup +; +;=============================================================================== +; +; Author: Wayne Warthen (wwarthen@gmail.com) +;_______________________________________________________________________________ +; +; Usage: +; MODE [/?] +; +; Operation: +; Determines if STARTUP.CMD exists on startup drive, user 0. If it is +; found, it is run via SUBMIT. +;_______________________________________________________________________________ +; +; Change Log: +; 2017-12-01 [WBW] Initial release +;_______________________________________________________________________________ +; +; ToDo: +; 1) Detect OS type (CP/M or ZSYS) and run different batch files as a result. +;_______________________________________________________________________________ +; +;=============================================================================== +; Definitions +;=============================================================================== +; +stksiz .equ $40 ; Working stack size +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +ident .equ $FFFC ; loc of RomWBW HBIOS ident ptr +; +rmj .equ 2 ; intended CBIOS version - major +rmn .equ 9 ; intended CBIOS version - minor +; +bf_cioinit .equ $04 ; HBIOS: CIOINIT function +bf_cioquery .equ $05 ; HBIOS: CIOQUERY function +bf_ciodevice .equ $06 ; HBIOS: CIODEVICE function +bf_sysget .equ $F8 ; HBIOS: SYSGET function +; +;=============================================================================== +; Code Section +;=============================================================================== +; + .org $100 +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +; + ; process + call process ; do main processing + jr nz,exit ; abort on error +; +exit: ; clean up and return to command processor + call crlf ; formatting + ld sp,(stksav) ; restore stack + ;jp restart ; return to CP/M via restart + ret ; return to CP/M w/o restart +; +; Initialization +; +init: +; +initx + ; initialization complete + xor a ; signal success + ret ; return +; +; Process +; +process: + ; skip to start of first parm + ld ix,$81 ; point to start of parm area (past len byte) + call nonblank ; skip to next non-blank char + jp z,runcmd ; no parms, do command processing +; +process1: + ; process options (if any) + cp '/' ; option prefix? + jp nz,erruse ; invalid option introducer + call option ; process option + ret nz ; some options mean we are done (e.g., "/?") + inc ix ; skip option character + call nonblank ; skip whitespace + jr nz,process1 ; continue option checking + jp runcmd ; end of parms, do cmd processing +; +; +; +runcmd: + call ldfil ; load executable + ret nz ; abort on error +; + xor a + ret +; +; Load file for execution +; +ldfil: + ld c,15 ; BDOS function: Open File + ld de,fcb ; pointer to FCB + call bdos ; do it + inc a ; check for err, 0xFF --> 0x00 + jp z,errfil ; handle file not found err +; + ld c,16 ; BDOS function: Close File + ld de,fcb ; pointer to FCB + call bdos ; do it + inc a ; check for err, 0xFF --> 0x00 + jp z,errfil ; handle file close err +; + xor a ; signal success + ret ; done + + +; +; Handle options +; +option: +; + inc ix ; next char + ld a,(ix) ; get it + cp '?' ; is it a '?' as expected? + jp z,usage ; yes, display usage + jp errprm ; anything else is an error +; +; Display usage +; +usage: +; + call crlf ; formatting + ld de,msgban ; point to version message part 1 + call prtstr ; print it + call crlf2 ; blank line + ld de,msguse ; point to usage message + call prtstr ; print it + or $FF ; signal no action performed + ret ; and return +; +; Print character in A without destroying any registers +; +prtchr: + push bc ; save registers + push de + push hl + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it + pop hl ; restore registers + pop de + pop bc + ret +; +prtdot: +; + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print a zero terminated string at (DE) without destroying any registers +; +prtstr: + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + ret +; +; Print the value in A in hex without destroying any registers +; +prthex: + push af ; save AF + push de ; save DE + call hexascii ; convert value in A to hex chars in DE + ld a,d ; get the high order hex char + call prtchr ; print it + ld a,e ; get the low order hex char + call prtchr ; print it + pop de ; restore DE + pop af ; restore AF + ret ; done +; +; print the hex word value in bc +; +prthexword: + push af + ld a,b + call prthex + ld a,c + call prthex + pop af + ret +; +; print the hex dword value in de:hl +; +prthex32: + push bc + push de + pop bc + call prthexword + push hl + pop bc + call prthexword + pop bc + ret +; +; Convert binary value in A to ascii hex characters in DE +; +hexascii: + ld d,a ; save A in D + call hexconv ; convert low nibble of A to hex + ld e,a ; save it in E + ld a,d ; get original value back + rlca ; rotate high order nibble to low bits + rlca + rlca + rlca + call hexconv ; convert nibble + ld d,a ; save it in D + ret ; done +; +; Convert low nibble of A to ascii hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Get the next non-blank character from (HL). +; +nonblank: + ld a,(ix) ; load next character + or a ; string ends with a null + ret z ; if null, return pointing to null + cp ' ' ; check for blank + ret nz ; return if not blank + inc ix ; if blank, increment character pointer + jr nonblank ; and loop +; +; Convert character in A to uppercase +; +ucase: + cp 'a' ; if below 'a' + ret c ; ... do nothing and return + cp 'z' + 1 ; if above 'z' + ret nc ; ... do nothing and return + res 5,a ; clear bit 5 to make lower case -> upper case + ret ; and return +; +; Add the value in A to HL (HL := HL + A) +; +addhl: + add a,l ; A := A + L + ld l,a ; Put result back in L + ret nc ; if no carry, we are done + inc h ; if carry, increment H + ret ; and return +; +; Jump indirect to address in HL +; +jphl: + jp (hl) +; +; Errors +; +erruse: ; command usage error (syntax) + ld de,msguse + jr err +; +errprm: ; command parameter error (syntax) + ld de,msgprm + jr err +; +errfil: ; STARTUP.CMD file not present + ld de,msgfil + jr err +; +err: ; print error string and return error signal + call crlf ; print newline +; +err1: ; without the leading crlf + call prtstr ; print error string +; +err2: ; without the string +; call crlf ; print newline + or $FF ; signal error + ret ; done +; +;=============================================================================== +; Storage Section +;=============================================================================== +; +fcb .db 0 ; Drive code, 0 = current drive + .db "START " ; File name, 8 chars + .db "COM" ; File type, 3 chars + .fill 36-($-fcb),0 ; zero fill remainder of fcb +; +cmdblk .db cmdlen ; length +cmdtxt .db " B:SUBMIT START" + .db 0 ; null terminator +cmdlen .equ $ - cmdtxt +cmdend .equ $ +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +; Messages +; +msgban .db "STARTUP v1.0, 01-Dec-2017",13,10 + .db "Copyright (C) 2017, Wayne Warthen, GNU GPL v3",0 +msguse .db "Usage: STARTUP [/?]",0 +msgprm .db "Parameter error (STARTUP /? for usage)",0 +msgfil .db "STARTUP.CMD file missing",0 +; + .end diff --git a/Source/Apps/timer/timer.asm b/Source/Apps/timer/timer.asm index ae5d67f8..7d428bb3 100644 --- a/Source/Apps/timer/timer.asm +++ b/Source/Apps/timer/timer.asm @@ -1,805 +1,805 @@ -;=============================================================================== -; TIMER - Display system timer value -; Version 1.31 24-July-2024 -;=============================================================================== -; -; Author: Wayne Warthen (wwarthen@gmail.com) -; Updated: MartinR (July 2024) - A user of uppercase mnemonics -;_______________________________________________________________________________ -; -; Usage: -; TIMER [/C] [/?] -; ex: TIMER (display current timer value) -; TIMER /? (display version and usage) -; TIMER /C (display timer value continuously) -; -; Operation: -; Reads and displays system timer value. -; -; This code will only execute on a Z80 CPU (or derivitive) -; -; This source code assembles with TASM V3.2 under Windows-11 using the -; following command line: -; tasm -80 -g3 -l TIMER.ASM TIMER.COM -; ie: Z80 CPU; output format 'binary' named .COM (rather than .OBJ) -; and includes a symbol table as part of the listing file. -;_______________________________________________________________________________ -; -; Change Log: -; 2018-01-14 [WBW] Initial release -; 2018-01-17 [WBW] Add HBIOS check -; 2019-11-08 [WBW] Add seconds support -; 2024-06-30 [MR ] Display values in decimal rather than hexadecimal -; 2024-07-24 [MR ] Also display value in Hours-Mins-Secs format -;_______________________________________________________________________________ -; -; Includes binary-to-decimal subroutine by Alwin Henseler -; Located at: https://www.msx.org/forum/development/msx-development/32-bit-long-ascii -;_______________________________________________________________________________ -; -; Includes division subroutines from: https://wikiti.brandonw.net/ -;;_______________________________________________________________________________ -; -#include "../../ver.inc" ; Used for building RomWBW -;#include "ver.inc" ; Used for testing purposes during code development -; -;=============================================================================== -; Definitions -;=============================================================================== -; -STKSIZ .EQU $40 ; Working stack size -; -RESTART .EQU $0000 ; CP/M restart vector -BDOS .EQU $0005 ; BDOS invocation vector -; -IDENT .EQU $FFFE ; loc of RomWBW HBIOS ident ptr -; -BF_SYSVER .EQU $F1 ; BIOS: VER function -BF_SYSGET .EQU $F8 ; HBIOS: SYSGET function -BF_SYSSET .EQU $F9 ; HBIOS: SYSSET function -BF_SYSGETTIMER .EQU $D0 ; TIMER subfunction -BF_SYSSETTIMER .EQU $D0 ; TIMER subfunction -BF_SYSGETSECS .EQU $D1 ; SECONDS subfunction -BF_SYSSETSECS .EQU $D1 ; SECONDS subfunction -; -;ASCII Control Characters -LF .EQU 00AH ; Line Feed -CR .EQU 00DH ; Carriage Return -; -;=============================================================================== -; Code Section -;=============================================================================== -; - .ORG $100 -; - ; setup stack (save old value) - LD (STKSAV),SP ; save stack - LD SP,STACK ; set new stack -; - ; initialization - CALL INIT ; initialize - JR NZ,EXIT ; abort if init fails -; - ; process - CALL PROCESS ; do main processing - JR NZ,EXIT ; abort on error -; -EXIT: ; clean up and return to command processor - CALL CRLF ; formatting - LD SP,(STKSAV) ; restore stack - ;JP RESTART ; return to CP/M via restart - RET ; return to CP/M w/o restart -; -; Initialization -; -INIT: - CALL CRLF ; formatting - LD DE,MSGBAN ; point to version message part 1 - CALL PRTSTR ; print it -; - CALL IDBIO ; identify active BIOS - CP 1 ; check for HBIOS - JP NZ,ERRBIO ; handle BIOS error -; - LD A,RMJ << 4 | RMN ; expected HBIOS ver - CP D ; compare with result above - JP NZ,ERRBIO ; handle BIOS error -; -INITX: - ; initialization complete - XOR A ; signal success - RET ; return -; -; Process -; -PROCESS: - ; look for start of parms - LD HL,$81 ; point to start of parm area (past len byte) -; -PROCESS00: - CALL NONBLANK ; skip to next non-blank char - JP Z,PROCESS0 ; no more parms, go to display -; - ; check for option, introduced by a "/" - CP '/' ; start of options? - JP NZ,USAGE ; yes, handle option - CALL OPTION ; do option processing - RET NZ ; done if non-zero return - JR PROCESS00 ; continue looking for options -; -PROCESS0: -; - ; Test of API function to set seconds value - ;LD B,BF_SYSSET ; HBIOS SYSGET function - ;LD C,BF_SYSSETSECS ; SECONDS subfunction - ;LD DE,0 ; set seconds value - ;LD HL,1000 ; ... to 1000 - ;RST 08 ; call HBIOS, DE:HL := seconds value -; - ; get and print seconds value - CALL CRLF2 ; formatting -; -PROCESS1: - LD B,BF_SYSGET ; HBIOS SYSGET function - LD C,BF_SYSGETTIMER ; TIMER subfunction - RST 08 ; call HBIOS, DE:HL := timer value - - LD A,(FIRST) - OR A - LD A,0 - LD (FIRST),A - JR NZ,PROCESS1A - - ; TEST FOR NEW VALUE - LD A,(LAST) ; last LSB value to A - CP L ; compare to current LSB - JP Z,PROCESS2 ; if equal, bypass display - -;******************************************************************************* -;******************************************************************************* - -; Formatting code added/amended to print values in decimal and Hours-Mins-Secs -; MartinR June & July-2024 - -PROCESS1A: -; Save and print new value - LD A,L ; new LSB value to A - LD (LAST),A ; save as last value - CALL PRTCR ; back to start of line - - CALL B2D32 ; Convert DE:HL into ASCII; Start of ASCII buffer returned in HL - EX DE,HL - CALL PRTSTR ; Display the value - - LD DE,STRTICK ; "Ticks" message - CALL PRTSTR ; Display it - -; Get and print seconds value in decimal - - LD B,BF_SYSGET ; HBIOS SYSGET function - LD C,BF_SYSGETSECS ; SECONDS subfunction - RST 08 ; Call HBIOS; DE:HL := seconds value; C := fractional part - - LD (SEC_MS),DE ; Store the most significant part of the 'seconds' value - LD (SEC_LS),HL ; And the less significant...... - LD A,C ; And also the fractional part - SLA A ; But double the 50Hz 'ticks' value to give 1/100ths of a second - LD (SEC_FR),A - - CALL B2D32 ; Convert DE:HL into ASCII; Start of ASCII buffer returned in HL - EX DE,HL - CALL PRTSTR ; Display the value - - CALL PRTDOT ; Print a '.' seperator - - LD A,(SEC_FR) ; Retrieve fractional part (1/100ths second) - CALL B2D8 ; Convert into ASCII - up to 3 digits. Umber of digits returned C - CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string - EX DE,HL ; Start of ASCII buffer returned in HL - CALL PRTSTR ; Display fractional part of the value - - LD DE,STRSEC ; "Seconds" message - CALL PRTSTR ; Display it - -; Now print the seconds value as HMS - - LD BC,(SEC_MS) ; Retrive the 'seconds' value into AC:IX - LD A,B - LD IX,(SEC_LS) - LD DE,3600 ; 3600 seconds in an hour - CALL DIV32BY16 ; AC:IX divided by DE; Answer in AC:IX; Remainder in HL - - PUSH HL ; Preserve the remainder on the stack - - LD D,A ; Shuffle registers around ready for conversion to ASCII - LD A,C ; AC:IX into DE:HL - LD E,A - PUSH IX - POP HL - - CALL B2D32 ; Convert DE:HL into ASCII; Start of ASCII buffer returned in HL - EX DE,HL - CALL PRTSTR ; Display the hours value - - CALL PRTCOLON ; Print a ':' seperator - - POP HL ; Retrive the remainder (seconds) - - LD C,60 ; 60 seconds in a minute - CALL DIV_HL_C ; HL divided by C; Answer in HL; Remainder in A - - PUSH AF ; Preserve the remainder (seconds) on the stack - - CALL B2D16 ; Convert HL into ASCII; Start of ASCII buffer returned in HL; Count in C - CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string - EX DE,HL - CALL PRTSTR ; Display the minutes value - - CALL PRTCOLON ; Print a ':' seperator - - POP AF ; Retrive the remainder (seconds) - - CALL B2D8 ; Convert A into ASCII; Start of ASCII buffer returned in HL; Count in C - CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string - EX DE,HL - CALL PRTSTR ; Display the seconds value - - CALL PRTDOT ; Print a '.' seperator - - LD A,(SEC_FR) ; Retrieve the fractional part (1/100ths) of the seconds - CALL B2D8 ; Convert A into ASCII; Start of ASCII buffer returned in HL - CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string - EX DE,HL - CALL PRTSTR ; Display the value - - LD DE,STRHMS ; Print "HH:MM:SS" message - CALL PRTSTR - -;******************************************************************************* -;******************************************************************************* - -PROCESS2: - LD A,(CONT) ; continuous display? - OR A ; test for true/false - JR Z,PROCESS3 ; if false, get out -; - LD C,6 ; BDOS: direct console I/O - LD E,$FF ; input char - CALL BDOS ; call BDOS, A := char - OR A ; test for zero - JP Z,PROCESS1 ; loop until char pressed -; -PROCESS3: - XOR A ; signal success - RET -; -; Handle special options -; -OPTION: - INC HL ; next char - LD A,(HL) ; get it - OR A ; zero terminator? - RET Z ; done if so - CP ' ' ; blank? - RET Z ; done if so - CP '?' ; is it a '?'? - JP Z,USAGE ; yes, display usage - CP 'C' ; is it a 'C', continuous? - JP Z,SETCONT ; yes, set continuous display - JP ERRPRM ; anything else is an error -; -USAGE: - JP ERRUSE ; display usage and get out -; -SETCONT: -; - OR $FF ; SET A TO TRUE - LD (CONT),A ; AND SET CONTINUOUS FLAG - JR OPTION ; CHECK FOR MORE OPTION LETTERS -; -; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 -; -IDBIO: -; - ; CHECK FOR UNA (UBIOS) - LD A,($FFFD) ; fixed location of UNA API vector - CP $C3 ; jp instruction? - JR NZ,IDBIO1 ; 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,IDBIO1 ; 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,IDBIO1 ; if not, not UNA, check others -; - LD BC,$04FA ; UNA: get BIOS date and version - RST 08 ; DE := ver, HL := date -; - LD A,2 ; UNA BIOS id = 2 - RET ; and done -; -IDBIO1: - ; Check for RomWBW (HBIOS) - LD HL,($FFFE) ; HL := HBIOS ident location - LD A,'W' ; First byte of ident - CP (HL) ; Compare - JR NZ,IDBIO2 ; Not HBIOS - INC HL ; Next byte of ident - LD A,~'W' ; Second byte of ident - CP (HL) ; Compare - JR NZ,IDBIO2 ; Not HBIOS -; - LD B,BF_SYSVER ; HBIOS: VER function - LD C,0 ; required reserved value - RST 08 ; DE := version, L := platform id -; - LD A,1 ; HBIOS BIOS id = 1 - RET ; and done -; -IDBIO2: - ; No idea what this is - XOR A ; Setup return value of 0 - RET ; and done -; -; Print character in A without destroying any registers -; -PRTCHR: - PUSH BC ; save registers - PUSH DE - PUSH HL - LD E,A ; character to print in E - LD C,$02 ; BDOS function to output a character - CALL BDOS ; do it - POP HL ; restore registers - POP DE - POP BC - RET -; -; Print a 0 if C=1 -; -PRT_LEAD0: - DEC C ; Decrement C, and a value of 1 becomee zero - RET NZ ; If C wasn't 1, then no leading space required - LD A,'0' ; Print the leading zero - JR Z,PRTCHR -; -PRTDOT: -; - ; shortcut to print a dot preserving all regs - PUSH AF ; save af - LD A,'.' ; load dot char - CALL PRTCHR ; print it - POP AF ; restore af - RET ; done -; -PRTCOLON: -; - ; shortcut to print a colon preserving all regs - PUSH AF ; save af - LD A,':' ; load colon char - CALL PRTCHR ; print it - POP AF ; restore af - RET ; done -; -PRTCR: -; - ; shortcut to print a CR preserving all regs - PUSH AF ; save af - LD A,13 ; load CR value - CALL PRTCHR ; print it - POP AF ; restore af - RET ; done -; -; Print a zero terminated string at (DE) without destroying any registers -; -PRTSTR: - PUSH DE -; -PRTSTR1: - LD A,(DE) ; get next char - OR A - JR Z,PRTSTR2 - CALL PRTCHR - INC DE - JR PRTSTR1 -; -PRTSTR2: - POP DE ; restore registers - RET -; -; Print the value in A in hex without destroying any registers -; -PRTHEX: - PUSH AF ; save AF - PUSH DE ; save DE - CALL HEXASCII ; convert value in A to hex chars in DE - LD A,D ; get the high order hex char - CALL PRTCHR ; print it - LD A,E ; get the low order hex char - CALL PRTCHR ; print it - POP DE ; restore DE - POP AF ; restore AF - RET ; done -; -; print the hex word value in bc -; -PRTHEXWORD: - PUSH AF - LD A,B - CALL PRTHEX - LD A,C - CALL PRTHEX - POP AF - RET -; -; print the hex dword value in de:hl -; -PRTHEX32: - PUSH BC - PUSH DE - POP BC - CALL PRTHEXWORD - PUSH HL - POP BC - CALL PRTHEXWORD - POP BC - RET -; -; Convert binary value in A to ascii hex characters in DE -; -HEXASCII: - LD D,A ; save A in D - CALL HEXCONV ; convert low nibble of A to hex - LD E,A ; save it in E - LD A,D ; get original value back - RLCA ; rotate high order nibble to low bits - RLCA - RLCA - RLCA - CALL HEXCONV ; convert nibble - LD D,A ; save it in D - RET ; done -; -; Convert low nibble of A to ascii hex -; -HEXCONV: - AND $0F ; low nibble only - ADD A,$90 - DAA - ADC A,$40 - DAA - RET -; -; Print value of A or HL in decimal with leading zero suppression -; Use prtdecb for A or prtdecw for HL -; -PRTDECB: - PUSH HL - LD H,0 - LD L,A - CALL PRTDECW ; print it - POP HL - RET -; -PRTDECW: - PUSH AF - PUSH BC - PUSH DE - PUSH HL - CALL PRTDEC0 - POP HL - POP DE - POP BC - POP AF - RET -; -PRTDEC0: - LD E,'0' - LD BC,-10000 - CALL PRTDEC1 - LD BC,-1000 - CALL PRTDEC1 - LD BC,-100 - CALL PRTDEC1 - LD C,-10 - CALL PRTDEC1 - LD E,0 - LD C,-1 -PRTDEC1: - LD A,'0' - 1 -PRTDEC2: - INC A - ADD HL,BC - JR C,PRTDEC2 - SBC HL,BC - CP E - RET Z - LD E,0 - CALL PRTCHR - RET -; -; Start a new line -; -CRLF2: - CALL CRLF ; two of them -CRLF: - PUSH AF ; preserve AF - LD A,CR - CALL PRTCHR ; print CR - LD A,LF - CALL PRTCHR ; print LF - POP AF ; restore AF - RET -; -; Get the next non-blank character from (HL). -; -NONBLANK: - LD A,(HL) ; load next character - OR A ; string ends with a null - RET Z ; if null, return pointing to null - CP ' ' ; check for blank - RET NZ ; return if not blank - INC HL ; if blank, increment character pointer - JR NONBLANK ; and loop -; -; Convert character in A to uppercase -; -UCASE: - CP 'a' ; if below 'a' - RET C ; ... do nothing and return - CP 'z' + 1 ; if above 'z' - RET NC ; ... do nothing and return - RES 5,A ; clear bit 5 to make lower case -> upper case - RET ; and return -; -; Add the value in A to HL (HL := HL + A) -; -ADDHL: - ADD A,L ; A := A + L - LD L,A ; Put result back in L - RET NC ; if no carry, we are done - INC H ; if carry, increment H - RET ; and return -; -; Jump indirect to address in HL -; -JPHL: - JP (HL) -; -; Errors -; -ERRUSE: ; command usage error (syntax) - LD DE,MSGUSE - JR ERR -; -ERRPRM: ; command parameter error (syntax) - LD DE,MSGPRM - JR ERR -; -ERRBIO: ; invalid BIOS or version - LD DE,MSGBIO - JR ERR -; -ERR: ; print error string and return error signal - CALL CRLF2 ; print newline -; -ERR1: ; without the leading crlf - CALL PRTSTR ; print error string -; -ERR2: ; without the string -; CALL CRLF ; print newline - OR $FF ; signal error - RET ; done -; -; -;=============================================================================== -; Subroutine to print decimal numbers -;=============================================================================== -; -; Combined routine for conversion of different sized binary numbers into -; directly printable ASCII(Z)-string -; Input value in registers, number size and -related to that- registers to fill -; is selected by calling the correct entry: -; -; entry inputregister(s) decimal value 0 to: -; B2D8 A 255 (3 digits) -; B2D16 HL 65535 5 " -; B2D24 E:HL 16777215 8 " -; B2D32 DE:HL 4294967295 10 " -; B2D48 BC:DE:HL 281474976710655 15 " -; B2D64 IX:BC:DE:HL 18446744073709551615 20 " -; -; The resulting string is placed into a small buffer attached to this routine, -; this buffer needs no initialization and can be modified as desired. -; The number is aligned to the right, and leading 0's are replaced with spaces. -; On exit HL points to the first digit, (B)C = number of decimals -; This way any re-alignment / postprocessing is made easy. -; Changes: AF,BC,DE,HL,IX -; -; by Alwin Henseler -; https://msx.org/forum/topic/who-who/dutch-hardware-guy-pops-back-sort -; -; Found at: -; https://www.msx.org/forum/development/msx-development/32-bit-long-ascii -; -; Tweaked to assemble using TASM 3.2 by MartinR 23June2024 -; -B2D8: LD H,0 - LD L,A -B2D16: LD E,0 -B2D24: LD D,0 -B2D32: LD BC,0 -B2D48: LD IX,0 ; zero all non-used bits -B2D64: LD (B2DINV),HL - LD (B2DINV+2),DE - LD (B2DINV+4),BC - LD (B2DINV+6),IX ; place full 64-bit input value in buffer - LD HL,B2DBUF - LD DE,B2DBUF+1 - LD (HL),' ' -B2DFILC .EQU $-1 ; address of fill-character - LD BC,18 - LDIR ; fill 1st 19 bytes of buffer with spaces - LD (B2DEND-1),BC ; set BCD value to "0" & place terminating 0 - LD E,1 ; no. of bytes in BCD value - LD HL,B2DINV+8 ; (address MSB input)+1 - LD BC,00909H - XOR A -B2DSKP0:DEC B - JR Z,B2DSIZ ; all 0: continue with postprocessing - DEC HL - OR (HL) ; find first byte <>0 - JR Z,B2DSKP0 -B2DFND1:DEC C - RLA - JR NC,B2DFND1 ; determine no. of most significant 1-bit - RRA - LD D,A ; byte from binary input value -B2DLUS2:PUSH HL - PUSH BC -B2DLUS1:LD HL,B2DEND-1 ; address LSB of BCD value - LD B,E ; current length of BCD value in bytes - RL D ; highest bit from input value -> carry -B2DLUS0:LD A,(HL) - ADC A,A - DAA - LD (HL),A ; double 1 BCD byte from intermediate result - DEC HL - DJNZ B2DLUS0 ; and go on to double entire BCD value (+carry!) - JR NC,B2DNXT - INC E ; carry at MSB -> BCD value grew 1 byte larger - LD (HL),1 ; initialize new MSB of BCD value -B2DNXT: DEC C - JR NZ,B2DLUS1 ; repeat for remaining bits from 1 input byte - POP BC ; no. of remaining bytes in input value - LD C,8 ; reset bit-counter - POP HL ; pointer to byte from input value - DEC HL - LD D,(HL) ; get next group of 8 bits - DJNZ B2DLUS2 ; and repeat until last byte from input value -B2DSIZ: LD HL,B2DEND ; address of terminating 0 - LD C,E ; size of BCD value in bytes - OR A - SBC HL,BC ; calculate address of MSB BCD - LD D,H - LD E,L - SBC HL,BC - EX DE,HL ; HL=address BCD value, DE=start of decimal value - LD B,C ; no. of bytes BCD - SLA C ; no. of bytes decimal (possibly 1 too high) - LD A,'0' - RLD ; shift bits 4-7 of (HL) into bit 0-3 of A - CP '0' ; (HL) was > 9h? - JR NZ,B2DEXPH ; if yes, start with recording high digit - DEC C ; correct number of decimals - INC DE ; correct start address - JR B2DEXPL ; continue with converting low digit -B2DEXP: RLD ; shift high digit (HL) into low digit of A -B2DEXPH:LD (DE),A ; record resulting ASCII-code - INC DE -B2DEXPL:RLD - LD (DE),A - INC DE - INC HL ; next BCD-byte - DJNZ B2DEXP ; and go on to convert each BCD-byte into 2 ASCII - SBC HL,BC ; return with HL pointing to 1st decimal - RET - -B2DINV: .FILL 8 ; space for 64-bit input value (LSB first) -B2DBUF: .FILL 20 ; space for 20 decimal digits -B2DEND: .DB 000H ; space for terminating character - -;******************************************************************************* - -; The following routine divides AC:IX by DE and places the quotient -; in AC:IX and the remainder in HL - -; https://wikiti.brandonw.net/ - -; IN: ACIX=dividend, DE=divisor -; OUT: ACIX=quotient, DE=divisor, HL=remainder, B=0 - -DIV32BY16: - LD HL,0 - LD B,32 -DIV32BY16_LOOP: - ADD IX,IX - RL C - RLA - ADC HL,HL - JR C,DIV32BY16_OVERFLOW - SBC HL,DE - JR NC,DIV32BY16_SETBIT - ADD HL,DE - DJNZ DIV32BY16_LOOP - RET -DIV32BY16_OVERFLOW: - OR A - SBC HL,DE -DIV32BY16_SETBIT: - INC IX - DJNZ DIV32BY16_LOOP - RET - -;******************************************************************************* - -; The following routine divides HL by C and places the quotient in HL -; and the remainder in A - -; https://wikiti.brandonw.net/ - -DIV_HL_C: - XOR A - LD B, 16 - -LOOPDIV1: - ADD HL, HL - RLA - JR C, $+5 - CP C - JR C, $+4 - - SUB C - INC L - - DJNZ LOOPDIV1 - - RET - -;=============================================================================== -; Messages Section -;=============================================================================== - -MSGBAN .DB "TIMER v1.31, 24-Jul-2024",CR,LF - .DB "Copyright (C) 2019, Wayne Warthen, GNU GPL v3",CR,LF - .DB "Updated by MartinR 2024",0 -MSGUSE .DB "Usage: TIMER [/C] [/?]",CR,LF - .DB " ex. TIMER (display current timer value)",CR,LF - .DB " TIMER /? (display version and usage)",CR,LF - .DB " TIMER /C (display timer value continuously)",0 -MSGPRM .DB "Parameter error (TIMER /? for usage)",0 -MSGBIO .DB "Incompatible BIOS or version, " - .DB "HBIOS v", '0' + rmj, ".", '0' + rmn, " required",0 -STRTICK .DB " Ticks ",0 -STRSEC .DB " Seconds ",0 -STRHMS .DB " HH:MM:SS",0 - -;=============================================================================== -; Storage Section -;=============================================================================== - -SEC_MS .DW 0 ; Storage space to preserve the seconds value as -SEC_LS .DW 0 ; most and less significant parts -SEC_FR .DB 0 ; And the fractional part (1/100s of a second) - -LAST .DB 0 ; last LSB of timer value -CONT .DB 0 ; non-zero indicates continuous display -FIRST .DB $FF ; first pass flag (true at start) - -STKSAV .DW 0 ; stack pointer saved at start - .FILL STKSIZ,0 ; stack -STACK .EQU $ ; new stack top - - .END +;=============================================================================== +; TIMER - Display system timer value +; Version 1.31 24-July-2024 +;=============================================================================== +; +; Author: Wayne Warthen (wwarthen@gmail.com) +; Updated: MartinR (July 2024) - A user of uppercase mnemonics +;_______________________________________________________________________________ +; +; Usage: +; TIMER [/C] [/?] +; ex: TIMER (display current timer value) +; TIMER /? (display version and usage) +; TIMER /C (display timer value continuously) +; +; Operation: +; Reads and displays system timer value. +; +; This code will only execute on a Z80 CPU (or derivitive) +; +; This source code assembles with TASM V3.2 under Windows-11 using the +; following command line: +; tasm -80 -g3 -l TIMER.ASM TIMER.COM +; ie: Z80 CPU; output format 'binary' named .COM (rather than .OBJ) +; and includes a symbol table as part of the listing file. +;_______________________________________________________________________________ +; +; Change Log: +; 2018-01-14 [WBW] Initial release +; 2018-01-17 [WBW] Add HBIOS check +; 2019-11-08 [WBW] Add seconds support +; 2024-06-30 [MR ] Display values in decimal rather than hexadecimal +; 2024-07-24 [MR ] Also display value in Hours-Mins-Secs format +;_______________________________________________________________________________ +; +; Includes binary-to-decimal subroutine by Alwin Henseler +; Located at: https://www.msx.org/forum/development/msx-development/32-bit-long-ascii +;_______________________________________________________________________________ +; +; Includes division subroutines from: https://wikiti.brandonw.net/ +;;_______________________________________________________________________________ +; +#include "../../ver.inc" ; Used for building RomWBW +;#include "ver.inc" ; Used for testing purposes during code development +; +;=============================================================================== +; Definitions +;=============================================================================== +; +STKSIZ .EQU $40 ; Working stack size +; +RESTART .EQU $0000 ; CP/M restart vector +BDOS .EQU $0005 ; BDOS invocation vector +; +IDENT .EQU $FFFC ; loc of RomWBW HBIOS ident ptr +; +BF_SYSVER .EQU $F1 ; BIOS: VER function +BF_SYSGET .EQU $F8 ; HBIOS: SYSGET function +BF_SYSSET .EQU $F9 ; HBIOS: SYSSET function +BF_SYSGETTIMER .EQU $D0 ; TIMER subfunction +BF_SYSSETTIMER .EQU $D0 ; TIMER subfunction +BF_SYSGETSECS .EQU $D1 ; SECONDS subfunction +BF_SYSSETSECS .EQU $D1 ; SECONDS subfunction +; +;ASCII Control Characters +LF .EQU 00AH ; Line Feed +CR .EQU 00DH ; Carriage Return +; +;=============================================================================== +; Code Section +;=============================================================================== +; + .ORG $100 +; + ; setup stack (save old value) + LD (STKSAV),SP ; save stack + LD SP,STACK ; set new stack +; + ; initialization + CALL INIT ; initialize + JR NZ,EXIT ; abort if init fails +; + ; process + CALL PROCESS ; do main processing + JR NZ,EXIT ; abort on error +; +EXIT: ; clean up and return to command processor + CALL CRLF ; formatting + LD SP,(STKSAV) ; restore stack + ;JP RESTART ; return to CP/M via restart + RET ; return to CP/M w/o restart +; +; Initialization +; +INIT: + CALL CRLF ; formatting + LD DE,MSGBAN ; point to version message part 1 + CALL PRTSTR ; print it +; + CALL IDBIO ; identify active BIOS + CP 1 ; check for HBIOS + JP NZ,ERRBIO ; handle BIOS error +; + LD A,RMJ << 4 | RMN ; expected HBIOS ver + CP D ; compare with result above + JP NZ,ERRBIO ; handle BIOS error +; +INITX: + ; initialization complete + XOR A ; signal success + RET ; return +; +; Process +; +PROCESS: + ; look for start of parms + LD HL,$81 ; point to start of parm area (past len byte) +; +PROCESS00: + CALL NONBLANK ; skip to next non-blank char + JP Z,PROCESS0 ; no more parms, go to display +; + ; check for option, introduced by a "/" + CP '/' ; start of options? + JP NZ,USAGE ; yes, handle option + CALL OPTION ; do option processing + RET NZ ; done if non-zero return + JR PROCESS00 ; continue looking for options +; +PROCESS0: +; + ; Test of API function to set seconds value + ;LD B,BF_SYSSET ; HBIOS SYSGET function + ;LD C,BF_SYSSETSECS ; SECONDS subfunction + ;LD DE,0 ; set seconds value + ;LD HL,1000 ; ... to 1000 + ;RST 08 ; call HBIOS, DE:HL := seconds value +; + ; get and print seconds value + CALL CRLF2 ; formatting +; +PROCESS1: + LD B,BF_SYSGET ; HBIOS SYSGET function + LD C,BF_SYSGETTIMER ; TIMER subfunction + RST 08 ; call HBIOS, DE:HL := timer value + + LD A,(FIRST) + OR A + LD A,0 + LD (FIRST),A + JR NZ,PROCESS1A + + ; TEST FOR NEW VALUE + LD A,(LAST) ; last LSB value to A + CP L ; compare to current LSB + JP Z,PROCESS2 ; if equal, bypass display + +;******************************************************************************* +;******************************************************************************* + +; Formatting code added/amended to print values in decimal and Hours-Mins-Secs +; MartinR June & July-2024 + +PROCESS1A: +; Save and print new value + LD A,L ; new LSB value to A + LD (LAST),A ; save as last value + CALL PRTCR ; back to start of line + + CALL B2D32 ; Convert DE:HL into ASCII; Start of ASCII buffer returned in HL + EX DE,HL + CALL PRTSTR ; Display the value + + LD DE,STRTICK ; "Ticks" message + CALL PRTSTR ; Display it + +; Get and print seconds value in decimal + + LD B,BF_SYSGET ; HBIOS SYSGET function + LD C,BF_SYSGETSECS ; SECONDS subfunction + RST 08 ; Call HBIOS; DE:HL := seconds value; C := fractional part + + LD (SEC_MS),DE ; Store the most significant part of the 'seconds' value + LD (SEC_LS),HL ; And the less significant...... + LD A,C ; And also the fractional part + SLA A ; But double the 50Hz 'ticks' value to give 1/100ths of a second + LD (SEC_FR),A + + CALL B2D32 ; Convert DE:HL into ASCII; Start of ASCII buffer returned in HL + EX DE,HL + CALL PRTSTR ; Display the value + + CALL PRTDOT ; Print a '.' seperator + + LD A,(SEC_FR) ; Retrieve fractional part (1/100ths second) + CALL B2D8 ; Convert into ASCII - up to 3 digits. Umber of digits returned C + CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string + EX DE,HL ; Start of ASCII buffer returned in HL + CALL PRTSTR ; Display fractional part of the value + + LD DE,STRSEC ; "Seconds" message + CALL PRTSTR ; Display it + +; Now print the seconds value as HMS + + LD BC,(SEC_MS) ; Retrive the 'seconds' value into AC:IX + LD A,B + LD IX,(SEC_LS) + LD DE,3600 ; 3600 seconds in an hour + CALL DIV32BY16 ; AC:IX divided by DE; Answer in AC:IX; Remainder in HL + + PUSH HL ; Preserve the remainder on the stack + + LD D,A ; Shuffle registers around ready for conversion to ASCII + LD A,C ; AC:IX into DE:HL + LD E,A + PUSH IX + POP HL + + CALL B2D32 ; Convert DE:HL into ASCII; Start of ASCII buffer returned in HL + EX DE,HL + CALL PRTSTR ; Display the hours value + + CALL PRTCOLON ; Print a ':' seperator + + POP HL ; Retrive the remainder (seconds) + + LD C,60 ; 60 seconds in a minute + CALL DIV_HL_C ; HL divided by C; Answer in HL; Remainder in A + + PUSH AF ; Preserve the remainder (seconds) on the stack + + CALL B2D16 ; Convert HL into ASCII; Start of ASCII buffer returned in HL; Count in C + CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string + EX DE,HL + CALL PRTSTR ; Display the minutes value + + CALL PRTCOLON ; Print a ':' seperator + + POP AF ; Retrive the remainder (seconds) + + CALL B2D8 ; Convert A into ASCII; Start of ASCII buffer returned in HL; Count in C + CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string + EX DE,HL + CALL PRTSTR ; Display the seconds value + + CALL PRTDOT ; Print a '.' seperator + + LD A,(SEC_FR) ; Retrieve the fractional part (1/100ths) of the seconds + CALL B2D8 ; Convert A into ASCII; Start of ASCII buffer returned in HL + CALL PRT_LEAD0 ; Print a leading zero if there is exactly 1 character in the string + EX DE,HL + CALL PRTSTR ; Display the value + + LD DE,STRHMS ; Print "HH:MM:SS" message + CALL PRTSTR + +;******************************************************************************* +;******************************************************************************* + +PROCESS2: + LD A,(CONT) ; continuous display? + OR A ; test for true/false + JR Z,PROCESS3 ; if false, get out +; + LD C,6 ; BDOS: direct console I/O + LD E,$FF ; input char + CALL BDOS ; call BDOS, A := char + OR A ; test for zero + JP Z,PROCESS1 ; loop until char pressed +; +PROCESS3: + XOR A ; signal success + RET +; +; Handle special options +; +OPTION: + INC HL ; next char + LD A,(HL) ; get it + OR A ; zero terminator? + RET Z ; done if so + CP ' ' ; blank? + RET Z ; done if so + CP '?' ; is it a '?'? + JP Z,USAGE ; yes, display usage + CP 'C' ; is it a 'C', continuous? + JP Z,SETCONT ; yes, set continuous display + JP ERRPRM ; anything else is an error +; +USAGE: + JP ERRUSE ; display usage and get out +; +SETCONT: +; + OR $FF ; SET A TO TRUE + LD (CONT),A ; AND SET CONTINUOUS FLAG + JR OPTION ; CHECK FOR MORE OPTION LETTERS +; +; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 +; +IDBIO: +; + ; CHECK FOR UNA (UBIOS) + LD A,($FFFD) ; fixed location of UNA API vector + CP $C3 ; jp instruction? + JR NZ,IDBIO1 ; 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,IDBIO1 ; 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,IDBIO1 ; if not, not UNA, check others +; + LD BC,$04FA ; UNA: get BIOS date and version + RST 08 ; DE := ver, HL := date +; + LD A,2 ; UNA BIOS id = 2 + RET ; and done +; +IDBIO1: + ; Check for RomWBW (HBIOS) + LD HL,(IDENT) ; HL := HBIOS ident location + LD A,'W' ; First byte of ident + CP (HL) ; Compare + JR NZ,IDBIO2 ; Not HBIOS + INC HL ; Next byte of ident + LD A,~'W' ; Second byte of ident + CP (HL) ; Compare + JR NZ,IDBIO2 ; Not HBIOS +; + LD B,BF_SYSVER ; HBIOS: VER function + LD C,0 ; required reserved value + RST 08 ; DE := version, L := platform id +; + LD A,1 ; HBIOS BIOS id = 1 + RET ; and done +; +IDBIO2: + ; No idea what this is + XOR A ; Setup return value of 0 + RET ; and done +; +; Print character in A without destroying any registers +; +PRTCHR: + PUSH BC ; save registers + PUSH DE + PUSH HL + LD E,A ; character to print in E + LD C,$02 ; BDOS function to output a character + CALL BDOS ; do it + POP HL ; restore registers + POP DE + POP BC + RET +; +; Print a 0 if C=1 +; +PRT_LEAD0: + DEC C ; Decrement C, and a value of 1 becomee zero + RET NZ ; If C wasn't 1, then no leading space required + LD A,'0' ; Print the leading zero + JR Z,PRTCHR +; +PRTDOT: +; + ; shortcut to print a dot preserving all regs + PUSH AF ; save af + LD A,'.' ; load dot char + CALL PRTCHR ; print it + POP AF ; restore af + RET ; done +; +PRTCOLON: +; + ; shortcut to print a colon preserving all regs + PUSH AF ; save af + LD A,':' ; load colon char + CALL PRTCHR ; print it + POP AF ; restore af + RET ; done +; +PRTCR: +; + ; shortcut to print a CR preserving all regs + PUSH AF ; save af + LD A,13 ; load CR value + CALL PRTCHR ; print it + POP AF ; restore af + RET ; done +; +; Print a zero terminated string at (DE) without destroying any registers +; +PRTSTR: + PUSH DE +; +PRTSTR1: + LD A,(DE) ; get next char + OR A + JR Z,PRTSTR2 + CALL PRTCHR + INC DE + JR PRTSTR1 +; +PRTSTR2: + POP DE ; restore registers + RET +; +; Print the value in A in hex without destroying any registers +; +PRTHEX: + PUSH AF ; save AF + PUSH DE ; save DE + CALL HEXASCII ; convert value in A to hex chars in DE + LD A,D ; get the high order hex char + CALL PRTCHR ; print it + LD A,E ; get the low order hex char + CALL PRTCHR ; print it + POP DE ; restore DE + POP AF ; restore AF + RET ; done +; +; print the hex word value in bc +; +PRTHEXWORD: + PUSH AF + LD A,B + CALL PRTHEX + LD A,C + CALL PRTHEX + POP AF + RET +; +; print the hex dword value in de:hl +; +PRTHEX32: + PUSH BC + PUSH DE + POP BC + CALL PRTHEXWORD + PUSH HL + POP BC + CALL PRTHEXWORD + POP BC + RET +; +; Convert binary value in A to ascii hex characters in DE +; +HEXASCII: + LD D,A ; save A in D + CALL HEXCONV ; convert low nibble of A to hex + LD E,A ; save it in E + LD A,D ; get original value back + RLCA ; rotate high order nibble to low bits + RLCA + RLCA + RLCA + CALL HEXCONV ; convert nibble + LD D,A ; save it in D + RET ; done +; +; Convert low nibble of A to ascii hex +; +HEXCONV: + AND $0F ; low nibble only + ADD A,$90 + DAA + ADC A,$40 + DAA + RET +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +PRTDECB: + PUSH HL + LD H,0 + LD L,A + CALL PRTDECW ; print it + POP HL + RET +; +PRTDECW: + PUSH AF + PUSH BC + PUSH DE + PUSH HL + CALL PRTDEC0 + POP HL + POP DE + POP BC + POP AF + RET +; +PRTDEC0: + LD E,'0' + LD BC,-10000 + CALL PRTDEC1 + LD BC,-1000 + CALL PRTDEC1 + LD BC,-100 + CALL PRTDEC1 + LD C,-10 + CALL PRTDEC1 + LD E,0 + LD C,-1 +PRTDEC1: + LD A,'0' - 1 +PRTDEC2: + INC A + ADD HL,BC + JR C,PRTDEC2 + SBC HL,BC + CP E + RET Z + LD E,0 + CALL PRTCHR + RET +; +; Start a new line +; +CRLF2: + CALL CRLF ; two of them +CRLF: + PUSH AF ; preserve AF + LD A,CR + CALL PRTCHR ; print CR + LD A,LF + CALL PRTCHR ; print LF + POP AF ; restore AF + RET +; +; Get the next non-blank character from (HL). +; +NONBLANK: + LD A,(HL) ; load next character + OR A ; string ends with a null + RET Z ; if null, return pointing to null + CP ' ' ; check for blank + RET NZ ; return if not blank + INC HL ; if blank, increment character pointer + JR NONBLANK ; and loop +; +; Convert character in A to uppercase +; +UCASE: + CP 'a' ; if below 'a' + RET C ; ... do nothing and return + CP 'z' + 1 ; if above 'z' + RET NC ; ... do nothing and return + RES 5,A ; clear bit 5 to make lower case -> upper case + RET ; and return +; +; Add the value in A to HL (HL := HL + A) +; +ADDHL: + ADD A,L ; A := A + L + LD L,A ; Put result back in L + RET NC ; if no carry, we are done + INC H ; if carry, increment H + RET ; and return +; +; Jump indirect to address in HL +; +JPHL: + JP (HL) +; +; Errors +; +ERRUSE: ; command usage error (syntax) + LD DE,MSGUSE + JR ERR +; +ERRPRM: ; command parameter error (syntax) + LD DE,MSGPRM + JR ERR +; +ERRBIO: ; invalid BIOS or version + LD DE,MSGBIO + JR ERR +; +ERR: ; print error string and return error signal + CALL CRLF2 ; print newline +; +ERR1: ; without the leading crlf + CALL PRTSTR ; print error string +; +ERR2: ; without the string +; CALL CRLF ; print newline + OR $FF ; signal error + RET ; done +; +; +;=============================================================================== +; Subroutine to print decimal numbers +;=============================================================================== +; +; Combined routine for conversion of different sized binary numbers into +; directly printable ASCII(Z)-string +; Input value in registers, number size and -related to that- registers to fill +; is selected by calling the correct entry: +; +; entry inputregister(s) decimal value 0 to: +; B2D8 A 255 (3 digits) +; B2D16 HL 65535 5 " +; B2D24 E:HL 16777215 8 " +; B2D32 DE:HL 4294967295 10 " +; B2D48 BC:DE:HL 281474976710655 15 " +; B2D64 IX:BC:DE:HL 18446744073709551615 20 " +; +; The resulting string is placed into a small buffer attached to this routine, +; this buffer needs no initialization and can be modified as desired. +; The number is aligned to the right, and leading 0's are replaced with spaces. +; On exit HL points to the first digit, (B)C = number of decimals +; This way any re-alignment / postprocessing is made easy. +; Changes: AF,BC,DE,HL,IX +; +; by Alwin Henseler +; https://msx.org/forum/topic/who-who/dutch-hardware-guy-pops-back-sort +; +; Found at: +; https://www.msx.org/forum/development/msx-development/32-bit-long-ascii +; +; Tweaked to assemble using TASM 3.2 by MartinR 23June2024 +; +B2D8: LD H,0 + LD L,A +B2D16: LD E,0 +B2D24: LD D,0 +B2D32: LD BC,0 +B2D48: LD IX,0 ; zero all non-used bits +B2D64: LD (B2DINV),HL + LD (B2DINV+2),DE + LD (B2DINV+4),BC + LD (B2DINV+6),IX ; place full 64-bit input value in buffer + LD HL,B2DBUF + LD DE,B2DBUF+1 + LD (HL),' ' +B2DFILC .EQU $-1 ; address of fill-character + LD BC,18 + LDIR ; fill 1st 19 bytes of buffer with spaces + LD (B2DEND-1),BC ; set BCD value to "0" & place terminating 0 + LD E,1 ; no. of bytes in BCD value + LD HL,B2DINV+8 ; (address MSB input)+1 + LD BC,00909H + XOR A +B2DSKP0:DEC B + JR Z,B2DSIZ ; all 0: continue with postprocessing + DEC HL + OR (HL) ; find first byte <>0 + JR Z,B2DSKP0 +B2DFND1:DEC C + RLA + JR NC,B2DFND1 ; determine no. of most significant 1-bit + RRA + LD D,A ; byte from binary input value +B2DLUS2:PUSH HL + PUSH BC +B2DLUS1:LD HL,B2DEND-1 ; address LSB of BCD value + LD B,E ; current length of BCD value in bytes + RL D ; highest bit from input value -> carry +B2DLUS0:LD A,(HL) + ADC A,A + DAA + LD (HL),A ; double 1 BCD byte from intermediate result + DEC HL + DJNZ B2DLUS0 ; and go on to double entire BCD value (+carry!) + JR NC,B2DNXT + INC E ; carry at MSB -> BCD value grew 1 byte larger + LD (HL),1 ; initialize new MSB of BCD value +B2DNXT: DEC C + JR NZ,B2DLUS1 ; repeat for remaining bits from 1 input byte + POP BC ; no. of remaining bytes in input value + LD C,8 ; reset bit-counter + POP HL ; pointer to byte from input value + DEC HL + LD D,(HL) ; get next group of 8 bits + DJNZ B2DLUS2 ; and repeat until last byte from input value +B2DSIZ: LD HL,B2DEND ; address of terminating 0 + LD C,E ; size of BCD value in bytes + OR A + SBC HL,BC ; calculate address of MSB BCD + LD D,H + LD E,L + SBC HL,BC + EX DE,HL ; HL=address BCD value, DE=start of decimal value + LD B,C ; no. of bytes BCD + SLA C ; no. of bytes decimal (possibly 1 too high) + LD A,'0' + RLD ; shift bits 4-7 of (HL) into bit 0-3 of A + CP '0' ; (HL) was > 9h? + JR NZ,B2DEXPH ; if yes, start with recording high digit + DEC C ; correct number of decimals + INC DE ; correct start address + JR B2DEXPL ; continue with converting low digit +B2DEXP: RLD ; shift high digit (HL) into low digit of A +B2DEXPH:LD (DE),A ; record resulting ASCII-code + INC DE +B2DEXPL:RLD + LD (DE),A + INC DE + INC HL ; next BCD-byte + DJNZ B2DEXP ; and go on to convert each BCD-byte into 2 ASCII + SBC HL,BC ; return with HL pointing to 1st decimal + RET + +B2DINV: .FILL 8 ; space for 64-bit input value (LSB first) +B2DBUF: .FILL 20 ; space for 20 decimal digits +B2DEND: .DB 000H ; space for terminating character + +;******************************************************************************* + +; The following routine divides AC:IX by DE and places the quotient +; in AC:IX and the remainder in HL + +; https://wikiti.brandonw.net/ + +; IN: ACIX=dividend, DE=divisor +; OUT: ACIX=quotient, DE=divisor, HL=remainder, B=0 + +DIV32BY16: + LD HL,0 + LD B,32 +DIV32BY16_LOOP: + ADD IX,IX + RL C + RLA + ADC HL,HL + JR C,DIV32BY16_OVERFLOW + SBC HL,DE + JR NC,DIV32BY16_SETBIT + ADD HL,DE + DJNZ DIV32BY16_LOOP + RET +DIV32BY16_OVERFLOW: + OR A + SBC HL,DE +DIV32BY16_SETBIT: + INC IX + DJNZ DIV32BY16_LOOP + RET + +;******************************************************************************* + +; The following routine divides HL by C and places the quotient in HL +; and the remainder in A + +; https://wikiti.brandonw.net/ + +DIV_HL_C: + XOR A + LD B, 16 + +LOOPDIV1: + ADD HL, HL + RLA + JR C, $+5 + CP C + JR C, $+4 + + SUB C + INC L + + DJNZ LOOPDIV1 + + RET + +;=============================================================================== +; Messages Section +;=============================================================================== + +MSGBAN .DB "TIMER v1.31, 24-Jul-2024",CR,LF + .DB "Copyright (C) 2019, Wayne Warthen, GNU GPL v3",CR,LF + .DB "Updated by MartinR 2024",0 +MSGUSE .DB "Usage: TIMER [/C] [/?]",CR,LF + .DB " ex. TIMER (display current timer value)",CR,LF + .DB " TIMER /? (display version and usage)",CR,LF + .DB " TIMER /C (display timer value continuously)",0 +MSGPRM .DB "Parameter error (TIMER /? for usage)",0 +MSGBIO .DB "Incompatible BIOS or version, " + .DB "HBIOS v", '0' + rmj, ".", '0' + rmn, " required",0 +STRTICK .DB " Ticks ",0 +STRSEC .DB " Seconds ",0 +STRHMS .DB " HH:MM:SS",0 + +;=============================================================================== +; Storage Section +;=============================================================================== + +SEC_MS .DW 0 ; Storage space to preserve the seconds value as +SEC_LS .DW 0 ; most and less significant parts +SEC_FR .DB 0 ; And the fractional part (1/100s of a second) + +LAST .DB 0 ; last LSB of timer value +CONT .DB 0 ; non-zero indicates continuous display +FIRST .DB $FF ; first pass flag (true at start) + +STKSAV .DW 0 ; stack pointer saved at start + .FILL STKSIZ,0 ; stack +STACK .EQU $ ; new stack top + + .END diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 2bf8a100..6c6a614a 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -1376,8 +1376,8 @@ HBX_BUF_END .EQU $ JP HBX_BNKSEL ; (+19) HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL JP HBX_BNKCPY ; (+22) HB_BNKCPY: FIXED ADR ENTRY FOR HBX_BNKCPY JP HBX_BNKCALL ; (+25) HB_BNKCALL: FIXED ADR ENTRY FOR HBX_BNKCALL - .DW HBX_IDENT ; (+28) ADDRESS OF HBIOS PROXY START (DEPRECATED) - .DW HBX_IDENT ; (+30) HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK + .DW HBX_IDENT ; (+28) HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK + .DW HBX_IDENT ; (+30) RESERVED (USED BY MSX PLATFORM), SET TO HBX_IDENT FOR BACKWARD COMPATIBILITY ; .FILL MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) .ORG HBX_IMG + HBX_SIZ ; RESTORE ORG diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index 33d073d1..3341cfe7 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -554,5 +554,4 @@ HB_INVOKE .EQU HBX_XFCFNS + (0 * 3) ; INVOKE HBIOS FUNCTION HB_BNKSEL .EQU HBX_XFCFNS + (1 * 3) ; SELECT LOW MEMORY BANK ID HB_BNKCPY .EQU HBX_XFCFNS + (2 * 3) ; INTERBANK MEMORY COPY HB_BNKCALL .EQU HBX_XFCFNS + (3 * 3) ; INTERBANK FUNCTION CALL -;HB_LOC .EQU HBX_XFCFNS + 12 ; ADDRESS OF HBIOS PROXY START (DEPRECATED) -HB_IDENT .EQU HBX_XFCFNS + 14 ; POINTER TO HBIOS IDENT DATA BLOCK +HB_IDENT .EQU HBX_XFCFNS + 12 ; POINTER TO HBIOS IDENT DATA BLOCK diff --git a/Source/HBIOS/sysconf.asm b/Source/HBIOS/sysconf.asm index eb178ac3..c49732b6 100644 --- a/Source/HBIOS/sysconf.asm +++ b/Source/HBIOS/sysconf.asm @@ -51,7 +51,7 @@ cmdmax .EQU $20 ; Max cmd input length stksiz .EQU $40 ; Working stack size restart .EQU $0000 ; CP/M restart vector bdos .EQU $0005 ; BDOS invocation vector -ident .EQU $FFFE ; loc of RomWBW HBIOS ident ptr +ident .EQU $FFFC ; loc of RomWBW HBIOS ident ptr ; ETX .EQU 3 ; CTRL-C BEL .EQU 7 ; ASCII bell diff --git a/Source/ver.inc b/Source/ver.inc index 84f37a95..20437a65 100644 --- a/Source/ver.inc +++ b/Source/ver.inc @@ -2,7 +2,7 @@ #DEFINE RMN 6 #DEFINE RUP 0 #DEFINE RTP 0 -#DEFINE BIOSVER "3.6.0-dev.26" +#DEFINE BIOSVER "3.6.0-dev.27" #define rmj RMJ #define rmn RMN #define rup RUP diff --git a/Source/ver.lib b/Source/ver.lib index 487fe048..cb11eb59 100644 --- a/Source/ver.lib +++ b/Source/ver.lib @@ -3,5 +3,5 @@ rmn equ 6 rup equ 0 rtp equ 0 biosver macro - db "3.6.0-dev.26" + db "3.6.0-dev.27" endm