3913 lines
181 KiB
NASM
3913 lines
181 KiB
NASM
;--------------------------------------------------------------------------------------------------------
|
|
;-
|
|
;- Name: cbiosII.asm
|
|
;- Created: January 2020
|
|
;- Author(s): Philip Smart
|
|
;- Description: Sharp MZ series CPM BIOS System.
|
|
;- This assembly language program is written to utilise the paged RAM memory modes of
|
|
;- the tranZPUter hardware running on the Sharp MZ80A computer. The purpose is to
|
|
;- provide more TPA to CP/M by hiding the support logic in a RAM bank outside of the
|
|
;- 64K address space of CPM. The basics have to exist within the 64K for CP/M to
|
|
;- function correctly, ie. disk buffers, stack and jump tables but the remainder
|
|
;- are placed in a different bank which has 48K available RAM just for CBIOS.
|
|
;-
|
|
;- Credits:
|
|
;- Copyright: (c) 2018-20 Philip Smart <philip.smart@net2net.org>
|
|
;-
|
|
;- History: Jan 2020 - Seperated Bank from RFS for dedicated use with CPM CBIOS.
|
|
; May 2020 - Advent of the new RFS PCB v2.0, quite a few changes to accommodate the
|
|
; additional and different hardware. The SPI is now onboard the PCB and
|
|
; not using the printer interface card.
|
|
; May 2020 - Cut taken from the MZ80A RFS version of CPM CBIOS to create a version of
|
|
; CPM suitable to run on the tranZPUter. The memory models are different
|
|
; providing more memory at different locations for use by CPM.
|
|
;--------------------------------------------------------------------------------------------------------
|
|
;- 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/>.
|
|
;--------------------------------------------------------------------------------------------------------
|
|
|
|
;======================================
|
|
;
|
|
; RAM BANK - CPM CBIOS II
|
|
;
|
|
;======================================
|
|
ORG 00000H
|
|
|
|
; In order to preserve the interrupt vectors when CPM mode 7 is enabled (ie. this
|
|
; bank is paged in), the area from 0x0000:0x003F maps to the memory block in mode 6
|
|
; so this is unuseable space in this bank. In addition, CPM uses 0x0000:0x0100
|
|
; for many vectors and buffers so this memory is also mapped to the memory block in
|
|
; mode 6.
|
|
;------------ 0x0000 -----------------------------------------------------------
|
|
PAD 00040H
|
|
;------------ 0x0040 -----------------------------------------------------------
|
|
PAD 00100H
|
|
;------------ 0x0100 -----------------------------------------------------------
|
|
|
|
LVARSTART EQU $ ; Start of local page variables.
|
|
SPV:
|
|
IBUFE: ; TAPE BUFFER (128 BYTES)
|
|
ATRB: DS 1 ; ATTRIBUTE
|
|
NAME: DS 17 ; FILE NAME
|
|
SIZE: DS 2 ; BYTESIZE
|
|
DTADR: DS 2 ; DATA ADDRESS
|
|
EXADR: DS 2 ; EXECUTION ADDRESS
|
|
COMNT: DS 92 ; Comment / code area of CMT header.
|
|
SWPW: DS 10 ; SWEEP WORK
|
|
KDATW: DS 2 ; KEY WORK
|
|
KANAF: DS 1 ; KANA FLAG (01=GRAPHIC MODE)
|
|
DSPXY: DS 2 ; DISPLAY COORDINATES
|
|
MANG: DS 6 ; COLUMN MANAGEMENT
|
|
MANGE: DS 1 ; COLUMN MANAGEMENT END
|
|
PBIAS: DS 1 ; PAGE BIAS
|
|
ROLTOP: DS 1 ; ROLL TOP BIAS
|
|
MGPNT: DS 1 ; COLUMN MANAG. POINTER
|
|
PAGETP: DS 2 ; PAGE TOP
|
|
ROLEND: DS 1 ; ROLL END
|
|
DS 14 ; BIAS
|
|
FLASH: DS 1 ; FLASHING DATA
|
|
SFTLK: DS 1 ; SHIFT LOCK
|
|
REVFLG: DS 1 ; REVERSE FLAG
|
|
FLSDT: DS 1 ; CURSOR DATA
|
|
STRGF: DS 1 ; STRING FLAG
|
|
DPRNT: DS 1 ; TAB COUNTER
|
|
SWRK: DS 1 ; KEY SOUND FLAG
|
|
TEMPW: DS 1 ; TEMPO WORK
|
|
ONTYO: DS 1 ; ONTYO WORK
|
|
OCTV: DS 1 ; OCTAVE WORK
|
|
RATIO: DS 2 ; ONPU RATIO
|
|
DSPXYADDR: DS 2 ; Address of last known position.
|
|
|
|
DRVAVAIL DS 1 ; Flag to indicate which drive controllers are available. Bit 2 = SD, Bit 1 = ROM, Bit 0 = FDC
|
|
MOTON DS 1 ; MOTOR ON = 1, OFF = 0
|
|
TMPADR DS 2 ; TEMPORARY ADDRESS STORAGE
|
|
TMPSIZE DS 2 ; TEMPORARY SIZE
|
|
TMPCNT DS 2 ; TEMPORARY COUNTER
|
|
;
|
|
FLASHCTL: DS 1 ; CURSOR FLASH CONTROL. BIT 0 = Cursor On/Off, BIT 1 = Cursor displayed.
|
|
TIMESEC: DS 6 ; RTC 48bit TIME IN MILLISECONDS
|
|
NDISKS: DS 1 ; Dynamically calculated number of disks on boot.
|
|
DISKTYPE: DS 1 ; Disk type of current selection.
|
|
MTROFFTIMER:DS 1 ; Second down counter for FDC motor off.
|
|
;
|
|
SEKDSK: DS 1 ; Seek disk number
|
|
SEKTRK: DS 2 ; Seek disk track
|
|
SEKSEC: DS 1 ; Seek sector number
|
|
SEKHST: DS 1 ; Seek sector host
|
|
;
|
|
HSTACT: DS 1 ;
|
|
;
|
|
UNACNT: DS 1 ; Unalloc rec cnt
|
|
UNADSK: DS 1 ; Last unalloc disk
|
|
UNATRK: DS 2 ; Last unalloc track
|
|
UNASEC: DS 1 ; Last unalloc sector
|
|
;
|
|
READOP: DS 1 ; If read operation then 1, else 0 for write.
|
|
RSFLAG: DS 1 ; Read sector flag.
|
|
WRTYPE: DS 1 ; Write operation type.
|
|
DMAADDR: DS 2 ; Last DMA address
|
|
|
|
FDCCMD DS 1 ; LAST FDC COMMAND SENT TO CONTROLLER.
|
|
INVFDCDATA: DS 1 ; INVERT DATA COMING FROM FDC, 1 = INVERT, 0 = AS IS
|
|
TRK0FD1 DS 1 ; FD 1 IS AT TRACK 0 = BIT 0 set
|
|
TRK0FD2 DS 1 ; FD 2 IS AT TRACK 0 = BIT 0 set
|
|
TRK0FD3 DS 1 ; FD 3 IS AT TRACK 0 = BIT 0 set
|
|
TRK0FD4 DS 1 ; FD 4 IS AT TRACK 0 = BIT 0 set
|
|
RETRIES DS 2 ; DATA READ RETRIES
|
|
DISKMAP: DS MAXDISKS ; Disk map of CPM logical to physical controller disk.
|
|
FDCDISK: DS 1 ; Physical disk number.
|
|
SECPERTRK: DS 1 ; Sectors per track for 1 head.
|
|
SECPERHEAD: DS 1 ; Sectors per head.
|
|
SECTORCNT: DS 1 ; Sector size as a count of how many sectors make 512 bytes.
|
|
HSTDSK: DS 1 ; Host disk number
|
|
HSTTRK: DS 2 ; Host track number
|
|
HSTSEC: DS 1 ; Host sector number
|
|
HSTWRT: DS 1 ; Host write flag
|
|
ERFLAG: DS 1 ; Error number, 0 = no error.
|
|
TRACKNO: DS 2 ; Host controller track number
|
|
SECTORNO: DS 1 ; Host controller sector number
|
|
|
|
CURSORPSAV DS 2 ; Cursor save position;default 0,0
|
|
HAVELOADED DS 1 ; To show that a value has been put in for Ansi emualtor.
|
|
ANSIFIRST DS 1 ; Holds first character of Ansi sequence
|
|
NUMBERBUF DS 20 ; Buffer for numbers in Ansi
|
|
NUMBERPOS DS 2 ; Address within buffer
|
|
CHARACTERNO DS 1 ; Byte within Ansi sequence. 0=first,255=other
|
|
CURSORCOUNT DS 1 ; 1/50ths of a second since last change
|
|
FONTSET DS 1 ; Ansi font setup.
|
|
JSW_FF DS 1 ; Byte value to turn on/off FF routine
|
|
JSW_LF DS 1 ; Byte value to turn on/off LF routine
|
|
CHARACTER DS 1 ; To buffer character to be printed.
|
|
CURSORPOS DS 2 ; Cursor position, default 0,0.
|
|
BOLDMODE DS 1
|
|
HIBRITEMODE DS 1 ; 0 means on, &C9 means off
|
|
UNDERSCMODE DS 1
|
|
ITALICMODE DS 1
|
|
INVMODE DS 1
|
|
CHGCURSMODE DS 1
|
|
ANSIMODE DS 1 ; 1 = on, 0 = off
|
|
COLOUR EQU 0
|
|
|
|
LVAREND EQU $ ; End of local page variables
|
|
|
|
IF $ > 0300H
|
|
ERROR "Keybuf var not aligned, addr=%s, required=%s"; % $, 0300H
|
|
ENDIF
|
|
ALIGN_NOPS 0300H
|
|
KEYBUF: DS KEYBUFSIZE, 0DH ; Interrupt driven keyboard buffer.
|
|
KEYCOUNT: DS 1, 000H
|
|
KEYWRITE: DS 2, 000H ; Pointer into the buffer where the next character should be placed.
|
|
KEYREAD: DS 2, 000H ; Pointer into the buffer where the next character can be read.
|
|
KEYLAST: DS 1, 000H ; KEY LAST VALUE
|
|
KEYRPT: DS 1, 000H ; KEY REPEAT COUNTER
|
|
|
|
DS 64, 0FFH ; Stack space for cold and warm boot.
|
|
BOOTSTACK EQU $
|
|
;
|
|
|
|
; Start of CPM entry points.
|
|
;
|
|
IF $ > 0400H
|
|
ERROR "Stack var not aligned, addr=%s, required=%s"; % $, 0400H
|
|
ENDIF
|
|
ALIGN_NOPS 0400H
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; BOOT
|
|
;
|
|
; The BOOT entry point gets control from the cold start loader and is
|
|
; responsible for basic system initialization, including sending a sign-on
|
|
; message, which can be omitted in the first version.
|
|
; If the IOBYTE function is implemented, it must be set at this point.
|
|
; The various system parameters that are set by the WBOOT entry point must be
|
|
; initialized, and control is transferred to the CCP at 3400 + b for further
|
|
; processing. Note that register C must be set to zero to select drive A.
|
|
;
|
|
; NB. This code is executed by the MZF loader. The following code is assembled
|
|
; in the header at $1108 to ensure correct startup.
|
|
; BOOTSTG1: LD A,TZMM_CPM2 ; Switch to CPM memory mode 2
|
|
; OUT (MMCFG), A
|
|
; JP QBOOT_ ; Execute cold boot.
|
|
; REBOOT: LD A,TZMM_TZFS ; Switch to TZFS memory mode.
|
|
; OUT (MMCFG),A
|
|
; JP MROMADDR ; Now restart in the SA1510 monitor.
|
|
;-------------------------------------------------------------------------------
|
|
QBOOT_: DI ; Disable Interrupts and sat mode. NB. Interrupts are physically disabled by 8255 Port C2 set to low.
|
|
IM 1
|
|
;
|
|
LD SP,BOOTSTACK ; Setup to use local stack until CPM takes over.
|
|
;
|
|
LD HL,0066H ; Set NMI so it doesnt bother us.
|
|
LD (HL), 0EDH ; Set to RETN instruction.
|
|
INC HL
|
|
LD (HL), 045H
|
|
;
|
|
LD HL,GVARSTART ; Start of global variable area
|
|
LD BC,GVAREND-GVARSTART ; Size of global variable area.
|
|
XOR A
|
|
LD D,A
|
|
INIT1: LD (HL),D ; Clear variable memory including stack space.
|
|
INC HL
|
|
DEC BC
|
|
LD A,B
|
|
OR C
|
|
JR NZ,INIT1
|
|
;
|
|
LD HL,LVARSTART ; Start of local page variable area
|
|
LD BC,LVAREND-LVARSTART ; Size of local page variable area.
|
|
XOR A
|
|
LD D,A
|
|
INIT2: LD (HL),D ; Clear variable memory.
|
|
INC HL
|
|
DEC BC
|
|
LD A,B
|
|
OR C
|
|
JR NZ,INIT2
|
|
;
|
|
CALL MODE ; Configure 8255 port C, set Motor Off, VGATE to 1 (off) and INTMSK to 0 (interrupts disabled).
|
|
LD A,004H
|
|
LD (TEMPW),A ; Setup the tempo for sound output.
|
|
|
|
INIT3: ; Setup keyboard buffer control.
|
|
LD A,0
|
|
LD (KEYCOUNT),A ; Set keyboard buffer to empty.
|
|
LD HL,KEYBUF
|
|
LD (KEYWRITE),HL ; Set write pointer to beginning of keyboard buffer.
|
|
LD (KEYREAD),HL ; Set read pointer to beginning of keyboard buffer.
|
|
|
|
; Setup keyboard rate control and set to CAPSLOCK mode.
|
|
; (0 = Off, 1 = CAPSLOCK, 2 = SHIFTLOCK).
|
|
LD A,000H ; Initialise key repeater.
|
|
LD (KEYRPT),A
|
|
LD A,001H
|
|
LD (SFTLK),A ; Setup shift lock, default = off.
|
|
|
|
; Setup the initial cursor, for CAPSLOCK this is a double underscore.
|
|
LD A,03EH
|
|
LD (FLSDT),A
|
|
LD A,080H ; Cursor on (Bit D7=1).
|
|
LD (FLASHCTL),A
|
|
|
|
; Initialise the display, either the Video Module, 40/80 Colour Card or standard 40 column display.
|
|
IF BUILD_VIDEOMODULE = 1
|
|
IN A, (CPLDINFO) ; Get hardware information.
|
|
BIT 3,A
|
|
JR Z, INIT80CHAR ; If no video module present then see if the 40/80 column board installed else need to use 40 char mode.
|
|
AND 007H
|
|
LD D, A
|
|
OR MODE_VIDEO_FPGA ; Ensure the video hardware is enabled.
|
|
OUT (CPLDCFG),A
|
|
LD A, D
|
|
OR MODE_80CHAR ; Enable 80 char display.
|
|
OUT (VMCTRL),A ; Activate.
|
|
LD A, D
|
|
CP MODE_MZ80A ; Check to see if this is the MZ80A, if so, change BUS speed.
|
|
JR NZ, INIT80END
|
|
; LD A, SYSMODE_MZ80B ; Set bus and default CPU speed to 4MHz
|
|
; OUT (SYSCTRL),A ; Activate.
|
|
JR INIT80END
|
|
ENDIF
|
|
INIT80CHAR: IF BUILD_80C = 1
|
|
LD HL,DSPCTL ; Setup address of display control register latch.
|
|
LD A, 128 ; 80 char mode.
|
|
LD E,(HL) ; Dummy operation to enable latch write via multivibrator.
|
|
LD (HL), A
|
|
ENDIF
|
|
;
|
|
; If no video module and no 40/80 Colour Card then the default will be 40 column display.
|
|
;
|
|
INIT80END: LD A,016H
|
|
CALL PRNT
|
|
LD A,071H ; Blue background, white characters in colour mode. Bit 7 is set as a write to bit 7 @ DFFFH selects 80Char mode.
|
|
LD HL,ARAM
|
|
CALL CLR8
|
|
CALL MLDSP
|
|
CALL NL
|
|
LD DE,CBIOSSIGNON ; Start of sign on message, as devices are detected they are added to the sign on.
|
|
CALL MONPRTSTR
|
|
CALL BEL ; Beep to indicate startup - for cases where screen is slow to startup.
|
|
LD A,0FFH
|
|
LD (SWRK),A
|
|
|
|
LD HL,NUMBERBUF
|
|
LD (NUMBERPOS),HL
|
|
;
|
|
XOR A
|
|
LD (IOBYT),A
|
|
LD (CDISK),A
|
|
|
|
; DRVAVAIL flag definition. Version 1.25 - removed ROM Drives and RAM drives as they provided no speed or use benefit compared with SD drives.
|
|
;
|
|
; 1 = Active.
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; ^ ^ ^ ^ ^ ^ ^ ^
|
|
; | | | | | | | |-- Floppy Drive Present
|
|
; | | | | | | |---- ROM Drive Present
|
|
; | | | | | |------ SD Card Present
|
|
; | | | | |-------- RAM Drive Present
|
|
; | | | |----------
|
|
; | | |------------
|
|
; | |--------------
|
|
; |---------------- Drives present
|
|
;
|
|
; Initialise the disk subsystem.
|
|
;
|
|
LD A,0 ; No drives yet detected so zero available mask.
|
|
SET 2,A ; The SD Card is always present on the I/O processor, we cant run without it..
|
|
;
|
|
LD DE,SDAVAIL
|
|
CALL PRTSTRTMSG
|
|
|
|
;
|
|
CALL DSKINIT ; Initialise the floppy disk subsystem.
|
|
JR NZ,STRT5
|
|
LD A,(DRVAVAIL)
|
|
SET 0,A ; Indicate Floppy drives are available.
|
|
|
|
LD DE,FDCAVAIL ; Output indicator that FDC drives are available.
|
|
CALL PRTSTRTMSG
|
|
;
|
|
STRT5: LD DE,CBIOSIGNEND ; Terminate the signon message which now includes list of drives detected.
|
|
CALL MONPRTSTR
|
|
CALL NL
|
|
;
|
|
; Setup the disk parameter blocks according
|
|
; to connected drives and available memory.
|
|
;
|
|
LD DE,DPBASE ; Base of parameter block.
|
|
LD A,0 ; Using scratch area, setup the disk count, pointer to ALV memory and pointer to CSV memory.
|
|
LD (CDIRBUF),A
|
|
LD HL,CSVALVMEM
|
|
LD (CDIRBUF+1),HL
|
|
|
|
; Add as many SD Drives as RAM permits.
|
|
STRT6: CALL ADDSDDRIVE ; Add a drive, NZ return means error, memory limit or max disks reached.
|
|
JR NZ,STRT8
|
|
JR STRT6
|
|
|
|
; Setup the 1.44MB Floppy Disk Drives.
|
|
;
|
|
STRT8: CALL ADDFLPYDRV
|
|
CALL ADDFLPYDRV ; No Floppy drives available then skip.
|
|
;
|
|
LD A,(CDIRBUF)
|
|
LD (NDISKS),A ; Setup max number of system disks found on this boot up.
|
|
|
|
; Setup timer interrupts
|
|
LD IX,TIMIN ; Pass the interrupt service handler vector.
|
|
LD BC,00000H ; Time starts at 00:00:00 01/01/1980 on initialisation.
|
|
LD DE,00000H
|
|
LD HL,00000H
|
|
CALL TIMESET
|
|
|
|
; Signon message after all the hardware has been initialised.
|
|
LD DE,CPMSIGNON
|
|
CALL MONPRTSTR
|
|
;
|
|
; CP/M init
|
|
CPMINIT: LD A,(DRVAVAIL)
|
|
BIT 0,A
|
|
JR Z,CPMINIT1
|
|
;
|
|
CALL DSKINIT ; Re-initialise the disk subsystem if available.
|
|
XOR A ; 0 to accumulator
|
|
LD (HSTACT),A ; Host buffer inactive
|
|
LD (UNACNT),A ; Clear unalloc count
|
|
;
|
|
CPMINIT1: LD A, 0C3H ; C3 IS A JMP INSTRUCTION
|
|
LD (00000H), A ; FOR JMP TO WBOOT
|
|
LD HL, WBOOTE ; WBOOT ENTRY POINT
|
|
LD (00001H), HL ; SET ADDRESS FIELD FOR JMP AT 0
|
|
LD (00005H), A ; FOR JMP TO BDOS
|
|
LD HL, CPMBDOS ; BDOS ENTRY POINT
|
|
LD (00006H), HL ; ADDRESS FIELD OF JUMP AT 5 TO BDOS
|
|
LD HL,TIMIN ; Re-install interrupt vector for RTC incase it was overwritten.
|
|
LD (00038H),A
|
|
LD (00039H),HL
|
|
LD BC,CPMUSERDMA
|
|
CALL QSETDMA_
|
|
;
|
|
; check if current disk is valid
|
|
LD A,(NDISKS) ; Get the dynamic disk count.
|
|
LD L,A
|
|
LD A, (CDISK) ; GET CURRENT USER/DISK NUMBER (UUUUDDDD)
|
|
AND 00FH ; Isolate the disk number.
|
|
CP L ; Drive number ok?
|
|
JR C, CPMINIT2 ; Yes, jump (Carry set if A < NDISKS)
|
|
LD A, (CDISK) ; No, set disk 0 (previous user)
|
|
AND 0F0H
|
|
LD (CDISK), A ; Save User/Disk
|
|
CPMINIT2: CALL SETDRVMAP ; Refresh the map of physical floppies to CPM drive number.
|
|
CALL SETDRVCFG
|
|
; LD A,(DISKTYPE)
|
|
; OR A
|
|
; CALL Z,SELDRIVE ; Select and start disk drive motor if floppy disk.
|
|
;
|
|
LD A, (CDISK)
|
|
LD C, A ; C = current User/Disk for CCP jump (UUUUDDDD)
|
|
JP BOOT_ ; Cold boot CPM now that most initialisation is complete. This is a direct jump to the fixed bios area 0xF000
|
|
|
|
; Method to add an SD drive into the CPM disk definitions.
|
|
; If the SD controller hasnt been detected the routine exits without configuration.
|
|
ADDSDDRIVE: LD A,(DRVAVAIL)
|
|
BIT 2,A
|
|
JR Z,ADDSDDRVEX ; No SD interface so skip.
|
|
;
|
|
; 16MB SD Card Drives.
|
|
;
|
|
LD BC,0 ; Setup CSV/ALV parameters for a 16MB SD Card drive.
|
|
LD (CDIRBUF+3),BC
|
|
LD BC,257 ; 2048/8 + 1
|
|
LD (CDIRBUF+5),BC
|
|
LD BC,DPB4
|
|
LD (CDIRBUF+7),BC ; Address of Disk Parameters
|
|
|
|
LD A,(CDIRBUF)
|
|
CP MAXDISKS - 2 ; Make sure we have parameter table entries available to add further drives, ensuring slots for the FDC.
|
|
JR Z,ADDSDDRVEX
|
|
;
|
|
LD (TZSVC_FILE_NO),A ; Indicate the drive number the file will be attached to.
|
|
LD A,TZSVC_CMD_ADDSDDRIVE ; I/O processor command to attach a CPM drive to the file number given.
|
|
CALL SVC_CMD
|
|
OR A
|
|
JR NZ,ADDSDDRVEX ; No drive available, skip.
|
|
;
|
|
; Check that RAM is available to add this drive.
|
|
;
|
|
LD BC,(CDIRBUF+1)
|
|
LD HL,CSVALVEND - 2048/8 + 1 ; Subtract the size of the ALV (CSV has no size for a fixed SD drive)
|
|
OR A
|
|
SBC HL,BC
|
|
JR C,ADDSDDRVEX ; If there is no more space, exit.
|
|
|
|
CALL COPYDPB ; Add in an SD drive.
|
|
XOR A
|
|
RET
|
|
ADDSDDRVEX: LD A,1
|
|
OR A
|
|
RET
|
|
|
|
; Method to add a Floppy drive into the CPM disk definitions table.
|
|
; If the Floppy controller hasnt been detected then skip without configuration.
|
|
ADDFLPYDRV: LD A,(DRVAVAIL)
|
|
BIT 0,A
|
|
JR Z,ADDSDDRVEX ; No Floppy drives available then skip.
|
|
|
|
LD A,(CDIRBUF)
|
|
CP MAXDISKS ; Use the disk count to ensure we only add upto 2 FDC drives.
|
|
JR Z,ADDSDDRVEX
|
|
|
|
LD BC,128/4 ; Setup CSV/ALV parameters for a 1.4MB Floppy drive.
|
|
LD (CDIRBUF+3),BC
|
|
LD BC,91 ; 720/8 + 1
|
|
LD (CDIRBUF+5),BC
|
|
LD BC,DPB3
|
|
LD (CDIRBUF+7),BC ; Address of Disk Parameters
|
|
|
|
LD BC,(CDIRBUF+1) ; Make sure there is memory available for the FDC drives.
|
|
LD HL,CSVALVEND - 720/8 + 1
|
|
OR A
|
|
SBC HL,BC
|
|
JR C,ADDSDDRVEX ; If there is no more space, exit.
|
|
CALL COPYDPB ; Add in a floppy drive.
|
|
|
|
XOR A
|
|
RET
|
|
|
|
; Helper method to print a message with a comma if Bit 7 of A is set.
|
|
PRTSTRTMSG: PUSH AF
|
|
BIT 7,A
|
|
JR Z,PRTCOMMA1
|
|
LD A,','
|
|
CALL PRNT
|
|
PRTCOMMA1: CALL MONPRTSTR
|
|
POP AF
|
|
SET 7,A
|
|
LD (DRVAVAIL),A
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; WBOOT
|
|
;
|
|
; The WBOOT entry point gets control when a warm start occurs.
|
|
; A warm start is performed whenever a user program branches to location
|
|
; 0000H, or when the CPU is reset from the front panel. The CP/M system must
|
|
; be loaded from the first two tracks of drive A up to, but not including,
|
|
; the BIOS, or CBIOS, if the user has completed the patch. System parameters
|
|
; must be initialized as follows:
|
|
;
|
|
; location 0,1,2
|
|
; Set to JMP WBOOT for warm starts (000H: JMP 4A03H + b)
|
|
;
|
|
; location 3
|
|
; Set initial value of IOBYTE, if implemented in the CBIOS
|
|
;
|
|
; location 4
|
|
; High nibble = current user number, low nibble = current drive
|
|
;
|
|
; location 5,6,7
|
|
; Set to JMP BDOS, which is the primary entry point to CP/M for transient
|
|
; programs. (0005H: JMP 3C06H + b)
|
|
;
|
|
; Refer to Section 6.9 for complete details of page zero use. Upon completion
|
|
; of the initialization, the WBOOT program must branch to the CCP at 3400H+b
|
|
; to restart the system.
|
|
; Upon entry to the CCP, register C is set to the drive to select after system
|
|
; initialization. The WBOOT routine should read location 4 in memory, verify
|
|
; that is a legal drive, and pass it to the CCP in register C.
|
|
;-------------------------------------------------------------------------------
|
|
QWBOOT_: DI
|
|
;
|
|
LD SP,BOOTSTACK
|
|
|
|
; Reload the CCP and BDOS from SD.
|
|
LD A,TZSVC_CMD_LOADBDOS ; I/O processor command to load the CCP+BDOS
|
|
LD HL,CBASE
|
|
LD (TZSVC_LOADADDR),HL ; Address where to load the CCP+BDOS
|
|
LD HL,CPMBIOS-CBASE
|
|
LD (TZSVC_LOADSIZE),HL ; Size of the CCP+BDOS area.
|
|
CALL SVC_CMD
|
|
OR A
|
|
JP Z, CPMINIT ; Initialise CPM and run.
|
|
LD DE,NOBDOS
|
|
CALL MONPRTSTR
|
|
WBOOT2: JR WBOOT2 ; Cannot continue, no BDOS/CCP.
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; CONOUT
|
|
;
|
|
; The character is sent from register C to the console output device.
|
|
; The character is in ASCII, with high-order parity bit set to zero. You
|
|
; might want to include a time-out on a line-feed or carriage return, if the
|
|
; console device requires some time interval at the end of the line (such as
|
|
; a TI Silent 700 terminal). You can filter out control characters that cause
|
|
; the console device to react in a strange way (CTRL_Z causes the Lear-
|
|
; Siegler terminal to clear the screen, for example).
|
|
;-------------------------------------------------------------------------------
|
|
QCONOUT_: LD A,C
|
|
CALL ANSITERM
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; CONIN
|
|
;
|
|
; The next console character is read into register A, and the parity bit is
|
|
; set, high-order bit, to zero. If no console character is ready, wait until
|
|
; a character is typed before returning.
|
|
;-------------------------------------------------------------------------------
|
|
QCONIN_: CALL GETKY
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; CONST
|
|
;
|
|
; You should sample the status of the currently assigned console device and
|
|
; return 0FFH in register A if a character is ready to read and 00H in
|
|
; register A if no console characters are ready.
|
|
;-------------------------------------------------------------------------------
|
|
QCONST_: CALL CHKKY
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; READER
|
|
;
|
|
; The next character is read from the currently assigned reader device into
|
|
; register A with zero parity (high-order bit must be zero); an end-of-file
|
|
; condition is reported by returning an ASCII CTRL_Z(1AH).
|
|
;-------------------------------------------------------------------------------
|
|
QREADER_: LD A, 01AH ; Reader not implemented.
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; PUNCH
|
|
;
|
|
; The character is sent from register C to the currently assigned punch
|
|
; device. The character is in ASCII with zero parity.
|
|
;-------------------------------------------------------------------------------
|
|
QPUNCH_: RET ; Punch not implemented
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; LIST
|
|
;
|
|
; The character is sent from register C to the currently assigned listing
|
|
; device. The character is in ASCII with zero parity bit.
|
|
;-------------------------------------------------------------------------------
|
|
QLIST_: RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; LISTST
|
|
;
|
|
; You return the ready status of the list device used by the DESPOOL program
|
|
; to improve console response during its operation. The value 00 is returned
|
|
; in A if the list device is not ready to accept a character and 0FFH if a
|
|
; character can be sent to the printer. A 00 value should be returned if LIST
|
|
; status is not implemented.
|
|
;-------------------------------------------------------------------------------
|
|
QLISTST_: XOR A ; Not implemented.
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; HOME
|
|
;
|
|
; The disk head of the currently selected disk (initially disk A) is moved to
|
|
; the track 00 position. If the controller allows access to the track 0 flag
|
|
; from the drive, the head is stepped until the track 0 flag is detected. If
|
|
; the controller does not support this feature, the HOME call is translated
|
|
; into a call to SETTRK with a parameter of 0.
|
|
;-------------------------------------------------------------------------------
|
|
QHOME_: LD BC,00000H
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; SETTRK
|
|
;
|
|
; Register BC contains the track number for subsequent disk accesses on the
|
|
; currently selected drive. The sector number in BC is the same as the number
|
|
; returned from the SECTRN entry point. You can choose to seek the selected
|
|
; track at this time or delay the seek until the next read or write actually
|
|
; occurs. Register BC can take on values in the range 0-76 corresponding to
|
|
; valid track numbers for standard floppy disk drives and 0-65535 for
|
|
; nonstandard disk subsystems.
|
|
;-------------------------------------------------------------------------------
|
|
QSETTRK_: LD (SEKTRK),BC ; Set track passed from BDOS in register BC.
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; SETSEC
|
|
;
|
|
; Register BC contains the sector number, 1 through 26, for subsequent disk
|
|
; accesses on the currently selected drive. The sector number in BC is the
|
|
; same as the number returned from the SECTRAN entry point. You can choose to
|
|
; send this information to the controller at this point or delay sector
|
|
; selection until a read or write operation occurs.
|
|
;-------------------------------------------------------------------------------
|
|
QSETSEC_: LD A,C ; Set sector passed from BDOS in register BC.
|
|
LD (SEKSEC), A
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; SETDMA
|
|
;
|
|
; Register BC contains the DMA (Disk Memory Access) address for subsequent
|
|
; read or write operations. For example, if B = 00H and C = 80H when SETDMA
|
|
; is called, all subsequent read operations read their data into 80H through
|
|
; 0FFH and all subsequent write operations get their data from 80H through
|
|
; 0FFH, until the next call to SETDMA occurs. The initial DMA address is
|
|
; assumed to be 80H. The controller need not actually support Direct Memory
|
|
; Access. If, for example, all data transfers are through I/O ports, the
|
|
; CBIOS that is constructed uses the 128 byte area starting at the selected
|
|
; DMA address for the memory buffer during the subsequent read or write
|
|
; operations.
|
|
;-------------------------------------------------------------------------------
|
|
QSETDMA_: LD (DMAADDR),BC
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; SELDSK
|
|
;
|
|
; The disk drive given by register C is selected for further operations,
|
|
; where register C contains 0 for drive A, 1 for drive B, and so on up to 15
|
|
; for drive P (the standard CP/M distribution version supports four drives).
|
|
; On each disk select, SELDSK must return in HL the base address of a 16-byte
|
|
; area, called the Disk Parameter Header, described in Section 6.10.
|
|
; For standard floppy disk drives, the contents of the header and associated
|
|
; tables do not change; thus, the program segment included in the sample
|
|
; CBIOS performs this operation automatically.
|
|
;
|
|
; If there is an attempt to select a nonexistent drive, SELDSK returns
|
|
; HL = 0000H as an error indicator. Although SELDSK must return the header
|
|
; address on each call, it is advisable to postpone the physical disk select
|
|
; operation until an I/O function (seek, read, or write) is actually
|
|
; performed, because disk selects often occur without ultimately performing
|
|
; any disk I/O, and many controllers unload the head of the current disk
|
|
; before selecting the new drive. This causes an excessive amount of noise
|
|
; and disk wear. The least significant bit of register E is zero if this is
|
|
; the first occurrence of the drive select since the last cold or warm start.
|
|
;-------------------------------------------------------------------------------
|
|
QSELDSK_: LD HL, 00000H ; HL = error code
|
|
LD A,(NDISKS)
|
|
LD B,A
|
|
LD A,C
|
|
CP B
|
|
JR NC,SELDSK1 ; Ensure we dont select a non existant disk.
|
|
LD (CDISK),A ; Setup drive.
|
|
SELDSK0: CALL SETDRVCFG
|
|
LD A,(DISKTYPE)
|
|
CP DSKTYP_SDC
|
|
JR Z,SELSDCDSK ; Select SD Card.
|
|
; If it is not an SD drive then it must be a floppy disk.
|
|
LD A,C
|
|
JR CALCHL
|
|
SELDSK1: RET
|
|
|
|
; For SD Cards, check that the SD Card is present, otherwise illegal disk.
|
|
SELSDCDSK: LD A,(DRVAVAIL)
|
|
BIT 2,A
|
|
JR Z,SELDSK1 ; No SD Card drives available then skip.
|
|
LD A,C
|
|
|
|
; Code for blocking and deblocking algorithm
|
|
; (see CP/M 2.2 Alteration Guide p.34 and APPENDIX G)
|
|
CALCHL: LD (SEKDSK),A
|
|
RLC A ; *2
|
|
RLC A ; *4
|
|
RLC A ; *8
|
|
RLC A ; *16
|
|
LD HL,DPBASE
|
|
LD B,0
|
|
LD C,A
|
|
ADD HL,BC
|
|
JR SELDSK1
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; SECTRAN
|
|
;
|
|
; Logical-to-physical sector translation is performed to improve the overall
|
|
; response of CP/M. Standard CP/M systems are shipped with a skew factor of
|
|
; 6, where six physical sectors are skipped between each logical read
|
|
; operation. This skew factor allows enough time between sectors for most
|
|
; programs to load their buffers without missing the next sector. In
|
|
; particular computer systems that use fast processors, memory, and disk
|
|
; subsystems, the skew factor might be changed to improve overall response.
|
|
; However, the user should maintain a single-density IBM-compatible version
|
|
; of CP/M for information transfer into and out of the computer system, using
|
|
; a skew factor of 6.
|
|
;
|
|
; In general, SECTRAN receives a logical sector number relative to zero in BC
|
|
; and a translate table address in DE. The sector number is used as an index
|
|
; into the translate table, with the resulting physical sector number in HL.
|
|
; For standard systems, the table and indexing code is provided in the CBIOS
|
|
; and need not be changed.
|
|
;-------------------------------------------------------------------------------
|
|
QSECTRN_: LD H,B
|
|
LD L,C
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; READ
|
|
;
|
|
; Assuming the drive has been selected, the track has been set, and the DMA
|
|
; address has been specified, the READ subroutine attempts to read one sector
|
|
; based upon these parameters and returns the following error codes in
|
|
; register A:
|
|
;
|
|
; 0 - no errors occurred
|
|
; 1 - non recoverable error condition occurred
|
|
;
|
|
; Currently, CP/M responds only to a zero or nonzero value as the return
|
|
; code. That is, if the value in register A is 0, CP/M assumes that the disk
|
|
; operation was completed properly. If an error occurs the CBIOS should
|
|
; attempt at least 10 retries to see if the error is recoverable. When an
|
|
; error is reported the BDOS prints the message BDOS ERR ON x: BAD SECTOR.
|
|
; The operator then has the option of pressing a carriage return to ignore
|
|
; the error, or CTRL_C to abort.
|
|
;-------------------------------------------------------------------------------
|
|
;
|
|
; Code for blocking and deblocking algorithm
|
|
; (see CP/M 2.2 Alteration Guide p.34 and APPENDIX G)
|
|
;
|
|
QREAD_: XOR A
|
|
LD (UNACNT), A
|
|
LD A, 1
|
|
LD (READOP), A ; read operation
|
|
LD (RSFLAG), A ; must read data
|
|
LD A, WRUAL
|
|
LD (WRTYPE), A ; treat as unalloc
|
|
CALL RWOPER ; to perform the read, returns with A=0 no errors or A > 0 errors.
|
|
RET
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; WRITE
|
|
;
|
|
; Data is written from the currently selected DMA address to the currently
|
|
; selected drive, track, and sector. For floppy disks, the data should be
|
|
; marked as nondeleted data to maintain compatibility with other CP/M
|
|
; systems. The error codes given in the READ command are returned in register
|
|
; A, with error recovery attempts as described above.
|
|
;-------------------------------------------------------------------------------
|
|
;
|
|
; Code for blocking and deblocking algorithm
|
|
; (see CP/M 2.2 Alteration Guide p.34 and APPENDIX G)
|
|
;
|
|
QWRITE_: XOR A ; 0 to accumulator
|
|
LD (READOP), A ; not a read operation
|
|
LD A, C ; write type in c
|
|
LD (WRTYPE), A
|
|
CP WRUAL ; write unallocated?
|
|
JR NZ, CHKUNA ; check for unalloc
|
|
; write to unallocated, set parameters
|
|
LD A, BLKSIZ/128 ; next unalloc recs
|
|
LD (UNACNT), A
|
|
LD A, (SEKDSK) ; disk to seek
|
|
LD (UNADSK), A ; unadsk = sekdsk
|
|
LD HL, (SEKTRK)
|
|
LD (UNATRK), HL ; unatrk = sectrk
|
|
LD A, (SEKSEC)
|
|
LD (UNASEC), A ; unasec = seksec
|
|
; check for write to unallocated sector
|
|
CHKUNA: LD A,(UNACNT) ; any unalloc remain?
|
|
OR A
|
|
JR Z, ALLOC ; skip if not
|
|
; more unallocated records remain
|
|
DEC A ; unacnt = unacnt-1
|
|
LD (UNACNT), A
|
|
LD A, (SEKDSK) ; same disk?
|
|
LD HL, UNADSK
|
|
CP (HL) ; sekdsk = unadsk?
|
|
JP NZ, ALLOC ; skip if not
|
|
; disks are the same
|
|
LD HL, UNATRK
|
|
CALL SEKTRKCMP ; sektrk = unatrk?
|
|
JP NZ, ALLOC ; skip if not
|
|
; tracks are the same
|
|
LD A, (SEKSEC) ; same sector?
|
|
LD HL, UNASEC
|
|
CP (HL) ; seksec = unasec?
|
|
JP NZ, ALLOC ; skip if not
|
|
; match, move to next sector for future ref
|
|
INC (HL) ; unasec = unasec+1
|
|
LD A, (HL) ; end of track?
|
|
CP CPMSPT ; count CP/M sectors
|
|
JR C, NOOVF ; skip if no overflow
|
|
; overflow to next track
|
|
LD (HL), 0 ; unasec = 0
|
|
LD HL, (UNATRK)
|
|
INC HL
|
|
LD (UNATRK), HL ; unatrk = unatrk+1
|
|
; match found, mark as unnecessary read
|
|
NOOVF: XOR A ; 0 to accumulator
|
|
LD (RSFLAG), A ; rsflag = 0
|
|
JR ALLOC2 ; to perform the write
|
|
; not an unallocated record, requires pre-read
|
|
ALLOC: XOR A ; 0 to accum
|
|
LD (UNACNT), A ; unacnt = 0
|
|
INC A ; 1 to accum
|
|
ALLOC2: LD (RSFLAG), A ; rsflag = 1
|
|
CALL RWOPER
|
|
RET
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; 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: DI
|
|
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 MONPRTSTR
|
|
POP DE
|
|
LD A,1 ; No response, error.
|
|
EI
|
|
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 MONPRTSTR
|
|
POP DE
|
|
LD A,2
|
|
EI
|
|
RET
|
|
SVC_CMD6: XOR A ; Success.
|
|
POP BC
|
|
POP BC
|
|
EI
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF SERVICE COMMAND METHODS
|
|
;-------------------------------------------------------------------------------
|
|
|
|
|
|
; Method to clear memory either to 0 or a given pattern.
|
|
;
|
|
CLR8Z: XOR A
|
|
CLR8: LD BC,00800H
|
|
CLRMEM: PUSH DE
|
|
LD D,A
|
|
L09E8: LD (HL),D
|
|
INC HL
|
|
DEC BC
|
|
LD A,B
|
|
OR C
|
|
JR NZ,L09E8
|
|
POP DE
|
|
RET
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF SD CARD DRIVE FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
; Method to read a sector from the SD Card.
|
|
; All reads occur in a 512byte sector.
|
|
;
|
|
; CPM Provides us with a track and sector, take these and pass them to the I/O
|
|
; processor which will map the params into the file associated with the drive.
|
|
;
|
|
; Inputs: (HSTTRK) - 16bit track number.
|
|
; (HSTSEC) - 8bit sector number.
|
|
; (CDISK) - Disk drive number.
|
|
SDCREAD: LD HL,(HSTTRK) ; 16bit track.
|
|
LD (TZSVC_TRACK_NO),HL
|
|
LD H,0 ; Only use 8 bit sector numbers at the moment.
|
|
LD A,(HSTSEC)
|
|
LD L,A
|
|
LD (TZSVC_SECTOR_NO),HL
|
|
LD A,(CDISK) ; Disk drive no.
|
|
LD (TZSVC_FILE_NO),A
|
|
;
|
|
LD A,TZSVC_CMD_READSDDRIVE
|
|
CALL SVC_CMD
|
|
OR A
|
|
JP READHST3
|
|
|
|
; Method to write a sector for CPM using its track/sector addressing.
|
|
; All writes occur in a 512byte sector.
|
|
;
|
|
; Inputs: (HSTTRK) - 16bit track number.
|
|
; (HSTSEC) - 8bit sector number.
|
|
; (CDISK) - Disk drive number.
|
|
; Outputs: A = 1 - Error.
|
|
; A = 0 - Success.
|
|
SDCWRITE: LD HL,(HSTTRK) ; 16bit track.
|
|
LD (TZSVC_TRACK_NO),HL
|
|
LD H,0 ; Only use 8 bit sector numbers at the moment.
|
|
LD A,(HSTSEC)
|
|
LD L,A
|
|
LD (TZSVC_SECTOR_NO),HL
|
|
LD A,(CDISK) ; Disk drive no.
|
|
LD (TZSVC_FILE_NO),A
|
|
;
|
|
LD A,TZSVC_CMD_WRITESDDRIVE
|
|
CALL SVC_CMD
|
|
OR A
|
|
JP WRITEHST3
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF SD CARD DRIVE FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF CPM DEBLOCKING ALGORITHM
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; RWOPER
|
|
;
|
|
; The common blocking/deblocking algorithm provided by DR to accommodate devices
|
|
; which have sector sizes bigger than the CPM 128byte standard sector.
|
|
; In this implementation a sector size of 512 has been chosen regardless of
|
|
; what the underlying hardware uses (ie. FDC is 256 byte for a standard MZ800
|
|
; format disk).
|
|
;-------------------------------------------------------------------------------
|
|
RWOPER: XOR A ; zero to accum
|
|
LD (ERFLAG), A ; no errors (yet)
|
|
LD A, (SEKSEC) ; compute host sector
|
|
OR A ; carry = 0
|
|
RRA ; shift right
|
|
OR A ; carry = 0
|
|
RRA ; shift right
|
|
LD (SEKHST), A ; host sector to seek
|
|
; active host sector?
|
|
LD HL, HSTACT ; host active flag
|
|
LD A, (HL)
|
|
LD (HL), 1 ; always becomes 1
|
|
OR A ; was it already?
|
|
JR Z, FILHST ; fill host if not
|
|
; host buffer active, same as seek buffer?
|
|
LD A, (SEKDSK)
|
|
LD HL, HSTDSK ; same disk?
|
|
CP (HL) ; sekdsk = hstdsk?
|
|
JR NZ, NOMATCH
|
|
; same disk, same track?
|
|
LD HL, HSTTRK
|
|
CALL SEKTRKCMP ; sektrk = hsttrk?
|
|
JR NZ, NOMATCH
|
|
; same disk, same track, same buffer?
|
|
LD A, (SEKHST)
|
|
LD HL, HSTSEC ; sekhst = hstsec?
|
|
CP (HL)
|
|
JR Z, MATCH ; skip if match
|
|
; proper disk, but not correct sector
|
|
NOMATCH: LD A, (HSTWRT) ; host written?
|
|
OR A
|
|
CALL NZ, WRITEHST ; clear host buff
|
|
; may have to fill the host buffer
|
|
FILHST: LD A, (SEKDSK)
|
|
LD (HSTDSK), A
|
|
LD HL, (SEKTRK)
|
|
LD (HSTTRK), HL
|
|
LD A, (SEKHST)
|
|
LD (HSTSEC), A
|
|
LD A, (RSFLAG) ; need to read?
|
|
OR A
|
|
CALL NZ, READHST ; yes, if 1
|
|
OR A
|
|
JR NZ,RWEXIT ; If A > 0 then read error occurred.
|
|
XOR A ; 0 to accum
|
|
LD (HSTWRT), A ; no pending write
|
|
; copy data to or from buffer
|
|
MATCH: LD A, (SEKSEC) ; mask buffer number
|
|
AND SECMSK ; least signif bits
|
|
LD L, A ; ready to shift
|
|
LD H, 0 ; double count
|
|
ADD HL, HL
|
|
ADD HL, HL
|
|
ADD HL, HL
|
|
ADD HL, HL
|
|
ADD HL, HL
|
|
ADD HL, HL
|
|
ADD HL, HL
|
|
; hl has relative host buffer address
|
|
LD DE, HSTBUF
|
|
ADD HL, DE ; hl = host address
|
|
EX DE, HL ; now in DE
|
|
LD HL, (DMAADDR) ; get/put CP/M data
|
|
LD C, 128 ; length of move
|
|
LD A, (READOP) ; which way?
|
|
OR A
|
|
JR NZ, RWMOVE ; skip if read
|
|
; write operation, mark and switch direction
|
|
LD A, 1
|
|
LD (HSTWRT), A ; hstwrt = 1
|
|
EX DE, HL ; source/dest swap
|
|
; c initially 128, DE is source, HL is dest
|
|
RWMOVE: LD A,(INVFDCDATA) ; Check to see if FDC data needs to be inverted. MB8866 controller works on negative logic.
|
|
RRCA
|
|
JR NC,RWMOVE3
|
|
RWMOVE2: CALL MEMCPYINV
|
|
JR RWMOVE4
|
|
RWMOVE3: CALL MEMCPY
|
|
; data has been moved to/from host buffer
|
|
RWMOVE4: LD A, (WRTYPE) ; write type
|
|
CP WRDIR ; to directory?
|
|
LD A, (ERFLAG) ; in case of errors
|
|
RET NZ ; no further processing
|
|
; clear host buffer for directory write
|
|
OR A ; errors?
|
|
RET NZ ; skip if so
|
|
XOR A ; 0 to accum
|
|
LD (HSTWRT), A ; buffer written
|
|
CALL WRITEHST
|
|
RWEXIT: LD A, (ERFLAG)
|
|
RET
|
|
|
|
; utility subroutine for 16-bit compare
|
|
; HL = .unatrk or .hsttrk, compare with sektrk
|
|
SEKTRKCMP: EX DE, HL
|
|
LD HL, SEKTRK
|
|
LD A, (DE) ; low byte compare
|
|
CP (HL) ; same?
|
|
RET NZ ; return if not
|
|
; low bytes equal, test high 1s
|
|
INC DE
|
|
INC HL
|
|
LD A, (DE)
|
|
CP (HL) ; sets flags
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------------------------
|
|
; Read physical sector from host
|
|
;
|
|
; Read data from the floppy disk or SD. A = 1 if an error occurred.
|
|
;------------------------------------------------------------------------------------------------
|
|
READHST: PUSH BC
|
|
PUSH HL
|
|
LD A,(DISKTYPE)
|
|
CP DSKTYP_SDC ; Is the drive an SD Card?
|
|
JP Z,SDCREAD
|
|
READHST2: CALL DSKREAD ; Floppy card, use the FDC Controller.
|
|
READHST3: POP HL
|
|
POP BC
|
|
RET
|
|
|
|
;------------------------------------------------------------------------------------------------
|
|
; Write physical sector to host
|
|
;
|
|
; Write data to the floppy disk or SD. A = 1 if an error occurred.
|
|
;------------------------------------------------------------------------------------------------
|
|
WRITEHST: PUSH BC
|
|
PUSH HL
|
|
LD A,(DISKTYPE)
|
|
CP DSKTYP_SDC ; Is the drive an SD Card?
|
|
JP Z,SDCWRITE
|
|
CALL DSKWRITE
|
|
WRITEHST3: POP HL
|
|
POP BC
|
|
RET
|
|
WRITEHST4: LD A,1 ; Error, cannot write.
|
|
JR WRITEHST3
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF CPM DEBLOCKING ALGORITHM
|
|
;-------------------------------------------------------------------------------
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF AUDIO CONTROLLER FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
; Melody function.
|
|
MLDY: PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD A,002H
|
|
LD (OCTV),A
|
|
LD B,001H
|
|
MLD1: LD A,(DE)
|
|
CP 00DH
|
|
JR Z,MLD4
|
|
CP 0C8H
|
|
JR Z,MLD4
|
|
CP 0CFH
|
|
JR Z,MLD2
|
|
CP 02DH
|
|
JR Z,MLD2
|
|
CP 02BH
|
|
JR Z,MLD3
|
|
CP 0D7H
|
|
JR Z,MLD3
|
|
CP 023H
|
|
LD HL,MTBL
|
|
JR NZ,MLD1A
|
|
LD HL,M?TBL
|
|
INC DE
|
|
MLD1A: CALL ONPU
|
|
JR C,MLD1
|
|
CALL RYTHM
|
|
JR C,MLD5
|
|
CALL MLDST
|
|
LD B,C
|
|
JR MLD1
|
|
MLD2: LD A,003H
|
|
MLD2A: LD (OCTV),A
|
|
INC DE
|
|
JR MLD1
|
|
MLD3: LD A,001H
|
|
JR MLD2A
|
|
MLD4: CALL RYTHM
|
|
MLD5: PUSH AF
|
|
CALL MLDSP
|
|
POP AF
|
|
POP HL
|
|
POP DE
|
|
POP BC
|
|
RET
|
|
|
|
ONPU: PUSH BC
|
|
LD B,008H
|
|
LD A,(DE)
|
|
ONP1A: CP (HL)
|
|
JR Z,ONP2
|
|
INC HL
|
|
INC HL
|
|
INC HL
|
|
DJNZ ONP1A
|
|
SCF
|
|
INC DE
|
|
POP BC
|
|
RET
|
|
|
|
ONP2: INC HL
|
|
PUSH DE
|
|
LD E,(HL)
|
|
INC HL
|
|
LD D,(HL)
|
|
EX DE,HL
|
|
LD A,H
|
|
OR A
|
|
JR Z,ONP2B
|
|
LD A,(OCTV)
|
|
ONP2A: DEC A
|
|
JR Z,ONP2B
|
|
ADD HL,HL
|
|
JR ONP2A
|
|
ONP2B: LD (RATIO),HL
|
|
LD HL,OCTV
|
|
LD (HL),002H
|
|
DEC HL
|
|
POP DE
|
|
INC DE
|
|
LD A,(DE)
|
|
LD B,A
|
|
AND 0F0H
|
|
CP 030H
|
|
JR Z,ONP2C
|
|
LD A,(HL)
|
|
JR ONP2D
|
|
ONP2C: INC DE
|
|
LD A,B
|
|
AND 00FH
|
|
LD (HL),A
|
|
ONP2D: LD HL,OPTBL
|
|
ADD A,L
|
|
LD L,A
|
|
LD C,(HL)
|
|
LD A,(TEMPW)
|
|
LD B,A
|
|
XOR A
|
|
JP MLDDLY
|
|
|
|
RYTHM: LD HL,KEYPA
|
|
LD (HL),0F0H
|
|
INC HL
|
|
LD A,(HL)
|
|
AND 081H
|
|
JR NZ,L02D5
|
|
SCF
|
|
RET
|
|
|
|
L02D5: LD A,(SUNDG)
|
|
RRCA
|
|
JR C,L02D5
|
|
L02DB: LD A,(SUNDG)
|
|
RRCA
|
|
JR NC,L02DB
|
|
DJNZ L02D5
|
|
XOR A
|
|
RET
|
|
|
|
MLDST: LD HL,(RATIO)
|
|
LD A,H
|
|
OR A
|
|
JR Z,MLDSP
|
|
PUSH DE
|
|
EX DE,HL
|
|
LD HL,CONT0
|
|
LD (HL),E
|
|
LD (HL),D
|
|
LD A,001H
|
|
POP DE
|
|
JR L02C4
|
|
MLDSP: LD A,034H
|
|
LD (CONTF),A
|
|
XOR A
|
|
L02C4: LD (SUNDG),A
|
|
RET
|
|
|
|
MLDDLY: ADD A,C
|
|
DJNZ MLDDLY
|
|
POP BC
|
|
LD C,A
|
|
XOR A
|
|
RET
|
|
|
|
|
|
TEMPO: PUSH AF
|
|
PUSH BC
|
|
AND 00FH
|
|
LD B,A
|
|
LD A,008H
|
|
SUB B
|
|
LD (TEMPW),A
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
|
|
;
|
|
; Method to sound the bell, basically play a constant tone.
|
|
;
|
|
BEL: PUSH DE
|
|
LD DE,00DB1H
|
|
CALL MLDY
|
|
POP DE
|
|
RET
|
|
|
|
;
|
|
; Melody (note) lookup table.
|
|
;
|
|
MTBL: DB 043H
|
|
DB 077H
|
|
DB 007H
|
|
DB 044H
|
|
DB 0A7H
|
|
DB 006H
|
|
DB 045H
|
|
DB 0EDH
|
|
DB 005H
|
|
DB 046H
|
|
DB 098H
|
|
DB 005H
|
|
DB 047H
|
|
DB 0FCH
|
|
DB 004H
|
|
DB 041H
|
|
DB 071H
|
|
DB 004H
|
|
DB 042H
|
|
DB 0F5H
|
|
DB 003H
|
|
DB 052H
|
|
DB 000H
|
|
DB 000H
|
|
M?TBL: DB 043H
|
|
DB 00CH
|
|
DB 007H
|
|
DB 044H
|
|
DB 047H
|
|
DB 006H
|
|
DB 045H
|
|
DB 098H
|
|
DB 005H
|
|
DB 046H
|
|
DB 048H
|
|
DB 005H
|
|
DB 047H
|
|
DB 0B4H
|
|
DB 004H
|
|
DB 041H
|
|
DB 031H
|
|
DB 004H
|
|
DB 042H
|
|
DB 0BBH
|
|
DB 003H
|
|
DB 052H
|
|
DB 000H
|
|
DB 000H
|
|
|
|
OPTBL: DB 001H
|
|
DB 002H
|
|
DB 003H
|
|
DB 004H
|
|
DB 006H
|
|
DB 008H
|
|
DB 00CH
|
|
DB 010H
|
|
DB 018H
|
|
DB 020H
|
|
;-------------------------------------------------------------------------------
|
|
; END OF AUDIO CONTROLLER FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF RTC FUNCTIONALITY (INTR HANDLER IN MAIN CBIOS)
|
|
;-------------------------------------------------------------------------------
|
|
;
|
|
; BC:DE:HL contains the time in milliseconds (100msec resolution) since 01/01/1980. In IX is held the interrupt service handler routine address for the RTC.
|
|
; HL contains lower 16 bits, DE contains middle 16 bits, BC contains upper 16bits, allows for a time from 00:00:00 to 23:59:59, for > 500000 days!
|
|
; NB. Caller must disable interrupts before calling this method.
|
|
TIMESET: LD (TIMESEC),HL ; Load lower 16 bits.
|
|
EX DE,HL
|
|
LD (TIMESEC+2),HL ; Load middle 16 bits.
|
|
PUSH BC
|
|
POP HL
|
|
LD (TIMESEC+4),HL ; Load upper 16 bits.
|
|
;
|
|
LD HL,CONTF
|
|
LD (HL),074H ; Set Counter 1, read/load lsb first then msb, mode 2 rate generator, binary
|
|
LD (HL),0B0H ; Set Counter 2, read/load lsb first then msb, mode 0 interrupt on terminal count, binary
|
|
DEC HL
|
|
LD DE,TMRTICKINTV ; 100Hz coming into Timer 2 from Timer 1, set divisor to set interrupts per second.
|
|
LD (HL),E ; Place current time in Counter 2
|
|
LD (HL),D
|
|
DEC HL
|
|
IF BUILD_MZ80A = 1
|
|
LD (HL),03BH ; Place divisor in Counter 1, = 315, thus 31500/315 = 100
|
|
LD (HL),001H
|
|
ENDIF
|
|
IF BUILD_MZ700 = 1
|
|
LD (HL),09CH ; Place divisor in Counter 1, = 156, thus 15611/156 = 100
|
|
LD (HL),000H
|
|
ENDIF
|
|
NOP
|
|
NOP
|
|
NOP
|
|
;
|
|
LD A, 0C3H ; Install the interrupt vector for when interrupts are enabled.
|
|
LD (00038H),A
|
|
LD (00039H),IX
|
|
RET
|
|
|
|
; Time Read;
|
|
; Returns BC:DE:HL where HL is lower 16bits, DE is middle 16bits and BC is upper 16bits of milliseconds since 01/01/1980.
|
|
TIMEREAD: LD HL,(TIMESEC+4)
|
|
PUSH HL
|
|
POP BC
|
|
LD HL,(TIMESEC+2)
|
|
EX DE,HL
|
|
LD HL,(TIMESEC)
|
|
RET
|
|
;-------------------------------------------------------------------------------
|
|
; END OF RTC FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF FDC CONTROLLER FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;------------------------------------------------------------------------------------------------
|
|
; Initialise drive and reset flags, Set motor off
|
|
;------------------------------------------------------------------------------------------------
|
|
DSKINIT: XOR A
|
|
OUT (FDC_MOTOR),A ; Motor 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
|
|
LD (MTROFFTIMER),A ; Clear the down counter for motor off.
|
|
LD A,(FDCJMP1) ; Check to see if the FDC AFI ROM is installed, use this as
|
|
AND 0DFH ; Byte can be either DD or FD dependent on the FDC wait line,
|
|
CP 0DDH ; so check both to determine if the FDC is present.
|
|
RET
|
|
|
|
; Function to create a mapping table between a CPM disk and a physical disk.
|
|
SETDRVMAP: PUSH HL
|
|
PUSH DE
|
|
PUSH BC
|
|
; Zero out the map.
|
|
LD B,MAXDISKS
|
|
LD HL,DISKMAP
|
|
LD A,0FFH
|
|
SETDRVMAP1: LD (HL),A
|
|
INC HL
|
|
DJNZ SETDRVMAP1
|
|
LD HL,DISKMAP ; Place in the Map for next drive.
|
|
; Now go through each disk from the Disk Parameter Base list.
|
|
LD B,0 ; Disk number count = CDISK.
|
|
LD DE,0 ; Physical disk number, D = FDC, E = SDC.
|
|
SETDRVMAP2: LD A,B
|
|
CP MAXDISKS
|
|
JR Z,SETDRVMAP6
|
|
INC B
|
|
PUSH HL
|
|
PUSH DE
|
|
PUSH BC
|
|
; For the Disk in A, find the parameter table.
|
|
RLC A ; *2
|
|
RLC A ; *4
|
|
RLC A ; *8
|
|
RLC A ; *16
|
|
LD HL,DPBASE ; Base of disk description block.
|
|
LD B,0
|
|
LD C,A
|
|
ADD HL,BC ; HL contains address of actual selected disk block.
|
|
LD C,10
|
|
ADD HL,BC ; HL contains address of pointer to disk parameter block.
|
|
LD E,(HL)
|
|
INC HL
|
|
LD D,(HL) ; DE contains address of disk parameter block.
|
|
EX DE,HL
|
|
LD A,(HL)
|
|
LD E,A
|
|
LD BC,15
|
|
ADD HL,BC ; Move to configuuration byte which identifies the disk type.
|
|
;
|
|
POP BC
|
|
POP DE
|
|
LD A,(HL)
|
|
POP HL
|
|
|
|
BIT 4,A ; Disk type = FDC
|
|
JR Z,SETDRVMAP4 ; Is this an FDC controlled disk, if so store the mapping number in the map unchanged.
|
|
;
|
|
BIT 3,A ; Is this an SD Card disk, if so, add 080H to the mapping number and store.
|
|
JR Z,SETDRVMAP5
|
|
LD A,E
|
|
OR 080H
|
|
INC E
|
|
JR SETDRVMAP5
|
|
;
|
|
SETDRVMAP4: LD A,D
|
|
INC D
|
|
SETDRVMAP5: LD (HL),A
|
|
INC HL
|
|
JR SETDRVMAP2
|
|
;
|
|
SETDRVMAP6: POP BC
|
|
POP DE
|
|
POP HL
|
|
RET
|
|
|
|
; Function to setup the drive parameters according to the CFG byte in the disk parameter block.
|
|
SETDRVCFG: PUSH HL
|
|
PUSH DE
|
|
PUSH BC
|
|
LD A,(CDISK)
|
|
RLC A ; *2
|
|
RLC A ; *4
|
|
RLC A ; *8
|
|
RLC A ; *16
|
|
LD HL,DPBASE ; Base of disk description block.
|
|
LD B,0
|
|
LD C,A
|
|
ADD HL,BC ; HL contains address of actual selected disk block.
|
|
LD C,10
|
|
ADD HL,BC ; HL contains address of pointer to disk parameter block.
|
|
LD E,(HL)
|
|
INC HL
|
|
LD D,(HL) ; DE contains address of disk parameter block.
|
|
EX DE,HL
|
|
LD A,(HL)
|
|
LD E,A
|
|
|
|
LD BC,15
|
|
ADD HL,BC ; Move to configuration byte.
|
|
XOR A
|
|
BIT 2,(HL)
|
|
JR Z,SETDRV0
|
|
INC A
|
|
SETDRV0: LD (INVFDCDATA),A ; Data inversion is set according to drive parameter.
|
|
LD A,4
|
|
BIT 1,(HL)
|
|
JR Z,SETDRV1
|
|
LD A,2
|
|
BIT 0,(HL)
|
|
JR Z,SETDRV1
|
|
LD A,1
|
|
SETDRV1: LD (SECTORCNT),A ; Set the disk sector size.
|
|
LD D,A
|
|
CP 4
|
|
LD A,E
|
|
JR Z,SETDRV1A
|
|
OR A
|
|
RR A
|
|
LD E,A
|
|
LD A,D
|
|
CP 2
|
|
LD A,E
|
|
JR Z,SETDRV1A
|
|
OR A
|
|
RR A ; Convert sectors per track from 128 bytes to 256 byte sectors.
|
|
SETDRV1A: INC A ; Add 1 to ease comparisons.
|
|
LD (SECPERTRK),A ; Only cater for 8bit, ie. 256 sectors.
|
|
DEC A
|
|
OR A
|
|
RR A
|
|
INC A ; Add 1 to ease comparisons.
|
|
LD (SECPERHEAD),A ; Convert sectors per track to sectors per head.
|
|
;
|
|
XOR A ; Disk type = FDC
|
|
BIT 4,(HL)
|
|
JR Z,SETDRV2
|
|
LD A,DSKTYP_SDC ; Disk type = SD Card
|
|
SETDRV2: LD (DISKTYPE),A
|
|
POP BC
|
|
POP DE
|
|
POP HL
|
|
RET
|
|
|
|
; Method to get the current disk drive mapped to the correct controller.
|
|
; The CPM CDISK is mapped via MAPDISK[CDISK] and the result:
|
|
; Bit 7 = 1 - SD Card drive.
|
|
; BIT 7:6 = 00 - Floppy drive.
|
|
GETMAPDSK: PUSH HL
|
|
PUSH BC
|
|
LD A,(CDISK)
|
|
LD HL,DISKMAP
|
|
LD C,A
|
|
LD B,0
|
|
ADD HL,BC
|
|
LD A,(HL) ; Get the physical number after mapping from the CDISK.
|
|
POP BC
|
|
POP HL
|
|
RET
|
|
|
|
; Select FDC drive (make active) based on value in DISKMAP[CDISK].
|
|
SELDRIVE: CALL GETMAPDSK
|
|
CP 040H ; Anything with bit 6 or 7 set is not an FDC drive.
|
|
RET NC ; This isnt a physical floppy disk, no need to perform any actions, exit.
|
|
;
|
|
LD (FDCDISK),A
|
|
CALL DSKMTRON ; yes, set motor on and wait
|
|
LD A,(FDCDISK) ; select drive no
|
|
OR 084H
|
|
OUT (FDC_MOTOR),A ; Motor on for drive 0-3
|
|
XOR A
|
|
LD (FDCCMD),A ; clr latest FDC command byte
|
|
LD HL,00000H
|
|
SELDRV2: DEC HL
|
|
LD A,H
|
|
OR L
|
|
JP Z,SELDRVERR ; Reset and print message that this is not a valid disk.
|
|
IN A,(FDC_STR) ; Status register.
|
|
CPL
|
|
RLCA
|
|
JR C,SELDRV2 ; Wait on Drive Ready Bit (bit 7)
|
|
LD A,(FDCDISK) ; Drive number
|
|
LD C,A
|
|
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,SELDRV3 ; If the drive hasnt been intialised to track 0, intialise and set flag.
|
|
CALL DSKSEEKTK0 ; Seek track 0.
|
|
SET 0,(HL) ; Set bit 0 of trk 0 flag
|
|
SELDRV3: CALL SETDRVCFG
|
|
RET
|
|
|
|
; Turn disk motor on if not already running.
|
|
DSKMTRON: LD A,255 ; Ensure motor is kept running whilst we read/write.
|
|
LD (MTROFFTIMER),A
|
|
LD A,(MOTON) ; Test to see if motor is on, if it isnt, switch it on.
|
|
RRCA
|
|
JR NC, DSKMOTORON
|
|
RET
|
|
DSKMOTORON: PUSH BC
|
|
LD A,080H
|
|
OUT (FDC_MOTOR),A ; Motor on
|
|
LD B,010H ;
|
|
DSKMTR2: CALL MTRDELAY ;
|
|
DJNZ DSKMTR2 ; Wait until becomes ready.
|
|
LD A,001H ; Set motor on flag.
|
|
LD (MOTON),A ;
|
|
POP BC
|
|
RET
|
|
|
|
FDCDLY1: PUSH DE
|
|
LD DE,00007H
|
|
JP MTRDEL2
|
|
|
|
MTRDELAY: PUSH DE
|
|
LD DE,01013H
|
|
MTRDEL2: DEC DE
|
|
LD A,E
|
|
OR D
|
|
JR NZ,MTRDEL2
|
|
POP DE
|
|
RET
|
|
|
|
DSKWRITE: LD A,MAXWRRETRY
|
|
LD (RETRIES),A
|
|
LD A,(SECTORCNT)
|
|
LD B,A
|
|
LD A,(HSTSEC)
|
|
DSKWRITE0A: DJNZ DSKWRITE0B
|
|
JR DSKWRITE1
|
|
DSKWRITE0B: OR A
|
|
RL A
|
|
JR DSKWRITE0A
|
|
DSKWRITE1: INC A
|
|
LD (SECTORNO), A ; Convert from Host 512 byte sector into local sector according to paraameter block.
|
|
LD HL,(HSTTRK)
|
|
LD (TRACKNO),HL
|
|
|
|
DSKWRITE2: CALL SETTRKSEC ; Set current track & sector, get load address to HL
|
|
DSKWRITE3: CALL SETHEAD ; Set side reg
|
|
CALL SEEK ; Command 1b output (seek)
|
|
JP NZ,SEEKRETRY ;
|
|
CALL OUTTKSEC ; Set track & sector reg
|
|
|
|
LD IX, 0F3FEH ; As below. L03FE
|
|
LD IY,WRITEDATA ; Write sector from memory.
|
|
DI
|
|
;
|
|
LD A,0B4H ; Write Sector multipe with Side Compare for side 1.
|
|
CALL DISKCMDWAIT
|
|
LD D,2 ; Regardless of 4x128, 2x256 or 1x512, we always read 512bytes by the 2x INI instruction with B=256.
|
|
STRTDATWR: LD B,0 ; 256 bytes to load.
|
|
JP (IX)
|
|
|
|
WRITEDATA: OUTI
|
|
JP NZ, 0F3FEH ; 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.
|
|
DEC D
|
|
JP NZ,0F3FEH ; If we havent read all sectors to form a 512 byte block, go for next sector.
|
|
JR DATASTOP
|
|
|
|
; 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: LD A,MAXRDRETRY
|
|
LD (RETRIES),A
|
|
LD A,(SECTORCNT)
|
|
LD B,A
|
|
LD A,(HSTSEC)
|
|
DSKREAD0A: DJNZ DSKREAD0B
|
|
JR DSKREAD1
|
|
DSKREAD0B: OR A
|
|
RL A
|
|
JR DSKREAD0A
|
|
DSKREAD1: INC A
|
|
LD (SECTORNO), A ; Convert from Host 512 byte sector into local sector according to paraameter block.
|
|
LD HL,(HSTTRK)
|
|
LD (TRACKNO),HL
|
|
DSKREAD2: CALL SETTRKSEC ; Set current track & sector, get load address to HL
|
|
DSKREAD3: CALL SETHEAD ; Set side reg
|
|
CALL SEEK ; Command 1b output (seek)
|
|
JP NZ,SEEKRETRY ;
|
|
CALL OUTTKSEC ; Set track & sector reg
|
|
LD IX, 0F3FEH ; As below. L03FE
|
|
LD IY,READDATA ; Read sector into memory.
|
|
DI
|
|
;
|
|
LD A,094H ; Read Sector multiple with Side Compare for side 1.
|
|
CALL DISKCMDWAIT
|
|
LD D,2 ; Regardless of 4x128, 2x256 or 1x512, we always read 512bytes by the 2x INI instruction with B=256.
|
|
STRTDATRD: LD B,0 ; 256 bytes to load.
|
|
JP (IX)
|
|
|
|
; Get data from disk sector to staging area.
|
|
READDATA: INI
|
|
JP NZ,0F3FEH ; 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.
|
|
DEC D
|
|
JP NZ,0F3FEH ; If we havent read all sectors to form a 512 byte block, go for next sector.
|
|
;
|
|
;
|
|
DATASTOP: LD A,0D8H ; Force interrupt command, Immediate interrupt (I3 bit 3=1) of multiple sector read.
|
|
CPL
|
|
OUT (FDC_CR),A
|
|
CALL WAITRDY ; Wait for controller to become ready, acknowledging interrupt.
|
|
IN A,(FDC_STR) ; Check for errors.
|
|
CPL
|
|
AND 0FFH
|
|
JR NZ,SEEKRETRY
|
|
UPDSECTOR: PUSH HL
|
|
LD A,(SECTORCNT)
|
|
LD HL,SECTORNO
|
|
ADD A,(HL) ; Update sector to account for sectors read. NB. All reads will start at such a position
|
|
LD (HL), A ; that a read will not span a track or head. Ensure that disk formats meet an even 512byte format.
|
|
POP HL
|
|
MOTOROFF: LD A,MTROFFMSECS ; Schedule motor to be turned off.
|
|
LD (MTROFFTIMER),A
|
|
XOR A ; Successful read, return 0
|
|
EI
|
|
RET
|
|
|
|
SEEKRETRY: LD B,A ; Preserve the FDC Error byte.
|
|
LD A,(RETRIES)
|
|
DEC A
|
|
LD (RETRIES),A
|
|
LD A,B
|
|
JP Z,RETRIESERR
|
|
CALL DSKSEEKTK0
|
|
LD A, (READOP)
|
|
OR A
|
|
LD A,(TRACKNO) ; NB. Track number is 16bit, FDC only uses lower 8bit and assumes little endian read.
|
|
JP Z, DSKWRITE2 ; Try write again.
|
|
JP DSKREAD2 ; Try the read again.
|
|
|
|
DISKCMDWAIT:LD (FDCCMD),A
|
|
CPL
|
|
OUT (FDC_CR),A
|
|
CALL WAITBUSY
|
|
RET
|
|
|
|
; Send a command to the disk controller.
|
|
DSKCMD: LD (FDCCMD),A ; Store latest FDC command.
|
|
CPL ; Compliment it (FDC bit value is reversed).
|
|
OUT (FDC_CR),A ; Send command to FDC.
|
|
CALL WAITRDY ; Wait to become ready.
|
|
IN A,(FDC_STR) ; Get status register.
|
|
CPL ; Inverse (FDC is reverse bit logic).
|
|
RET
|
|
|
|
; Seek to programmed track.
|
|
SEEK: LD A,01BH ; Seek command, load head, verify stepping 6ms.
|
|
CALL DSKCMD
|
|
AND 099H
|
|
RET
|
|
|
|
; Set current track & sector, get load address to HL
|
|
SETTRKSEC: CALL SELDRIVE
|
|
LD A,(TRACKNO) ; NB. Track number is 16bit, FDC only uses lower 8bit and assumes little endian read.
|
|
LD HL, HSTBUF
|
|
RET
|
|
|
|
; Compute side/head.
|
|
SETHEAD: CPL ;
|
|
OUT (FDC_DR),A ; Output track no for SEEK command.
|
|
PUSH HL
|
|
LD HL,SECPERHEAD
|
|
LD A,(SECTORNO) ; Check sector, if greater than sector per track, change head.
|
|
CP (HL)
|
|
POP HL
|
|
JR NC,SETHD2 ; Yes, even, set side/head 1
|
|
LD A,001H ; No, odd, set side/head 0
|
|
JR SETHD3
|
|
|
|
; Set side/head register.
|
|
SETHD2: XOR A ; Side 0
|
|
SETHD3: CPL ; Side 1
|
|
OUT (FDC_SIDE),A ; Side/head register.
|
|
RET
|
|
|
|
; Set track and sector register.
|
|
OUTTKSEC: PUSH HL
|
|
LD HL,SECPERHEAD
|
|
;
|
|
LD C,FDC_DR ; Port for data retrieval in the INI instruction in main block.
|
|
LD A,(TRACKNO) ; Current track number, NB. Track number is 16bit, FDC only uses lower 8bit and assumes little endian read.
|
|
CPL
|
|
OUT (FDC_TR),A ; Track reg
|
|
;
|
|
LD A,(SECTORNO) ; Current sector number
|
|
CP (HL)
|
|
JR C,OUTTKSEC2
|
|
SUB (HL)
|
|
INC A ; Account for the +1 added to ease comparisons.
|
|
OUTTKSEC2: CPL
|
|
OUT (FDC_SCR),A ; Sector reg
|
|
POP HL
|
|
RET
|
|
|
|
; Seek to track 0.
|
|
DSKSEEKTK0: CALL DSKMTRON ; Make sure disk is spinning.
|
|
LD A,00BH ; Restore command, seek track 0.
|
|
CALL DSKCMD ; Send command to FDC.
|
|
AND 085H ; Process result.
|
|
XOR 004H
|
|
RET Z
|
|
JP DSKSEEKERR
|
|
|
|
; Wait for the drive to become ready.
|
|
WAITRDY: PUSH DE
|
|
PUSH HL
|
|
CALL FDCDLY1
|
|
LD E,007H
|
|
WAITRDY2: LD HL,00000H
|
|
WAITRDY3: DEC HL
|
|
LD A,H
|
|
OR L
|
|
JR Z,WAITRDY4
|
|
IN A,(FDC_STR)
|
|
CPL
|
|
RRCA
|
|
JR C,WAITRDY3
|
|
POP HL
|
|
POP DE
|
|
RET
|
|
|
|
WAITRDY4: DEC E
|
|
JR NZ,WAITRDY2
|
|
POP HL
|
|
POP DE
|
|
JP WAITRDYERR
|
|
|
|
WAITBUSY: PUSH DE
|
|
PUSH HL
|
|
CALL FDCDLY1
|
|
LD E,007H ; 7 Chances of a 16bit down count delay waiting for DRQ.
|
|
WAITBUSY2: LD HL,00000H
|
|
WAITBUSY3: DEC HL
|
|
LD A,H
|
|
OR L
|
|
JR Z,WAITBUSY4 ; Down counter expired, decrement retries, error on 0.
|
|
IN A,(FDC_STR) ; Get the FDC Status
|
|
CPL ; Switch to positive logic.
|
|
RRCA ; Shift Busy flag into Carry.
|
|
JR NC,WAITBUSY3 ; Busy not set, decrement counter and retry.
|
|
POP HL
|
|
POP DE
|
|
RET
|
|
|
|
WAITBUSY4: DEC E
|
|
JR NZ,WAITBUSY2
|
|
POP HL
|
|
POP DE
|
|
JP DSKERR
|
|
|
|
|
|
; Error processing. Consists of printing a message followed by debug data (if enabled) and returning with carry set
|
|
; to indicate error.
|
|
DSKERR: LD DE,LOADERR ; Loading error message
|
|
JR HDLERROR
|
|
|
|
SELDRVERR: LD DE,SELDRVMSG ; Select drive error message.
|
|
JR HDLERROR
|
|
|
|
WAITRDYERR: LD DE,WAITRDYMSG ; Waiting for ready timeout error message.
|
|
JR HDLERROR
|
|
|
|
DSKSEEKERR: LD DE,DSKSEEKMSG ; Disk seek to track error message.
|
|
JR HDLERROR
|
|
|
|
RETRIESERR: BIT 2,A ; Data overrun error if 1.
|
|
LD DE,DATAOVRMSG
|
|
JR NZ, RETRIESERR2
|
|
BIT 3,A ; CRC error if 1.
|
|
LD DE,CRCERRMSG
|
|
JR NZ,RETRIESERR2
|
|
LD DE,RETRIESMSG ; Data sector read error message.
|
|
RETRIESERR2:
|
|
|
|
; Process error, dump debug data and return fail code.
|
|
HDLERROR: SCF
|
|
CALL DEBUG
|
|
HOLPRTSTR: LD A,(DE)
|
|
OR A
|
|
JR Z,HDLPRTSTR3
|
|
INC DE
|
|
HOLPRTSTR2: CALL PRNT
|
|
JR HOLPRTSTR
|
|
HDLPRTSTR3: XOR A
|
|
CALL DSKINIT
|
|
CALL DSKMTRON
|
|
LD A,001H ; Indicate error by setting 1 in A register.
|
|
EI
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF FDC CONTROLLER FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; UTILITIES
|
|
;-------------------------------------------------------------------------------
|
|
|
|
; Function to print a string with control character interpretation.
|
|
MONPRTSTR: LD A,(DE)
|
|
OR A
|
|
RET Z
|
|
INC DE
|
|
MONPRTSTR2: CALL PRNT
|
|
JR MONPRTSTR
|
|
|
|
; Helper method to set up a Disk Parameter Block.
|
|
; Input: Drive Count = (CDIRBUF)
|
|
; CSV/ALV Memory Pointer (CDIRBUF+1)
|
|
; CSV Size (CDIRBUF+3)
|
|
; ALV Size (CDIRBUF+5)
|
|
; Disk parameters address CDIRBUF+7)
|
|
; Output: Updated CSV/ALV Pointer (CDIRBUF+1)
|
|
; Updated disk count (CDIRBUF)
|
|
COPYDPB: LD HL,DPBTMPL ; Base of parameter template.
|
|
LD BC,10
|
|
LDIR ; Copy the lower part of the DPB as it is static.
|
|
LD HL,CDIRBUF+7 ; Get the address of the disk parameters.
|
|
LDI
|
|
LDI
|
|
LD BC,(CDIRBUF+3) ; Add the CSV size for this entry to the pointer and store.
|
|
LD A,B ; Fixed drives dont have a CSV, so if 0, copy 0 and not allocate memory.
|
|
OR C
|
|
LD HL,CDIRBUF+1 ; Now get the free CSV/ALV pointer.
|
|
JR NZ,COPYDPB1
|
|
LD HL,CDIRBUF+3
|
|
COPYDPB1: LDI
|
|
LDI
|
|
LD HL,(CDIRBUF+1)
|
|
LD BC,(CDIRBUF+3) ; Add the CSV size for this entry to the pointer and store.
|
|
ADD HL,BC
|
|
LD (CDIRBUF+1),HL
|
|
LD HL,CDIRBUF+1
|
|
LDI
|
|
LDI
|
|
LD HL,(CDIRBUF+1)
|
|
LD BC,(CDIRBUF+5) ; Now add the size of the ALV for this drive to the pointer for the next drive.
|
|
ADD HL,BC
|
|
LD (CDIRBUF+1),HL ; Store.
|
|
LD A,(CDIRBUF)
|
|
INC A
|
|
LD (CDIRBUF),A ; Update drive count.
|
|
RET
|
|
|
|
|
|
; A function from the z88dk stdlib, a delay loop with T state accuracy.
|
|
;
|
|
; enter : hl = tstates >= 141
|
|
; uses : af, bc, hl
|
|
T_DELAY: LD BC,-141
|
|
ADD HL,BC
|
|
LD BC,-23
|
|
TDELAYLOOP: ADD HL,BC
|
|
JR C, TDELAYLOOP
|
|
LD A,L
|
|
ADD A,15
|
|
JR NC, TDELAYG0
|
|
CP 8
|
|
JR C, TDELAYG1
|
|
OR 0
|
|
TDELAYG0: INC HL
|
|
TDELAYG1: RRA
|
|
JR C, TDELAYB0
|
|
NOP
|
|
TDELAYB0: RRA
|
|
JR NC, TDELAYB1
|
|
OR 0
|
|
TDELAYB1: RRA
|
|
RET NC
|
|
RET
|
|
|
|
; Method to multiply a 16bit number by another 16 bit number to arrive at a 32bit result.
|
|
; Input: DE = Factor 1
|
|
; BC = Factor 2
|
|
; Output:DEHL = 32bit Product
|
|
;
|
|
MULT16X16: LD HL,0
|
|
LD A,16
|
|
MULT16X1: ADD HL,HL
|
|
RL E
|
|
RL D
|
|
JR NC,$+6
|
|
ADD HL,BC
|
|
JR NC,$+3
|
|
INC DE
|
|
DEC A
|
|
JR NZ,MULT16X1
|
|
RET
|
|
|
|
; Method to add a 16bit number to a 32bit number to obtain a 32bit product.
|
|
; Input: DEHL = 32bit Addend
|
|
; BC = 16bit Addend
|
|
; Output:DEHL = 32bit sum.
|
|
;
|
|
ADD3216: ADD HL,BC
|
|
EX DE,HL
|
|
LD BC,0
|
|
ADC HL,BC
|
|
EX DE,HL
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF UTILITIES
|
|
;-------------------------------------------------------------------------------
|
|
|
|
; CPM Boot code.
|
|
;
|
|
; When CPM is loaded by TZFS it will execute startup code at this vector in 64K block 0. Once the memory mode
|
|
; switch executed then this block is paged in, so the follow on instructions must be in place otherwise the CPU
|
|
; will go into the wilderness!
|
|
;
|
|
IF $ > 01108H
|
|
ERROR "CMT comment area not aligned, needed for CPM bootstrap. Addr=%s, required=%s"; % $, 01108H
|
|
ENDIF
|
|
ALIGN_NOPS 01108H
|
|
BOOTSTG1: LD A,TZMM_CPM2
|
|
OUT (MMCFG), A
|
|
JP QBOOT_
|
|
; Method to reboot the machine back into TZFS. This code exists both in memory mode 2 and 7 at the same location so when a switch is made from
|
|
; mode 7 to mode 2, the code continues.
|
|
REBOOT: LD A,TZMM_TZFS
|
|
OUT (MMCFG),A
|
|
|
|
; Switch machine back to default state.
|
|
IF BUILD_VIDEOMODULE = 1
|
|
IN A,(VMCTRL) ; Get current display mode.
|
|
AND ~MODE_80CHAR ; Disable 80 char display.
|
|
OUT (VMCTRL),A ; Activate.
|
|
; LD A, SYSMODE_MZ80A ; Set bus and default CPU speed to 2MHz
|
|
; OUT (SYSCTRL),A ; Activate.
|
|
ELSE
|
|
; Change to 40 character mode on the 40/80 Char Colour board v1.0.
|
|
LD (DSPCTL), A
|
|
LD HL,DSPCTL ; Setup address of display control register latch.
|
|
LD A, 0 ; 40 char mode.
|
|
LD E,(HL) ; Dummy operation to enable latch write via multivibrator.
|
|
LD (HL), A
|
|
ENDIF
|
|
;
|
|
JP MROMADDR ; Now restart in the SA1510 monitor.
|
|
|
|
|
|
ALIGN_NOPS 01200H
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF KEYBOARD FUNCTIONALITY (INTR HANDLER SEPERATE IN CBIOS)
|
|
;-------------------------------------------------------------------------------
|
|
|
|
MODE: LD HL,KEYPF
|
|
LD (HL),08AH
|
|
LD (HL),007H ; Set Motor to Off.
|
|
LD (HL),004H ; Disable interrupts by setting INTMSK to 0.
|
|
LD (HL),001H ; Set VGATE to 1.
|
|
RET
|
|
|
|
; Method to check if a key has been pressed and stored in buffer..
|
|
CHKKY: LD A, (KEYCOUNT)
|
|
OR A
|
|
JR Z,CHKKY2
|
|
LD A,0FFH
|
|
RET
|
|
CHKKY2: XOR A
|
|
RET
|
|
|
|
GETKY: PUSH HL
|
|
LD A,(KEYCOUNT)
|
|
OR A
|
|
JR Z,GETKY2
|
|
GETKY1: DI ; Disable interrupts, we dont want a race state occurring.
|
|
LD A,(KEYCOUNT)
|
|
DEC A ; Take 1 off the total count as we are reading a character out of the buffer.
|
|
LD (KEYCOUNT),A
|
|
LD HL,(KEYREAD) ; Get the position in the buffer where the next available character resides.
|
|
LD A,(HL) ; Read the character and save.
|
|
PUSH AF
|
|
INC L ; Update the read pointer and save.
|
|
LD A,L
|
|
AND KEYBUFSIZE-1
|
|
LD L,A
|
|
LD (KEYREAD),HL
|
|
POP AF
|
|
EI ; Interrupts back on so keys and RTC are actioned.
|
|
JR PRCKEY ; Process the key, action any non ASCII keys.
|
|
;
|
|
GETKY2: LD A,(KEYCOUNT) ; No key available so loop until one is.
|
|
OR A
|
|
JR Z,GETKY2
|
|
JR GETKY1
|
|
;
|
|
PRCKEY: CP CR ; CR
|
|
JR NZ,PRCKY3
|
|
JR PRCKYE
|
|
PRCKY3: CP HOMEKEY ; HOME
|
|
JR NZ,PRCKY4
|
|
JR GETKY2
|
|
PRCKY4: CP CLRKEY ; CLR
|
|
JR NZ,PRCKY5
|
|
JR GETKY2
|
|
PRCKY5: CP INSERT ; INSERT
|
|
JR NZ,PRCKY6
|
|
JR GETKY2
|
|
PRCKY6: CP DBLZERO ; 00
|
|
JR NZ,PRCKY7
|
|
LD A,'0'
|
|
LD (KEYBUF),A ; Place a character into the keybuffer so we double up on 0
|
|
JR PRCKYX
|
|
PRCKY7: CP BREAKKEY ; Break key processing.
|
|
JR NZ,PRCKY8
|
|
JR PRCKYE
|
|
PRCKY8: CP DELETE
|
|
JR NZ,PRCKYX
|
|
LD A,BACKS ; Map DELETE to BACKSPACE, BACKSPACE is Rubout, DELETE is echo in CPM.
|
|
PRCKYX:
|
|
PRCKYE:
|
|
POP HL
|
|
RET
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF KEYBOARD FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF SCREEN FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
; CR PAGE MODE1
|
|
.CR: CALL .MANG
|
|
RRCA
|
|
JP NC,CURS2
|
|
LD L,000H
|
|
INC H
|
|
CP ROW - 1 ; End of line?
|
|
JR Z,.CP1
|
|
INC H
|
|
JP CURS1
|
|
|
|
.CP1: LD (DSPXY),HL
|
|
|
|
; SCROLLER
|
|
.SCROL: LD BC,SCRNSZ - COLW ; Scroll COLW -1 lines
|
|
LD DE,SCRN ; Start of the screen.
|
|
LD HL,SCRN + COLW ; Start of screen + 1 line.
|
|
PUSH BC ; 1000 STORE
|
|
LDIR
|
|
POP BC
|
|
PUSH DE
|
|
LD DE,SCRN + 800H ; COLOR RAM SCROLL
|
|
LD HL,SCRN + 800H + COLW ; SCROLL TOP + 1 LINE
|
|
LDIR
|
|
LD B,COLW ; ONE LINE
|
|
EX DE,HL
|
|
IF BUILD_80C = 0
|
|
LD A,071H ; Black background, white characters. Bit 7 is clear as a write to bit 7 @ DFFFH selects 40Char mode.
|
|
ELSE
|
|
LD A,071H ; Blue background, white characters in colour mode. Bit 7 is set as a write to bit 7 @ DFFFH selects 80Char mode.
|
|
ENDIF
|
|
;LD A,71H ; COLOR RAM INITIAL DATA
|
|
CALL DINT
|
|
POP HL
|
|
LD B,COLW
|
|
CALL CLER ; LAST LINE CLEAR
|
|
LD BC,ROW + 1 ; ROW NUMBER+1
|
|
LD DE,MANG ; LOGICAL MANAGEMENT
|
|
LD HL,MANG+1
|
|
LDIR
|
|
LD (HL),0
|
|
LD A,(MANG)
|
|
OR A
|
|
JP Z,RSTR
|
|
LD HL,DSPXY+1
|
|
DEC (HL)
|
|
JR .SCROL
|
|
|
|
DPCT: PUSH AF ; Display control, character is mapped to a function call.
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD B,A
|
|
AND 0F0H
|
|
CP 0C0H
|
|
JP NZ,RSTR
|
|
XOR B
|
|
RLCA
|
|
LD C,A
|
|
LD B,000H
|
|
LD HL,.CTBL
|
|
DPCT1: ADD HL,BC
|
|
LD E,(HL)
|
|
INC HL
|
|
LD D,(HL)
|
|
EX DE,HL
|
|
JP (HL)
|
|
|
|
|
|
PRT: LD A,C
|
|
CALL ADCN
|
|
LD C,A
|
|
AND 0F0H
|
|
CP 0F0H
|
|
RET Z
|
|
|
|
CP 0C0H
|
|
LD A,C
|
|
JR NZ,PRNT3
|
|
PRNT5: CALL DPCT
|
|
CP 0C3H
|
|
JR Z,PRNT4
|
|
CP 0C5H
|
|
JR Z,PRNT2
|
|
CP 0CDH ; CR
|
|
JR Z,PRNT2
|
|
CP 0C6H
|
|
RET NZ
|
|
|
|
PRNT2: XOR A
|
|
PRNT2A: LD (DPRNT),A
|
|
RET
|
|
|
|
PRNT3: CALL DSP
|
|
PRNT4: LD A,(DPRNT)
|
|
INC A
|
|
CP COLW*2 ; 050H
|
|
JR C,PRNT4A
|
|
SUB COLW*2 ; 050H
|
|
PRNT4A: JR PRNT2A
|
|
|
|
NL: LD A,(DPRNT)
|
|
OR A
|
|
RET Z
|
|
|
|
LTNL: LD A,0CDH
|
|
JR PRNT5
|
|
PRTT: CALL PRTS
|
|
LD A,(DPRNT)
|
|
OR A
|
|
RET Z
|
|
|
|
L098C: SUB 00AH
|
|
JR C,PRTT
|
|
JR NZ,L098C
|
|
RET
|
|
|
|
; Function to disable the cursor display.
|
|
;
|
|
CURSOROFF: DI
|
|
CALL CURSRSTR ; Restore character under the cursor.
|
|
LD HL,FLASHCTL ; Indicate cursor is now off.
|
|
RES 7,(HL)
|
|
EI
|
|
RET
|
|
|
|
;
|
|
; Function to enable the cursor display.
|
|
;
|
|
CURSORON: DI
|
|
CALL DSPXYTOADDR ; Update the screen address for where the cursor should appear.
|
|
LD HL,FLASHCTL ; Indicate cursor is now on.
|
|
SET 7,(HL)
|
|
EI
|
|
RET
|
|
|
|
;
|
|
; Function to restore the character beneath the cursor iff the cursor is being dislayed.
|
|
;
|
|
CURSRSTR: PUSH HL
|
|
PUSH AF
|
|
LD HL,FLASHCTL ; Check to see if there is a cursor at the current screen location.
|
|
BIT 6,(HL)
|
|
JR Z,CURSRSTR1
|
|
RES 6,(HL)
|
|
LD HL,(DSPXYADDR) ; There is so we must restore the original character before further processing.
|
|
LD A,(FLASH)
|
|
LD (HL),A
|
|
CURSRSTR1: POP AF
|
|
POP HL
|
|
RET
|
|
|
|
;
|
|
; Function to convert XY co-ordinates to a physical screen location and save.
|
|
;
|
|
DSPXYTOADDR:PUSH HL
|
|
PUSH DE
|
|
PUSH BC
|
|
LD BC,(DSPXY) ; Calculate the new cursor position based on the XY coordinates.
|
|
LD DE,COLW
|
|
LD HL,SCRN - COLW
|
|
DSPXYTOA1: ADD HL,DE
|
|
DEC B
|
|
JP P,DSPXYTOA1
|
|
LD B,000H
|
|
ADD HL,BC
|
|
RES 3,H
|
|
LD (DSPXYADDR),HL ; Store the new address.
|
|
LD A,(HL) ; Store the new character.
|
|
LD (FLASH),A
|
|
DSPXYTOA2: POP BC
|
|
POP DE
|
|
POP HL
|
|
RET
|
|
|
|
;
|
|
; Function to print a space.
|
|
;
|
|
PRTS: LD A,020H
|
|
|
|
; Function to print a character to the screen. If the character is a control code it is processed as necessary
|
|
; otherwise the character is converted from ASCII display and displayed.
|
|
;
|
|
PRNT: DI
|
|
CALL CURSRSTR ; Restore char under cursor.
|
|
CP 00DH
|
|
JR Z,NEWLINE
|
|
CP 00AH
|
|
JR Z,NEWLINE
|
|
CP 07FH
|
|
JR Z,DELCHR
|
|
CP BACKS
|
|
JR Z,DELCHR
|
|
PUSH BC
|
|
LD C,A
|
|
LD B,A
|
|
CALL PRT
|
|
LD A,B
|
|
POP BC
|
|
PRNT1: CALL DSPXYTOADDR
|
|
EI
|
|
RET
|
|
|
|
; Delete a character on screen.
|
|
DELCHR: LD A,0C7H
|
|
CALL DPCT
|
|
JR PRNT1
|
|
|
|
NEWLINE: CALL NL
|
|
JR PRNT1
|
|
|
|
;
|
|
|
|
;
|
|
; Function to print out the contents of HL as 4 digit Hexadecimal.
|
|
;
|
|
PRTHL: LD A,H
|
|
CALL PRTHX
|
|
LD A,L
|
|
JR PRTHX
|
|
RET
|
|
|
|
;
|
|
; Function to print out the contents of A as 2 digit Hexadecimal
|
|
;
|
|
PRTHX: PUSH AF
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
CALL ASC
|
|
CALL PRNT
|
|
POP AF
|
|
CALL ASC
|
|
JP PRNT
|
|
|
|
ASC: AND 00FH
|
|
CP 00AH
|
|
JR C,NOADD
|
|
ADD A,007H
|
|
NOADD: ADD A,030H
|
|
RET
|
|
|
|
;CLR8Z: XOR A
|
|
; LD BC,00800H
|
|
; PUSH DE
|
|
; LD D,A
|
|
;L09E8: LD (HL),D
|
|
; INC HL
|
|
; DEC BC
|
|
; LD A,B
|
|
; OR C
|
|
; JR NZ,L09E8
|
|
; POP DE
|
|
; RET
|
|
|
|
REV: LD HL,REVFLG
|
|
LD A,(HL)
|
|
OR A
|
|
CPL
|
|
LD (HL),A
|
|
JR Z,REV1
|
|
LD A,(INVDSP)
|
|
JR REV2
|
|
REV1: LD A,(NRMDSP)
|
|
REV2: JP RSTR
|
|
|
|
.MANG: LD HL,MANG
|
|
.MANG2: LD A,(DSPXY + 1)
|
|
ADD A,L
|
|
LD L,A
|
|
LD A,(HL)
|
|
INC HL
|
|
RL (HL)
|
|
OR (HL)
|
|
RR (HL)
|
|
RRCA
|
|
EX DE,HL
|
|
LD HL,(DSPXY)
|
|
RET
|
|
|
|
L09C7: PUSH DE
|
|
PUSH HL
|
|
LD HL,PBIAS
|
|
XOR A
|
|
RLD
|
|
LD D,A
|
|
LD E,(HL)
|
|
RRD
|
|
XOR A
|
|
RR D
|
|
RR E
|
|
LD HL,SCRN
|
|
ADD HL,DE
|
|
LD (PAGETP),HL
|
|
POP HL
|
|
POP DE
|
|
RET
|
|
|
|
DSP: PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD B,A
|
|
CALL PONT
|
|
LD (HL),B
|
|
LD HL,(DSPXY)
|
|
LD A,L
|
|
DSP01: CP COLW - 1 ; End of line.
|
|
JP NZ,CURSR
|
|
CALL .MANG
|
|
JR C,CURSR
|
|
.DSP03: EX DE,HL
|
|
LD (HL),001H
|
|
INC HL
|
|
LD (HL),000H
|
|
JP CURSR
|
|
|
|
CURSD: LD HL,(DSPXY)
|
|
LD A,H
|
|
CP ROW - 1
|
|
JR Z,CURS4
|
|
INC H
|
|
CURS1: ;CALL MGP.I
|
|
CURS3: LD (DSPXY),HL
|
|
JR RSTR
|
|
|
|
CURSU: LD HL,(DSPXY)
|
|
LD A,H
|
|
OR A
|
|
JR Z,CURS5
|
|
DEC H
|
|
CURSU1: JR CURS3
|
|
|
|
CURSR: LD HL,(DSPXY)
|
|
LD A,L
|
|
CP COLW - 1 ; End of line
|
|
JR NC,CURS2
|
|
INC L
|
|
JR CURS3
|
|
CURS2: LD L,000H
|
|
INC H
|
|
LD A,H
|
|
CP ROW
|
|
JR C,CURS1
|
|
LD H,ROW - 1
|
|
LD (DSPXY),HL
|
|
CURS4: JP .SCROL
|
|
|
|
CURSL: LD HL,(DSPXY)
|
|
LD A,L
|
|
OR A
|
|
JR Z,CURS5A
|
|
DEC L
|
|
JR CURS3
|
|
CURS5A: LD L,COLW - 1 ; End of line
|
|
DEC H
|
|
JP P,CURSU1
|
|
LD H,000H
|
|
LD (DSPXY),HL
|
|
CURS5: JR RSTR
|
|
|
|
CLRS: LD HL,MANG
|
|
LD B,01BH
|
|
CALL CLER
|
|
LD HL,SCRN
|
|
PUSH HL
|
|
CALL CLR8Z
|
|
IF BUILD_80C = 0
|
|
LD A,071H ; Black background, white characters. Bit 7 is clear as a write to bit 7 @ DFFFH selects 40Char mode.
|
|
ELSE
|
|
LD A,071H ; Blue background, white characters in colour mode. Bit 7 is set as a write to bit 7 @ DFFFH selects 80Char mode.
|
|
ENDIF
|
|
;LD A,71H ; COLOR DATA
|
|
CALL CLR8 ; D800H-DFFFH CLEAR
|
|
POP HL
|
|
CLRS1: LD A,(SCLDSP)
|
|
HOM0: LD HL,00000H
|
|
JP CURS3
|
|
|
|
RSTR: POP HL
|
|
RSTR1: POP DE
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
|
|
DEL: LD HL,(DSPXY)
|
|
LD A,H
|
|
OR L
|
|
JR Z,RSTR
|
|
LD A,L
|
|
OR A
|
|
JR NZ,DEL1
|
|
CALL .MANG
|
|
JR C,DEL1
|
|
CALL PONT
|
|
DEC HL
|
|
LD (HL),000H
|
|
JR CURSL
|
|
DEL1: CALL .MANG
|
|
RRCA
|
|
LD A,COLW
|
|
JR NC,L0F13
|
|
RLCA
|
|
L0F13: SUB L
|
|
LD B,A
|
|
CALL PONT
|
|
PUSH HL
|
|
POP DE
|
|
DEC DE
|
|
SET 4,D
|
|
DEL2: RES 3,H
|
|
RES 3,D
|
|
LD A,(HL)
|
|
LD (DE),A
|
|
INC HL
|
|
INC DE
|
|
DJNZ DEL2
|
|
DEC HL
|
|
LD (HL),000H
|
|
JP CURSL
|
|
|
|
INST: CALL .MANG
|
|
RRCA
|
|
LD L,COLW - 1 ; End of line
|
|
LD A,L
|
|
JR NC,INST1A
|
|
INC H
|
|
INST1A: CALL PNT1
|
|
PUSH HL
|
|
LD HL,(DSPXY)
|
|
JR NC,INST2
|
|
LD A,(COLW*2)-1 ; 04FH
|
|
INST2: SUB L
|
|
LD B,A
|
|
POP DE
|
|
LD A,(DE)
|
|
OR A
|
|
JR NZ,RSTR
|
|
CALL PONT
|
|
LD A,(HL)
|
|
LD (HL),000H
|
|
INST1: INC HL
|
|
RES 3,H
|
|
LD E,(HL)
|
|
LD (HL),A
|
|
LD A,E
|
|
DJNZ INST1
|
|
JR RSTR
|
|
|
|
PONT: LD HL,(DSPXY)
|
|
PNT1: PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
POP BC
|
|
LD DE,COLW
|
|
LD HL,SCRN - COLW
|
|
PNT2: ADD HL,DE
|
|
DEC B
|
|
JP P,PNT2
|
|
LD B,000H
|
|
ADD HL,BC
|
|
RES 3,H
|
|
POP DE
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
|
|
CLER: XOR A
|
|
JR DINT
|
|
CLRFF: LD A,0FFH
|
|
DINT: LD (HL),A
|
|
INC HL
|
|
DJNZ DINT
|
|
RET
|
|
|
|
ADCN: PUSH BC
|
|
PUSH HL
|
|
LD HL,ATBL ;00AB5H
|
|
LD C,A
|
|
LD B,000H
|
|
ADD HL,BC
|
|
LD A,(HL)
|
|
JR DACN3
|
|
|
|
DACN: PUSH BC
|
|
PUSH HL
|
|
PUSH DE
|
|
LD HL,ATBL
|
|
LD D,H
|
|
LD E,L
|
|
LD BC,00100H
|
|
CPIR
|
|
JR Z,DACN1
|
|
LD A,0F0H
|
|
DACN2: POP DE
|
|
DACN3: POP HL
|
|
POP BC
|
|
RET
|
|
|
|
DACN1: OR A
|
|
DEC HL
|
|
SBC HL,DE
|
|
LD A,L
|
|
JR DACN2
|
|
|
|
; CTBL PAGE MODE1
|
|
.CTBL: DW .SCROL
|
|
DW CURSD
|
|
DW CURSU
|
|
DW CURSR
|
|
DW CURSL
|
|
DW HOM0
|
|
DW CLRS
|
|
DW DEL
|
|
DW INST
|
|
DW RSTR
|
|
DW RSTR
|
|
DW RSTR
|
|
DW REV
|
|
DW .CR
|
|
DW RSTR
|
|
DW RSTR
|
|
|
|
; ASCII TO DISPLAY CODE TABLE
|
|
ATBL: DB 0CCH ; NUL '\0' (null character)
|
|
DB 0E0H ; SOH (start of heading)
|
|
DB 0F2H ; STX (start of text)
|
|
DB 0F3H ; ETX (end of text)
|
|
DB 0CEH ; EOT (end of transmission)
|
|
DB 0CFH ; ENQ (enquiry)
|
|
DB 0F6H ; ACK (acknowledge)
|
|
DB 0F7H ; BEL '\a' (bell)
|
|
DB 0F8H ; BS '\b' (backspace)
|
|
DB 0F9H ; HT '\t' (horizontal tab)
|
|
DB 0FAH ; LF '\n' (new line)
|
|
DB 0FBH ; VT '\v' (vertical tab)
|
|
DB 0FCH ; FF '\f' (form feed)
|
|
DB 0FDH ; CR '\r' (carriage ret)
|
|
DB 0FEH ; SO (shift out)
|
|
DB 0FFH ; SI (shift in)
|
|
DB 0E1H ; DLE (data link escape)
|
|
DB 0C1H ; DC1 (device control 1)
|
|
DB 0C2H ; DC2 (device control 2)
|
|
DB 0C3H ; DC3 (device control 3)
|
|
DB 0C4H ; DC4 (device control 4)
|
|
DB 0C5H ; NAK (negative ack.)
|
|
DB 0C6H ; SYN (synchronous idle)
|
|
DB 0E2H ; ETB (end of trans. blk)
|
|
DB 0E3H ; CAN (cancel)
|
|
DB 0E4H ; EM (end of medium)
|
|
DB 0E5H ; SUB (substitute)
|
|
DB 0E6H ; ESC (escape)
|
|
DB 0EBH ; FS (file separator)
|
|
DB 0EEH ; GS (group separator)
|
|
DB 0EFH ; RS (record separator)
|
|
DB 0F4H ; US (unit separator)
|
|
DB 000H ; SPACE
|
|
DB 061H ; !
|
|
DB 062H ; "
|
|
DB 063H ; #
|
|
DB 064H ; $
|
|
DB 065H ; %
|
|
DB 066H ; &
|
|
DB 067H ; '
|
|
DB 068H ; (
|
|
DB 069H ; )
|
|
DB 06BH ; *
|
|
DB 06AH ; +
|
|
DB 02FH ; ,
|
|
DB 02AH ; -
|
|
DB 02EH ; .
|
|
DB 02DH ; /
|
|
DB 020H ; 0
|
|
DB 021H ; 1
|
|
DB 022H ; 2
|
|
DB 023H ; 3
|
|
DB 024H ; 4
|
|
DB 025H ; 5
|
|
DB 026H ; 6
|
|
DB 027H ; 7
|
|
DB 028H ; 8
|
|
DB 029H ; 9
|
|
DB 04FH ; :
|
|
DB 02CH ; ;
|
|
DB 051H ; <
|
|
DB 02BH ; =
|
|
DB 057H ; >
|
|
DB 049H ; ?
|
|
DB 055H ; @
|
|
DB 001H ; A
|
|
DB 002H ; B
|
|
DB 003H ; C
|
|
DB 004H ; D
|
|
DB 005H ; E
|
|
DB 006H ; F
|
|
DB 007H ; G
|
|
DB 008H ; H
|
|
DB 009H ; I
|
|
DB 00AH ; J
|
|
DB 00BH ; K
|
|
DB 00CH ; L
|
|
DB 00DH ; M
|
|
DB 00EH ; N
|
|
DB 00FH ; O
|
|
DB 010H ; P
|
|
DB 011H ; Q
|
|
DB 012H ; R
|
|
DB 013H ; S
|
|
DB 014H ; T
|
|
DB 015H ; U
|
|
DB 016H ; V
|
|
DB 017H ; W
|
|
DB 018H ; X
|
|
DB 019H ; Y
|
|
DB 01AH ; Z
|
|
DB 052H ; [
|
|
DB 059H ; \ '\\'
|
|
DB 054H ; ]
|
|
DB 0BEH ; ^
|
|
DB 03CH ; _
|
|
DB 0C7H ; `
|
|
DB 081H ; a
|
|
DB 082H ; b
|
|
DB 083H ; c
|
|
DB 084H ; d
|
|
DB 085H ; e
|
|
DB 086H ; f
|
|
DB 087H ; g
|
|
DB 088H ; h
|
|
DB 089H ; i
|
|
DB 08AH ; j
|
|
DB 08BH ; k
|
|
DB 08CH ; l
|
|
DB 08DH ; m
|
|
DB 08EH ; n
|
|
DB 08FH ; o
|
|
DB 090H ; p
|
|
DB 091H ; q
|
|
DB 092H ; r
|
|
DB 093H ; s
|
|
DB 094H ; t
|
|
DB 095H ; u
|
|
DB 096H ; v
|
|
DB 097H ; w
|
|
DB 098H ; x
|
|
DB 099H ; y
|
|
DB 09AH ; z
|
|
DB 0BCH ; {
|
|
DB 080H ; |
|
|
DB 040H ; }
|
|
DB 0A5H ; ~
|
|
DB 0C0H ; DEL
|
|
DB 040H
|
|
DB 0BDH
|
|
DB 09DH
|
|
DB 0B1H
|
|
DB 0B5H
|
|
DB 0B9H
|
|
DB 0B4H
|
|
DB 09EH
|
|
DB 0B2H
|
|
DB 0B6H
|
|
DB 0BAH
|
|
DB 0BEH
|
|
DB 09FH
|
|
DB 0B3H
|
|
DB 0B7H
|
|
DB 0BBH
|
|
DB 0BFH
|
|
DB 0A3H
|
|
DB 085H
|
|
DB 0A4H
|
|
DB 0A5H
|
|
DB 0A6H
|
|
DB 094H
|
|
DB 087H
|
|
DB 088H
|
|
DB 09CH
|
|
DB 082H
|
|
DB 098H
|
|
DB 084H
|
|
DB 092H
|
|
DB 090H
|
|
DB 083H
|
|
DB 091H
|
|
DB 081H
|
|
DB 09AH
|
|
DB 097H
|
|
DB 093H
|
|
DB 095H
|
|
DB 089H
|
|
DB 0A1H
|
|
DB 0AFH
|
|
DB 08BH
|
|
DB 086H
|
|
DB 096H
|
|
DB 0A2H
|
|
DB 0ABH
|
|
DB 0AAH
|
|
DB 08AH
|
|
DB 08EH
|
|
DB 0B0H
|
|
DB 0ADH
|
|
DB 08DH
|
|
DB 0A7H
|
|
DB 0A8H
|
|
DB 0A9H
|
|
DB 08FH
|
|
DB 08CH
|
|
DB 0AEH
|
|
DB 0ACH
|
|
DB 09BH
|
|
DB 0A0H
|
|
DB 099H
|
|
DB 0BCH
|
|
DB 0B8H
|
|
DB 080H
|
|
DB 03BH
|
|
DB 03AH
|
|
DB 070H
|
|
DB 03CH
|
|
DB 071H
|
|
DB 05AH
|
|
DB 03DH
|
|
DB 043H
|
|
DB 056H
|
|
DB 03FH
|
|
DB 01EH
|
|
DB 04AH
|
|
DB 01CH
|
|
DB 05DH
|
|
DB 03EH
|
|
DB 05CH
|
|
DB 01FH
|
|
DB 05FH
|
|
DB 05EH
|
|
DB 037H
|
|
DB 07BH
|
|
DB 07FH
|
|
DB 036H
|
|
DB 07AH
|
|
DB 07EH
|
|
DB 033H
|
|
DB 04BH
|
|
DB 04CH
|
|
DB 01DH
|
|
DB 06CH
|
|
DB 05BH
|
|
DB 078H
|
|
DB 041H
|
|
DB 035H
|
|
DB 034H
|
|
DB 074H
|
|
DB 030H
|
|
DB 038H
|
|
DB 075H
|
|
DB 039H
|
|
DB 04DH
|
|
DB 06FH
|
|
DB 06EH
|
|
DB 032H
|
|
DB 077H
|
|
DB 076H
|
|
DB 072H
|
|
DB 073H
|
|
DB 047H
|
|
DB 07CH
|
|
DB 053H
|
|
DB 031H
|
|
DB 04EH
|
|
DB 06DH
|
|
DB 048H
|
|
DB 046H
|
|
DB 07DH
|
|
DB 044H
|
|
DB 01BH
|
|
DB 058H
|
|
DB 079H
|
|
DB 042H
|
|
DB 060H
|
|
DB 0FDH
|
|
DB 0CBH
|
|
DB 000H
|
|
DB 01EH
|
|
;-------------------------------------------------------------------------------
|
|
; END OF SCREEN FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;----------------------------------------
|
|
;
|
|
; ANSI EMULATION
|
|
;
|
|
; Emulate the Ansi standard
|
|
; N.B. Turned on when Chr
|
|
; 27 recieved.
|
|
; Entry - A = Char
|
|
; Exit - None
|
|
; Used - None
|
|
;
|
|
;----------------------------------------
|
|
ANSITERM: PUSH HL
|
|
PUSH DE
|
|
PUSH BC
|
|
PUSH AF
|
|
LD C,A ; Move character into C for safe keeping
|
|
;
|
|
LD A,(ANSIMODE)
|
|
OR A
|
|
JR NZ,ANSI2
|
|
LD A,C
|
|
CP 27
|
|
JP NZ,NOTANSI ; If it is Chr 27 then we haven't just
|
|
; been turned on, so don't bother with
|
|
; all the checking.
|
|
LD A,1 ; Turn on.
|
|
LD (ANSIMODE),A
|
|
JP AnsiMore
|
|
|
|
ANSI2: LD A,(CHARACTERNO) ; CHARACTER number in sequence
|
|
OR A ; Is this the first character?
|
|
JP Z,AnsiFirst ; Yes, deal with this strange occurance!
|
|
|
|
LD A,C ; Put character back in C to check
|
|
|
|
CP ";" ; Is it a semi colon?
|
|
JP Z,AnsiSemi
|
|
|
|
CP "0" ; Is it a number?
|
|
JR C,ANSI_NN ; If <0 then no
|
|
CP "9"+1 ; If >9 then no
|
|
JP C,AnsiNumber
|
|
|
|
ANSI_NN: CP "?" ; Simple trap for simple problem!
|
|
JP Z,AnsiMore
|
|
|
|
CP "@" ; Is it a letter?
|
|
JP C,ANSIEXIT ; Abandon if not letter; something wrong
|
|
|
|
ANSIFOUND: CALL CURSRSTR ; Restore any character under the cursor.
|
|
LD HL,(NUMBERPOS) ; Get value of number buffer
|
|
LD A,(HAVELOADED) ; Did we put anything in this byte?
|
|
OR A
|
|
JR NZ,AF1
|
|
LD (HL),255 ; Mark the fact that nothing was put in
|
|
AF1: INC HL
|
|
LD A,254
|
|
LD (HL),A ; Mark end of sequence (for unlimited length sequences)
|
|
|
|
;Disable cursor as unwanted side effects such as screen flicker may occur.
|
|
LD A,(FLASHCTL)
|
|
BIT 7,A
|
|
CALL NZ,CURSOROFF
|
|
|
|
XOR A
|
|
LD (CURSORCOUNT),A ; Restart count
|
|
LD A,0C9h
|
|
LD (CHGCURSMODE),A ; Disable flashing temp.
|
|
|
|
LD HL,NUMBERBUF ; For the routine called.
|
|
LD A,C ; Restore number
|
|
;
|
|
; Now work out what happens...
|
|
;
|
|
CP "A" ; Check for supported Ansi characters
|
|
JP Z,CUU ; Upwards
|
|
CP "B"
|
|
JP Z,CUD ; Downwards
|
|
CP "C"
|
|
JP Z,CUF ; Forward
|
|
CP "D"
|
|
JP Z,CUB ; Backward
|
|
CP "H"
|
|
JP Z,CUP ; Locate
|
|
CP "f"
|
|
JP Z,HVP ; Locate
|
|
CP "J"
|
|
JP Z,ED ; Clear screen
|
|
CP "m"
|
|
JP Z,SGR ; Set graphics renditon
|
|
CP "K"
|
|
JP Z,EL ; Clear to end of line
|
|
CP "s"
|
|
JP Z,SCP ; Save the cursor position
|
|
CP "u"
|
|
JP Z,RCP ; Restore the cursor position
|
|
|
|
ANSIEXIT: CALL CURSORON ; If t
|
|
LD HL,NUMBERBUF ; Numbers buffer position
|
|
LD (NUMBERPOS),HL
|
|
XOR A
|
|
LD (CHARACTERNO),A ; Next time it runs, it will be the
|
|
; first character
|
|
LD (HAVELOADED),A ; We haven't filled this byte!
|
|
LD (CHGCURSMODE),A ; Cursor allowed back again!
|
|
XOR A
|
|
LD (ANSIMODE),A
|
|
JR AnsiMore
|
|
NOTANSI: CP 000h ; Filter unprintable characters.
|
|
JR Z,AnsiMore
|
|
CALL PRNT
|
|
AnsiMore: POP AF
|
|
POP BC
|
|
POP DE
|
|
POP HL
|
|
RET
|
|
|
|
;
|
|
; The various routines needed to handle the filtered characters
|
|
;
|
|
AnsiFirst: LD A,255
|
|
LD (CHARACTERNO),A ; Next character is not first!
|
|
LD A,C ; Get character back
|
|
LD (ANSIFIRST),A ; Save first character to check later
|
|
CP "(" ; ( and [ have characters to follow
|
|
JP Z,AnsiMore ; and are legal.
|
|
CP "["
|
|
JP Z,AnsiMore
|
|
CP 09Bh ; CSI
|
|
JP Z,AnsiF1 ; Pretend that "[" was first ;-)
|
|
JP ANSIEXIT ; = and > don't have anything to follow
|
|
; them but are legal.
|
|
; Others are illegal, so abandon anyway.
|
|
AnsiF1: LD A,"[" ; Put a "[" for first character
|
|
LD (ANSIFIRST),A
|
|
JP ANSIEXIT
|
|
|
|
AnsiSemi: LD HL,(NUMBERPOS) ; Move the number pointer to the
|
|
LD A,(HAVELOADED) ; Did we put anything in this byte?
|
|
OR A
|
|
JR NZ,AS1
|
|
LD (HL),255 ; Mark the fact that nothing was put in
|
|
AS1: INC HL ; move to next byte
|
|
LD (NUMBERPOS),HL
|
|
XOR A
|
|
LD (HAVELOADED),A ; New byte => not filled!
|
|
JP AnsiMore
|
|
|
|
AnsiNumber: LD HL,(NUMBERPOS) ; Get address for number
|
|
LD A,(HAVELOADED)
|
|
OR A ; If value is zero
|
|
JR NZ,AN1
|
|
LD A,C ; Get value into A
|
|
SUB "0" ; Remove ASCII offset
|
|
LD (HL),A ; Save and Exit
|
|
LD A,255
|
|
LD (HAVELOADED),A ; Yes, we _have_ put something in!
|
|
JP AnsiMore
|
|
|
|
AN1: LD A,(HL) ; Stored value in A; TBA in C
|
|
ADD A,A ; 2 *
|
|
LD D,A ; Save the 2* for later
|
|
ADD A,A ; 4 *
|
|
ADD A,A ; 8 *
|
|
ADD A,D ; 10 *
|
|
ADD A,C ; 10 * + new num
|
|
SUB "0" ; And remove offset from C value!
|
|
LD (HL),A ; Save and Exit.
|
|
JP AnsiMore ; Note routine will only work up to 100
|
|
; which should be okay for this application.
|
|
|
|
;--------------------------------
|
|
; GET NUMBER
|
|
;
|
|
; Gets the next number from
|
|
; the list
|
|
;
|
|
; Entry - HL = address to get
|
|
; from
|
|
; Exit - HL = next address
|
|
; A = value
|
|
; IF a=255 then default value
|
|
; If a=254 then end of sequence
|
|
; Used - None
|
|
;--------------------------------
|
|
GetNumber: LD A,(HL) ; Get number
|
|
CP 254
|
|
RET Z ; Return if end of sequence,ie still point to
|
|
; end
|
|
INC HL ; Return pointing to next byte
|
|
RET ; Else next address and return
|
|
|
|
;*** ANSI UP
|
|
;
|
|
CUU: CALL GetNumber ; Number into A
|
|
LD B,A ; Save value into B
|
|
CP 255
|
|
JR NZ,CUUlp
|
|
LD B,1 ; Default value
|
|
CUUlp: LD A,(DSPXY+1) ; A <- Row
|
|
CP B ; Is it too far?
|
|
JR C,CUU1
|
|
SUB B ; No, then go back that far.
|
|
JR CUU2
|
|
CUU1: LD A,0 ; Make the choice, top line.
|
|
CUU2: LD (DSPXY+1),A ; Row <- A
|
|
JP ANSIEXIT
|
|
|
|
;*** ANSI DOWN
|
|
;
|
|
CUD: LD A,(ANSIFIRST)
|
|
CP "["
|
|
JP NZ,ANSIEXIT ; Ignore ESC(B
|
|
CALL GetNumber
|
|
LD B,A ; Save value in b
|
|
CP 255
|
|
JR NZ,CUDlp
|
|
LD B,1 ; Default
|
|
CUDlp: LD A,(DSPXY+1) ; A <- Row
|
|
ADD A,B
|
|
CP ROW ; Too far?
|
|
JP C,CUD1
|
|
LD A,ROW-1 ; Too far then bottom of screen
|
|
CUD1: LD (DSPXY+1),A ; Row <- A
|
|
JP ANSIEXIT
|
|
|
|
;*** ANSI RIGHT
|
|
;
|
|
CUF: CALL GetNumber ; Number into A
|
|
LD B,A ; Value saved in B
|
|
CP 255
|
|
JR NZ,CUFget
|
|
LD B,1 ; Default
|
|
CUFget: LD A,(DSPXY) ; A <- Column
|
|
ADD A,B ; Add movement.
|
|
CP 80 ; Too far?
|
|
JR C,CUF2
|
|
LD A,79 ; Yes, right edge
|
|
CUF2: LD (DSPXY),A ; Column <- A
|
|
JP ANSIEXIT
|
|
|
|
;*** ANSI LEFT
|
|
;
|
|
CUB: CALL GetNumber ; Number into A
|
|
LD B,A ; Save value in B
|
|
CP 255
|
|
JR NZ,CUBget
|
|
LD B,1 ; Default
|
|
CUBget: LD A,(DSPXY) ; A <- Column
|
|
CP B ; Too far?
|
|
JR C,CUB1a
|
|
SUB B
|
|
JR CUB1b
|
|
CUB1a: LD A,0
|
|
CUB1b: LD (DSPXY),A ; Column <-A
|
|
JP ANSIEXIT
|
|
|
|
;*** ANSI LOCATE
|
|
;
|
|
HVP:
|
|
CUP: CALL GetNumber
|
|
CP 255
|
|
CALL Z,DefaultLine ; Default = 1
|
|
CP 254 ; Sequence End -> 1
|
|
CALL Z,DefaultLine
|
|
CP ROW+1 ; Out of range then don't move
|
|
JP NC,ANSIEXIT
|
|
OR A
|
|
CALL Z,DefaultLine ; 0 means default, some strange reason
|
|
LD D,A
|
|
CALL GetNumber
|
|
CP 255 ; Default = 1
|
|
CALL Z,DefaultColumn
|
|
CP 254 ; Sequence End -> 1
|
|
CALL Z,DefaultColumn
|
|
CP 81 ; Out of range, then don't move
|
|
JP NC,ANSIEXIT
|
|
OR A
|
|
CALL Z,DefaultColumn ; 0 means go with default
|
|
LD E,A
|
|
EX DE,HL
|
|
DEC H ; Translate from Ansi co-ordinates to hardware
|
|
DEC L ; co-ordinates
|
|
LD (DSPXY),HL ; Set the cursor position.
|
|
JP ANSIEXIT
|
|
|
|
DefaultColumn:
|
|
DefaultLine:LD A,1
|
|
RET
|
|
|
|
;*** ANSI CLEAR SCREEN
|
|
;
|
|
ED: CALL GetNumber
|
|
OR A
|
|
JP Z,ED1 ; Zero means first option
|
|
CP 254 ; Also default
|
|
JP Z,ED1
|
|
CP 255
|
|
JP Z,ED1
|
|
CP 1
|
|
JP Z,ED2
|
|
CP 2
|
|
JP NZ,ANSIEXIT
|
|
|
|
;*** Option 2
|
|
;
|
|
ED3: LD HL,0
|
|
LD (DSPXY),HL ; Home the cursor
|
|
LD A,(JSW_FF)
|
|
OR A
|
|
JP NZ,ED_Set_LF
|
|
CALL CALCSCADDR
|
|
CALL CLRSCRN
|
|
JP ANSIEXIT
|
|
|
|
ED_Set_LF: XOR A ; Note simply so that
|
|
LD (JSW_LF),A ; ESC[2J works the same as CTRL-L
|
|
JP ANSIEXIT
|
|
|
|
;*** Option 0
|
|
;
|
|
ED1: LD HL,(DSPXY) ; Get and save cursor position
|
|
LD A,H
|
|
OR L
|
|
JP Z,ED3 ; If we are at the top of the
|
|
; screen and clearing to the bottom
|
|
; then we are clearing all the screen!
|
|
PUSH HL
|
|
LD A,ROW-1
|
|
SUB H ; ROW - Row
|
|
LD HL,0 ; Zero start
|
|
OR A ; Do we have any lines to add?
|
|
JR Z,ED1_2 ; If no bypass that addition!
|
|
LD B,A ; Number of lines to count
|
|
LD DE,80
|
|
ED1_1: ADD HL,DE
|
|
DJNZ ED1_1
|
|
ED1_2: EX DE,HL ; Value into DE
|
|
POP HL
|
|
LD A,80
|
|
SUB L ; 80 - Columns
|
|
LD L,A ; Add to value before
|
|
LD H,0
|
|
ADD HL,DE
|
|
PUSH HL ; Value saved for later
|
|
LD HL,(DSPXY) ; _that_ value again!
|
|
POP BC ; Number to blank
|
|
CALL CALCSCADDR
|
|
CALL CLRSCRN ; Now do it!
|
|
JP ANSIEXIT ; Then exit properly
|
|
|
|
;*** Option 1 - clear from cursor to beginning of screen
|
|
;
|
|
ED2: LD HL,(DSPXY) ; Get and save cursor position
|
|
PUSH HL
|
|
LD A,H
|
|
LD HL,0 ; Zero start
|
|
OR A ; Do we have any lines to add?
|
|
JR Z,ED2_2 ; If no bypass that addition!
|
|
LD B,A ; Number of lines
|
|
LD DE,80
|
|
ED2_1: ADD HL,DE
|
|
DJNZ ED2_1
|
|
ED2_2: EX DE,HL ; Value into DE
|
|
POP HL
|
|
LD H,0
|
|
ADD HL,DE
|
|
PUSH HL ; Value saved for later
|
|
LD HL,0 ; Find the begining!
|
|
POP BC ; Number to blank
|
|
CALL CLRSCRN ; Now do it!
|
|
JP ANSIEXIT ; Then exit properly
|
|
|
|
; *** ANSI CLEAR LINE
|
|
;
|
|
EL: CALL GetNumber ; Get value
|
|
CP 0
|
|
JP Z,EL1 ; Zero & Default are the same
|
|
CP 255
|
|
JP Z,EL1
|
|
CP 254
|
|
JP Z,EL1
|
|
CP 1
|
|
JP Z,EL2
|
|
CP 2
|
|
JP NZ,ANSIEXIT ; Otherwise don't do a thing
|
|
|
|
;*** Option 2 - clear entire line.
|
|
;
|
|
LD HL,(DSPXY)
|
|
LD L,0
|
|
LD (DSPXY),HL
|
|
CALL CALCSCADDR
|
|
LD BC,80 ; 80 bytes to clear (whole line)
|
|
CALL CLRSCRN
|
|
JP ANSIEXIT
|
|
|
|
;*** Option 0 - Clear from Cursor to end of line.
|
|
;
|
|
EL1: LD HL,(DSPXY)
|
|
LD A,80 ; Calculate distance to end of line
|
|
SUB L
|
|
LD C,A
|
|
LD B,0
|
|
LD (DSPXY),HL
|
|
PUSH HL
|
|
POP DE
|
|
CALL CALCSCADDR
|
|
CALL CLRSCRN
|
|
JP ANSIEXIT
|
|
|
|
;*** Option 1 - clear from cursor to beginning of line.
|
|
;
|
|
EL2: LD HL,(DSPXY)
|
|
LD C,L ; BC = distance from start of line
|
|
LD B,0
|
|
LD L,0
|
|
LD (DSPXY),HL
|
|
CALL CALCSCADDR
|
|
CALL CLRSCRN
|
|
JP ANSIEXIT
|
|
|
|
; In HL = XY Pos
|
|
; Out = Screen address.
|
|
CALCSCADDR: PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
LD A,H
|
|
LD B,H
|
|
LD C,L
|
|
LD HL,SCRN
|
|
OR A
|
|
JR Z,CALC3
|
|
LD DE,80
|
|
CALC2: ADD HL,DE
|
|
DJNZ CALC2
|
|
CALC3: POP DE
|
|
ADD HL,BC
|
|
POP DE
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
|
|
; HL = address
|
|
; BC = length
|
|
CLRSCRN: PUSH HL ; 1 for later!
|
|
LD D,H
|
|
LD E,L
|
|
INC DE ; DE <- HL +1
|
|
PUSH BC ; Save the value a little longer!
|
|
XOR A
|
|
LD (HL), A ; Blank this area!
|
|
LDIR ; *** just like magic ***
|
|
; only I forgot it in 22a!
|
|
POP BC ; Restore values
|
|
POP HL
|
|
LD DE,2048 ; Move to attributes block
|
|
ADD HL,DE
|
|
LD D,H
|
|
LD E,L
|
|
INC DE ; DE = HL + 1
|
|
LD A,(FONTSET) ; Save in the current values.
|
|
LD (HL),A
|
|
LDIR
|
|
RET
|
|
|
|
;*** ANSI SET GRAPHICS RENDITION
|
|
;
|
|
SGR: CALL GetNumber
|
|
CP 254 ; 254 signifies end of sequence
|
|
JP Z,ANSIEXIT
|
|
OR A
|
|
CALL Z,AllOff
|
|
CP 255 ; Default means all off
|
|
CALL Z,AllOff
|
|
CP 1
|
|
CALL Z,BoldOn
|
|
CP 2
|
|
CALL Z,BoldOff
|
|
CP 4
|
|
CALL Z,UnderOn
|
|
CP 5
|
|
CALL Z,ItalicOn
|
|
CP 6
|
|
CALL Z,ItalicOn
|
|
CP 7
|
|
CALL Z,InverseOn
|
|
JP SGR ; Code is re-entrant
|
|
|
|
;--------------------------------
|
|
;
|
|
; RESET GRAPHICS
|
|
;
|
|
; Entry - None
|
|
; Exit - None
|
|
; Used - None
|
|
;--------------------------------
|
|
AllOff: PUSH AF ; Save registers
|
|
LD A,0C9h ; = off
|
|
LD (BOLDMODE),A ; Turn the flags off
|
|
LD (ITALICMODE),A
|
|
LD (UNDERSCMODE),A
|
|
LD (INVMODE),A
|
|
LD A,017h ; Black background, white chars.
|
|
LD (FONTSET),A ; Reset the bit map store
|
|
POP AF ; Restore register
|
|
RET
|
|
|
|
;--------------------------------
|
|
;
|
|
; TURN BOLD ON
|
|
;
|
|
; Entry - None
|
|
; Exit - None
|
|
; Used - None
|
|
;--------------------------------
|
|
BoldOn: PUSH AF ; Save register
|
|
XOR A ; 0 means on
|
|
LD (BOLDMODE),A
|
|
BOn1: LD A,(FONTSET)
|
|
SET 0,A ; turn ON indicator flag
|
|
LD (FONTSET),A
|
|
POP AF ; Restore register
|
|
RET
|
|
|
|
;--------------------------------
|
|
;
|
|
; TURN BOLD OFF
|
|
;
|
|
; Entry - None
|
|
; Exit - None
|
|
; Used - None
|
|
;--------------------------------
|
|
BoldOff: PUSH AF ; Save register
|
|
PUSH BC
|
|
LD A,0C9h ; &C9 means off
|
|
LD (BOLDMODE),A
|
|
BO1: LD A,(FONTSET)
|
|
RES 0,A ; turn OFF indicator flag
|
|
LD (FONTSET),A
|
|
POP BC
|
|
POP AF ; Restore register
|
|
RET
|
|
|
|
;--------------------------------
|
|
;
|
|
; TURN ITALICS ON
|
|
; (replaces flashing)
|
|
; Entry - None
|
|
; Exit - None
|
|
; Used - None
|
|
;--------------------------------
|
|
ItalicOn: PUSH AF ; Save AF
|
|
XOR A
|
|
LD (ITALICMODE),A ; 0 means on
|
|
LD A,(FONTSET)
|
|
SET 1,A ; turn ON indicator flag
|
|
LD (FONTSET),A
|
|
POP AF ; Restore register
|
|
RET
|
|
|
|
;--------------------------------
|
|
;
|
|
; TURN UNDERLINE ON
|
|
;
|
|
; Entry - None
|
|
; Exit - None
|
|
; Used - None
|
|
;--------------------------------
|
|
UnderOn: PUSH AF ; Save register
|
|
XOR A ; 0 means on
|
|
LD (UNDERSCMODE),A
|
|
LD A,(FONTSET)
|
|
SET 2,A ; turn ON indicator flag
|
|
LD (FONTSET),A
|
|
POP AF ; Restore register
|
|
RET
|
|
|
|
;--------------------------------
|
|
;
|
|
; TURN INVERSE ON
|
|
;
|
|
; Entry - None
|
|
; Exit - None
|
|
; Used - None
|
|
;--------------------------------
|
|
InverseOn: PUSH AF ; Save register
|
|
XOR A ; 0 means on
|
|
LD (INVMODE),A
|
|
LD A,(FONTSET)
|
|
SET 3,A ; turn ON indicator flag
|
|
LD (FONTSET),A
|
|
POP AF ; Restore AF
|
|
RET
|
|
|
|
;*** ANSI SAVE CURSOR POSITION
|
|
;
|
|
SCP: LD HL,(DSPXY) ; (backup) <- (current)
|
|
LD (CURSORPSAV),HL
|
|
JP ANSIEXIT
|
|
|
|
;*** ANSI RESTORE CURSOR POSITION
|
|
;
|
|
RCP: LD HL,(CURSORPSAV) ; (current) <- (backup)
|
|
LD (DSPXY),HL
|
|
JP ANSIEXIT
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF ANSI TERMINAL FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF STATIC LOOKUP TABLES AND CONSTANTS
|
|
;-------------------------------------------------------------------------------
|
|
|
|
; Disk Parameter Header template.
|
|
DPBTMPL: DW 0000H, 0000H, 0000H, 0000H, CDIRBUF
|
|
|
|
|
|
;--------------------------------------
|
|
; Test Message table
|
|
;--------------------------------------
|
|
|
|
CBIOSSIGNON:IF BUILD_80C = 1
|
|
DB "** CBIOS v1.12, (C) P.D. Smart, 2019-21. Drives:", NUL
|
|
ELSE
|
|
DB "CBIOS v1.12, (C) P.D. Smart, 2019-21.", CR
|
|
DB "Drives:", NUL
|
|
ENDIF
|
|
CBIOSIGNEND:IF BUILD_80C = 1
|
|
DB " **", CR, NUL
|
|
ELSE
|
|
DB CR, NUL
|
|
ENDIF
|
|
CPMSIGNON: IF BUILD_80C = 1
|
|
DB "CP/M v2.23 (64K) Copyright(c) 1979 by Digital Research", CR, LF, NUL
|
|
ELSE
|
|
DB "CP/M v2.23 (c) 1979 by Digital Research", CR, LF, NUL
|
|
ENDIF
|
|
SDAVAIL: DB "SD", NUL
|
|
FDCAVAIL: DB "FDC", NUL
|
|
NOBDOS: DB "I/O Processor failed to load BDOS, aborting!", CR, LF, NUL
|
|
SVCRESPERR: DB "I/O Response Error, time out!", CR, NUL
|
|
SVCIOERR: DB "I/O Error, time out!", CR, NUL
|
|
|
|
LOADERR: DB "DISK ERROR - LOADING", CR, NUL
|
|
SELDRVMSG: DB "DISK ERROR - SELECT", CR, NUL
|
|
WAITRDYMSG: DB "DISK ERROR - WAIT", CR, NUL
|
|
DSKSEEKMSG: DB "DISK ERROR - SEEK", CR, NUL
|
|
RETRIESMSG: DB "DISK ERROR - RETRIES", CR, NUL
|
|
DATAOVRMSG: DB "DISK ERROR - DATA OVERRUN", CR, NUL
|
|
CRCERRMSG: DB "DISK ERROR - CRC ERROR", CR, NUL
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; END OF STATIC LOOKUP TABLES AND CONSTANTS
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;-------------------------------------------------------------------------------
|
|
; START OF DEBUGGING FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|
|
; Debug routine to print out all registers and dump a section of memory for analysis.
|
|
;
|
|
DEBUG: IF ENADEBUG = 1
|
|
LD (DBGSTACKP),SP
|
|
LD SP,DBGSTACK
|
|
;
|
|
PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
;
|
|
PUSH AF
|
|
PUSH HL
|
|
PUSH DE
|
|
PUSH BC
|
|
PUSH AF
|
|
LD DE, INFOMSG
|
|
CALL MONPRTSTR
|
|
POP BC
|
|
LD A,B
|
|
CALL PRTHX
|
|
LD A,C
|
|
CALL PRTHX
|
|
LD DE, INFOMSG2
|
|
CALL MONPRTSTR
|
|
POP BC
|
|
LD A,B
|
|
CALL PRTHX
|
|
LD A,C
|
|
CALL PRTHX
|
|
LD DE, INFOMSG3
|
|
CALL MONPRTSTR
|
|
POP DE
|
|
LD A,D
|
|
CALL PRTHX
|
|
LD A,E
|
|
CALL PRTHX
|
|
LD DE, INFOMSG4
|
|
CALL MONPRTSTR
|
|
POP HL
|
|
LD A,H
|
|
CALL PRTHX
|
|
LD A,L
|
|
CALL PRTHX
|
|
LD DE, INFOMSG5
|
|
CALL MONPRTSTR
|
|
LD HL,(DBGSTACKP)
|
|
LD A,H
|
|
CALL PRTHX
|
|
LD A,L
|
|
CALL PRTHX
|
|
CALL NL
|
|
|
|
LD DE, DRVMSG
|
|
CALL MONPRTSTR
|
|
LD A, (CDISK)
|
|
CALL PRTHX
|
|
|
|
LD DE, FDCDRVMSG
|
|
CALL MONPRTSTR
|
|
LD A, (FDCDISK)
|
|
CALL PRTHX
|
|
|
|
LD DE, SEKTRKMSG
|
|
CALL MONPRTSTR
|
|
LD BC,(SEKTRK)
|
|
LD A,B
|
|
CALL PRTHX
|
|
LD A,C
|
|
CALL PRTHX
|
|
CALL PRTS
|
|
LD A,(SEKSEC)
|
|
CALL PRTHX
|
|
CALL PRTS
|
|
LD A,(SEKHST)
|
|
CALL PRTHX
|
|
|
|
LD DE, HSTTRKMSG
|
|
CALL MONPRTSTR
|
|
LD BC,(HSTTRK)
|
|
LD A,B
|
|
CALL PRTHX
|
|
LD A,C
|
|
CALL PRTHX
|
|
CALL PRTS
|
|
LD A,(HSTSEC)
|
|
CALL PRTHX
|
|
|
|
LD DE, UNATRKMSG
|
|
CALL MONPRTSTR
|
|
LD BC,(UNATRK)
|
|
LD A,B
|
|
CALL PRTHX
|
|
LD A,C
|
|
CALL PRTHX
|
|
CALL PRTS
|
|
LD A,(UNASEC)
|
|
CALL PRTHX
|
|
|
|
LD DE, CTLTRKMSG
|
|
CALL MONPRTSTR
|
|
LD A,(TRACKNO) ; NB. Track number is 16bit, FDC only uses lower 8bit and assumes little endian read.
|
|
CALL PRTHX
|
|
CALL PRTS
|
|
LD A,(SECTORNO)
|
|
CALL PRTHX
|
|
|
|
LD DE, DMAMSG
|
|
CALL MONPRTSTR
|
|
LD BC,(DMAADDR)
|
|
LD A,B
|
|
CALL PRTHX
|
|
LD A,C
|
|
CALL PRTHX
|
|
CALL NL
|
|
;
|
|
POP AF
|
|
JR C, SKIPDUMP
|
|
;
|
|
LD HL,DPBASE ; Dump the startup vectors.
|
|
LD DE, 1000H
|
|
ADD HL, DE
|
|
EX DE,HL
|
|
LD HL,DPBASE
|
|
CALL DUMPX
|
|
|
|
LD HL,00000h ; Dump the startup vectors.
|
|
LD DE, 00A0H
|
|
ADD HL, DE
|
|
EX DE,HL
|
|
LD HL,00000h
|
|
CALL DUMPX
|
|
|
|
LD HL,IBUFE ; Dump the data area.
|
|
LD DE, 0300H
|
|
ADD HL, DE
|
|
EX DE,HL
|
|
LD HL,IBUFE
|
|
CALL DUMPX
|
|
|
|
LD HL,CBASE ; Dump the CCP + BDOS area.
|
|
LD DE,CPMBIOS - CBASE
|
|
ADD HL, DE
|
|
EX DE,HL
|
|
LD HL,CBASE
|
|
CALL DUMPX
|
|
|
|
SKIPDUMP: ;JR SKIPDUMP
|
|
POP HL
|
|
POP DE
|
|
POP BC
|
|
POP AF
|
|
;
|
|
LD SP,(DBGSTACKP)
|
|
RET
|
|
|
|
; HL = Start
|
|
; DE = End
|
|
DUMPX: LD A,10
|
|
DUM1: LD (TMPCNT),A
|
|
DUM3: LD B,010h
|
|
LD C,02Fh
|
|
CALL NLPHL
|
|
DUM2: CALL SPHEX
|
|
INC HL
|
|
PUSH AF
|
|
LD A,(DSPXY)
|
|
ADD A,C
|
|
LD (DSPXY),A
|
|
POP AF
|
|
CP 020h
|
|
JR NC,L0D51
|
|
LD A,02Eh
|
|
L0D51: CALL PRNT
|
|
LD A,(DSPXY)
|
|
INC C
|
|
SUB C
|
|
LD (DSPXY),A
|
|
DEC C
|
|
DEC C
|
|
DEC C
|
|
PUSH HL
|
|
SBC HL,DE
|
|
POP HL
|
|
JR NC,DUM7
|
|
L0D78: DJNZ DUM2
|
|
LD A,(TMPCNT)
|
|
DEC A
|
|
LD (TMPCNT),A
|
|
JR NZ,DUM3
|
|
DUM4: CALL CHKKY
|
|
CP 0FFH
|
|
JR NZ,DUM4
|
|
CALL GETKY
|
|
CP 'D'
|
|
JR NZ,DUM5
|
|
LD A,8
|
|
JR DUM1
|
|
DUM5: CP 'U'
|
|
JR NZ,DUM6
|
|
PUSH DE
|
|
LD DE,00100H
|
|
OR A
|
|
SBC HL,DE
|
|
POP DE
|
|
LD A,8
|
|
JR DUM1
|
|
DUM6: CP 'X'
|
|
JR Z,DUM7
|
|
JR DUMPX
|
|
DUM7: CALL NL
|
|
RET
|
|
|
|
NLPHL: CALL NL
|
|
CALL PRTHL
|
|
RET
|
|
|
|
; SPACE PRINT AND DISP ACC
|
|
; INPUT:HL=DISP. ADR.
|
|
SPHEX: CALL PRTS ; SPACE PRINT
|
|
LD A,(HL)
|
|
CALL PRTHX ; DSP OF ACC (ASCII)
|
|
LD A,(HL)
|
|
RET
|
|
|
|
; Debugger messages, bit cryptic but this is due to limited space on the screen.
|
|
;
|
|
DRVMSG: DB "DRV=", 000H
|
|
FDCDRVMSG: DB ",FDC=", 000H
|
|
SEKTRKMSG: DB ",S=", 000H
|
|
HSTTRKMSG: DB ",H=", 000H
|
|
UNATRKMSG: DB ",U=", 000H
|
|
CTLTRKMSG: DB ",C=", 000H
|
|
DMAMSG: DB ",DMA=", 000H
|
|
INFOMSG: DB "AF=", NUL
|
|
INFOMSG2: DB ",BC=", 000H
|
|
INFOMSG3: DB ",DE=", 000H
|
|
INFOMSG4: DB ",HL=", 000H
|
|
INFOMSG5: DB ",SP=", 000H
|
|
|
|
; Seperate stack for the debugger so as not to affect anything it is reporting on.
|
|
;
|
|
DBGSTACKP: DS 2
|
|
DS 128, 0AAH
|
|
DBGSTACK: EQU $
|
|
|
|
ALIGN 00400H
|
|
ENDIF
|
|
;-------------------------------------------------------------------------------
|
|
; END OF DEBUGGING FUNCTIONALITY
|
|
;-------------------------------------------------------------------------------
|