;-------------------------------------------------------------------------------------------------------- ;- ;- Name: rfs.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-2023 Philip Smart ;- ;- History: v1.0 July 2019 - Merged 2 utilities to create this compilation. ;- v2.0 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. ;- v2.0 July 2020 - Updated for the v2.1 hardware. RFS can run with a tranZPUter board with ;- or without the K64 I/O processor. RFS wont use the K64 processor all ;- operations are done by the Z80 under RFS. ;- v2.1 April 2021- Updates for the v2.1 RFS board. ;- v2.2 June 2023 - Updates for the Kuma 40/80 upgrade and FusionX. ;- v2.3 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. ;- v2.31 Dec 2025 - Bug fixes. Disabled internal floppy control logic for SFD700 as it is not ;- needed, AFI ROM always needs to be present, especially for MZ-80A. ;- ;-------------------------------------------------------------------------------------------------------- ;- 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 . ;-------------------------------------------------------------------------------------------------------- ; Bring in additional resources. INCLUDE "rfs_definitions.asm" IF BUILD_SFD700 = 1 ORG 0E000H ALIGN 0E300H ENDIF ; Monitor command table (SFD700). This table contains the list of recognised commands along with the ; handler function and bank in which it is located. ; ; 7 6 5:3 2:0 ; END MATCH BANK SIZE CMDTABLE2: IF BUILD_SFD700 = 1 DB 000H | 000H | 038H | 003H DB "ASM" ; Assembler. DW ASM_MAIN DB 000H | 000H | 000H | 005H DB "BASIC" ; Load and run BASIC SA-5510. DW LOADBASIC DB 000H | 000H | 020H | 001H DB 'B' ; Bell. DW SGX DB 000H | 000H | 000H | 003H DB "CPM" ; Load and run CPM. DW LOADCPM DB 000H | 000H | 018H | 002H DB "CP" ; Copy Memory. DW MCOPY DB 000H | 000H | 018H | 001H DB 'C' ; Clear Memory. DW INITMEMX DB 000H | 000H | 038H | 004H DB "DASM" ; Disassembler. DW DASM_MAIN DB 000H | 000H | 018H | 001H DB 'D' ; Dump Memory. DW DUMPX DB 000H | 000H | 008H | 001H DB 'F' ; 'F' RFS Floppy boot code. DW FDCK DB 000H | 000H | 030H | 001H DB 'H' ; Help screen. DW HELP DB 000H | 000H | 000H | 002H DB "IR" ; List ROM directory. DW DIRROM DB 000H | 000H | 000H | 001H DB 'J' ; Jump to address. DW GOTOX DB 000H | 000H | 020H | 004H DB "LTNX" ; Load from CMT without auto execution. DW LOADTAPENX DB 000H | 000H | 020H | 002H DB "LT" ; Load from CMT DW LOADTAPE DB 000H | 000H | 000H | 004H DB "LRNX" ; Load from ROM without auto execution. DW LOADROMNX DB 000H | 000H | 000H | 002H DB "LR" ; Load from ROM DW LOADROM DB 000H | 000H | 020H | 001H DB "L" ; Original Load from CMT DW LOADTAPE DB 000H | 000H | 018H | 001H DB 'M' ; Edit Memory. DW MCORX DB 000H | 000H | 018H | 001H DB 'P' ; Printer test. DW PTESTX DB 000H | 000H | 020H | 001H DB 'R' ; Memory test. DW MEMTEST DB 000H | 000H | 020H | 002H DB "ST" ; Save to CMT DW SAVEX DB 000H | 000H | 020H | 001H DB 'S' ; Save to CMT DW SAVEX DB 000H | 000H | 000H | 004H DB "TEST" ; A test function used in debugging. DW LOCALTEST DB 000H | 000H | 020H | 001H DB 'T' ; Timer test. DW TIMERTST DB 000H | 000H | 000H | 001H DB 'V' ; Verify CMT Save. DW VRFYX DB 080H | 000H | 000H | 001H ENDIF IF BUILD_SFD700 = 1 ALIGN UROMADDR ENDIF ;============================================================ ; ; USER ROM BANK 0 - Main RFS Entry point and functions. ; ;============================================================ ORG UROMADDR ;-------------------------------- ; Common code spanning all banks. ;-------------------------------- ROMFS: NOP HWSELROM ; Select the first ROM. JP ROMFS_1 ; Skip the reset vector. JP 00000H ; Other banks will switch at this point thus forcing a full reset. ALIGN_NOPS UROMBSTBL ;------------------------------------------------------------------------------------------ ; 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. ;------------------------------------------------------------------------------------------ ; BKSW0to0: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK0 ; Required bank to call. JR BKSW0_0 BKSW0to1: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK1 ; Required bank to call. JR BKSW0_0 BKSW0to2: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK2 ; Required bank to call. JR BKSW0_0 BKSW0to3: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK3 ; Required bank to call. JR BKSW0_0 BKSW0to4: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK4 ; Required bank to call. JR BKSW0_0 BKSW0to5: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK5 ; Required bank to call. JR BKSW0_0 BKSW0to6: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK6 ; Required bank to call. JR BKSW0_0 BKSW0to7: PUSH AF LD A, ROMBANK0 ; Calling bank (ie. us). PUSH AF LD A, ROMBANK7 ; Required bank to call. ; BKSW0_0: PUSH HL ; Place function to call on stack LD HL, BKSWRET0 ; 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. BKSWRET0: POP AF ; Get bank which called us. BNKSWSELRET POP AF RET ; Return to caller. ALIGN RFSJMPTABLE ORG RFSJMPTABLE ;------------------------------------------------------------------------------------------ ; Enhanced function Jump table. ; This table is generally used by the monitor ROM to call functions within the User ROM. ;------------------------------------------------------------------------------------------ PRTMZF: JP _PRTMZF ; UROMADDR+80H - Print out an MZF header stored in the IBUFE location. PRTDBG: JP _PRTDBG ; UROMADDR+83H - Print out debug information, if enabled. CMT_RDINF: JP _CMT_RDINF ; UROMADDR+86H - Tape/SD intercept handler - Read Header CMT_RDDATA: JP _CMT_RDDATA ; UROMADDR+89H - Tape/SD intercept handler - Read Data CMT_WRINF: JP _CMT_WRINF ; UROMADDR+80H - Tape/SD intercept handler - Write Header CMT_WRDATA: JP _CMT_WRDATA ; UROMADDR+8FH - Tape/SD intercept handler - Write Data CMT_VERIFY: JP _CMT_VERIFY ; UROMADDR+92H - Tape/SD intercept handler - Verify Data CMT_DIR: JP _CMT_DIR ; UROMADDR+95H - SD card directory listing command. CNV_ATOS: JP _CNV_ATOS ; UROMADDR+98H - Convert string from Ascii to Sharp Ascii ;----------------------------------------- ;----------------------------------------- ; Initialisation and startup. ;----------------------------------------- ; ; NB. Bank control registers are left selected. Any software needing access to the top 8 bytes of a ; ROM/RAM page need to disable them, perform their actions then re-emable. ; JP ROMFS_1 ; Skip the reset vector. ; ROMFS_1: LD A, (ROMBK1) ; Ensure all banks are at default CP 8 ; If the ROMBK1 value is 255, an illegal value, then the machine has just started so initialise memory. JR C, ROMFS_3 XOR A ; Clear the lower stack space as we use it for variables. LD B, 7*8 LD HL, 01000H ROMFS_2: LD (HL),A INC HL DJNZ ROMFS_2 SETCODELTCH ; On RomDisk setup coded latch to default. LD A, (ROMBK1) ROMFS_3: HWSELMROM ; start up. LD A, (ROMBK2) HWSELUROM ;------------------------------------------------------------------------------- ; START OF RFS INITIALISATION AND COMMAND ENTRY PROCESSOR FUNCTIONALITY. ;------------------------------------------------------------------------------- ; ; Replacement command processor in place of the SA1510 command processor. ; MONITOR: IF FUSIONX_ENA+BUILD_SFD700 = 0 IN A,(CPLDINFO) ; See if a tranZPUter board is present. AND 0E7H ; Mask out the CPLD Version and host HW. LD C,A CP 020H ; Upper bits specify the version, should be at least 1. JR C,CHKTZ1 AND 007H ; Get Hardware, should be an MZ-80A for RFS. CP MODE_MZ80A LD A,C JR Z,CHKTZ1 XOR A CHKTZ1: AND 0E0H ELSE XOR A ENDIF LD (TZPU), A ; Flag = 0 if no tranZPUter present otherwise contains version (1 - 15). IF VIDEOMODULE_ENA = 1 LD HL,DSPCTL ; Setup address of display control register latch. ENDIF ; XOR A ; Set the initial SDCFS active drive number. LD (SDDRIVENO),A ; IF BUILD_ROMDISK = 1 LD A, (ROMBK1) ; Is the 80column MZ-80A monitor active? Yes, set display as 80col. CP 1 JR Z, SET80CHAR CP 0 JR NZ, SIGNON ENDIF IF BUILD_SFD700 = 1 ; Ensure in 40 column mode. ENDIF ; SET40CHAR: IF VIDEOMODULE_ENA = 1 XOR A ; Using MROM in Bank 0 = 40 char mode. LD E,(HL) ; Dummy operation to enable latch write via multivibrator. LD (HL), A ENDIF IF KUMA80_ENA = 1 ; Kuma modification toggles the INTEN bit PC2 of the 8255 to switch mode, 0 = 40 column. LD A,04H LD (KEYPF),A ENDIF XOR A LD (SCRNMODE), A LD (SPAGE), A ; Allow MZ80A scrolling JR SIGNON SET80CHAR: IF VIDEOMODULE_ENA = 1 LD A, 128 ; Using MROM in Bank 1 = 80 char mode. LD E,(HL) ; Dummy operation to enable latch write via multivibrator. LD (HL), A ENDIF IF KUMA80_ENA = 1 ; Kuma modification toggles the INTEN bit PC2 of the 8255 to switch mode, 1 = 80 column. LD A,05H LD (KEYPF),A ENDIF LD A, 1 LD (SCRNMODE), A LD A, 0FFH LD (SPAGE), A ; MZ80K Scrolling in 80 column mode for time being. ; SIGNON: LD A,0C4h ; Move cursor left to overwrite part of SA-1510 monitor banner. LD E,004h ; 2 times. SIGNON1: CALL DPCT DEC E JR NZ,SIGNON1 ; LD A,(TZPU) OR A JR Z,SIGNON2 LD DE,MSGSONTZ JR SIGNON3 ; SIGNON2: LD DE,MSGSON ; Sign on message, SIGNON3: LD HL,PRINTMSG CALL BKSW0to6 ; JR ST1X ; Initialise SD card, report any errors. IF BUILD_ROMDISK = 1 LD HL, SDINIT ; SD Card Initialisation CALL BKSW0to2 ; Call the initialisation routine. LD A,L OR A ; 0 = No error. JR Z,ST1X ; Place error code in C to print as a number and report with the error message. ADD A,'0' LD C,A LD DE,MSGSDINITER LD HL,PRINTMSG CALL BKSW0to6 ENDIF ; Command processor, table based. ; A line is input then a comparison made with entries in the table. If a match is found then the bank and function ; address are extracted and a call to the function @ given bank made. The commands can be of variable length ; but important to not that longer commands using the same letters as shorter commands must appear first in the table. ; ST1X: CALL NL ; Command line monitor extension. LD A,'*' CALL PRNT LD DE,BUFER CALL GETL ; LD A,(BUFER+1) ; Drive change number 0..9. Each number represents an RFS SDCFS Drive number. CP '0' JR C,CMDCMP CP ':' JR NC,CMDCMP SUB '0' LD D,A LD A,(BUFER+2) CP CR ; If a CR is present then we match, a drive selection number was entered. LD A,D JR NZ,CMDCMP ; Simple command, just update the active drive number. LD (SDDRIVENO),A JR ST1X ; CMDCMP: XOR A ; Clear the result variable used by interbank calls. Some functions set this variable and we act on it. LD (RESULT),A IF BUILD_ROMDISK = 1 LD HL,CMDTABLE ENDIF IF BUILD_SFD700 = 1 LD HL,CMDTABLE2 ; SFD700 Command table located in lower location. ENDIF CMDCMP0: LD DE,BUFER+1 ; First command byte after the * prompt. LD A,(HL) CP 000H JR Z,ST1X ; Skip processing on lines where just CR pressed. BIT 7,A ; Bit 7 set on command properties indicates table end, exit if needed. JR NZ,CMDNOCMP LD C,A ; Command properties into C SET 6,C ; Assume command match. AND 007H ; Mask out bytes in command mask. LD B,A ; Number of bytes in command. INC HL CMDCMP1: LD A,(DE) ; Compare all bytes and reset match bit if we find a difference. CP (HL) JR Z, CMDCMP2 RES 6,C ; No command match. CMDCMP2: INC DE INC HL DJNZ CMDCMP1 BIT 6,C ; Bit 7 is still set then we have a command match. JR NZ,CMDCMP3 INC HL INC HL ; Skip over function address JR CMDCMP0 ; Try match next command. CMDCMP3: LD A,(HL) ; Command function address into HL INC HL LD H,(HL) LD L,A PUSH HL ; Push the address of the function to be called. LD (TMPADR),DE ; Store the key buffer location where arguments start. LD A,C ; Get back command properties, ie. bank number SRL A SRL A SRL A AND 007H ; Mask out just the bank number of the command. CP 000H JR Z,CMDCMP6 ; No point using the bank switching logic for the current bank 0. LD B,A LD HL,BKSW0to0 ; Base address of bank switching functions. LD DE,BKSW0to1 - BKSW0to0 ; DE is the number of bytes between bank switch calls. OR A JR Z,CMDCMP5 CMDCMP4: ADD HL,DE ; Basically adding the bank size to the address to get ROM location. DJNZ CMDCMP4 CMDCMP5: EX DE,HL ; Address of bank switch function into DE. POP HL ; Get address of command into HL. LD BC,CMDCMPEND PUSH BC ; Address to return to after command is executed. PUSH DE ; Now jump to DE which will switch to the correct bank and execute function at HL. LD DE,(TMPADR) RET ; Return to address in DE, which is the required bank. CMDCMP6: LD DE,CMDCMPEND ; Put return address onto stack. PUSH DE LD DE,(TMPADR) ; For the current bank, just jump to the function. JP (HL) CMDNOCMP: LD A,(BUFER+1) ; If nothing was entered, ignore line otherwise print questions to show command wasnt recognised. OR A JR Z,CMDCMPEND CP 00DH JR Z,CMDCMPEND LD DE,MSGBADCMD LD HL,PRINTMSG CALL BKSW0to6 CMDCMPEND: LD A,(RESULT) CP 0FEH ; A Result code of 0FEH means execute loaded code, address is in the CMT Header EXADR location. JP NZ,ST1X LD HL,(EXADR) JP (HL) ; Monitor command table (ROMDISK). This table contains the list of recognised commands along with the ; handler function and bank in which it is located. ; ; 7 6 5:3 2:0 ; END MATCH BANK SIZE CMDTABLE: IF BUILD_ROMDISK = 1 DB 000H | 000H | 000H | 002H ; Bit 2:0 = Command Size, 5:3 = Bank, 6 = Command match, 7 = Command table end. DB "40" ; 40 Char screen mode. DW SETMODE40 DB 000H | 000H | 000H | 002H DB "80" ; 80 Char screen mode. DW SETMODE80 ;DB 000H | 000H | 000H | 004H ;DB "7008" ; Switch to 80 column MZ700 mode. ;DW SETMODE7008 ;DB 000H | 000H | 000H | 003H ;DB "700" ; Switch to 40 column MZ700 mode. ;DW SETMODE700 DB 000H | 000H | 000H | 005H DB "BASIC" ; Load and run BASIC SA-5510. DW LOADBASIC DB 000H | 000H | 020H | 001H DB 'B' ; Bell. DW SGX DB 000H | 000H | 000H | 003H DB "CPM" ; Load and run CPM. DW LOADCPM DB 000H | 000H | 018H | 002H DB "CP" ; Copy Memory. DW MCOPY DB 000H | 000H | 018H | 001H DB 'C' ; Clear Memory. DW INITMEMX DB 000H | 000H | 018H | 001H DB 'D' ; Dump Memory. DW DUMPX DB 000H | 000H | 010H | 002H DB "EC" ; Erase file. DW ERASESD DB 000H | 000H | 008H | 001H DB 'F' ; 'F' RFS Floppy boot code. DW FLOPPY DB 000H | 000H | 008H | 001H DB 0AAH ; 'f' Original Floppy boot code. DW FDCK DB 000H | 000H | 030H | 001H DB 'H' ; Help screen. DW HELP DB 000H | 000H | 000H | 002H DB "IR" ; List ROM directory. DW DIRROM DB 000H | 000H | 010H | 002H DB "IC" ; List SD Card directory. DW DIRSDCARD DB 000H | 000H | 000H | 001H DB 'J' ; Jump to address. DW GOTOX DB 000H | 000H | 020H | 004H DB "LTNX" ; Load from CMT without auto execution. DW LOADTAPENX DB 000H | 000H | 020H | 002H DB "LT" ; Load from CMT DW LOADTAPE DB 000H | 000H | 000H | 004H DB "LRNX" ; Load from ROM without auto execution. DW LOADROMNX DB 000H | 000H | 000H | 002H DB "LR" ; Load from ROM DW LOADROM DB 000H | 000H | 010H | 004H DB "LCNX" ; Load from SDCARD without auto execution. DW LOADSDCARDX DB 000H | 000H | 010H | 002H DB "LC" ; Load from SD CARD DW LOADSDCARD DB 000H | 000H | 020H | 001H DB "L" ; Original Load from CMT DW LOADTAPE DB 000H | 000H | 018H | 001H DB 'M' ; Edit Memory. DW MCORX DB 000H | 000H | 018H | 001H DB 'P' ; Printer test. DW PTESTX DB 000H | 000H | 020H | 001H DB 'R' ; Memory test. DW MEMTEST DB 000H | 000H | 018H | 004H DB "SD2T" ; Copy SD Card to Tape. DW SD2TAPE DB 000H | 000H | 010H | 002H DB "SC" ; Save to SD CARD DW SAVESDCARD DB 000H | 000H | 020H | 002H DB "ST" ; Save to CMT DW SAVEX DB 000H | 000H | 020H | 001H DB 'S' ; Save to CMT DW SAVEX DB 000H | 000H | 000H | 004H DB "TEST" ; A test function used in debugging. DW LOCALTEST DB 000H | 000H | 018H | 004H DB "T2SD" ; Copy Tape to SD Card. DW TAPE2SD DB 000H | 000H | 020H | 001H DB 'T' ; Timer test. DW TIMERTST DB 000H | 000H | 000H | 001H DB 'V' ; Verify CMT Save. DW VRFYX DB 000H | 000H | 000H | 001H DB 'X' ; Exchange to hi load rom so DRAM = 0000:0CFFF DW HIROM DB 080H | 000H | 000H | 001H ENDIF ;------------------------------------------------------------------------------- ; END OF RFS INITIALISATION AND COMMAND ENTRY PROCESSOR FUNCTIONALITY. ;------------------------------------------------------------------------------- ; A method used when testing hardware, scope and code will change but one of its purposes is to generate a scope signal pattern. ; LOCALTEST: LD A,64 LD (0EFFBH),A JP LOCALTEST ;------------------------------------------------------------------------------- ; START OF RFS COMMAND FUNCTIONS. ;------------------------------------------------------------------------------- ; Method to branch execution to a user given address. ; GOTOX: CALL HEXIYX JP (HL) HEXIYX: EX (SP),IY POP AF CALL HLHEX JR C,HEXIYX2 JP (IY) HEXIYX2: POP AF ; Waste the intermediate caller address RET ;==================================== ; ; Screen Width Commands ; ;==================================== HIROM: IF BUILD_ROMDISK = 1 LD A, (MEMSW) ; Swap ROM into high range slot. LD A, ROMBANK2 LD (ROMBK1),A ; Save bank being enabled. HWSELMROM ; Switch to the hiload rom in bank 2. JP 0C000H ENDIF SETMODE40: IF BUILD_ROMDISK = 1 LD A, ROMBANK0 ; Switch to 40Char monitor. LD (ROMBK1),A HWSELMROM IF VIDEOMODULE_ENA = 1 LD HL,DSPCTL ; Setup address of display control register latch. LD A, 0 LD E,(HL) ; Dummy operation to enable latch write via multivibrator. LD (HL), A ENDIF IF KUMA80_ENA = 1 ; Kuma80 modification uses INTEN on PC@ of 8255, 0 = 40 column. LD A,04H LD (KEYPF),A ENDIF JP MONIT ENDIF SETMODE80: IF BUILD_ROMDISK = 1 LD A, ROMBANK1 ; Switch to 80char monitor. LD (ROMBK1),A HWSELMROM IF VIDEOMODULE_ENA = 1 LD HL,DSPCTL ; Setup address of display control register latch. LD A, 128 LD E,(HL) ; Dummy operation to enable latch write via multivibrator. LD (HL), A ENDIF IF KUMA80_ENA = 1 ; Kuma80 modification uses INTEN on PC@ of 8255, 0 = 40 column. LD A,05H LD (KEYPF),A ENDIF JP MONIT ENDIF NOTZPU: LD DE,MSGNOTZINST ; No tranZPUter installed. LD HL,PRINTMSG CALL BKSW0to6 RET ; The RFS depends on variables stored in unused parts of the Monitor scratch area. ; When switching into a compatibility mode the memory is switched and these variables go ; out of scope. This routine clears the memory and sets any crucial variables after ; memory switch so that a restart functions as expected. ; SETMODECLR: POP HL ; Get return address, will go OOS after memory mode change. LD A,TZMM_COMPAT OUT (MMCFG),A ; Set memory mode to compatibility. XOR A ; Clear out the RFS variable area in the tranZPUter memory. LD DE, 01000H LD B, 030H SETCLR_1: LD (DE),A INC DE DJNZ SETCLR_1 JP (HL) ; Return to caller. ; Command to switch to the MZ700 compatibility mode with 80 column display. ; ;SETMODE7008:LD A,(TZPU) ; Check there is a tranZPUter card installed. ; OR A ; JR Z,NOTZPU ; LD HL,DSPCTL ; Setup address of display control register latch. ; LD A, 128 ; Setup for 80char display. ; LD E,(HL) ; Dummy operation to enable latch write via multivibrator. ; LD (HL), A ; CALL SETMODECLR ; Set memory mode and clear variable area. ; LD A,ROMBANK5 ; Select the 80 column version of the 1Z-013A ROM. ;SETMODE_2: LD (ROMBK1),A ; LD (BNKSELMROM),A ; LD A,MODE_MZ700 ; Set the CPLD compatibility mode. ;SETMODE_3: OUT (CPLDCFG),A ; JP MONIT ; Cold start the monitor. ; Command to switch to the MZ700 compatibility mode with original 40 column display. ; ;SETMODE700: LD A,(TZPU) ; Check there is a tranZPUter card installed. ; OR A ; JR Z,NOTZPU ; LD HL,DSPCTL ; Setup address of display control register latch. ; LD A, 0 ; Setup for 40char display. ; LD E,(HL) ; Dummy operation to enable latch write via multivibrator. ; LD (HL), A ; CALL SETMODECLR ; Set memory mode and clear variable area. ; LD A,ROMBANK4 ; Select the 40 column version of the 1Z-013A ROM. ; JR SETMODE_2 ;==================================== ; ; ROM File System Commands ; ;==================================== ; HL contains address of block to check. ISMZF: PUSH BC PUSH DE PUSH HL ; LD A,(HL) CP OBJCD ; Only interested in machine code images. JR NZ, ISMZFNOT ; INC HL LD DE,NAME ; Checks to confirm this is an MZF header. LD B,FNSIZE ; Maximum of 17 characters, including terminator in filename. ISMZFNXT: LD A,(HL) LD (DE),A CP 00DH ; If we find a terminator then this indicates potentially a valid name. JR Z, ISMZFNXT3 CP 000H ; Same applies for NULL terminator. JR Z, ISMZFNXT3 CP 020H ; >= Space JR C, ISMZFNOT CP 05DH ; =< ] JR C, ISMZFNXT3 ISMZFNXT2: CP 091H JR C, ISMZFNOT ; DEL or > 0x7F, cant be a valid filename so this is not an MZF header. ISMZFNXT3: INC DE INC HL DJNZ ISMZFNXT ISMZFYES: CP A ; Set zero flag to indicate match. ISMZFNOT: POP HL POP DE POP BC RET _PRTDBG: IF ENADEBUG = 1 PUSH HL PUSH DE PUSH BC PUSH AF IF BUILD_ROMDISK = 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 = 1 LD A,(WRKROMBK1) HWSELMROM ; Set the MROM bank back to scanned bank. ENDIF POP AF POP BC POP DE POP HL RET ENDIF _PRTMZF: PUSH BC PUSH DE PUSH HL ; IF BUILD_ROMDISK = 1 LD A,(ROMBK1) ; Ensure main MROM is switched in. HWSELMROM ENDIF ; LD A,(SCRNMODE) CP 0 LD H,47 JR Z,PRTMZF0 LD H,93 PRTMZF0: LD A,(TMPLINECNT) ; Pause if we fill the screen. LD E,A INC E CP H JR NZ,PRTNOPAUSE LD E, 0 PRTPAUSE: CALL GETKY CP ' ' JR Z,PRTNOPAUSE CP 'X' ; Exit from listing. LD A,001H JR Z,PRTMZF4 JR PRTPAUSE PRTNOPAUSE: 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. _PRTMSG: LD A,(DE) INC DE CP 000H JR Z,_PRTMSGE CP 00DH JR Z,_PRTMSGE CALL PRNT DJNZ _PRTMSG ; _PRTMSGE: LD HL, (DSPXY) ; LD A,L CP 20 LD A,20 JR C, PRTMZF2 ; LD A,(SCRNMODE) ; 40 Char mode? 2 columns of filenames displayed so NL. CP 0 JR Z,PRTMZF1 ; LD A,L ; 80 Char mode we print 4 columns of filenames. CP 40 LD A,40 JR C, PRTMZF2 ; LD A,L CP 60 LD A,60 JR C, PRTMZF2 ; PRTMZF1: CALL NL JR PRTMZF3 PRTMZF2: LD L,A LD (DSPXY),HL PRTMZF3: XOR A PRTMZF4: OR A PUSH AF IF BUILD_ROMDISK = 1 LD A, (WRKROMBK1) HWSELMROM ENDIF POP AF POP HL POP DE POP BC RET ; Method to list the directory of the ROM devices. ; DIRROM: ;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 BKSW0to6 ; D = File sequence number. LD D,0 ; File numbering start. ; ; Get directory of User ROM (RomDisk). ; IF BUILD_ROMDISK = 1 LD A,ROMBANK3 LD (WRKROMBK1),A HWSELMROM CALL DIRMROM ENDIF ; ; Scan MROM Bank ; B = Bank Page ; C = Block in page ; LD B,MROMPAGES ; First set of pages are reserved in MROM bank. LD C,0 ; Block in page. ; DIRNXTPG: 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 ISMZF POP DE POP BC JR NZ, DIRNOTMZF ; CALL PRTMZF JR NZ,DIRNXTPGX INC D ; Next file sequence number. ; DIRNOTMZF: INC C ; Next block. LD A,C CP MROMSIZE/RFSSECTSZ ; Max blocks per page reached? JR C, DIRNXTPG2 LD C,0 INC B DIRNXTPG2: LD A,B CP 080h ; MROM has 128 banks of 4K, so stop when we reach 128. JR NZ, DIRNXTPG DIRNXTPGX: 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 ; In: ; HL = filename ; D = File sequence number. ; Out: ; B = Bank Page file found ; C = Block where found. ; D = File sequence number. ; Z set if found. FINDMZF: 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 ConvertStringToNumber ; See if a file number was given instead of a filename. JR NZ, FINDMZF0 ; LD (TMPCNT), HL ; Store filenumber making load by filenumber valid. ; ; Scan MROM Bank ; B = Bank Page ; C = Block in page ; FINDMZF0: 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. FINDMZF1: LD A,B LD (WRKROMBK1), A HWSELMROM ; Select bank. FINDMZF2: 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 ISMZF POP DE POP BC LD A,(ROMBK1) HWSELMROM ; Set the MROM bank back to original. JR NZ, FINDMZF4 ; Z set if we found an MZF record. INC HL ; Save address of filename. PUSH HL ; CALL PRTMZF ; 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, FINDMZF3 LD A,L ; Check file number, load if match CP D JR NZ, FINDMZF3 ; Check name just in case. POP HL JR FINDMZFYES ; Else the filenumber matches so load the file. FINDMZF3: 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 CMPSTRING POP BC POP DE JR Z, FINDMZFYES INC D ; Next file sequence number. FINDMZF4: INC C LD A,C CP MROMSIZE/RFSSECTSZ ; Max blocks per page reached? JR C, FINDMZF5 LD C,0 INC B FINDMZF5: LD A,B CP 080h ; MROM has 128 banks of 4K, so stop when we get to 128. JR NZ, FINDMZF1 INC B JR FINDMZFNO FINDMZFYES: ; Flag set by previous test. FINDMZFNO: PUSH AF LD A,(ROMBK1) HWSELMROM ; Set the MROM bank back to original. POP AF RET ; Load Program from ROM ; IN DE Name of program to load. ; OUT zero Set if string1 = string2, reset if string1 != string2. ; carry Set if string1 > string2, reset if string1 <= string2. LOADROMNX: LD L,0FFH JR LOADROM1 LOADROM: LD L,000H LOADROM1: ;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 = 1 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,MROMLOAD0 ENDIF ; CALL FINDMZF ; Find the bank and block where the file resides. HL = filename. JR Z, LROMLOAD ; JR LROMNTFND ; Requested file not found. ; MROMLOAD0: PUSH BC ; Preserve bank and block where MZF file found. PUSH AF LD A,(ROMBK1) ; Page in monitor so we can print a message. HWSELMROM LD DE,MSGLOAD+1 ; Skip initial CR. LD BC,NAME LD HL,PRINTMSG CALL BKSW0to6 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. JP Z, LROMLOAD5 LROMNTFND: POP HL ; Dont need execute flag anymore so waste it. LD A,(ROMBK1) HWSELMROM LD HL,PRINTMSG LD DE,MSGNOTFND ; Not found CALL BKSW0to6 LOADROMEND:;EI RET ; ; Load program from RFS Bank 1 (MROM Bank) ; LROMLOAD: PUSH BC ; PUSH BC ; Print Loading LD DE,MSGLOAD+1 LD BC,NAME LD HL,PRINTMSG CALL BKSW0to6 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, LROMLOAD4 LD HL, (SIZE) JR LROMLOAD4 ; HL = address in active block to read. ; B = Bank ; C = Block LROMLOAD2: LD A, B LD (WRKROMBK1), A HWSELMROM LROMLOAD3: 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, LROMLOAD4 LD BC, (TMPSIZE) LD HL, 0 LROMLOAD4: 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, LROMLOAD8 LDIR LD BC, (TMPSIZE) LD A, B ; Post check to ensure we still have bytes OR C JR Z, LROMLOAD8 ; LD (TMPADR),DE ; Address we are loading into. POP BC LROMLOAD6: INC C LD A, C CP MROMSIZE/RFSSECTSZ ; Max blocks per page reached? JR C, LROMLOAD7 LD C, 0 INC B ; LROMLOAD7: LD A, B CP 080h JR Z, LROMLOAD5 JR LROMLOAD2 ; LROMLOAD8: POP BC LROMLOAD5: 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,LROMLOAD9 ; Go back to monitor if it has been, else execute. LD HL,(EXADR) ;EI ; No need to block interrupts now as MROM bank restored. JP (HL) ; Execution address. LROMLOAD9: RET ; Quick method to load CPM. So long as the filename doesnt change this method will load and boot CPM. LOADCPM: LD DE,CPMFN48 ; Load up the 48K version of CPM LOADPRGNM: PUSH HL LD HL,BUFER LOADPRGNM1: LD A,(DE) LD (HL),A CP CR JR Z,LOADPRGNM2 INC DE INC HL JR LOADPRGNM1 LOADPRGNM2: POP HL LD DE,BUFER JP LOADROM ; Quick method to load the basic interpreter. So long as the filename doesnt change this method will load and boot Basic. LOADBASIC: LD DE,BASICFILENM JR LOADPRGNM LOADPROG: LD HL,LOADSDCARD CALL BKSW0to2 RET ;------------------------------------------------------------------------------- ; END OF RFS COMMAND FUNCTIONS. ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; DEVICE DRIVERS - Intercept handlers to provide enhanced services to ; existing MA-80A BIOS API functions. ;------------------------------------------------------------------------------- ; Method to set the RFS Drive number from the Load/Save string provided. SETDRIVE: LD A,(DE) ; If a drive is given it will be in format : OR A ; Exit if null or CR found, no drive specifier present. JR Z,SETDRV3 CP 00DH JR Z,SETDRV3 CP '"' ; String quotes, skip over. JR NZ,SETDRV1 INC DE JR SETDRIVE ; SETDRV1: LD A,(DE) ; Check for :, if no colon exit. LD C,A INC DE LD A,(DE) DEC DE CP ':' JR NZ, SETDRV3 ; LD A,C CP 'C' ; CMT unit specified by C: JR Z,SETDRV2 SUB '0' ; Check the drive number, should be in range 0..9 JP C,SD_INVDRV CP 10 JP NC,SD_INVDRV SETDRV2: INC DE LD (SDDRIVENO),A ; Store drive number for later use. XOR A LD (CMTFILENO),A ; Setup the starting file number for sequential file reads (ie. when no filename given). ; PUSH DE ; Need to remove the drive qualifier once processed. PUSH DE INC DE INC DE ; Move onto filename. EX DE,HL POP DE LD BC,SDDIR_FNSZ LDIR POP DE ; SETDRV3: XOR A RET ; Method to check if the active drive is the CMT. CHECKCMT: LD A,(SDDRIVENO) CP 'C' RET ; Convert the lower 4 bits of A into a Hex character. TOHEXDIGIT: AND 00FH ; Simple logic, add 30H to get 0..9, add additional 7 if value >= 10 to get digits A..F. CP 00AH JR C,NOADD ADD A,007H NOADD: ADD A,030H RET ; Convert a number into Hex string and store in buffer pointed to by DE. ; TOHEX: PUSH DE PUSH AF ; Save AF to retrieve lower 4 bits. RRCA ; Shift upper 4 bits to lower to convert to hex. RRCA RRCA RRCA CALL TOHEXDIGIT LD (DE),A ; Store and convert lower 4 bits. INC DE POP AF CALL TOHEXDIGIT LD (DE),A INC DE LD A,CR ; Terminate with a CR. LD (DE),A POP DE ; DE back to start of string. RET ; Handler to intercept the CMT Read Header Information call and insert selectable ; SD Card RFS Drive functionality. ; DE contains a pointer to memory containing the file to load. If (DE) = NULL then ; load the next sequential file from the SD card directory. ; DE = Filename. Can contain a drive specifier in format : ; ; No registers or flags should be affected as we dont know the caller state. _CMT_RDINF: CALL SETDRIVE ; Set drive if specified. RET NZ CALL CHECKCMT ; If drive is set to the CMT Unit exit with Z set so that the original CMT handlers are called. JP Z,?RDI LD A,(DE) ; Check to see if empty string given, if so expand the default Next file number into the buffer. CP CR JR NZ,_CMT_RDINF1 LD A,(CMTFILENO) ; Get next sequential number and convert to hex. PUSH AF CALL TOHEX POP AF INC A ; Increment number so next call retrieves the next sequential file. LD (CMTFILENO),A ; _CMT_RDINF1:PUSH DE LD HL,LOADSDINF ; DE already points to the filename, call LOADSDINF to locate it on the SD card and setup the header. CALL BKSW0to2 ; Copy the filename into the Buffer provided allowing for file number to name expansion. POP DE LD HL,NAME LD BC,SDDIR_FNSZ LDIR ; LD A,(RESULT) OR A RET Z ; 0 = success, return with carry clear. SCF ; > 0 = fail, return with carry set. RET ; Handler to intercept the CMT Read Data call and insert selectable SD Card RFS ; Drive functionality. ; ; No registers or flags should be affected as we dont know the caller state. _CMT_RDDATA:LD HL,LOADSDDATA CALL BKSW0to2 LD A,(RESULT) OR A JR NZ,_CMT_RDERR RET _CMT_RDERR: SCF RET ; Handler to intercept the CMT Write Header Information call and insert selectable ; SD Card RFS Drive functionality. ; ; No registers or flags should be affected as we dont know the caller state. ; ; At the moment, the WRINF call only creates a filename if non specified. The actual write to file occurs in WRDATA. Once I have more understanding of ; how the sequential data mode works I can adapt it to be compatible. _CMT_WRINF: LD DE,NAME ; Caller has already setup the CMT header so we use this for processing. ; CALL SETDRIVE ; Set drive if specified. RET NZ CALL CHECKCMT JP Z,?WRI ; LD A,(DE) ; Check to see if empty string given, if so create a default name. CP CR JR NZ,_CMT_WRINF1 ; LD HL,DEFAULTFN LD BC,DEFAULTFNE - DEFAULTFN LDIR LD A,(CMTFILENO) ; Get next sequential number and convert to hex. PUSH AF CALL TOHEX POP AF INC A ; Increment number so next call retrieves the next sequential file. LD (CMTFILENO),A ; _CMT_WRINF1:LD A,0 ; Always success as nothing is written. OR A RET ; Handler to intercept the CMT Write Data call and insert selectable SD Card RFS ; Drive functionality. ; ; No registers or flags should be affected as we dont know the caller state. _CMT_WRDATA: LD HL,SAVESDDATA CALL BKSW0to2 LD A,(RESULT) OR A JR NZ,_CMT_RDERR RET ; Handler to intercept the CMT Verify Data call and insert selectable SD Card ; RFS Drive functionality. ; ; No registers or flags should be affected as we dont know the caller state. _CMT_VERIFY:CALL SETDRIVE ; Set drive if specified. RET NZ CALL CHECKCMT JR Z,_VERIFY LD DE,MSGNOVERIFY JR SD_ERRMSG _VERIFY: JP ?VRFY SD_INVDRV: LD DE,MSGINVDRV ; Invalid drive specified. JR SD_ERRMSG SD_NOTFND: LD DE,MSGNOTFND SD_ERRMSG: LD HL,PRINTMSG CALL BKSW0to6 ; Print message that file wasnt found. LD A,1 OR A RET ; Method to list the contents of the active RFS drive number. _CMT_DIR: CALL SETDRIVE ; Change to the given drive. RET NZ CALL CHECKCMT ; Cannot DIR tape drive so give error. JP Z,_CMT_NODIR LD HL,DIRSDCARD CALL BKSW0to2 ; Call the standard RFS directory command. RET _CMT_NODIR: LD DE,MSGNOCMTDIR JR SD_ERRMSG ; Stub to call the ASCII to Sharp ASCII conversion routine stored in Bank 5. ; Inputs: DE = String to convert, NULL or CR terminated. ; B = Maximum number of characters to convert. ; All registers except AF preserved. ; _CNV_ATOS: PUSH HL LD HL,CNVSTR_AS CALL BKSW0to5 POP HL RET ;------------------------------------------------------------------------------- ; END OF DEVICE DRIVERS ;------------------------------------------------------------------------------- ;-------------------------------------- ; ; Message table - Refer to bank 6 for ; all messages. ; ;-------------------------------------- ; Quick load program names. CPMFN48: DB "CPM223RFS", 00DH BASICFILENM:DB "BASIC SA-5510RFS", 00DH DEFAULTFN: DB "DEFAULT" DEFAULTFNE: EQU $ ; Bring in additional resources. USE_CMPSTRING: EQU 1 USE_SUBSTRING: EQU 0 USE_INDEX: EQU 0 USE_STRINSERT: EQU 0 USE_STRDELETE: EQU 0 USE_CONCAT: EQU 0 USE_CNVUPPER: EQU 1 USE_CNVCHRTONUM: EQU 1 USE_ISNUMERIC: EQU 1 USE_CNVSTRTONUM: EQU 1 ; INCLUDE "macros.asm" INCLUDE "rfs_utilities.asm" ; ; Ensure we fill the entire 2K by padding with FF's. ; ALIGN 0EFF8h ORG 0EFF8h DB 0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0AAh IF BUILD_SFD700 = 1 ALIGN 0F000H ENDIF MEND: ; ; Include all other banks which make up the RFS User sited ROM. ; INCLUDE "rfs_bank1.asm" INCLUDE "rfs_bank2.asm" INCLUDE "rfs_bank3.asm" INCLUDE "rfs_bank4.asm" INCLUDE "rfs_bank5.asm" INCLUDE "rfs_bank6.asm" INCLUDE "rfs_bank7.asm"