Files
TZFS/asm/tzfs.asm
2023-05-24 09:14:09 +01:00

2615 lines
137 KiB
NASM

;--------------------------------------------------------------------------------------------------------
;-
;- Name: tzfs.asm
;- Created: July 2019
;- Author(s): Philip Smart
;- Description: Sharp MZ series tzfs (tranZPUter Filing System).
;- This assembly language program is a branch from the original RFS written for the
;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different
;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an
;- I/O processor in the K64F/ZPU.
;-
;- Credits:
;- Copyright: (c) 2018-2023 Philip Smart <philip.smart@net2net.org>
;-
;- History: May 2020 v1.0 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
;- July 2020 v1.1 - Not many changes but updated version to v1.1 to coincide with the
;- hardware v1.1 version, thus differentiating between v1.0 board and v1.1.
;- July 2020 - Updates to accomodate the v2.1 hardware. Additional commands and fixed a
;- few bugs like the load from card by name!
;- Dec 2020 - Updates to accommodate v1.3 of the tranZPUter SW-700 board where soft
;- CPU's now become possible.
;- Jan 2021 - Additional changes to accommodate soft CPU's.
;- Mar 2021 - Bug fixes - MZ-700/MZ-80A address differences.
;- - Added optional machine model code on load command to enable 700/800
;- programs to be loaded without changing the MZ800 mode switch.
;- Apr 2021 - Added 40/80 Colour Card control. Reorganised to free up space.
;- Apr 2021 v1.5 - Updated to add ?RDI/?RDD/?WRI/?WRD/DIR/CD methods to ease conversion of
;- programs from cassette storage to SD storage, first conversion being
;- BASIC SA-5510.
;- Jul 2021 v1.6 - Updated the CMT routines to now be configurable so that all MZ series
;- are catered for, ie. read/write 80B machines.
;- Feb 2023 v1.7 - TZFS now running on FusionX. Changes to ensure compatibility and
;- addition of new commands, assemble, disassemble, fill, write I/O,
;- read I/O.
;- May 2023 v1.8 - Added tape delay compensation command.
;-
;--------------------------------------------------------------------------------------------------------
;- 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/>.
;--------------------------------------------------------------------------------------------------------
; Configuration for TZFS variable and service structure memory allocation.
TZVARMEM: EQU 0EC80H ; Location where TZFS variables will be stored.
TZVARSIZE: EQU 00100H ; Size of the TZFS variable area.
TZSVCMEM: EQU 0ED80H ; Start of a memory structure used to communicate with the K64F I/O processor for services such as disk access.
; Bring in additional resources.
INCLUDE "tzfs_definitions.asm"
INCLUDE "tzfs_variables.asm"
INCLUDE "tzfs_mondef.asm"
INCLUDE "tzfs_svcstruct.asm"
;============================================================
;
; USER ROM BANK - Main TZFS Entry point and common functions.
; TZFS BANK 1 -
;
;============================================================
ORG UROMADDR
;--------------------------------
; Startup code
;--------------------------------
TZFS: NOP ; Nop is needed for monitor autostart.
LD A,(WARMSTART) ; Is this the second time we are called? First time sets the memory map to TZMM_TZFS and enables the RAM based monitor.
OR A
JP NZ,TZFS_1 ; Already called so jump to the monitor component of TZFS.
;
LD A,TZMM_TZFS
LD (MMCFGVAL),A ; Store the value in a memory variable as we cant read the latch once programmed.
OUT (MMCFG),A ; Switch to the TZFS memory mode, SA1510/monitor is now in RAM at 0000H
;
LD A,1 ; TZMM_BOOT doesnt allow writes to User ROM space, so need to be in mode TZMM_TZFS first.
LD (WARMSTART),A ; Set warm start flag so next invocation goes to monitor.
JP MROMADDR ; Cold start the RAM based SA1510/monitor which in turn will recall us to warm start.
ALIGN_NOPS UROMBSTBL
;------------------------------------------------------------------------------------------
; Bank switching code, allows a call to code in another bank.
; For TZFS, the area E800-EFFF is locked and the area F000-FFFF is paged as needed.
;------------------------------------------------------------------------------------------
; Methods to access public functions in paged area F000-FFFF. The memory mode is switched
; which means any access to F000-FFFF will be directed to a different portion of the 512K
; static RAM - this is coded into the FlashRAM decoder. Once the memory mode is switched a
; call is made to the required function and upon return the memory mode is returned to the
; previous value. The memory mode is stored on the stack and all registers are preserved for
; full re-entrant functionality.
BANKTOBANK_:JMPTOBNK
ALIGN TZFSJMPTABLE
ORG TZFSJMPTABLE
;------------------------------------------------------------------------------------------
; External function Jump table.
; This table is used by external (to TZFS) programs to invoke functionality as required.
; The entry point is fixed, starting at TZFSJMPTABLE incrementing by 3 for each call.
;------------------------------------------------------------------------------------------
CMT_RDINF: JP _CMT_RDINF ; UROMADDR+80H - Tape/SD intercept handler - Read Header
CMT_RDDATA: JP _CMT_RDDATA ; UROMADDR+83H - Tape/SD intercept handler - Read Data
CMT_WRINF: JP _CMT_WRINF ; UROMADDR+86H - Tape/SD intercept handler - Write Header
CMT_WRDATA: JP _CMT_WRDATA ; UROMADDR+89H - Tape/SD intercept handler - Write Data
CMT_VERIFY: JP _CMT_VERIFY ; UROMADDR+8CH - Tape/SD intercept handler - Verify Data
CMT_DIR: JP _CMT_DIR ; UROMADDR+8FH - SD card directory listing command.
CMT_CD: JP _CMT_CD ; UROMADDR+92H - SD change directory command.
SET_FREQ: JP ?SETFREQ ; UROMADDR+95H - Set Frequency command.
;------------------------------------------------------------------------------------------
; Enhanced function Jump table.
; This table is generally used by a banked page to call a function within another banked
; page. The name is the same as the original function but prefixed by a ?.
; All registers are preserved going to the called function and returning from it.
;------------------------------------------------------------------------------------------
?PRINTMSG: CALLBNK PRINTMSG, TZMM_TZFS2
?PRINTASCII:CALLBNK PRINTASCII, TZMM_TZFS2
?PRTFN: CALLBNK PRTFN, TZMM_TZFS2
?PRTSTR: CALLBNK PRTSTR, TZMM_TZFS2
?HELP: CALLBNK HELP, TZMM_TZFS2
?MCORX: CALLBNK MCORX, TZMM_TZFS3
?TAPECOMP: CALLBNK TAPECOMP, TZMM_TZFS3
?COPYM: CALLBNK COPYM, TZMM_TZFS3
?WRITEIO: CALLBNK WRITEIO, TZMM_TZFS3
?READIO: CALLBNK READIO, TZMM_TZFS3
?DUMPBC: CALLBNK DUMPBC, TZMM_TZFS3
?DUMPX: CALLBNK DUMPX, TZMM_TZFS3
?DUMP: CALLBNK DUMP, TZMM_TZFS3
?FILL: CALLBNK FILL, TZMM_TZFS3
?GETMEM: CALLBNK GETMEM, TZMM_TZFS
?SETMEM: CALLBNK SETMEM, TZMM_TZFS
?DASM: CALLBNK DASM_MAIN, TZMM_TZFS4
?ASM: CALLBNK ASM_MAIN, TZMM_TZFS4
IF BUILD_FUSIONX = 0
?SETVMODE: CALLBNK SETVMODE, TZMM_TZFS3
?SETVGAMODE: CALLBNK SETVGAMODE,TZMM_TZFS3
?SETVBORDER: CALLBNK SETVBORDER,TZMM_TZFS3
ENDIF ; BUILD_FUSIONX
?SETFREQ: CALLBNK SETFREQ, TZMM_TZFS3
IF BUILD_FUSIONX = 0
?SETT80: CALLBNK SETT80, TZMM_TZFS3
?SETZ80: CALLBNK SETZ80, TZMM_TZFS3
?SETZPUEVO: CALLBNK SETZPUEVO, TZMM_TZFS3
ENDIF ; BUILD_FUSIONX
?TIMERTST: CALLBNK TIMERTST, TZMM_TZFS3
?PTESTX: CALLBNK PTESTX, TZMM_TZFS3
?GETMODEL: CALLBNK GETMODEL, TZMM_TZFS3
?PLTST: CALLBNK PLTST, TZMM_TZFS3
CNV_ATOS: CALLBNK CNVSTR_AS, TZMM_TZFS2 ;
?RDITZFS: CALLBNK RDITZFS, TZMM_TZFS3
?RDDTZFS: CALLBNK RDDTZFS, TZMM_TZFS3
?WRITZFS: CALLBNK WRITZFS, TZMM_TZFS3
?WRDTZFS: CALLBNK WRDTZFS, TZMM_TZFS3
IF BUILD_FUSIONX = 0
?SETMZ80K: CALLBNK SETMZ80K, TZMM_TZFS3
?SETMZ80C: CALLBNK SETMZ80C, TZMM_TZFS3
?SETMZ1200: CALLBNK SETMZ1200, TZMM_TZFS3
?SETMZ80A: CALLBNK SETMZ80A, TZMM_TZFS3
?SETMZ700: CALLBNK SETMZ700, TZMM_TZFS3
?SETMZ1500: CALLBNK SETMZ1500, TZMM_TZFS3
?SETMZ800: CALLBNK SETMZ800, TZMM_TZFS3
?SETMZ80B: CALLBNK SETMZ80B, TZMM_TZFS3
?SETMZ2000: CALLBNK SETMZ2000, TZMM_TZFS3
?SETMZ2200: CALLBNK SETMZ2200, TZMM_TZFS3
?SETMZ2500: CALLBNK SETMZ2500, TZMM_TZFS3
ENDIF ; BUILD_FUSIONX
;-----------------------------------------
;-----------------------------------------
; Initialisation and startup.
;-----------------------------------------
;
;
TZFS_1: LD SP,TZSTACK ; Setup our stack.
XOR A ; Clear the variable and stack space.
LD B, TZSTACK - HLSAVE ; Clear all the variable space except for the startup variables as a restart shouldnt clear them.
LD HL, HLSAVE
TZFS_2: LD (HL),A
INC HL
DJNZ TZFS_2
;-------------------------------------------------------------------------------
; START OF TZFS INITIALISATION AND COMMAND ENTRY PROCESSOR FUNCTIONALITY.
;-------------------------------------------------------------------------------
;
; Replacement command processor in place of the ROM MONITOR command processor.
;
MONITOR: LD A, (SCRNMODE)
LD C, A
BIT 1, A ; FPGA video enabled?
JR Z, MONITOR1
;
IN A,(CPLDCFG)
OR MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware to enable FPGA video.
OUT (CPLDCFG),A
;
MONITOR1: LD HL,DSPCTL ; Control register address for the 40/80 Colour Card.
LD A, C ; Recall screen mode.
BIT 0, A
JP NZ, SET80CHAR
JP SET40CHAR
;
SIGNON: LD A,0C4h ; Move cursor left to overwrite part of SA-1510/monitor banner.
LD E,004h ; 4 times.
SIGNON1: CALL DPCT
DEC E
JR NZ,SIGNON1
LD DE,MSGSON ; Sign on message,
CALL ?PRINTMSG
IN A,(CPUINFO) ; Check to see if soft CPU's are available.
AND CPUMODE_IS_SOFT_MASK
CP CPUMODE_IS_SOFT_AVAIL
JR NZ,SIGNON2
IN A,(CPUSTATUS) ; Check to see if the T80 is running.
AND CPUMODE_IS_T80 ; T80 running?
JR Z,SIGNON2
IF BUILD_FUSIONX = 0
LD DE,MSGSONT80
CALL ?PRINTMSG
ENDIF ; BUILD_FUSIONX
SIGNON2: LD DE,MSGSONEND
CALL ?PRINTMSG
; 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
;
CMDCMP: LD HL,CMDTABLE
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
LD (TMPADR),DE ; Store the key buffer location where arguments start.
LD HL,CMDCMPEND ; Location to return to after function is called.
EX (SP),HL ; Swap the return location with the location to call.
PUSH HL ; Put location to call at top of stack.
RET ; Pop into PC and run.
;
CMDNOCMP: LD DE,MSGBADCMD
CALL ?PRINTMSG
CMDCMPEND: JP ST1X
;-------------------------------------------------------------------------------
; END OF TZFS INITIALISATION AND COMMAND ENTRY PROCESSOR FUNCTIONALITY.
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; SERVICE COMMAND METHODS
;-------------------------------------------------------------------------------
; Method to send a command to the I/O processor and verify it is being acted upon.
; THe method, after sending the command, polls the service structure result to see if the I/O processor has updated it. If it doesnt update the result
; then after a period of time the command is resent. After a number of retries the command aborts with error. This is needed in case of the I/O processor crashing
; we dont want the host to lock up.
;
; Inputs:
; A = Command.
; Outputs:
; A = 0 - Success, command being processed.
; A = 1 - Failure, no contact with I/O processor.
; A = 2 - Failure, no result from I/O processor, it could have crashed or SD card removed!
SVC_CMD: PUSH BC
LD (TZSVCCMD), A ; Load up the command into the service record.
LD A,TZSVC_STATUS_REQUEST
LD (TZSVCRESULT),A ; Set the service structure result to REQUEST, if this changes then the K64 is processing.
LD BC, TZSVCWAITIORETRIES ; Safety in case the IO request wasnt seen by the I/O processor, if we havent seen a response in the service
SVC_CMD1: PUSH BC
LD A,(TZSVCCMD)
OUT (SVCREQ),A ; Make the service request via the service request port.
LD BC,0
SVC_CMD2: LD A,(TZSVCRESULT)
CP TZSVC_STATUS_REQUEST ; I/O processor when it recognises the request sets the status to PROCESSING or gives a result, if this hasnt occurred the the K64F hasnt begun processing.
JR NZ, SVC_CMD3
DEC BC
LD A,B
OR C
JR NZ, SVC_CMD2
POP BC
DEC BC
LD A,B
OR C
JR NZ,SVC_CMD1 ; Retry sending the I/O command.
;
PUSH DE
LD DE,SVCIOERR
CALL ?PRINTMSG
POP DE
POP BC
LD A,1 ; No response, error.
RET
SVC_CMD3: POP BC
;
LD BC,TZSVCWAITCOUNT ; Number of loops to wait for a response before setting error.
SVC_CMD4: PUSH BC
LD BC,0
SVC_CMD5: LD A,(TZSVCRESULT)
CP TZSVC_STATUS_PROCESSING ; Wait until the I/O processor sets the result, again timeout in case it locks up.
JR NZ, SVC_CMD6
DEC BC
LD A,B
OR C
JR NZ,SVC_CMD5
POP BC
DEC BC
LD A,B
OR C
JR NZ,SVC_CMD4 ; Retry polling for result.
;
PUSH DE
LD DE,SVCRESPERR
CALL ?PRINTMSG
POP DE
POP BC
LD A,2
RET
SVC_CMD6: XOR A ; Success.
POP BC
POP BC
RET
;-------------------------------------------------------------------------------
; END OF SERVICE COMMAND METHODS
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; UTILITIES
;-------------------------------------------------------------------------------
; Method to read 4 bytes from a buffer pointed to by DE and attempt to convert to a 16bit number. If it fails, print out an error
; message and return with C set.
;
; Input: DE = Address of digits to conver.
; Output: HL = 16 bit number.
READ4HEX: CALL HLHEX
JR C,READ4HEXERR
INC DE
INC DE
INC DE
INC DE
OR A ; Clear carry flag.
RET
READ4HEXERR:LD DE,MSGREAD4HEX ; Load up error message, print and exit.
CALL ?PRINTMSG
SCF
RET
; SPACE PRINT AND DISP ACC
; INPUT:HL=DISP. ADR.
SPHEX: CALL PRNTS ; SPACE PRINT
LD A,(HL)
CALL PRTHX ; DSP OF ACC (ASCII)
LD A,(HL)
RET
; NEW LINE AND PRINT HL REG (ASCII)
NLPHL: CALL NL
CALL PRTHL
RET
HEXIYX: EX (SP),IY
POP AF
CALL HLHEX
JR C,HEXIYX2
JP (IY)
HEXIYX2: POP AF ; Waste the intermediate caller address
RET
; 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 "tzfs_utilities.asm"
;-------------------------------------------------------------------------------
; END OF UTILITIES
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------
; RAM STORAGE AREA
;-------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; VARIABLES AND STACK SPACE
;-------------------------------------------------------------------------------
ALIGN TZVARMEM
ALIGN_NOPS TZVARMEM + TZVARSIZE
;-------------------------------------------------------------------------------
; END OF VARIABLES AND STACK SPACE
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; TZ SERVICE STRUCTURE AND VARIABLES
;-------------------------------------------------------------------------------
ALIGN TZSVCMEM
ALIGN_NOPS TZSVCMEM + TZSVCSIZE
;-------------------------------------------------------------------------------
; END OF TZ SERVICE STRUCTURE AND VARIABLES
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------
; END OF RAM STORAGE AREA
;-------------------------------------------------------------------------------------------
ORG BANKRAMADDR
;-------------------------------------------------------------------------------
; START OF MEMORY CMDLINE TOOLS FUNCTIONALITY
;-------------------------------------------------------------------------------
; Method to branch execution to a user given address.
;
GOTOX: CALL HEXIYX
JP (HL)
; Method to read a byte out of main memory when configured in default TZFS1 mode.
GETMEM: LD A,(HL)
RET
; Method to write a byte into main memory when configured in default TZFS1 mode.
SETMEM: LD (HL),A
RET
;====================================
;
; Screen Width and Mode Commands
;
;====================================
; Setup the screen as 40x25 chars.
SET40CHAR: IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
JR Z,SET40_1
;
AND 007H ; Get the base machine mode, use as the starting mode for the video.
LD D, A
LD A, C ; Check to see if a mode override has been set.
BIT 2, A
LD A, VMMODE_VGA_OFF
JR Z, SET40_0
;
LD A, C ; Recall the stored mode and ready for register update.
RRCA
RRCA
RRCA
RRCA
AND 00FH
LD D,A
;
LD A, (SCRNMODE2) ; Get the VGA mode and set.
SET40_0: OUT (VMVGAMODE), A
LD A, D
OUT (VMCTRL),A ; Activate.
JR SET40_2
;
SET40_1: XOR A ; 40 char mode.
LD E,(HL) ; Dummy operation to enable latch write via multivibrator.
LD (HL), A
;
SET40_2: XOR A
LD (SPAGE), A ; Allow MZ80A scrolling
JP SIGNON
;
; Setup the screen as 80x25 chars.
;
SET80CHAR: IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
JR Z,SET80_1 ; No FPGA hardware so try and set set 80 char mode on the assumption the 40/80 Colour Card is installed.
;
AND 007H
OR MODE_80CHAR ; Set 80 char flag.
LD D, A
;
LD A, C ; Check to see if a mode override has been set.
BIT 2, A
LD A, VMMODE_VGA_OFF
JR Z, SET80_0
LD A, C ; Recall the stored mode and ready for register update.
RRCA
RRCA
RRCA
RRCA
AND 00FH
OR MODE_80CHAR ; Set 80 char flag.
LD D,A
;
LD A, (SCRNMODE2) ; Get the VGA mode and set.
SET80_0: OUT (VMVGAMODE),A
LD A, D
OR MODE_80CHAR ; Set 80 char flag.
OUT (VMCTRL),A ; Activate.
LD A, C ; Indicate we are using the FPGA video hardware.
SET 1, A
LD (SCRNMODE), A
JR SET80_2
;
SET80_1: LD A, 128 ; 80 char mode.
LD E,(HL) ; Dummy operation to enable latch write via multivibrator.
LD (HL), A
;
SET80_2: LD A, 0FFH
LD (SPAGE), A ; MZ80K Scrolling in 80 column mode for time being.
JP SIGNON
;
; Commands to start the machine in its original mode loading either a 40 or 80 column BIOS as directed.
SETMODE40: IN A,(CPLDINFO) ; Get configuration of hardware.
AND 07H ; Get model info.
CP MODE_MZ80A
JR Z, SETMODE40A ; MZ80A hardware so setup MZ80A 40 char mode.
CP MODE_MZ700
JP Z, SETMODE700 ; MZ700 hardware so setup MZ700 40 char mode.
LD DE, MSGUNKNHW ; Indicate detected hardware not yet handled.
CALL ?PRINTMSG
RET ; Return status to caller, 0 = success.
SETMODE80: IN A,(CPLDINFO) ; Get configuration of hardware.
AND 07H ; Get model info.
CP MODE_MZ80A
JR Z, SETMODE80A ; MZ80A hardware so setup MZ80A 80 char mode.
CP MODE_MZ700
JP Z, SETMODE7008 ; MZ700 hardware so setup MZ700 80 char mode.
LD DE, MSGUNKNHW ; Indicate detected hardware not yet handled.
CALL ?PRINTMSG
RET ; Return status to caller, 0 = success.
; Start the machine as an MZ-80A in 40 char mode.
SETMODE40A: IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
LD A,MODE_MZ80A ; Set the tranZPUter CPLD hardware translation to MZ80A mode.
JR NZ,SETMODE40_0
LD HL,DSPCTL ; Assume the 40/80 card is installed, switch to 40char mode.
XOR A
LD E,(HL)
LD (HL),A
JR SETMODE40_2
;
SETMODE40_0:LD A,VMMODE_MZ80A ; Setup the display to 40 char MZ80A mode.
OUT (VMCTRL),A ; Activate.
LD A, MODE_MZ80A + MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware translation to MZ80A mode with FPGA video enabled.
SETMODE40_1:OUT (CPLDCFG),A ;
SETMODE40_2:XOR A
LD (SPAGE), A ; Allow MZ80A scrolling
LD A,(SCRNMODE)
RES 0, A
LD (SCRNMODE),A ; Bit 0 = 0 = 40char mode on reset.
;
IN A,(CPLDINFO) ; Check to see if this is an MZ700, if it is not, setup the correct frequency.
AND 007H
CP MODE_MZ80A
JR Z,SETMODE40_3
LD A,SYSMODE_MZ80A ; Setup the board to run at 2MHz
OUT (SYSCTRL),A ; Activate
SETMODE40_3:LD A,TZSVC_CMD_LOAD40ABIOS ; Request the I/O processor loads the SA1510 40column BIOS into memory.
SETBIOS: CALL SVC_CMD ; And make communications wit the I/O processor, returning with the result of load operation.
OR A
JP Z,MROMADDR
LD DE,MSGFAILBIOS
CALL ?PRINTMSG
RET ; Return status to caller, 0 = success.
; Start the machine as an MZ-80A in 80 char mode.
SETMODE80A: IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
LD A, MODE_MZ80A ; Set the tranZPUter CPLD hardware translation to MZ80A mode.
JR NZ,SETMODE80_0
LD HL,DSPCTL ; Assume the 40/80 card is installed, switch to 80char mode.
LD A,128
LD E,(HL)
LD (HL),A
JR SETMODE80_2
;
SETMODE80_0:LD A,VMMODE_MZ80A + MODE_80CHAR ; Setup the display to 80 char MZ80A mode.
OUT (VMCTRL),A ; Activate.
LD A, MODE_MZ80A + MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware translation to MZ80A mode with FPGA video enabled.
SETMODE80_1:OUT (CPLDCFG),A ;
SETMODE80_2:LD A, 0FFH
LD (SPAGE), A ; MZ80K Scrolling in 80 column mode for time being.
LD A,(SCRNMODE)
SET 0, A ; Indicate 80 column mode for startup.
LD (SCRNMODE),A
IN A,(CPLDINFO) ; Check to see if this is an MZ700, if it is not, setup the correct frequency.
AND 007H
CP MODE_MZ80A
JR Z,SETMODE80_3
LD A,SYSMODE_MZ80A ; Setup the board to run at 2MHz
OUT (SYSCTRL),A ; Activate
SETMODE80_3:LD A,TZSVC_CMD_LOAD80ABIOS ; Request the I/O processor loads the SA1510 80column BIOS into memory.
JR SETBIOS
; Commands to switch into MZ-700 compatible mode. This involves switching the CPLD mode which makes hardware keyboard mapping
; and changing the frequency, and also enabling of additional traps to detect and change memory mode which are catered for in
; hardware on v2+ boards.
SETMODE700: IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
LD A, MODE_MZ700 ; Set the tranZPUter CPLD hardware translation to MZ700 mode.
JR Z,SETMODE7_1
LD A,VMMODE_MZ700 ; Setup the display to 40 char MZ700 mode.
OUT (VMCTRL),A ; Activate.
LD A, MODE_MZ700 + MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware translation to MZ700 mode with FPGA video enabled.
SETMODE7_1: OUT (CPLDCFG),A ;
XOR A
LD (SPAGE), A ; Allow MZ80A scrolling
LD A,(SCRNMODE)
RES 0, A
LD (SCRNMODE),A ; 0 = 40char mode on reset.
IN A,(CPLDINFO) ; Check to see if this is an MZ700, if it is not, setup the correct frequency.
AND 007H
CP MODE_MZ700
JR Z,SETMODE7_2
LD A,SYSMODE_MZ700 ; Setup the board to run at 3.54MHz
OUT (SYSCTRL),A ; Activate
SETMODE7_2: LD A,TZSVC_CMD_LOAD700BIOS40 ; Request the I/O processor loads the MZ700 1Z-013A 40column BIOS into memory.
JR SETBIOS
SETMODE7008:IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
JR Z,SETMODE7_1 ; No hardware so cannot select 80 char mode.
LD A,VMMODE_MZ700 + MODE_80CHAR ; Setup the display to 80char MZ700 mode.
OUT (VMCTRL),A ; Activate.
LD A, MODE_MZ700 + MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware translation to MZ700 mode with FPGA video enabled.
SETMODE78_1:OUT (CPLDCFG),A ;
LD A, 0FFH
LD (SPAGE), A ; MZ80K Scrolling in 80 column mode for time being.
LD A,(SCRNMODE)
SET 0, A ; Indicate 80 column mode for startup.
LD (SCRNMODE),A
IN A,(CPLDINFO) ; Check to see if this is an MZ700, if it is not, setup the correct frequency.
AND 007H
CP MODE_MZ700
JR Z,SETMODE78_2
LD A,SYSMODE_MZ700 ; Setup the board to run at 3.54MHz
OUT (SYSCTRL),A ; Activate
SETMODE78_2:LD A,TZSVC_CMD_LOAD700BIOS80 ; Request the I/O processor loads the SA1510 80column BIOS into memory.
JP SETBIOS
; Command to switch into the Sharp MZ-80B compatible mode. This involves loading the IPL, switching
; the frequency to 4MHz and enabling of additional traps to detect and change memory mode.
SETMODE80B: IN A,(CPLDINFO) ; Get configuration of hardware.
BIT 3,A
JP Z,SETMODE40_1 ; Without the video hardware cannot select 80B mode.
LD A,VMMODE_MZ80B + MODE_80CHAR ; Setup the display to 80char MZ80B mode.
OUT (VMCTRL),A ; Activate.
LD A, MODE_MZ80B + MODE_VIDEO_FPGA ; Set the tranZPUter CPLD hardware translation to MZ80B mode with FPGA video enabled.
SETMODE8B_1:OUT (CPLDCFG),A ;
LD A, 0FFH
LD (SPAGE), A ; MZ80K Scrolling in 80 column mode for time being.
LD A,(SCRNMODE)
SET 0,A ; Indicate 80 column mode for startup.
LD (SCRNMODE),A
IN A,(CPLDINFO) ; Check to see if this is an MZ700, if it is not, setup the correct frequency.
AND 007H
CP MODE_MZ700
JR Z,SETMODE8B_2
LD A,SYSMODE_MZ700 ; Setup the board to run at 3.54MHz
OUT (SYSCTRL),A ; Activate
SETMODE8B_2:LD A,TZSVC_CMD_LOAD80BIPL ; Request the I/O processor loads the IPL and switches frequency.
JP SETBIOS
; Exit out of TZFS - This entails clearing the DRAM as it wont have been refreshed, switching memory mode and then branching to the monitor start entry point.
; This is all done by the I/O processor as we need to be in memory mode 0 where all tranZPUter memory is paged out.
;
EXITTZFS: LD A,TZSVC_CMD_EXIT ; Request the I/O processor restarts the host in original mode.
CALL SVC_CMD
OR A
JP Z,MROMADDR
LD DE,MSGFAILEXIT ; Print message if the I/O processor cant process the command.
CALL ?PRINTMSG
RET ; Return status to caller, 0 = success.
; Method to get the CMT parameters from the command line.
; The parameters which should be given are:
; XXXXYYYYZZZZ - where XXXX = Start Address, YYYY = End Address, ZZZZ = Execution Address.
; If the start, end and execution address parameters are correct, prompt for a filename which will be written into the CMT header.
; Output: Reg C = 0 - Success
; = 1 - Error.
GETCMTPARM: CALL READ4HEX ; Start address
JR C,GETCMT1
LD (DTADR),HL ; data adress buffer
LD B,H
LD C,L
CALL READ4HEX ; End address
JR C,GETCMT1
SBC HL,BC
LD (SIZE),HL ; byte size buffer
CALL READ4HEX ; Execution address
JR C,GETCMT1
LD (EXADR),HL ; buffer
CALL ?GETMODEL ; Get model if provided.
LD (HWMODEL),A
PUSH AF
CALL NL
LD DE,MSGSAVE ; 'FILENAME? '
CALL ?PRINTMSG ; Print out the filename.
LD DE,BUFER
CALL GETL
LD HL,BUFER+10
LD DE,NAME ; name buffer
LD BC,FNSIZE
LDIR ; C = 0 means success.
POP AF ; Model data returned in AF.
SCF
CCF
RET
GETCMT1: SCF ; C = 1 means an error occured.
RET
;-------------------------------------------------------------------------------
; END OF MEMORY CMDLINE TOOLS FUNCTIONALITY
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; START OF CMT CONTROLLER FUNCTIONALITY
;-------------------------------------------------------------------------------
; CMT Utility to Load a program from tape.
;
; Three entry points:
; LOADTAPE = Load the first program shifting to lo memory if required and execute.
; LOADTAPENX = Load the first program and return without executing.
; LOADTAPECP = Load the first program to address 0x1200 and return.
;
LOADTAPECP: LD A,0FFH
LD (CMTAUTOEXEC),A
JR LOADTAPE2
LOADTAPENX: LD A,0FFH
JR LOADTAPE1
LOADTAPE: LD A,000H
LOADTAPE1: LD (CMTAUTOEXEC),A
XOR A
LOADTAPE2: LD (CMTCOPY),A ; Set cmt copy mode, 0xFF if we are copying.
LD A,0FFH ; If called interbank, set a result code in memory to detect success.
LD (RESULT),A
;
CALL ?GETMODEL ; Get machine model option.
LD (HWMODEL),A
;
CALL ?RDITZFS
JP C,?ERX2
LD DE,MSGLOAD ; 'LOADING '
LD BC,NAME
CALL ?PRINTMSG
XOR A
LD (CMTLOLOAD),A
LD HL,(DTADR) ; Common code, store load address in case we shift or manipulate loading.
LD (DTADRSTORE),HL
LD A,(CMTCOPY) ; If were copying we always load at 0x1200
OR A
JR Z,LOADTAPE3
LD HL,01200H
LOADTAPE2A: LD (DTADR),HL
LOADTAPE3: LD HL,(DTADR) ; If were loading and the load address is below 0x1200, shift it to 0x1200 to load then move into correct location.
LD A,H
OR L
JR NZ,LOADTAPE4
LD A,0FFh
LD (CMTLOLOAD),A
LD HL,01200h
LD (DTADR),HL
;
LOADTAPE4: CALL ?RDDTZFS
;
LOADTAPEI1: JP C,?ERX2
LD HL,(DTADRSTORE) ; Restore the original load address into the CMT header.
LD (DTADR),HL
LD A,(CMTCOPY)
OR A
JR NZ,LOADTAPE6
LOADTAPE5: LD A,(CMTAUTOEXEC) ; Get back the auto execute flag.
OR A
JR NZ,LOADTAPE6 ; Dont execute..
LD A,(CMTLOLOAD)
CP 0FFh
JR Z,LOADTAPELM ; Execute at low memory?
LD BC,00100h
LD HL,(EXADR)
JP (HL)
LOADTAPELM: LD A,(MEMSW) ; Perform memory switch, mapping out ROM from $0000 to $C000
LD HL,01200h ; Shift the program down to RAM at $0000
LD DE,00000h
LD BC,(SIZE)
LDIR
LD BC,00100h
LD HL,(EXADR) ; Fetch exec address and run.
JP (HL)
LOADTAPE6: LD DE,MSGCMTDATA
PUSH HL ; Load address as parameter 2.
LD HL,(EXADR)
PUSH HL ; Execution address as parameter 1.
LD BC,(SIZE) ; Size as BC parameter.
CALL ?PRINTMSG
POP BC
POP BC ; Waste parameters.
XOR A ; Success.
LD (RESULT),A
RET
; Method to save an application stored in memory to a cassette in the CMT. The start, size and execution address are either given in BUFER via the
; command line and the a filename is prompted for and read, or alternatively all the data is passed into the function already set in the CMT header.
; The tape is then opened and the header + data are written out.
;
SAVECMT: LD A,0FFH ; Set SDCOPY to indicate this is a copy command and not a command line save.
JR SAVEX1
;
; Normal entry point, the cmdline contains XXXXYYYYZZZZ where XXXX=start, YYYY=size, ZZZZ=exec addr. A filenname is prompted for and read.
; The data is stored in the CMT header prior to writing out the header and data..
;
SAVEX: CALL GETCMTPARM ; Get the CMT parameters.
RET C ; Exit if an error occurred.
XOR A
SAVEX1: LD (SDCOPY),A
OR A
JR NZ,SAVEX1_1 ; Dont set the attribute if copying, use the defined value.
LD A,OBJCD ; Set attribute: OBJ
LD (ATRB),A
;
SAVEX1_1: LD A,0FFH
LD (RESULT),A ; For interbank calls, pass result via a memory variable. Assume failure unless updated.
;
CALL ?WRITZFS
?ERX1: JP C,?ERX2
;
;LD A,(SDCOPY)
;OR A
;JR Z,SAVEX2
LD DE,(DTADR)
LD A,D ; If copying and address is below 1001H, then data is held at 1200H so update header for write.
CP 001H
JR NC,SAVEX2
LD DE,01200H
LD (DTADR),DE
SAVEX2: CALL ?WRDTZFS
;
WRITAPEE1: JR C,?ERX1
LD DE,MSGSAVEOK ; 'OK!'
CALL ?PRINTMSG
LD A,0 ; Success.
LD (RESULT),A
RET
?ERX2: LD (RESULT),A ; Set break key pressed code or error code.
CP 002h
JR NZ,?ERX3
RET
?ERX3: LD DE,MSGE1 ; 'CHECK SUM ER.'
CALL ?PRINTMSG
LD A,(RESULT)
RET
; Method to verify that a tape write occurred free of error. After a write, the tape is read and compared with the memory that created it.
;
VRFYX: CALL ?VRFY
JP C,?ERX2
LD DE,MSGOK ; 'OK!'
CALL ?PRINTMSG
RET
; Method to toggle the audible key press sound, ie a beep when a key is pressed.
;
SGX: LD A,(SWRK)
RRA
CCF
RLA
LD (SWRK),A
RET
;-------------------------------------------------------------------------------
; END OF CMT CONTROLLER FUNCTIONALITY
;-------------------------------------------------------------------------------
; The FDC controller uses it's busy/wait signal as a ROM address line input, this
; causes a jump in the code dependent on the signal status. It gets around the 2MHz
; Z80 not being quick enough to process the signal by polling.
;------------ 0xF3CE -----------------------------------------------------------
ALIGN_NOPS FDCJMP1
ORG FDCJMP1
FDCJMPL: JP (IX)
;------------ 0xF400 -----------------------------------------------------------
;-------------------------------------------------------------------------------
; START OF MEMORY TEST FUNCTIONALITY
;-------------------------------------------------------------------------------
MEMTEST: LD B,240 ; Number of loops
LOOP: LD HL,MEMSTART ; Start of checked memory,
LD D,0CFh ; End memory check CF00
LOOP1: LD A,000h
CP L
JR NZ,LOOP1b
CALL PRTHL ; Print HL as 4digit hex.
LD A,0C4h ; Move cursor left.
LD E,004h ; 4 times.
LOOP1a: CALL DPCT
DEC E
JR NZ,LOOP1a
LOOP1b: INC HL
LD A,H
CP D ; Have we reached end of memory.
JR Z,LOOP3 ; Yes, exit.
LD A,(HL) ; Read memory location under test, ie. 0.
CPL ; Subtract, ie. FF - A, ie FF - 0 = FF.
LD (HL),A ; Write it back, ie. FF.
SUB (HL) ; Subtract written memory value from A, ie. should be 0.
JR NZ,LOOP2 ; Not zero, we have an error.
LD A,(HL) ; Reread memory location, ie. FF
CPL ; Subtract FF - FF
LD (HL),A ; Write 0
SUB (HL) ; Subtract 0
JR Z,LOOP1 ; Loop if the same, ie. 0
LOOP2: LD A,16h
CALL PRNT ; Print A
CALL PRTHX ; Print HL as 4 digit hex.
CALL PRNTS ; Print space.
XOR A
LD (HL),A
LD A,(HL) ; Get into A the failing bits.
CALL PRTHX ; Print A as 2 digit hex.
CALL PRNTS ; Print space.
LD A,0FFh ; Repeat but first load FF into memory
LD (HL),A
LD A,(HL)
CALL PRTHX ; Print A as 2 digit hex.
NOP
JR LOOP4
LOOP3: CALL PRTHL
LD DE,OKCHECK
CALL MSG ; Print check message in DE
LD A,B ; Print loop count.
CALL PRTHX
LD DE,OKMSG
CALL MSG ; Print ok message in DE
CALL NL
DEC B
JR NZ,LOOP
LD DE,DONEMSG
CALL MSG ; Print check message in DE
JP ST1X
LOOP4: LD B,09h
CALL PRNTS ; Print space.
XOR A ; Zero A
SCF ; Set Carry
LOOP5: PUSH AF ; Store A and Flags
LD (HL),A ; Store 0 to bad location.
LD A,(HL) ; Read back
CALL PRTHX ; Print A as 2 digit hex.
CALL PRNTS ; Print space
POP AF ; Get back A (ie. 0 + C)
RLA ; Rotate left A. Bit LSB becomes Carry (ie. 1 first instance), Carry becomes MSB
DJNZ LOOP5 ; Loop if not zero, ie. print out all bit locations written and read to memory to locate bad bit.
XOR A ; Zero A, clears flags.
LD A,80h
LD B,08h
LOOP6: PUSH AF ; Repeat above but AND memory location with original A (ie. 80)
LD C,A ; Basically walk through all the bits to find which one is stuck.
LD (HL),A
LD A,(HL)
AND C
NOP
JR Z,LOOP8 ; If zero then print out the bit number
NOP
NOP
LD A,C
CPL
LD (HL),A
LD A,(HL)
AND C
JR NZ,LOOP8 ; As above, if the compliment doesnt yield zero, print out the bit number.
LOOP7: POP AF
RRCA
NOP
DJNZ LOOP6
JP ST1X
LOOP8: CALL LETNL ; New line.
LD DE,BITMSG ; BIT message
CALL MSG ; Print message in DE
LD A,B
DEC A
CALL PRTHX ; Print A as 2 digit hex, ie. BIT number.
CALL LETNL ; New line
LD DE,BANKMSG ; BANK message
CALL MSG ; Print message in DE
LD A,H
CP 50h ; 'P'
JR NC,LOOP9 ; Work out bank number, 1, 2 or 3.
LD A,01h
JR LOOP11
LOOP9: CP 90h
JR NC,LOOP10
LD A,02h
JR LOOP11
LOOP10: LD A,03h
LOOP11: CALL PRTHX ; Print A as 2 digit hex, ie. BANK number.
JR LOOP7
;DLY1S: PUSH AF
; PUSH BC
; LD C,10
;L0324: CALL DLY12
; DEC C
; JR NZ,L0324
; POP BC
; POP AF
; RET
;-------------------------------------------------------------------------------
; END OF MEMORY TEST FUNCTIONALITY
;-------------------------------------------------------------------------------
; Method to print out an SDC directory entry name along with an incremental file number. The file number can be
; used as a quick reference to a file rather than the filename.
;
; Input: HL = Address of filename.
; D = File number.
; A = File type.
;
PRTDIR: PUSH BC
PUSH DE
PUSH HL
LD C,A ; Preserve the file type.
;
LD A,(SCRNMODE)
BIT 0, A
LD H,47
JR Z,PRTDIR0
LD H,93
PRTDIR0: LD A,(TMPLINECNT) ; Pause if we fill the screen.
LD E,A
INC E
CP H
JR NZ,PRTNOWAIT
LD E, 0
PRTDIRWAIT: CALL GETKY
CP ' '
JR Z,PRTNOWAIT
CP 'X' ; Exit from listing.
LD A,001H
JR Z,PRTDIR4
JR PRTDIRWAIT
PRTNOWAIT: LD A,E
LD (TMPLINECNT),A
;
LD A, D ; Print out file number and increment.
CALL PRTHX
LD A,C
CP OBJCD
LD A, '.' ; File type is MACHINE CODE program.
JR Z,PRTDIR0A
LD A,C
CP BTX1CD
LD A,'-' ; File type is BASIC.
JR Z,PRTDIR0A
LD A,C
CP BTX2CD
LD A,'_' ; File type is BASIC.
JR Z,PRTDIR0A
LD A,'+'
PRTDIR0A: CALL PRNT
POP DE
PUSH DE ; Get pointer to the file name and print.
CALL ?PRTFN ; Print out the filename.
;
LD HL, (DSPXY)
;
LD A,L
CP 20
LD A,20
JR C, PRTDIR2
;
LD A,(SCRNMODE) ; 40 Char mode? 2 columns of filenames displayed so NL.
BIT 0,A
JR Z,PRTDIR1
;
LD A,L ; 80 Char mode we print 4 columns of filenames.
CP 40
LD A,40
JR C, PRTDIR2
;
LD A,L
CP 60
LD A,60
JR C, PRTDIR2
;
PRTDIR1: CALL NL
JR PRTDIR3
PRTDIR2: LD L,A
LD (DSPXY),HL
PRTDIR3: XOR A
PRTDIR4: OR A
POP HL
POP DE
POP BC
RET
; Method to request a sector full of directory entries from the I/O processor.
;
; Inputs:
; A = Director Sector number to request (set of directory entries in 512byte blocks).
; Outputs:
; A = 0 - success, directory sector filled.
; A = 255 - I/O Error.
; A > 1 - Result from I/O processor, which is normally the error code.
;
SVC_GETDIR: LD (TZSVCDIRSEC),A ; Save the sector number into the service structure.
;
OR A ; Sector is 0 then setup for initial read.
LD A, TZSVC_CMD_READDIR ; Readdir command opens the directory. The default directory and wildcard have either been placed in the
JR Z,SVC_GETD1 ; buffer by earlier commands or will be defaulted by the I/O processor.
LD A, TZSVC_CMD_NEXTDIR ; Request the next directory sector. The I/O processor either gets the next block or uses the TZSVCDIRSEC value.
SVC_GETD1: LD (TZSVCCMD), A ; Load up the command into the service record.
CALL SVC_CMD ; And make communications wit the I/O processor, returning with the required record.
OR A
LD A,255 ; Report I/O error as 255.
RET NZ
;
LD A,(TZSVCRESULT)
RET ; Return status to caller, 0 = success.
; Method to get an SD Directory entry.
; The I/O processor communications structure uses a 512 byte sector to pass SD data. A sector is cached and each call evaluates if the required request is in cache, if it is not,
; a new sector is read.
;
; Input: D = Directory entry number to retrieve.
; Output: HL = Address of directory entry.
; A = 0, no errors, A > 1 error.
GETSDDIRENT:PUSH BC
PUSH DE;
;
LD A,D
SRL A
SRL A
SRL A
SRL A ; Divide by 16 to get sector number.
LD C,A
LD A,(TZSVCDIRSEC) ; Do we have this sector in the buffer? If we do, use it.
CP C
JR Z,GETDIRSD0
LD A,TZSVC_FTYPE_MZF ; Setup to filter on MZF type files.
LD (TZSVC_FILE_TYPE),A
LD A,C
LD (TZSVCDIRSEC), A ; Store the directory sector we need.
;
CALL SVC_GETDIR ; Read a sector full of directory entries..
;
OR A
JR NZ,DIRSDERR
;
GETDIRSD0: POP DE
PUSH DE
LD A,D ; Retrieve the directory entry number required.
AND 00FH
LD HL,TZSVCSECTOR
JR Z,GETDIRSD2
LD B,A
LD DE,TZSVCDIR_ENTSZ ; Directory entry size
GETDIRSD1: ADD HL,DE ; Directory entry address into HL.
DJNZ GETDIRSD1
GETDIRSD2: POP DE
POP BC
LD A,0
GETDIRSD3: OR A
RET
;
DIRSDERR: EX DE,HL ; Print error message, show HL as it contains sector number where error occurred.
PUSH HL
POP BC ; HL to BC as the call requires the value to be displayed in BC.
LD DE,MSGSDRERR
CALL ?PRINTMSG ; Print out the filename.
POP DE
POP BC
LD A,1
JR GETDIRSD3
;PUSH HL
;POP BC
;LD DE, TESTMSG
;CALL ?PRINTMSG
;PUSH DE
;POP BC
;LD DE, TESTMSG2
;CALL ?PRINTMSG
; Method to set the file search wildcard prior to requesting a directory listing. The I/O processor applies this filter only returning directories
; which match the wildcard, ie. A* returns directories starting A...
;
; Inputs:
; DE = Pointer to BUFER start of wildcard.
;
; HL and B are not preserved.
SETWILDCARD:LD HL, TZSVCWILDC ; Location of directory name in the service record.
LD B, TZSVCWILDSZ-1
CALL GETSTRING ; Copy the string into the service record.
RET
; Method to list the directory of the SD Card.
;
; This method creates a unique sequenced number starting at 0 and attaches to each successive valid directory entry
; The file number and file name are then printed out in tabular format. The file number can be used in Load/Save commands
; instead of the filename.
;
; Inputs:
; DE = Pointer to BUFER start of wildcard if present.
;
DIRSDCARD: CALL SETWILDCARD
LD A,1 ; Setup screen for printing, account for the title line. TMPLINECNT is used for page pause.
LD (TMPLINECNT),A
LD A,0FFH
LD (TZSVCDIRSEC),A ; Reset the sector buffer in memory indicator, using 0xFF will force a reread..
;
DIRSD0: LD D,0 ; Directory entry number
LD B,0
DIRSD1: CALL GETSDDIRENT ; Get SD Directory entry details for directory entry number stored in D.
RET NZ
DIRSD2: LD A,(HL)
INC HL
OR A
RET Z
CALL PRTDIR ; Valid entry so print directory number and name pointed to by HL.
JR NZ,DIRSD4
DIRSD3: INC D ; Onto next directory entry number.
DJNZ DIRSD1
DIRSD4: RET
;
; Quick method to load the basic interpreter. So long as the filename doesnt change this method will load and boot Basic.
LOADBASIC:
IF BUILD_MZ80A > 0
LD DE,BASICFNM80A
ENDIF
IF BUILD_MZ700 > 0
LD DE,BASICFNM700
ENDIF
IF BUILD_MZ1500 > 0
LD DE,BASICFNM1500
ENDIF
JR LOADSDCARD
; Quick method to load CPM. So long as the filename doesnt change this method will load and boot CPM.
LOADCPM:
IF BUILD_MZ80A > 0
LD DE,CPMFNAME80A
ENDIF
IF BUILD_MZ700 > 0
LD DE,CPMFNAME700
ENDIF
IF BUILD_MZ1500 > 0
LD DE,CPMFNAME1500
ENDIF
JR LOADSDCARD
; Entry point when copying the SD file. Setup flags to indicate copying to effect any special processing.
; The idea is to load the file into memory, dont execute and pass back the parameters within the CMT header.
;
LOADSDCP: LD A,0FFH
LD (SDAUTOEXEC),A
JR LOADSD2
; Method/entry point to load a file header only. This method is for compatibility with the Sharp ?RDI/?RDD methods.
;
LOADSDINF: LD A,TZSVC_FTYPE_MZFHDR
JR LOADSD2C
; Method/entry point to load a file with header already preset. This method is for compatibility with the Sharp ?RDI/?RDD methods.
;
LOADSDDATA: LD A,0FEH ; Mark dont execute and dont print details.
LD (SDAUTOEXEC),A
XOR A
LD (SDCOPY),A
LD A,TZSVC_FTYPE_MZF ; Full file load.
LD (TZSVC_FILE_TYPE),A
LD HL,(DTADR) ; Load address comes from the header as caller may have changed it, ie. BASIC.
LD (TZSVC_LOADADDR),HL
LD A,0FFH ; Reset result code ready for new result.
LD (RESULT),A
JR LOADSD3A ; Load program defined in CMT header.
; Load a program from the SD Card into RAM and/or execute it.
;
; DE points to a number or filename to load.
LOADSDCARDX:LD A,0FFH
JR LOADSD1
LOADSDCARD: XOR A
LOADSD1: LD (SDAUTOEXEC),A
XOR A ; Clear copying flag.
LOADSD2: LD (SDCOPY),A
LD HL,0FFFFH ; Setup the load address to 0xFFFF = load address definded in file MZF header.
LOADSD2D: LD (TZSVC_LOADADDR),HL
;
LD A,TZSVC_FTYPE_MZF ; Default to full file load.
LOADSD2C: LD (TZSVC_FILE_TYPE),A
;
PUSH DE
LD A,0FFH ; For interbank calls, save result in a memory variable.
LD (RESULT),A
LD (TZSVC_FILE_NO), A
CALL _2HEX
JR C, LOADSD2A ;
LD (TZSVC_FILE_NO),A ; A file number was found so store it in the service structure.
LOADSD2A: CALL ?GETMODEL ; Get machine model option.
LD (HWMODEL),A
CP 008H ; Original mainboard memory is target?
LD A,000H ; tranZPUter.
JR C,LOADSD2B ; MZ-80K .. MZ-2000 modes on tranZPUter.
INC A ; Mainboard mode.
LOADSD2B: LD (TZSVC_MEM_TARGET), A
POP HL
LD A,(TZSVC_FILE_NO) ; Test to see if a file number was found, if none then a filename was given, so copy.
CP 0FFH
JR NZ,LOADSD3A
LOADSD3: LD DE,TZSVC_FILENAME
LD BC,TZSVCFILESZ
LDIR ; Copy in the MZF filename.
;
LOADSD3A: LD A,TZSVC_CMD_LOADFILE
LD (TZSVCCMD), A ; Load up the command into the service record.
CALL SVC_CMD ; And make communications with the I/O processor, returning with the required record.
OR A
JR Z, LOADSD4
LD A,255 ; Report I/O error as 255.
JP LOADSDX2
LOADSD4: LD A,(TZSVCRESULT)
OR A
JR NZ, LOADSD4A
LD A,(TZSVC_FILE_TYPE) ; Check to see if we are making a full file load, if header only then return.
CP TZSVC_FTYPE_MZF
JR Z, LOADSD14
JR LOADSDX
LOADSD4A: LD DE,MSGNOTFND
CALL ?PRINTMSG ; Print message that file wasnt found.
LD A,1
JR LOADSDX2
; The file has been found and loaded into memory by the I/O processor.
LD DE,MSGLOAD+1 ; Skip initial CR.
LD BC,NAME
CALL ?PRINTMSG ; Print out the filename.
LOADSD14: LD A,(SDCOPY) ; Copy mode?
OR A
JR NZ,LOADSD18
LD A,(SDAUTOEXEC) ; Autoexecute turned off?
CP 0FFh
JP Z,LOADSD15 ; Go back to monitor if it has been turned off, else execute.
CP 0FEH ; Extension for ?RDD - if set to 0FEH then dont print information just return.
JR Z,LOADSDX
;
LD A,(TZSVCSECTOR+TZFS_ATRB) ; Fetch the CMT data from the service sector.
LD HL,(TZSVCSECTOR+TZFS_EXADR) ; Save the execution address as it may not be in scope later on.
LD DE,(TZSVCSECTOR+TZFS_DTADR) ; Save the data address, used to check if it was a low memory load.
;
CP OBJCD ; Standard binary file?
JR Z,LOADSD14A
CP TZOBJCD0 ; TZFS binary file for a particular bank?
JR C,LOADSD17
LOADSD14A: LD A,(TZSVC_MEM_TARGET) ; Are we loading/executing in original host memory?
OR A
JR NZ,ORIPRGBOOT ; Yes, then need special bootstrap.
;
IN A,(CPLDINFO) ; Check hardware, if not MZ700/MZ800 skip memory reconfig.
AND 07H
CP MODE_MZ700
JR Z, LOADSD14B ; 700 mode we just check if the lower bank needs paging in.
CP MODE_MZ800
JR NZ, LOADSD14C
;
; DE = Load Address
LOADSD14B: LD A,010H ; Load address below 1000H? If so, page out monitor ROM.
CP D
JR C,LOADSD14C
JR NZ,LOADSD14C
OUT (MMIO0), A ; Program loaded below 1000H so page in memory.
;
LOADSD14C: LD A,(HWMODEL) ; Get hardware model the loaded program should execute under.
CP MODE_MZ800 ; Only interested in the MZ-800 at the moment, K to 700 models dont need special settings.
JR Z,LOADSD14D
JR LOADSD14E
;
LOADSD14D: XOR A
OUT (GDCMD),A ; Set MZ 800 mode
CALL ?PLTST ; Set the palette.
;
; HL = Execution address.
LOADSD14E: XOR A
JP (HL) ; Execution address.
LOADSD15: LD DE,MSGCMTDATA ; Indicate where the program was loaded and the execution address.
LD HL,(TZSVCSECTOR+TZFS_DTADR)
PUSH HL
LD HL,(TZSVCSECTOR+TZFS_EXADR)
PUSH HL
LD BC,(TZSVCSECTOR+TZFS_SIZE)
LOADSD16: CALL ?PRINTMSG ; Print out the filename.
POP BC
POP BC ; Remove parameters off stack.
LOADSDX: LD A,0 ; Non error exit.
;
LOADSDX2: LD (RESULT),A
RET
;
LOADSD17: LD DE,MSGNOTBIN
CALL ?PRINTMSG ; Print out the filename.
LD A,1
JR LOADSDX2
;
LOADSD18: XOR A
JR LOADSDX2
; Code to bootstrap a program residing in the host memory.
; It is assumed, running in TZFS, that the memory map is of TZFS and actions taken accordingly.
ORIPRGBOOT: LD A,(TMPCNT) ; Get requested mode before it goes out of scope and store.
LD C,A
;
LD A,TZMM_HOSTACCESS ; Page in host memory so we can read the execution address and run the program.
OUT (MMCFG),A
EXX ; Execution and load address are stored in HL/DE from the tape header.
LD DE,PRGBOOTJMP ; Move the relocatable code into the safe area, in this case the upper attribute RAM.
LD HL,ORIBOOTREL
LD BC,ORIBOOTRELEND - ORIBOOTREL
LDIR
EXX
JP PRGBOOTJMP
; Relocatable code which operates in a safe area within original host memory. This code then switches memory mode
; and executes the stored code.
ORIBOOTREL: LD SP,PRGBOOTJMP + (ORIBOOTRELEND - ORIBOOTREL) ; Relative as this code block is moved.
;
LD A,TZMM_ORIG ; Switch to original host mode.
OUT (MMCFG),A
OUT (MMIO4),A
; Determine if this program is loaded below 1200h? We cant initialise monitor variables for this case ; as it may corrupt the program.
LD A,D
CP 011H
JR C,ORIBOOT1 ; Some programs load data in the tape header or scratch area so need to work on 1000H or below.
;
PUSH HL ; The loaded program may call or reference monitor api procedures and the monitor scratch area
LD HL,SWPW ; state will be unknown, we therefore need to zero it to ensure correct loaded program execution.
LD B,BUFER - SWPW
XOR A
ORIBOOT0: LD (HL), A
INC HL
DJNZ ORIBOOT0
LD A,004H
LD (TEMPW),A ; Set the sound tempo to default.
;
LD A,24 ; Set the display coordinates to end of screen to not corrupt existing data.
LD (DSPXY+1),A
POP HL
;
ORIBOOT1: IN A,(CPLDINFO) ; Check hardware, if not MZ700/MZ800 skip memory reconfig.
AND 07H
CP MODE_MZ700
JR Z, ORIBOOT3 ; 700 mode we just check if the lower bank needs paging in.
CP MODE_MZ800
JR NZ, ORIBOOT4
;
ORIBOOT2: LD A,C ; Check user requested mode, original or alternative (ie. MZ-700 mode on an MZ-800).
CP 09H
JR Z,ORIBOOT3
;
XOR A ; Set the graphics display gatearray command register to enable 800 mode.
OUT (GDCMD),A
;OUT (MMIO4),A
; Set the MZ-800 palette.
PUSH HL
LD BC,05F0H ; C=port (Pallet Write), B=count
LD HL,PRGBOOTJMP + (ORIPLTDT - ORIBOOTREL) ; Data
OTIR
XOR A
LD BC,06CFH ; Border Black
OUT (C),A ; Send to port.
POP HL
;
ORIBOOT3: LD A,D ; Load address below 1000H? If so, page out monitor ROM.
CP 011H
JR NC, ORIBOOT4
OUT (MMIO0), A ; Page in lower DRAM as the program executes from below 0x1000.
;
ORIBOOT4: JP (HL) ; Execute program.
; Initialization table for Palette
;
ORIPLTDT: DB 0,10H,20H,30H,40H
; Temporary stack.
DS 32
ORISTACK EQU $
;
ORIBOOTRELEND:
; The FDC controller uses it's busy/wait signal as a ROM address line input, this
; causes a jump in the code dependent on the signal status. It gets around the 2MHz
; Z80 not being quick enough to process the signal by polling.
;------------ 0xF7C0 -----------------------------------------------------------
ALIGN_NOPS FDCJMP2
ORG FDCJMP2
FDCJMPH: JP (IY)
;------------ 0xF800 -----------------------------------------------------------
; Method to erase a file on the SD. Details of the file are passed to the I/O processor and if the file is found
; it is deleted from the SD.
; Input: DE = String containing filenumber or filename to erase.
; Output: A = 0 Success, 1 = Fail.
ERASESD: PUSH DE
LD A,0FFh ; Tag the filenumber as invalid.
LD (TZSVC_FILE_NO), A
CALL _2HEX
JR C, ERASESD1 ;
LD (TZSVC_FILE_NO),A ; A file number was found so store it in the service structure.
ERASESD1: POP HL
LD A,(TZSVC_FILE_NO) ; Test to see if a file number was found, if one wasnt then a filename was given, so copy.
CP 0FFH
JR NZ,ERASESD2
LD DE,TZSVC_FILENAME
LD BC,TZSVCFILESZ
LDIR ; Copy in the MZF filename.
ERASESD2: LD A,TZSVC_FTYPE_MZF ; Set to MZF type files.
LD (TZSVC_FILE_TYPE),A
LD A,TZSVC_CMD_ERASEFILE
LD (TZSVCCMD), A ; Load up the command into the service record.
CALL SVC_CMD ; And make communications wit the I/O processor, returning with the required record.
OR A
JR Z, ERASESD3
LD A,255 ; Report I/O error as 255.
RET
ERASESD3: LD A,(TZSVC_FILE_NO) ; Get the file number for the message output.
LD C,A
LD B,0
LD A,(TZSVCRESULT)
OR A
JR Z, ERASESD4
;
LD DE,MSGERAFAIL ; Fail, print out message.
CALL ?PRINTMSG ; Print out the filename.
LD A,1
RET
ERASESD4: LD DE,MSGERASEDIR
CALL ?PRINTMSG ; Print out the filename.
LD A,0 ; Success.
RET
; Setup for saving an application to SD Card but using the CMT header. Also set the copy flag because the values in the header
; may not reflect where the image is stored (ie. CTM LOAD=0x0000 -> data is at 0x1200).
;
SAVESDCARDX:LD A,0FFH
JR SAVESD1
; Method to save a block of memory to the SD card as a program.
; The parameters which should be given are:
; XXXXYYYYZZZZ - where XXXX = Start Address, YYYY = End Address, ZZZZ = Execution Address.
; Prompt for a filename which will be written into the CMT header.
; All the values are stored in the CMT header and copied as needed into the SD file.
;
SAVESDCARD: CALL GETCMTPARM ; Get the CMT parameters.
RET C ; Exit if an error occurred.
;
LD A,OBJCD ; Set attribute: OBJ
LD (ATRB),A
;
SAVESDDATA: XOR A ; Disable the copy flag.
SAVESD1: LD (SDCOPY),A
LD A,0FFH ; Interbank calls, pass result via a memory variable. Assume failure unless updated.
LD (RESULT),A
; Save the file by making a service call to the I/O processor, it will allocate a filename on the SD, read the tranZPUter memory directly based on the values in the
; service record.
SAVESD2: LD A,TZSVC_FTYPE_MZF ; Set to MZF type files.
LD (TZSVC_FILE_TYPE),A
LD A,TZSVC_CMD_SAVEFILE
LD (TZSVCCMD), A ; Load up the command into the service record.
CALL SVC_CMD ; And make communications with the I/O processor, returning with the required record.
OR A
JR Z, SAVESD3
LD A,255 ; Report I/O error as 255.
RET
SAVESD3: LD A,(TZSVC_FILE_NO) ; Get the file number for the message output.
LD C,A
LD B,0
LD A,(TZSVCRESULT)
OR A
JR Z, SAVESD4
;
LD DE,MSGSVFAIL ; Fail, print out message.
CALL ?PRINTMSG ; Print out the filename.
LD A,1
JR SAVESD5
SAVESD4: LD A,0 ; Success.
SAVESD5: LD (RESULT),A
RET
; Method to change the directory on the SD card where files are loaded and saved into. This involves getting a name
; and storing it in the service command structure for the I/O processor to use when searching for a file to read or saving a file.
; If the cache is in operation it is flushed and reloaded, any errors are reported and the user has to correct the error before issuing further
; SD commands.
;
; Inputs:
; DE = Pointer into BUFER where the string commences. Skip whitespace and copy upto the end marker 0x0D.
;
CHGSDDIR: LD HL, TZSVC_DIRNAME ; Location of directory name in the service record.
LD B,TZSVCDIRSZ-1 ; Ensure we dont overflow the buffer.
CALL GETSTRING
;
LD A,TZSVC_FTYPE_MZF ; Setup to filter on MZF type files.
LD (TZSVC_FILE_TYPE),A
LD A,TZSVC_CMD_CHANGEDIR ; Inform I/O processor that a directory change has taken place, allows it to cache the new dir.
LD (TZSVCCMD), A ; Load up the command into the service record.
CALL SVC_CMD ; And make communications wit the I/O processor, returning with the required record.
OR A
JR Z, CHGDIR1
LD A,255 ; Report I/O error as 255.
RET
CHGDIR1: LD A,(TZSVCRESULT)
OR A
JR Z, CHGDIR2 ; No errors.
;
LD DE,MSGCDFAIL ; Fail, print out message.
CALL ?PRINTMSG ; Print out the filename.
LD A,1
JR CHGDIR3
CHGDIR2: LD A,0 ; Success.
CHGDIR3: LD (RESULT),A
OR A
RET
;-------------------------------------------------------------------------------
; START OF TAPE/SD CMDLINE TOOLS FUNCTIONALITY
;-------------------------------------------------------------------------------
; Method to copy an application on a tape to an SD stored application. The tape drive is read and the first
; encountered program is loaded into memory at 0x1200. The CMT header is populated with the correct details (even if
; the load address isnt 0x1200, the CMT Header contains the correct value).
; A call is then made to write the application to the SD card.
; If the bulk method is called, we continue in a never ending loop, converting tape after tape.
;
TAPE2SDBULK:LD A, 1 ; Flag to indicate this is a bulk conversion.
JR TAPE2SD1
TAPE2SD: XOR A ; Flag to indicate this is a single conversion.
TAPE2SD1: PUSH AF ; Load from tape into memory, filling the tape CMT header and loading data into location 0x1200.
PUSH DE
CALL LOADTAPECP ; Call the Loadtape command, non execute version to get the tape contents into memory.
LD A,(RESULT)
OR A
JR NZ,TAPE2SDERR
; Save to SD Card.
CALL SAVESDCARDX
LD A,(RESULT)
OR A
JR NZ,TAPE2SDERR
LD DE,MSGT2SDOK
CALL ?PRINTMSG
POP DE
POP AF
OR A
JR Z, TAPE2SDERR3
JR TAPE2SD1
TAPE2SDERR: CP 2 ; Break key pressed?
JR Z,TAPE2SDERR2
LD DE,MSGT2SDERR
CALL ?PRINTMSG
TAPE2SDERR2:POP DE
POP AF
TAPE2SDERR3:RET
; Method to copy an SD stored application to a Cassette tape in the CMT.
; The directory entry number or filename is passed to the command and the entry is located within the SD
; directory structure. The file is then loaded into memory and the CMT header populated. A call is then made
; to write out the data to tape.
;
SD2TAPE: ; Load from SD, fill the CMT header then call CMT save.
CALL LOADSDCP
LD A,(RESULT)
OR A
JR NZ,SD2TAPEERR
; Tidy up header, original monitors expect CR in name for unused bytes.
LD HL,NAME
LD B,FNSIZE
SD2TAPE0: LD A,(HL)
OR A
JR NZ,SD2TAPE1
LD A,0DH
SD2TAPE1: LD (HL),A
INC HL
DJNZ SD2TAPE0
;
CALL SAVECMT
LD A,(RESULT)
OR A
JR NZ,SD2TAPEERR
RET
SD2TAPEERR: LD DE,MSGSD2TERR
CALL ?PRINTMSG
RET
;-------------------------------------------------------------------------------
; END OF TAPE/SD CMDLINE TOOLS FUNCTIONALITY
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; START OF FLOPPY DISK CONTROLLER FUNCTIONALITY
;-------------------------------------------------------------------------------
; Method to check if the floppy interface ROM is present and if it is, jump to its entry point.
;
FDCK: CALL FDCKROM ; Check to see if the Floppy ROM is present, exit if it isnt.
CALL Z,FDCROMADDR
RET ; JP CMDCMPEND
FDCKROM: LD A,(FDCROMADDR)
OR A
RET
FLOPPY: PUSH DE ; Preserve pointer to input buffer.
LD DE,BPARA ; Copy disk parameter block into RAM work area. (From)
LD HL,PRMBLK ; (To)
LD BC,0000BH ; 11 bytes of config data.
LDIR ; BC=0, HL=F0E8, DE=1013
POP DE ; init 1001-1005, port $DC mit $00
LD A,(DE) ; If not at the end of the line, then process as the boot disk number.
CP 00Dh ;
JR NZ,GETBOOTDSK ;
CALL DSKINIT ; Initialise disk and flags.
L000F: LD DE,MSGBOOTDRV ;
CALL ?PRINTMSG
LD DE,BUFER ;
CALL GETL ;
LD A,(DE) ;
CP 01BH ; Check input value is in range 1-4.
RET Z ;
LD HL,MSGLOADERR - MSGBOOTDRV - 2 ; Address of input location after printing out prompt.
ADD HL,DE ;
LD A,(HL) ;
CP 00DH ;
JR Z,L003A ;
GETBOOTDSK: CALL HEX ; Convert number to binary
JR C,L000F ; If illegal, loop back and re-prompt.
DEC A ;
CP 004H ; Check in range, if not loop back.
JR NC,L000F ;
LD (BPARA),A ; Store in parameter block.
L003A: LD IX,BPARA ; Point to drive number.,
CALL DSKREAD ; Read sector 1 of trk 0
LD HL,0CE00H ; Now compare the first 7 bytes of what was read to see if this is a bootable disk.
LD DE,DSKID ;
LD B,007H ;
L0049: LD C,(HL) ;
LD A,(DE) ;
CP C ;
JP NZ,L008C ; If NZ then this is not a master disk, ie not bootable, so error exit with message.
INC HL ;
INC DE ;
DJNZ L0049 ;
LD DE,MSGIPLLOAD ;
CALL ?PRINTMSG
LD DE,0CE07H ; Program name stored at 8th byte in boot sector.
CALL ?PRTFN
LD HL,(0CE16H) ; Get the load address
LD (IX+005H),L ; And store in parameter block at 100D/100E
LD (IX+006H),H ;
INC HL
DEC HL
JR NZ, NOTCPM ; If load address is 0 then where loading CPM.
; LD A,(MEMSW) ; Page out ROM.
NOTCPM: LD HL,(0CE14H) ; Get the size
LD (IX+003H),L ; And store in parameter block at 100B/100C
LD (IX+004H),H ;
LD HL,(0CE1EH) ; Get logical sector number
LD (IX+001H),L ; And store in parameter block at 1009/100A
LD (IX+002H),H ;
CALL DSKREAD ; Read the required data and store in memory.
CALL DSKINIT ; Reset the disk ready for next operation.
LD HL,(0CE18H) ; Get the execution address
JP (HL) ; And execute.
DSKLOADERR: LD DE,MSGLOADERR ; Loading error message
JR L008F ; (+003h)
L008C: LD DE,MSGDSKNOTMST ; This is not a boot/master disk message.
L008F: CALL ?PRINTMSG
LD DE,ERRTONE ; Play error tone.
CALL MELDY
JP ST1X ; Stack may be a mess due to the way the original AFI was written.
L0104: LD A,(MOTON) ; motor on flag
RRCA ; motor off?
CALL NC,DSKMOTORON ; yes, set motor on and wait
LD A,(IX+000H) ;drive no
OR 084H ;
OUT (0DCH),A ; Motor on for drive 0-3
XOR A ;
LD (FDCCMD),A ; clr latest FDC command byte
LD HL,00000H ;
L0119: DEC HL ;
LD A,H ;
OR L ;
JP Z,DSKERR ; Reset and print message that this is not a bootable disk.
IN A,(0D8H) ; Status register.
CPL ;
RLCA ;
JR C,L0119 ; Wait on motor off (bit 7)
LD C,(IX+000H) ; Drive number
LD HL,TRK0FD1 ; 1 track 0 flag for each drive
LD B,000H ;
ADD HL,BC ; Compute related flag 1002/1003/1004/1005
BIT 0,(HL) ;
JR NZ,L0137 ;
CALL DSKSEEKTK0 ; Seek track 0.
SET 0,(HL) ; Set bit 0 of trk 0 flag
L0137: RET
; Turn disk motor on.
DSKMOTORON: LD A,080H
OUT (0DCH),A ; Motor on
LD B,010H ;
L013E: CALL L02C7 ;
DJNZ L013E ; Wait until becomes ready.
LD A,001H ; Set motor on flag.
LD (MOTON),A ;
RET
L0149: LD A,01BH
CALL DSKCMD
AND 099H
RET
; Initialise drive and reset flags, Set motor off
DSKINIT: XOR A
OUT (0DCH),A ; Motor on/off
LD (TRK0FD1),A ; Track 0 flag drive 1
LD (TRK0FD2),A ; Track 0 flag drive 2
LD (TRK0FD3),A ; Track 0 flag drive 3
LD (TRK0FD4),A ; Track 0 flag drive 4
LD (MOTON),A ; Motor on flag
RET
DSKSEEKTK0: LD A,00BH ; Restore command, seek track 0.
CALL DSKCMD ; Send command to FDC.
AND 085H ; Process result.
XOR 004H
RET Z
JP DSKERR
DSKCMD: LD (FDCCMD),A ; Store latest FDC command.
CPL ; Compliment it (FDC bit value is reversed).
OUT (0D8H),A ; Send command to FDC.
CALL L017E ; Wait to become ready.
IN A,(0D8H) ; Get status register.
CPL ; Inverse (FDC is reverse bit logic).
RET
L017E: PUSH DE
PUSH HL
CALL L02C0
LD E,007H
L0185: LD HL,00000H
L0188: DEC HL
LD A,H
OR L
JR Z,L0196 ; (+009h)
IN A,(0D8H)
CPL
RRCA
JR C,L0188 ; (-00bh)
POP HL
POP DE
RET
L0196: DEC E
JR NZ,L0185 ; (-014h)
JP DSKERR
L019C: PUSH DE
PUSH HL
CALL L02C0
LD E,007H
L01A3: LD HL,00000H
L01A6: DEC HL
LD A,H
OR L
JR Z,L01B4 ; (+009h)
IN A,(0D8H)
CPL
RRCA
JR NC,L01A6 ; (-00bh)
POP HL
POP DE
RET
L01B4: DEC E
JR NZ,L01A3 ; (-014h)
JP DSKERR
; Read disk starting at the first logical sector in param block 1009/100A
; Continue reading for the given size 100B/100C and store in the location
; Pointed to by the address stored in the parameter block. 100D/100E
DSKREAD: CALL L0220 ; Compute logical sector-no to track-no & sector-no, retries=10
L01BD: CALL L0229 ; Set current track & sector, get load address to HL
L01C0: CALL L0249 ; Set side reg
CALL L0149 ; Command 1b output (seek)
JR NZ,L0216 ;
CALL L0259 ; Set track & sector reg
PUSH IX ; Save 1008H
LD IX, FDCJMPL ; As below. L03FE
LD IY,L01DF ; Read sector into memory.
DI
LD A,094H ; Latest FDC command byte
CALL L028A
L01DB: LD B,000H
JP (IX)
; Get data from disk sector to staging area (CE00).
L01DF: INI
LD A,(DE) ; If not at the end of the line, then process as the boot disk number.
JP NZ, FDCJMPL ; This is crucial, as the Z80 is running at 2MHz it is not fast enough so needs
; hardware acceleration in the form of a banked ROM, if disk not ready jumps to IX, if
; data ready, jumps to IY. L03FE
POP IX
INC (IX+008H) ; Increment current sector number
LD A,(IX+008H) ; Load current sector number
PUSH IX ; Save 1008H
LD IX, FDCJMPL ; As above. L03FE
CP 011H ; Sector 17? Need to loop to next track.
JR Z,L01FB
DEC D
JR NZ,L01DB
JR L01FC ; (+001h)
L01FB: DEC D
L01FC: CALL L0294
CALL L02D2
POP IX
IN A,(0D8H)
CPL
AND 0FFH
JR NZ,L0216 ; (+00bh)
CALL L0278
JP Z,L021B
LD A,(IX+007H)
JR L01C0 ; (-056h)
L0216: CALL L026A
JR L01BD ; (-05eh)
L021B: LD A,080H
OUT (0DCH),A ; Motor on
RET
L0220: CALL L02A3 ; compute logical sector no to track no & sector no
LD A,00AH ; 10 retries
LD (RETRIES),A
RET
; Set current track & sector, get load address to HL
L0229: CALL L0104
LD D,(IX+004H) ; Number of sectors to read
LD A,(IX+003H) ; Bytes to read
OR A ; 0?
JR Z,L0236 ; Yes
INC D ; Number of sectors to read + 1
L0236: LD A,(IX+00AH) ; Start sector number
LD (IX+008H),A ; To current sector number
LD A,(IX+009H) ; Start track number
LD (IX+007H),A ; To current track number
LD L,(IX+005H) ; Load address low byte
LD H,(IX+006H) ; Load address high byte
RET
; Compute side/head.
L0249: SRL A ; Track number even?
CPL ;
OUT (0DBH),A ; Output track no.
JR NC,L0254 ; Yes, even, set side/head 1
LD A,001H ; No, odd, set side/head 0
JR L0255
; Set side/head register.
L0254: XOR A ; Side 0
L0255: CPL ; Side 1
OUT (0DDH),A ; Side/head register.
RET
; Set track and sector register.
L0259: LD C,0DBH
LD A,(IX+007H) ; Current track number
SRL A
CPL
OUT (0D9H),A ; Track reg
LD A,(IX+008H) ; Current sector number
CPL
OUT (0DAH),A ; Sector reg
RET
L026A: LD A,(RETRIES)
DEC A
LD (RETRIES),A
JP Z,DSKERR
CALL DSKSEEKTK0
RET
L0278: LD A,(IX+008H)
CP 011H
JR NZ,L0287 ; (+008h)
LD A,001H
LD (IX+008H),A
INC (IX+007H)
L0287: LD A,D
OR A
RET
L028A: LD (FDCCMD),A
CPL
OUT (0D8H),A
CALL L019C
RET
L0294: LD A,0D8H
CPL
OUT (0D8H),A
CALL L017E
RET
DSKERR: CALL DSKINIT
JP DSKLOADERR
; Logical sector number to physical track and sector.
L02A3: LD B,000H
LD DE,00010H ; No of sectors per trk (16)
LD L,(IX+001H) ; Logical sector number
LD H,(IX+002H) ; 2 bytes in length
XOR A
L02AF: SBC HL,DE ; Subtract 16 sectors/trk
JR C,L02B6 ; Yes, negative value
INC B ; Count track
JR L02AF ; Loop
L02B6: ADD HL,DE ; Reset HL to the previous
LD H,B ; Track
INC L ; Correction +1
LD (IX+009H),H ; Start track no
LD (IX+00AH),L ; Start sector no
RET
L02C0: PUSH DE
LD DE,00007H
JP L02CB
L02C7: PUSH DE
LD DE,01013H
L02CB: DEC DE
LD A,E
OR D
JR NZ,L02CB ; (-005h)
POP DE
RET
L02D2: PUSH AF
LD A,(0119CH)
CP 0F0H
JR NZ,L02DB ; (+001h)
EI
L02DB: POP AF
RET
;wait on bit 0 and bit 1 = 0 of state reg
L0300: IN A,(0D8H) ; State reg
RRCA
JR C,L0300 ; Wait on not busy
RRCA
JR C,L0300 ; Wait on data reg ready
JP (IY) ; to f1df
;-------------------------------------------------------------------------------
; END OF FLOPPY DISK CONTROLLER FUNCTIONALITY
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; START OF UTILITIES
;-------------------------------------------------------------------------------
; Method to get a string parameter and copy it into the provided buffer.
;
; Inputs:
; DE = Pointer to BUFER where user entered data has been placed.
; HL = Pointer to Destination buffer.
; B = Max number of characters to read.
; Outputs:
; DE and HL point to end of bufer and buffer resepectively.
; B = Characters copied (ie. B - input B = no characters).
;
GETSTRING: LD A,(DE) ; Skip white space before copy.
CP 33
JR NC, GETSTR1
CP 00DH
JR Z, GETSTR2 ; No directory means use the I/O set default.
OR A
JR Z, GETSTR2
INC DE
JR GETSTRING
GETSTR1: LD (HL),A ; Copy the name entered by user. Validation is done on the I/O processor, bad directory name will result in error next read/write.
INC DE
INC HL
LD A,(DE) ; Get next char and check it isnt CR, end of input line character.
CP 00DH
JR Z,GETSTR2 ; Finished if we encounter CR.
DJNZ GETSTR1 ; Loop until buffer is full, ignore characters beyond buffer limit.
GETSTR2: XOR A ; Place end of buffer terminator as I/O processor uses C strings.
LD (HL),A
RET
;-------------------------------------------------------------------------------
; END OF UTILITIES
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; API METHODS - Intercept handlers to provide enhanced services to
; existing MA-700 BIOS API functions.
;-------------------------------------------------------------------------------
; Method to check if the active drive is the CMT.
CHECKCMT: LD A,(CMTINACTIVE) ; Test the flag to see if the default is to use the CMT for the CMT/SD intercept handlers.
OR A ; Flag set to > 0 if the CMT is not active.
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.
; 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.
;
; No registers or flags should be affected as we dont know the caller state.
_CMT_RDINF: 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
CALL LOADSDINF ; DE already points to the filename, call LOADSDINF to locate it on the SD card and setup the header.
POP DE
OR A
SCF
RET NZ ; > 0 = fail, return with carry set.
; Copy the filename into the Buffer provided allowing for file number to name expansion.
LD HL,NAME
LD BC,TZSVCFILESZ
LDIR
;
OR A
RET ; 0 = success, return with carry clear.
; Handler to intercept the CMT Read Data call and insert selectable SD Card
; Drive functionality.
;
; No registers or flags should be affected as we dont know the caller state.
_CMT_RDDATA:CALL LOADSDDATA
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 none 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 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:CALL SAVESDDATA
LD A,(RESULT)
OR A
JR NZ,_CMT_RDERR
RET
; Handler to intercept the CMT Verify Data call and insert selectable SD Card
; Drive functionality.
;
; No registers or flags should be affected as we dont know the caller state.
_CMT_VERIFY:CALL CHECKCMT
JR Z,_VERIFY
LD DE,MSGNOVERIFY
JR SD_ERRMSG
_VERIFY: JP ?VRFY
SD_NOTFND: LD DE,MSGNOTFND
SD_ERRMSG: CALL ?PRINTMSG
LD A,1
OR A
RET
; Method list the active directory contents.
_CMT_DIR: CALL CHECKCMT ; Cannot DIR tape drive so give error.
JP Z,_CMT_NODIR
CALL DIRSDCARD ; List the directory contents with optional directory/wildcard filter.
RET
_CMT_NODIR: LD DE,MSGNOCMTDIR
JR SD_ERRMSG
; Method to set the active directory or CMT unit/SD card. ie. \BAS to change to directory \BAS on the SD card, C to switch to CMT unit.
_CMT_CD: LD A,(DE)
CP 'C' ; Check to see if we are enabling the CMT unit.
JR NZ,_CMT_CD2
XOR A ; CMT is now active so clear the inactive flag.
_CMT_CD1: LD (CMTINACTIVE),A
RET
_CMT_CD2: CALL CHGSDDIR ; Change directory, if not valid do not update the CMTINACTIVE flag.
RET NZ
LD A,1
JR _CMT_CD1
;-------------------------------------------------------------------------------
; END OF API METHODS
;-------------------------------------------------------------------------------
; 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,0
LD C,SVCREQ
OUT (C),A
RET
; Quick load program names.
CPMFNAME80A:DB "CPM223 MZ-80A-80", 000H
BASICFNM80A:DB "BASIC-SA-5510-TZ", 000H
CPMFNAME700:DB "CPM223 MZ-700-80", 000H
CPMFNAME1500:DB "CPM223 MZ-1500-4", 000H
BASICFNM700:DB "S-BASIC", 000H
BASICFNM1500:DB "S-BASIC", 000H
DEFAULTFN: DB "DEFAULT"
DEFAULTFNE: EQU $
; Error tone.
ERRTONE: DB "A0", 0D7H, "ARA", 0D7H, "AR", 00DH
; Identifier to indicate this is a valid boot disk
DSKID: DB 002H, "IPLPRO"
; Parameter block to indicate configuration and load area.
PRMBLK: DB 000H, 000H, 000H, 000H, 001H, 000H, 0CEH, 000H, 000H, 000H, 000H
; Monitor command table. 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 UNUSED SIZE
CMDTABLE: ;DB 000H | 000H | 000H | 003H
;DB "40A" ; Switch to the 40char Sharp MZ-80A compatbile mode.
;DW SETMODE40A
;DB 000H | 000H | 000H | 003H
;DB "80A" ; Switch to the 80char Sharp MZ-80A compatbile mode.
;DW SETMODE80A
;DB 000H | 000H | 000H | 003H
;DB "80B" ; Switch to the Sharp MZ-80B compatbile mode.
;DW SETMODE80B
DB 000H | 000H | 000H | 001H ; Bit 2:0 = Command Size, 5:3 = Bank, 6 = Command match, 7 = Command table end.
DB '4' ; 40 Char screen mode.
DW SETMODE40
DB 000H | 000H | 000H | 001H
DB '8' ; 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 | 003H
DB "ASM" ; Assembler.
DW ?ASM
DB 000H | 000H | 000H | 005H
DB "BASIC" ; Load and run BASIC SA-5510.
DW LOADBASIC
DB 000H | 000H | 000H | 001H
DB 'B' ; Bell.
DW SGX
DB 000H | 000H | 000H | 003H
DB "CPM" ; Load and run CPM.
DW LOADCPM
DB 000H | 000H | 000H | 002H
DB "CP" ; Copy memory
DW ?COPYM
DB 000H | 000H | 000H | 002H
DB "CD" ; SD Card Directory change command.
DW CHGSDDIR
DB 000H | 000H | 000H | 004H
DB "DASM" ; Disassembler.
DW ?DASM
DB 000H | 000H | 000H | 003H
DB "DIR" ; List SD Card directory.
DW DIRSDCARD
DB 000H | 000H | 000H | 001H
DB 'D' ; Dump Memory.
DW ?DUMPX
DB 000H | 000H | 000H | 002H
DB "EC" ; Erase file.
DW ERASESD
DB 000H | 000H | 000H | 002H
DB "EX" ; Exit out of TZFS to original Monitor.
DW EXITTZFS
DB 000H | 000H | 000H | 004H
DB "FILL" ; Fill Memory.
DW ?FILL
DB 000H | 000H | 000H | 004H
DB "FREQ" ; Set or change the CPU frequency.
DW ?SETFREQ
DB 000H | 000H | 000H | 001H
DB 'F' ; RFS Floppy boot code.
DW FLOPPY
DB 000H | 000H | 000H | 001H
DB 'H' ; Help screen.
DW ?HELP
DB 000H | 000H | 000H | 001H
DB 'J' ; Jump to address.
DW GOTOX
DB 000H | 000H | 000H | 004H
DB "LTNX" ; Load from CMT without auto execution.
DW LOADTAPENX
DB 000H | 000H | 000H | 002H
DB "LT" ; Load from CMT
DW LOADTAPE
DB 000H | 000H | 000H | 004H
DB "LCNX" ; Load from SDCARD without auto execution.
DW LOADSDCARDX
DB 000H | 000H | 000H | 002H
DB "LC" ; Load from SD CARD
DW LOADSDCARD
DB 000H | 000H | 000H | 001H
DB "L" ; Original Load from CMT
DW LOADTAPE
;
IF BUILD_FUSIONX = 0
DB 000H | 000H | 000H | 005H
DB "MZ80K" ; Invoke MZ80K Hardware Emulation.
DW ?SETMZ80K
DB 000H | 000H | 000H | 005H
DB "MZ80C" ; Invoke MZ80C Hardware Emulation.
DW ?SETMZ80C
DB 000H | 000H | 000H | 006H
DB "MZ1200" ; Invoke MZ1200 Hardware Emulation.
DW ?SETMZ1200
DB 000H | 000H | 000H | 005H
DB "MZ80A" ; Invoke MZ80A Hardware Emulation.
DW ?SETMZ80A
DB 000H | 000H | 000H | 005H
DB "MZ700" ; Invoke MZ700 Hardware Emulation.
DW ?SETMZ700
DB 000H | 000H | 000H | 006H
DB "MZ1500" ; Invoke MZ1500 Hardware Emulation.
DW ?SETMZ1500
DB 000H | 000H | 000H | 005H
DB "MZ800" ; Invoke MZ800 Hardware Emulation.
DW ?SETMZ800
DB 000H | 000H | 000H | 005H
DB "MZ80B" ; Invoke MZ80B Hardware Emulation.
DW ?SETMZ80B
DB 000H | 000H | 000H | 006H
DB "MZ2000" ; Invoke MZ2000 Hardware Emulation.
DW ?SETMZ2000
DB 000H | 000H | 000H | 006H
DB "MZ2200" ; Invoke MZ2200 Hardware Emulation.
DW ?SETMZ2200
DB 000H | 000H | 000H | 006H
DB "MZ2500" ; Invoke MZ2500 Hardware Emulation.
DW ?SETMZ2500
DB 000H | 000H | 000H | 002H
DB "MZ" ; Invoke default MZ80A Hardware Emulation.
DW ?SETMZ80A
ENDIF
;
DB 000H | 000H | 000H | 001H
DB 'M' ; Edit Memory.
DW ?MCORX
DB 000H | 000H | 000H | 001H
DB 'P' ; Printer test.
DW ?PTESTX
DB 000H | 000H | 000H | 003H
DB "RIO" ; Read I/O
DW ?READIO
DB 000H | 000H | 000H | 001H
DB 'R' ; Memory test.
DW MEMTEST
DB 000H | 000H | 000H | 004H
DB "SD2T" ; Copy SD Card to Tape.
DW SD2TAPE
DB 000H | 000H | 000H | 002H
DB "SC" ; Save to SD CARD
DW SAVESDCARD
DB 000H | 000H | 000H | 002H
DB "ST" ; Save to CMT
DW SAVEX
DB 000H | 000H | 000H | 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 | 000H | 005H
DB "T2SDB" ; Copy Tape to SD Card in bulk mode.
DW TAPE2SDBULK
DB 000H | 000H | 000H | 004H
DB "T2SD" ; Copy Tape to SD Card.
DW TAPE2SD
IF BUILD_FUSIONX = 0
DB 000H | 000H | 000H | 003H
DB "T80" ; Switch to soft T80 CPU.
DW ?SETT80
ENDIF
DB 000H | 000H | 000H | 002H
DB "TC" ; Tape timing compensation.
DW ?TAPECOMP
DB 000H | 000H | 000H | 001H
DB 'T' ; Timer test.
DW ?TIMERTST
IF BUILD_FUSIONX = 0
DB 000H | 000H | 000H | 007H
DB "VBORDER" ; Set VGA border colour.
DW ?SETVBORDER
DB 000H | 000H | 000H | 005H
DB "VMODE" ; Set VGA mode.
DW ?SETVMODE
DB 000H | 000H | 000H | 003H
DB "VGA" ; Set VGA mode.
DW ?SETVGAMODE
ENDIF
DB 000H | 000H | 000H | 001H
DB 'V' ; Verify CMT Save.
DW VRFYX
DB 000H | 000H | 000H | 003H
DB "WIO" ; Write I/O
DW ?WRITEIO
IF BUILD_FUSIONX = 0
DB 000H | 000H | 000H | 003H
DB "Z80" ; Switch to soft Z80 CPU.
DW ?SETZ80
DB 000H | 000H | 000H | 003H
DB "ZPU" ; Switch to soft ZPU Evolution CPU.
DW ?SETZPUEVO
DB 000H | 000H | 000H | 001H
ENDIF
;-------------------------------------------------------------------------------
; END OF TZFS COMMAND FUNCTIONS.
;-------------------------------------------------------------------------------
;
; Ensure we fill the entire 64K by padding with 00's.
;
ALIGN_NOPS 10000H
MEND:
;
; Include all other banks which make up the TZFS system.
;
INCLUDE "tzfs_bank2.asm"
INCLUDE "tzfs_bank3.asm"
INCLUDE "tzfs_bank4.asm"