Files
RFS/asm/rfs_bank9.asm
2026-04-01 23:29:33 +01:00

875 lines
37 KiB
NASM

;--------------------------------------------------------------------------------------------------------
;-
;- Name: rfs_bank9.asm
;- Created: July 2019
;- Author(s): Philip Smart
;- Description: Sharp MZ series Rom Filing System.
;- This assembly language program is written to utilise the banked flashroms added with
;- the MZ-80A RFS hardware upgrade.
;-
;- Credits:
;- Copyright: (c) 2018-2026 Philip Smart <philip.smart@net2net.org>
;-
;- History: July 2019 - Merged 2 utilities to create this compilation.
;- May 2020 - Bank switch changes with release of v2 pcb with coded latch. The coded
;- latch adds additional instruction overhead as the control latches share
;- the same address space as the Flash RAMS thus the extra hardware to
;- only enable the control registers if a fixed number of reads is made
;- into the upper 8 bytes which normally wouldnt occur. Caveat - ensure
;- that no loop instruction is ever placed into EFF8H - EFFFH.
;- Aug 2023 - Updates to make RFS run under the SFD700 Floppy Disk Interface board.
;- UROM remains the same, a 2K paged ROM, MROM is located at F000 when
;- RFS is built for the SFD700.
;- Mar 2026 - Moved ROM directory, find, load and print functions from bank 0 for
;- picoZ80/RomDisk builds to free space in bank 0.
;-
;--------------------------------------------------------------------------------------------------------
;- This source file is free software: you can redistribute it and-or modify
;- it under the terms of the GNU General Public License as published
;- by the Free Software Foundation, either version 3 of the License, or
;- (at your option) any later version.
;-
;- This source file is distributed in the hope that it will be useful,
;- but WITHOUT ANY WARRANTY; without even the implied warranty of
;- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;- GNU General Public License for more details.
;-
;- You should have received a copy of the GNU General Public License
;- along with this program. If not, see <http://www.gnu.org/licenses/>.
;--------------------------------------------------------------------------------------------------------
IF BUILD_SFD700 = 1
ORG 0E000H
ALIGN 0E300H
DB "BANK9"
ALIGN UROMADDR
ENDIF
;===========================================================
;
; USER ROM BANK 9 -
;
;===========================================================
ORG UROMADDR
;--------------------------------
; Common code spanning all banks.
;--------------------------------
NOP
HWSELROM2 ; Select the first ROM page.
;
; No mans land... this should have switched to Bank 0 and at this point there is a jump to 00000H.
JP 00000H ; This is for safety!!
;------------------------------------------------------------------------------------------
; Bank switching code, allows a call to code in another bank.
; This code is duplicated in each bank such that a bank switch doesnt affect logic flow.
;------------------------------------------------------------------------------------------
ALIGN_NOPS UROMBSTBL
;
BKSW9to0: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK0 ; Required bank to call.
JR BKSW9_0
BKSW9to1: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK1 ; Required bank to call.
JR BKSW9_0
BKSW9to2: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK2 ; Required bank to call.
JR BKSW9_0
BKSW9to3: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK3 ; Required bank to call.
JR BKSW9_0
BKSW9to4: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK4 ; Required bank to call.
JR BKSW9_0
BKSW9to5: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK5 ; Required bank to call.
JR BKSW9_0
BKSW9to6: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK6 ; Required bank to call.
JR BKSW9_0
BKSW9to7: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK7 ; Required bank to call.
JR BKSW9_0
BKSW9to8: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK8 ; Required bank to call.
JR BKSW9_0
BKSW9to9: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK9 ; Required bank to call.
JR BKSW9_0
BKSW9to10: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK10 ; Required bank to call.
JR BKSW9_0
BKSW9to11: PUSH AF
LD A, ROMBANK9 ; Calling bank (ie. us).
PUSH AF
LD A, ROMBANK11 ; Required bank to call.
;
BKSW9_0: PUSH HL ; Place function to call on stack
LD HL, BKSWRET8 ; Place bank switchers return address on stack.
EX (SP),HL
LD (TMPSTACKP),SP ; Save the stack pointer as some old code corrupts it.
BNKSWSEL
JP (HL) ; Jump to required function.
BKSWRET9: POP AF ; Get bank which called us.
BNKSWSELRET
POP AF
RET
;-------------------------------------------------------------------------------
; START OF METHODS
;-------------------------------------------------------------------------------
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
;------------------------------------------------------------------------------------------
; Jump table for functions accessed from monitor ROM.
; PRTMZF and PRTDBG are at fixed offsets from UROMADDR (0xA0 and 0xA3).
;------------------------------------------------------------------------------------------
ALIGN_NOPS RFSJMPTABLE
ORG RFSJMPTABLE
PRTMZF9: JP _PRTMZF9
PRTDBG9: JP _PRTDBG9
;------------------------------------------------------------------------------------------
; Function: ISMZF9
; Description: Check if the data pointed to by HL looks like a valid MZF header.
; On return Z flag set = valid MZF, NZ = not valid.
;------------------------------------------------------------------------------------------
ISMZF9: PUSH BC
PUSH DE
PUSH HL
;
LD A,(HL)
CP OBJCD ; Only interested in machine code images.
JR NZ, ISMZFNOT9
;
INC HL
LD DE,NAME ; Checks to confirm this is an MZF header.
LD B,FNSIZE ; Maximum of 17 characters, including terminator in filename.
ISMZFNXT9: LD A,(HL)
LD (DE),A
CP 00DH ; If we find a terminator then this indicates potentially a valid name.
JR Z, ISMZFNXT39
CP 000H ; Same applies for NULL terminator.
JR Z, ISMZFNXT39
CP 020H ; >= Space
JR C, ISMZFNOT9
CP 05DH ; =< ]
JR C, ISMZFNXT39
ISMZFNXT29: CP 091H
JR C, ISMZFNOT9 ; DEL or > 0x7F, cant be a valid filename so this is not an MZF header.
ISMZFNXT39: INC DE
INC HL
DJNZ ISMZFNXT9
ISMZFYES9: CP A ; Set zero flag to indicate match.
ISMZFNOT9: POP HL
POP DE
POP BC
RET
;------------------------------------------------------------------------------------------
; Function: _PRTDBG9
; Description: Debug output, conditional on ENADEBUG=1.
;------------------------------------------------------------------------------------------
_PRTDBG9: IF ENADEBUG = 1
PUSH HL
PUSH DE
PUSH BC
PUSH AF
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
LD A,(ROMBK1)
HWSELMROM ; Set the MROM bank back to original.
ENDIF
CALL PRTHL ; HL
LD A, ' '
CALL PRNT
LD H,B
LD L,C
CALL PRTHL ; BC
LD A, ' '
CALL PRNT
LD H,D
LD L,E
CALL PRTHL ; DE
LD A, ' '
CALL PRNT
POP HL ; Get AF into HL.
PUSH HL
CALL PRTHL ; AF
LD A, ' '
CALL PRNT
LD A, ':'
CALL PRNT
LD A, ' '
CALL PRNT
; CALL NL
; CALL GETKY
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
LD A,(WRKROMBK1)
HWSELMROM ; Set the MROM bank back to scanned bank.
ENDIF
POP AF
POP BC
POP DE
POP HL
RET
ENDIF
;------------------------------------------------------------------------------------------
; Function: _PRTMZF9
; Description: Print MZF directory entry with pagination.
; D = file sequence number.
; On return NZ = user pressed X to exit listing.
;------------------------------------------------------------------------------------------
_PRTMZF9: PUSH BC
PUSH DE
PUSH HL
;
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
LD A,(ROMBK1) ; Ensure main MROM is switched in.
HWSELMROM
ENDIF
;
LD A,(SCRNMODE)
CP 0
LD H,47
JR Z,PRTMZF09
LD H,93
PRTMZF09: LD A,(TMPLINECNT) ; Pause if we fill the screen.
LD E,A
INC E
CP H
JR NZ,PRTNOPAUSE9
LD E, 0
PRTPAUSE9: CALL GETKY
CP ' '
JR Z,PRTNOPAUSE9
CP 'X' ; Exit from listing.
LD A,001H
JR Z,PRTMZF49
JR PRTPAUSE9
PRTNOPAUSE9:LD A,E
LD (TMPLINECNT),A
;
LD A, D ; Print out file number and increment.
CALL PRTHX
LD A, '.' ; File type is MACHINE CODE program.
CALL PRNT
LD DE,NAME ; Print out filename.
LD B,FNSIZE ; Maximum size of filename.
_PRTMSG9: LD A,(DE)
INC DE
CP 000H
JR Z,_PRTMSGE9
CP 00DH
JR Z,_PRTMSGE9
CALL PRNT
DJNZ _PRTMSG9
;
_PRTMSGE9: LD HL, (DSPXY)
;
LD A,L
CP 20
LD A,20
JR C, PRTMZF29
;
LD A,(SCRNMODE) ; 40 Char mode? 2 columns of filenames displayed so NL.
CP 0
JR Z,PRTMZF19
;
LD A,L ; 80 Char mode we print 4 columns of filenames.
CP 40
LD A,40
JR C, PRTMZF29
;
LD A,L
CP 60
LD A,60
JR C, PRTMZF29
;
PRTMZF19: CALL NL
JR PRTMZF39
PRTMZF29: LD L,A
LD (DSPXY),HL
PRTMZF39: XOR A
PRTMZF49: OR A
PUSH AF
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
LD A, (WRKROMBK1)
HWSELMROM
ENDIF
POP AF
POP HL
POP DE
POP BC
RET
;------------------------------------------------------------------------------------------
; Function: DIRROM9
; Description: ROM directory listing command.
;------------------------------------------------------------------------------------------
DIRROM9: ;DI ; Disable interrupts as we are switching out the main rom.
;
LD A,1 ; Account for the title.
LD (TMPLINECNT),A
;
LD DE,MSGRDIRLST ; Print out header.
LD HL,PRINTMSG
CALL BKSW9to6
; D = File sequence number.
LD D,0 ; File numbering start.
;
; Get directory of User ROM (RomDisk).
;
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
; Set ROMBK2 to bank 9 so MROM code (_DIRMROM, _PRTMZF) restores
; UROM to this bank on exit. Our return addresses are in bank 9.
LD A,ROMBANK9
LD (ROMBK2),A
;
LD A,ROMBANK3
LD (WRKROMBK1),A
HWSELMROM
CALL DIRMROM
;
; Restore ROMBK2 to default.
LD A,ROMBANK0
LD (ROMBK2),A
ENDIF
;
; Scan MROM Banks (16..127) for application files stored in spare banks.
;
LD B,MROMPAGES ; First set of pages are reserved in MROM bank.
LD C,0 ; Block in page.
;
DIRNXTPG9: LD A,B
LD (WRKROMBK1), A
HWSELMROM ; Select bank.
PUSH BC ; Preserve bank count/block number.
PUSH DE ; Preserve file numbering.
LD A,C
IF RFSSECTSZ >= 512
RLCA
ENDIF
IF RFSSECTSZ >= 1024
RLCA
ENDIF
LD B,A
LD C,0
LD HL,MROMSTART ; Add block offset to get the valid block address.
ADD HL,BC
CALL ISMZF9
POP DE
POP BC
JR NZ, DIRNOTMZF9
;
CALL PRTMZF9
JR NZ,DIRNXTPGX9
INC D ; Next file sequence number.
;
DIRNOTMZF9: INC C ; Next block.
LD A,C
CP MROMSIZE/RFSSECTSZ ; Max blocks per page reached?
JR C, DIRNXTPG29
LD C,0
INC B
DIRNXTPG29: LD A,B
CP 080h ; MROM has 128 banks of 4K, so stop when we reach 128.
JR NZ, DIRNXTPG9
DIRNXTPGX9: LD A,(ROMBK1)
HWSELMROM ; Set the MROM bank back to original.
;EI ; No need to block interrupts now as MROM bank restored.
RET ; End of scan, return to monitor
;------------------------------------------------------------------------------------------
; Function: FINDMZF9
; Description: Find a file in the ROM banks by name or file number.
; HL = pointer to filename or file number string.
; D = file sequence number start.
; On return Z = found, NZ = not found.
; B = bank, C = block where file resides.
;------------------------------------------------------------------------------------------
FINDMZF9: PUSH DE
LD (TMPADR), HL ; Save name of program to load.
EX DE, HL ; String needed in DE for conversion.
LD HL,0FFFFh ; Tag the filenumber as invalid.
LD (TMPCNT), HL
CALL ConvertStringToNumber9 ; See if a file number was given instead of a filename.
JR NZ, FINDMZF09 ;
LD (TMPCNT), HL ; Store filenumber making load by filenumber valid.
;
; Scan MROM Bank
; B = Bank Page
; C = Block in page
;
FINDMZF09: POP DE ; Get file sequence number in D.
LD B,MROMPAGES ; First set of pages are reserved in User ROM bank.
LD C,0 ; Block in page.
FINDMZF19: LD A,B
LD (WRKROMBK1), A
HWSELMROM ; Select bank.
FINDMZF29: PUSH BC ; Preserve bank count/block number.
PUSH DE ; Preserve file numbering.
LD HL,MROMSTART ; Add block offset to get the valid block.
LD A,C
IF RFSSECTSZ >= 512
RLCA
ENDIF
IF RFSSECTSZ >= 1024
RLCA
ENDIF
LD B,A
LD C,0
ADD HL,BC
CALL ISMZF9
POP DE
POP BC
LD A,(ROMBK1)
HWSELMROM ; Set the MROM bank back to original.
JR NZ, FINDMZF49 ; Z set if we found an MZF record.
INC HL ; Save address of filename.
PUSH HL
; CALL PRTMZF9 ; Print out for confirmation.
LD HL,(TMPCNT)
LD A,H
CP 0FFh ; If TMPCNT tagged as 0xFF then we dont have a filenumber so must match filename.
JR Z, FINDMZF39
LD A,L ; Check file number, load if match
CP D
JR NZ, FINDMZF39 ; Check name just in case.
POP HL
JR FINDMZFYES9 ; Else the filenumber matches so load the file.
FINDMZF39: POP HL
PUSH DE
PUSH BC
LD DE,(TMPADR) ; Original DE put onto stack, original filename into HL
LD BC,FNSIZE
LD A,(WRKROMBK1)
HWSELMROM ; Select correct bank for comparison.
CALL CMPSTRING9
POP BC
POP DE
JR Z, FINDMZFYES9
INC D ; Next file sequence number.
FINDMZF49: INC C
LD A,C
CP MROMSIZE/RFSSECTSZ ; Max blocks per page reached?
JR C, FINDMZF59
LD C,0
INC B
FINDMZF59: LD A,B
CP 080h ; MROM has 128 banks of 4K, so stop when we get to 128.
JR NZ, FINDMZF19
INC B
JR FINDMZFNO9
FINDMZFYES9: ; Flag set by previous test.
FINDMZFNO9: PUSH AF
LD A,(ROMBK1)
HWSELMROM ; Set the MROM bank back to original.
POP AF
RET
;------------------------------------------------------------------------------------------
; Function: LOADROMNX9 / LOADROM9
; Description: Load a program from ROM banks.
; LOADROMNX9 = load without auto-execute.
; LOADROM9 = load with auto-execute.
; DE = pointer to filename.
;------------------------------------------------------------------------------------------
LOADROMNX9: LD L,0FFH
JR LOADROM19
LOADROM9: LD L,000H
LOADROM19: ;DI
PUSH HL ; Preserve execute flag.
EX DE,HL ; User ROM expects HL to have the filename pointer.
; D = File sequence number.
LD D,0 ; File numbering start.
;
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
; Set ROMBK2 to bank 9 so MROM code restores UROM to this bank on exit.
LD A,ROMBANK9
LD (ROMBK2),A
;
PUSH HL ; Save pointer to filename for FINDMZF in Monitor ROM.
LD A,ROMBANK3 ; Activate the RFS Utilities MROM bank.
LD (WRKROMBK1), A
HWSELMROM
CALL MFINDMZF ; Try and find the file in User ROM via MROM utility.
POP HL
JR Z,MROMLOAD09
;
; Not found via MROM — restore ROMBK2 to default before trying FINDMZF9.
LD A,ROMBANK0
LD (ROMBK2),A
ENDIF
;
CALL FINDMZF9 ; Find the bank and block where the file resides. HL = filename.
JR Z, LROMLOAD9
;
JR LROMNTFND9 ; Requested file not found.
;
MROMLOAD09: PUSH BC ; Preserve bank and block where MZF file found.
PUSH AF ; Preserve 7:6 of A which is upper bank select.
LD A,(ROMBK1) ; Page in monitor so we can print a message.
HWSELMROM
LD DE,MSGLOAD+1 ; Skip initial file type identifier.
LD BC,NAME
LD HL,PRINTMSG
CALL BKSW9to6
LD A,(WRKROMBK1) ; Revert to MROM bank to load the application.
HWSELMROM
POP AF
POP BC
;
CALL MROMLOAD ; Load the file from User ROM via MROM utility.
; Restore ROMBK2 to default. LD does not affect flags so Z from MROMLOAD is preserved.
LD A,ROMBANK0
LD (ROMBK2),A
JP Z, LROMLOAD59
LROMNTFND9: POP HL ; Dont need execute flag anymore so waste it.
LD A,(ROMBK1)
HWSELMROM
LD HL,PRINTMSG
LD DE,MSGNOTFND ; Not found
CALL BKSW9to6
LOADROMEND9:;EI
RET
;
; Load program from RFS Bank 1 (MROM Bank)
;
LROMLOAD9: PUSH BC
;
PUSH BC ; Print Loading <file>
LD DE,MSGLOAD+1
LD BC,NAME
LD HL,PRINTMSG
CALL BKSW9to6
POP BC
;
LD A,B
LD (WRKROMBK1),A
HWSELMROM
;
LD DE, IBUFE ; Copy the header into the work area.
LD HL, MROMSTART ; Add block offset to get the valid block.
LD A,C
IF RFSSECTSZ >= 512
RLCA
ENDIF
IF RFSSECTSZ >= 1024
RLCA
ENDIF
LD B,A
LD C,0
ADD HL,BC
LD BC, MZFHDRSZ
LDIR
PUSH HL
LD DE, (DTADR)
LD HL, (SIZE)
LD BC, RFSSECTSZ - MZFHDRSZ
SBC HL, BC
JR NC, LROMLOAD49
LD HL, (SIZE)
JR LROMLOAD49
; HL = address in active block to read.
; B = Bank
; C = Block
LROMLOAD29: LD A, B
LD (WRKROMBK1), A
HWSELMROM
LROMLOAD39: PUSH BC
LD HL, MROMSTART
LD A, C
IF RFSSECTSZ >= 512
RLCA
ENDIF
IF RFSSECTSZ >= 1024
RLCA
ENDIF
LD B, A
LD C, 0
ADD HL,BC
PUSH HL
LD DE, (TMPADR)
LD HL, (TMPSIZE)
LD BC, RFSSECTSZ
SBC HL, BC
JR NC, LROMLOAD49
LD BC, (TMPSIZE)
LD HL, 0
LROMLOAD49: LD (TMPSIZE), HL ; HL contains remaining amount of bytes to load.
POP HL
;
LD A, B ; Pre check to ensure BC is not zero.
OR C
JR Z, LROMLOAD89
LDIR
LD BC, (TMPSIZE)
LD A, B ; Post check to ensure we still have bytes
OR C
JR Z, LROMLOAD89
;
LD (TMPADR),DE ; Address we are loading into.
POP BC
LROMLOAD69: INC C
LD A, C
CP MROMSIZE/RFSSECTSZ ; Max blocks per page reached?
JR C, LROMLOAD79
LD C, 0
INC B
;
LROMLOAD79: LD A, B
CP 080h ; MROM has 128 banks of 4K, stop at 128.
JR Z, LROMLOAD59
JR LROMLOAD29
;
LROMLOAD89: POP BC
LROMLOAD59: POP HL ; Retrieve execute flag.
LD A,(ROMBK1)
HWSELMROM ; Set the MROM bank back to original.
LD A,L ; Autoexecute turned off?
CP 0FFh
JP Z,LROMLOAD99 ; Go back to monitor if it has been, else execute.
; Signal the command dispatcher (in bank 0) to execute the loaded program.
; We cannot JP (HL) directly from bank 9 because the UROM bank would still
; be 9 when BASIC starts — the BIOS jump table at E8A0 needs bank 0.
; Setting RESULT to 0FEH and returning via BKSWRET restores bank 0 first,
; then the command dispatcher sees 0FEH and does JP (HL) from bank 0.
LD A,0FEH
LD (RESULT),A
;JP LROMLOAD99 ; Fall through to RET.
LROMLOAD99: RET
; Quick method to load CPM. So long as the filename doesnt change this method will load and boot CPM.
LOADCPM9: LD DE,CPMFN489 ; Load up the 48K version of CPM
LOADPRGNM9: PUSH HL
LD HL,BUFER
LOADPRGNM19:LD A,(DE)
LD (HL),A
CP CR
JR Z,LOADPRGNM29
INC DE
INC HL
JR LOADPRGNM19
LOADPRGNM29:POP HL
LD DE,BUFER
JP LOADROM9
; Quick method to load the basic interpreter. So long as the filename doesnt change this method will load and boot Basic.
LOADBASIC9: LD DE,BASICFILENM9
JR LOADPRGNM9
; Quick load program names.
CPMFN489: DB "CPM223RFS", 00DH
BASICFILENM9:DB "BASIC SA-5510RFS", 00DH
;------------------------------------------------------------------------------------------
; Utility functions (local copies for bank 9, suffixed to avoid label conflicts).
; These are duplicated from rfs_utilities.asm because the bank 0 copies are not
; accessible when bank 9 is active.
;------------------------------------------------------------------------------------------
; Compare two strings.
; HL = pointer to string 1, DE = pointer to string 2, BC = max length.
; On exit: Z = match, NZ = no match.
CMPSTRING9: PUSH HL
PUSH DE
CMPSTR19: LD A, (DE)
CP 000h
JR Z, CMPSTR39
CP 00Dh
JR Z, CMPSTR39
CPI
JR NZ, CMPSTR29
INC DE
JP PE, CMPSTR19
CMPSTR29: DEC HL
CP (HL)
CMPSTR49: POP DE
POP HL
RET
CMPSTR39: LD A, (HL)
CP 000h
JR Z, CMPSTR49
CP 00Dh
JR Z, CMPSTR49
SCF
JR CMPSTR49
; Convert character to upper case.
ConvertCharToUCase9:
CP 'a'
RET C
CP 'z'+1
RET NC
SUB 'a'-'A'
RET
; Convert character to numeric value (0-15).
ConvertCharToNumber9:
CALL ConvertCharToUCase9
CP '0'
JR C,@Bad9
CP '9'+1
JR C,@OK9
CP 'A'
JR C,@Bad9
CP 'F'+1
JR C,@OK9
@Bad9: LD A,0FFh
OR A
RET
@OK9: SUB '0'
CP 00Ah
JR C,@Fin9
SUB 007h
@Fin9: CP A
RET
; Is character numeric ('0'-'9')?
IsCharNumeric9:
CP '0'
JR C,@Not9
CP '9'+1
RET C
@Not9: OR A
RET
; Convert hexadecimal or decimal string to number.
; DE = pointer to string. On exit: Z+HL=number, or NZ=failure.
ConvertStringToNumber9:
PUSH BC
LD HL,0
LD A,(DE)
CP '+'
JR Z,@Dec9
CP '$'
JR Z,@Hdec9
CP 39
JR Z,@Char9
CP '"'
JR Z,@Char9
CP '0'
JR NZ,@HxNx9
INC DE
LD A,(DE)
CALL ConvertCharToUCase9
CP 'X'
JR NZ,@HxNx9
@Hdec9: INC DE
@HxNx9: LD A,(DE)
CP ')'
JR Z,@Succ9
CP 32+1
JR C,@Succ9
CALL ConvertCharToNumber9
JR NZ,@Fail9
INC DE
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
OR L
LD L,A
JR @HxNx9
@Dec9: INC DE
@DcNx9: LD A,(DE)
CP ')'
JR Z,@Succ9
CP 32+1
JR C,@Succ9
CALL IsCharNumeric9
JR NC,@Fail9
CALL ConvertCharToNumber9
JR NZ,@Fail9
INC DE
PUSH DE
LD B,9
LD D,H
LD E,L
@DcLp9: ADD HL,DE
DJNZ @DcLp9
POP DE
ADD A,L
LD L,A
JR NC,@DcNx9
INC H
JR @DcNx9
@Char9: INC DE
LD A,(DE)
LD L,A
LD H,0
@Succ9: POP BC
XOR A
RET
@Fail9: POP BC
LD A,0FFh
OR A
RET
ENDIF
;-------------------------------------------------------------------------------
; END OF METHODS
;-------------------------------------------------------------------------------
; RomDisk - Pad to EFFF boundary.
IF BUILD_ROMDISK+BUILD_PICOZ80 = 1
ALIGN 0EFF8h
ORG 0EFF8h
DB 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh
ENDIF
; SFD700 - Pad to 10000H
IF BUILD_SFD700 = 1
ALIGN 10000H
ENDIF