Files
tzpuFusionX/software/asm/cbios.asm
Philip Smart 066e049538 Add Z80 assembly sources, ROMs and build tools to repository
Un-ignore software/asm/, software/tools/, and software/roms/ so that
CI/CD builds on Jenkins can assemble Z80 ROMs, TZFS, and CP/M from
source. Previously these files were only available on the dev machine.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 15:42:50 +00:00

1616 lines
81 KiB
NASM

;--------------------------------------------------------------------------------------------------------
;-
;- Name: cbios.asm
;- Created: January 2020
;- Author(s): Philip Smart
;- Description: Sharp MZ series CPM BIOS System.
;- This is the CPM CBIOS for the Sharp MZ80A hardware plus RFS/80 char upgrades.
;- It makes extensive use of the paged roms to add functionality and conserve
;- RAM for the CPM applications.
;-
;- Credits: Some of the comments and parts of the standard CPM deblocking/blocking algorithm
;- come from the Z80-MBC2 project, (C) SuperFabius.
;- 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/>.
;--------------------------------------------------------------------------------------------------------
; Bring in additional macros.
INCLUDE "cpm_buildversion.asm"
INCLUDE "cpm_definitions.asm"
INCLUDE "macros.asm"
; Start of the CBIOS area is RAM for variables, disk parameters and scratch areas and buffers.
; 2K is provided for CBIOS RAM.
;
ORG CBIOSSTART
; The CBIOS code resides in Memory mode 16 andstarts at 0xF000:0xF7FFF, the common variable and
; buffer area is stored in the top 2K, ie. 0xF800:0xFFFF. The CBIOS code is mainly hooks, the main
; logic is stored in the bank 0x0000:0xD000 in Memory mode 17. Memory mode 16 is a contiguous block
; of RAM from 0x0000:0xFFFF, all Sharp MZ80A hardware is paged out.
;
; One caveat due to the FDC controller, blocks 0xF3C0-0xF3FF and 0xF7C0-0xF7FF
; are not useable as the code in locations 0xF3FE:0xF3FF and 0xF7FE:0xF7FF are
; hardware controlled by the floppy controller. The design of the tranZPUter only
; allows RAM configuration down to 64byte chunks hence the 2x64byte blocks being
; unuseable.
;-------------------------------------------------------------------------------
;
; BIOS jump table
;
;-------------------------------------------------------------------------------
JP ?BOOT_
JP ?WBOOT_
JP ?CONST_
JP ?CONIN_
JP ?CONOUT_
JP ?LIST_
JP ?PUNCH_
JP ?READER_
JP ?HOME_
JP ?SELDSK_
JP ?SETTRK_
JP ?SETSEC_
JP ?SETDMA_
JP ?READ_
JP ?WRITE_
JP ?LISTST_
JP ?SECTRN_
JP ?DEBUG_
;-------------------------------------------------------------------------------
; TIMER INTERRUPT
;
; This is the RTC interrupt, which interrupts every 100msec. RTC is maintained
; by keeping an in memory count of seconds past 00:00:00 and an AMPM flag.
;-------------------------------------------------------------------------------
TIMIN: LD (SPISRSAVE),SP ; CP/M has a small working stack, an interrupt could exhaust it so save interrupts stack and use a local stack.
LD SP,ISRSTACK
;
PUSH AF ; Save used registers.
PUSH BC
PUSH DE
PUSH HL
;
LD A,TZMM_CPM2 ; We meed to be in memory mode 7 to process the interrupts as this allows us access to the hardware.
OUT (MMCFG),A
;
; Reset the interrupt counter.
LD HL,CONTF ; CTC Control register, set to reload the 100ms interrupt time period.
LD (HL),080H ; Select Counter 2, latch counter, read lsb first, mode 0 and binary.
PUSH HL
DEC HL
LD E,(HL)
LD D,(HL) ; Obtain the overrun count if any (due to disabled interrupts).
LD HL, 00001H ; Add full range to count to obtain the period of overrun time.
SBC HL,DE
EX DE,HL
POP HL
LD (HL),0B0H ; Select Counter 2, load lsb first, mode 0 interrupt on terminal count, binary
DEC HL
LD (HL),TMRTICKINTV
LD (HL),000H ; Another 100msec delay till next interrupt.
;
; Update the RTC with the time period.
LD HL,(TIMESEC) ; Lower 16bits of counter.
ADD HL,DE
LD (TIMESEC),HL
JR NC,TIMIN1 ; On overflow we increment middle 16bits.
;
LD HL,(TIMESEC+2)
INC HL
LD (TIMESEC+2),HL
LD A,H
OR L
JR NZ,TIMIN1 ; On overflow we increment upper 16bits.
;
LD HL,(TIMESEC+4)
INC HL
LD (TIMESEC+4),HL
;
; Flash a cursor at the current XY location.
;
TIMIN1: LD HL,FLASHCTL
BIT 7,(HL) ; Is cursor enabled? If it isnt, skip further processing.
JR Z,TIMIN2
;
FLSHCTL0: LD A,(KEYPC) ; Flashing component, on each timer tick, display the cursor or the original screen character.
LD C,A
XOR (HL) ; Detect a cursor change signal.
RLCA
RLCA
JR NC,TIMIN2 ; No change, skip.
RES 6,(HL)
LD A,C ; We know there was a change, so decide what to display and write to screen.
RLCA
RLCA
LD A,(FLASH)
JR NC,FLSHCTL1
SET 6,(HL) ; We are going to display the cursor, so save the underlying character.
LD A,(FLSDT) ; Retrieve the cursor character.
FLSHCTL1: LD HL,(DSPXYADDR) ; Load the desired cursor or character onto the screen.
LD (HL),A
;
; FDC Motor Off Timer
;
TIMIN2: LD A,(MTROFFTIMER) ; Is the timer non-zero?
OR A
JP Z,TIMIN3
DEC A ; Decrement.
LD (MTROFFTIMER),A
JP NZ,TIMIN3 ; If zero after decrement, turn off the motor.
OUT (FDC_MOTOR),A ; Turn Motor off
LD (MOTON),A ; Clear Motor on flag
;
; Keyboard processing.
;
TIMIN3:
;
; Keyboard routine for the Sharp MZ-80A hardware.
;
IF BUILD_MZ80A = 1 ; Perform keyboard sweep - inline to avoid overhead of a call.
; KEYBOARD SWEEP
;
; EXIT B,D7=0 NO DATA
; =1 DATA
; D6=0 SHIFT OFF
; =1 SHIFT ON
; C = ROW & COLUMN
;
SWEP: XOR A
LD (KDATW),A ; Reset key counter
LD B,0FAH ; Starting scan line, D3:0 = scan = line 10. D5:4 not used, D7=Cursor flash.
LD D,A
; BREAK TEST
; BREAK ON : ZERO = 1
; OFF : ZERO = 0
; NO KEY : CY = 0
; KEY IN : CY = 1
; A D6=1: SHIFT ON
; =0: SHIFT OFF
; D5=1: CTRL ON
; =0: CTRL OFF
; D4=1: GRAPH ON
; =0: GRAPH OFF
BREAK: LD A,0F0H
LD (KEYPA),A ; Port A scan line 0
NOP
LD A,(KEYPB) ; Read back key data.
OR A
RLA
JR NC,BREAK3 ; CTRL/BREAK key pressed?
RRA
RRA ; Check if SHIFT key pressed/
JR NC,BREAK1 ; SHIFT BREAK not pressed, jump.
RRA
JR NC,BREAK2 ; Check for GRAPH.
CCF
JR SWEP6 ;SWEP1
BREAK1: LD A,040H ; A D6=1 SHIFT ON
SCF
JR SWEP6
BREAK2: LD A,001H ; No keys found to be pressed on scanline 0.
LD (KDATW),A
LD A,010H ; A D4=1 GRAPH
SCF
JR SWEP6
BREAK3: AND 006H ; SHIFT + GRAPH + BREAK?
JR Z,SWEP1A
AND 002H ; SHIFT ?
JR Z,SWEP1 ; Z = 1 = SHIFT BREAK pressed/
LD A,020H ; A D5=1 CTRL
SCF
JR SWEP6
SWEP1: LD D,088H ; Break ON
JR SWEP9
SWEP1A: JP REBOOT ; Shift + Graph + Break ON = RESET.
;
SWEP6: LD HL,SWPW
PUSH HL
JR NC,SWEP11
LD D,A
AND 060H ; Shift & Ctrl =no data.
JR NZ,SWEP11
LD A,D ; Graph Check
XOR (HL)
BIT 4,A
LD (HL),D
JR Z,SWEP0
SWEP01: SET 7,D ; Data available, set flag.
SWEP0: DEC B
POP HL ; SWEP column work
INC HL
LD A,B
LD (KEYPA),A ; Port A (8255) D3:0 = Scan line output.
CP 0F0H
JR NZ,SWEP3 ; If we are not at scan line 0 then check for key data.
LD A,(HL) ; SWPW
CP 003H ; Have we scanned all lines, if yes then no data?
JR C,SWEP9
LD (HL),000H ;
RES 7,D ; Reset data in as no data awailable.
SWEP9: LD B,D
JR ISRKEY0
SWEP11: LD (HL),000H
JR SWEP0
SWEP3: LD A,(KEYPB) ; Port B (8255) D7:0 = Key data in for given scan line.
LD E,A
CPL
AND (HL)
LD (HL),E
PUSH HL
LD HL,KDATW
PUSH BC
LD B,008H
SWEP8: RLC E
JR C,SWEP7
INC (HL)
SWEP7: DJNZ SWEP8
POP BC
OR A
JR Z,SWEP0
LD E,A
SWEP2: LD H,008H
LD A,B
DEC A ; TBL adjust
AND 00FH
RLCA
RLCA
RLCA
LD C,A
LD A,E
SWEP12: DEC H
RRCA
JR NC,SWEP12
LD A,H
ADD A,C
LD C,A
JP SWEP01
ISRKEY0: LD A,B
RLCA
JP C,ISRKEY2 ; CY=1 then data available.
LD HL,KDATW
LD A,(HL) ; Is a key being held down?
OR A
JR NZ, ISRAUTORPT ; It is so process as an auto repeat key.
XOR A
LD (KEYRPT),A ; No key held then clear the auto repeat initial pause counter.
LD A,NOKEY ; No key code.
ISRKEY1: LD HL,KDATW
LD E,A
LD A,(HL) ; Current key scan line position.
INC HL
LD D,(HL) ; Previous key position.
LD (HL),A ; Previous <= current
SUB D ; Are they the same?
JR NC,ISRKEY11
INC (HL) ;
ISRKEY11: LD A,E
ISRKEY10: CP NOKEY
JR Z,ISREXIT
LD (KEYLAST),A
ISRKEYRPT: LD A,(KEYCOUNT) ; Get current count of bytes in the keyboard buffer.
CP KEYBUFSIZE - 1
JR NC, ISREXIT ; Keyboard buffer full, so waste character.
INC A
LD (KEYCOUNT),A
LD HL,(KEYWRITE) ; Get the write buffer pointer.
LD (HL), E ; Store the character.
INC L
LD A,L
AND KEYBUFSIZE-1 ; Circular buffer, keep boundaries.
LD L,A
LD (KEYWRITE),HL ; Store updated pointer.
;
ISREXIT: LD A,(MMCFGVAL) ; Return to the memory mode prior to interrupt call.
OUT (MMCFG),A
;
POP HL
POP DE
POP BC
POP AF
;
LD SP,(SPISRSAVE)
EI
RET
;
; Helper to determine if a key is being held down and autorepeat should be applied.
; The criterion is a timer, if this expires then autorepeat is applied.
;
ISRAUTORPT: LD A,(KEYRPT) ; Increment an initial pause counter.
INC A
CP 10
JR C,ISRAUTO1 ; Once expired we can auto repeat the last key.
LD A,(KEYLAST)
CP 080H
JR NC,ISREXIT ; Dont auto repeat control keys.
LD E,A
JR ISRKEYRPT
ISRAUTO1: LD (KEYRPT),A
JR ISREXIT
;
; Method to alternate through the 3 shift modes, CAPSLOCK=1, SHIFTLOCK=2, NO LOCK=0
;
LOCKTOGGLE: LD HL,FLSDT
LD A,(SFTLK)
INC A
CP 3
JR C,LOCK0
XOR A
LOCK0: LD (SFTLK),A
OR A
LD (HL),043H ; Thick block cursor when lower case.
JR Z,LOCK1
CP 1
LD (HL),03EH ; Thick underscore when CAPS lock.
JR Z,LOCK1
LD (HL),0EFH ; Block cursor when SHIFT lock.
LOCK1: JP ISREXIT
ISRKEY2: RLCA
RLCA
RLCA
JP C,LOCKTOGGLE ; GRAPH key which acts as the Shift Lock.
RLCA
JP C,ISRBRK ; BREAK key.
LD H,000H
LD L,C
LD A,C
CP 038H ; TEN KEY check.
JR NC,ISRKEY6 ; Jump if TENKEY.
LD A,B
RLCA
LD B,A
LD A,(SFTLK)
OR A
LD A,B
JR Z,ISRKEY14
RLA
CCF
RRA
ISRKEY14: RLA
RLA
JR NC,ISRKEY3
ISRKEY15: LD DE,KTBLC
ISRKEY5: ADD HL,DE
ISRKEY55: LD A,(HL)
JP ISRKEY1
ISRKEY3: RRA
JR NC,ISRKEY6
LD A,(SFTLK)
CP 1
LD DE,KTBLCL
JR Z,ISRKEY5
LD DE,KTBLS
JR ISRKEY5
ISRKEY6: LD DE,KTBL
JR ISRKEY5
ISRKEY4: RLCA
RLCA
JR C,ISRKEY15
LD DE,KTBL
JR ISRKEY5
; Break key pressed, handled in getkey routine.
ISRBRK: LD A,(KEYLAST)
CP BREAKKEY
JP Z,ISREXIT
XOR A ; Reset the keyboard buffer.
LD (KEYCOUNT),A
LD HL,KEYBUF
LD (KEYWRITE),HL
LD (KEYREAD),HL
LD A,BREAKKEY
JP ISRKEY10
KTBL: ; Strobe 0
DB '"'
DB '!'
DB 'W'
DB 'Q'
DB 'A'
DB INSERT
DB NULL
DB 'Z'
; Strobe 1
DB '$'
DB '#'
DB 'R'
DB 'E'
DB 'D'
DB 'S'
DB 'X'
DB 'C'
; Strobe 2
DB '&'
DB '%'
DB 'Y'
DB 'T'
DB 'G'
DB 'F'
DB 'V'
DB 'B'
; Strobe 3
DB '('
DB '\''
DB 'I'
DB 'U'
DB 'J'
DB 'H'
DB 'N'
DB SPACE
; Strobe 4
DB '_'
DB ')'
DB 'P'
DB 'O'
DB 'L'
DB 'K'
DB '<'
DB 'M'
; Strobe 5
DB '~'
DB '='
DB '{'
DB '`'
DB '*'
DB '+'
DB CURSLEFT
DB '>'
; Strobe 6
DB HOMEKEY
DB '|'
DB CURSRIGHT
DB CURSUP
DB CR
DB '}'
DB NULL
DB CURSUP
; Strobe 7
DB '8'
DB '7'
DB '5'
DB '4'
DB '2'
DB '1'
DB DBLZERO
DB '0'
; Strobe 8
DB '*'
DB '9'
DB '-'
DB '6'
DB NULL
DB '3'
DB NULL
DB ','
KTBLS: ; Strobe 0
DB '2'
DB '1'
DB 'w'
DB 'q'
DB 'a'
DB DELETE
DB NULL
DB 'z'
; Strobe 1
DB '4'
DB '3'
DB 'r'
DB 'e'
DB 'd'
DB 's'
DB 'x'
DB 'c'
; Strobe 2
DB '6'
DB '5'
DB 'y'
DB 't'
DB 'g'
DB 'f'
DB 'v'
DB 'b'
; Strobe 3
DB '8'
DB '7'
DB 'i'
DB 'u'
DB 'j'
DB 'h'
DB 'n'
DB SPACE
; Strobe 4
DB '0'
DB '9'
DB 'p'
DB 'o'
DB 'l'
DB 'k'
DB ','
DB 'm'
; Strobe 5
DB '^'
DB '-'
DB '['
DB '@'
DB ':'
DB ';'
DB '/'
DB '.'
; Strobe 6
DB CLRKEY
DB '\\'
DB CURSLEFT
DB CURSDOWN
DB CR
DB ']'
DB NULL
DB '?'
KTBLCL: ; Strobe 0
DB '2'
DB '1'
DB 'W'
DB 'Q'
DB 'A'
DB DELETE
DB NULL
DB 'Z'
; Strobe 1
DB '4'
DB '3'
DB 'R'
DB 'E'
DB 'D'
DB 'S'
DB 'X'
DB 'C'
; Strobe 2
DB '6'
DB '5'
DB 'Y'
DB 'T'
DB 'G'
DB 'F'
DB 'V'
DB 'B'
; Strobe 3
DB '8'
DB '7'
DB 'I'
DB 'U'
DB 'J'
DB 'H'
DB 'N'
DB SPACE
; Strobe 4
DB '0'
DB '9'
DB 'P'
DB 'O'
DB 'L'
DB 'K'
DB ','
DB 'M'
; Strobe 5
DB '^'
DB '-'
DB '['
DB '@'
DB ':'
DB ';'
DB '/'
DB '.'
; Strobe 6
DB CLRKEY
DB '\\'
DB CURSLEFT
DB CURSDOWN
DB CR
DB ']'
DB NULL
DB '?'
KTBLC: ; CTRL ON
; Strobe 0
DB NOKEY
DB NOKEY
DB CTRL_W
DB CTRL_Q
DB CTRL_A
DB NOKEY
DB 000H
DB CTRL_Z
; Strobe 1
DB NOKEY
DB NOKEY
DB CTRL_R
DB CTRL_E
DB CTRL_D
DB CTRL_S
DB CTRL_X
DB CTRL_C
; Strobe 2
DB NOKEY
DB NOKEY
DB CTRL_Y
DB CTRL_T
DB CTRL_G
DB CTRL_F
DB CTRL_V
DB CTRL_B
; Strobe 3
DB NOKEY
DB NOKEY
DB CTRL_I
DB CTRL_U
DB CTRL_J
DB CTRL_H
DB CTRL_N
DB NOKEY
; Strobe 4
DB NOKEY
DB NOKEY
DB CTRL_P
DB CTRL_O
DB CTRL_L
DB CTRL_K
DB NOKEY
DB CTRL_M
; Strobe 5
DB CTRL_CAPPA
DB CTRL_UNDSCR
DB ESC
DB CTRL_AT
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
; Strobe 6
DB NOKEY
DB CTRL_SLASH
DB NOKEY
DB NOKEY
DB NOKEY
DB CTRL_RB
DB NOKEY
ENDIF
;
; Keyboard routine for the MZ-700 hardware.
;
IF BUILD_MZ700 = 1
;
; KEY BOARD SWEEP
; EXIT B,D7=0 NO DATA
; =1 DATA
; D6=0 SHIFT OFF
; =1 SHIFT ON
; D5=0 CTRL OFF
; =1 CTRL ON
; D4=0 SHIFT+CTRL OFF
; =1 SHIFT+CTRL ON
; C = ROW & COLUMN
; 7 6 5 4 3 2 1 0
; * * ^ ^ ^ < < <
XOR A
LD B,0F8H
LD D,A
; BREAK KEY CHECK
; AND SHIFT, CTRL KEY CHECK
; EXIT BREAK ON : ZERO=1
; OFF: ZERO=0
; NO KEY : CY =0
; KEY IN : CY =1
; A D6=1 : SHIFT ON
; =0 : OFF
; D5=1 : CTRL ON
; =0 : OFF
; D4=1 : SHIFT+CNT ON
; =0 : OFF
; D3=1 : BREAK ON
; =0 : OFF
BREAK: LD A,0F8H ; LINE 8SWEEP
LD (KEYPA),A
NOP
LD A,(KEYPB)
CP 03EH ; BREAK + CTRL + SHIFT = RESET TO MONITOR
JP Z, REBOOT
OR A
RRA
JP C,BREAK2 ; SHIFT ?
RLA
RLA
JR NC,BREAK1 ; BREAK ?
LD A,40H ; SHIFT D6=1
SCF
JR SWEP6
BREAK1: XOR A ; SHIFT ?
JR SWEP6
; BREAK SUBROUTINE BYPASS 1
; CTRL OR NOT KEY
BREAK2: BIT 5,A ; NOT OR CTRL
JR Z,BREAK3 ; CTRL
OR A ; NOTKEY A=7FH
JR SWEP6
BREAK3: LD A,20H ; CTRL D5=1
OR A ; ZERO FLG CLR
SCF
JR SWEP6
SWEP1: LD D,88H ; BREAK ON
JR SWEP9
SWEP6: JR NC,SWEP0
LD D,A
JR SWEP0
SWEP01: SET 7,D
SWEP0: DEC B
LD A,B
LD (KEYPA),A
CP 0EFH ; MAP SWEEP END ?
JR NZ,SWEP3
CP 0F8H ; BREAK KEY ROW
JR Z,SWEP0
SWEP9: LD B,D
JP ISRKEY0
SWEP3: LD A,(KEYPB)
LD E,A
CPL
OR A
JR Z,SWEP0
LD E,A
SWEP2: LD H,8
LD A,B
AND 0FH
RLCA
RLCA
RLCA
LD C,A
LD A,E
L0A89: DEC H
RRCA
JR NC,L0A89
LD A,H
ADD A,C
LD C,A
JR SWEP01
ISRKEY0: LD A,B
RLCA
JP C,ISRKEY2 ; CY=1 then data available.
XOR A
LD (KEYRPT),A ; No key held then clear the auto repeat initial pause counter.
LD A,NOKEY ; No key code.
JR ISRKEY10
;
ISRKEY1: LD E, A
LD A,(KEYLAST)
CP E
JR Z, ISRAUTORPT
LD A, E
ISRKEY10: CP NOKEY
LD (KEYLAST),A
JR Z,ISREXIT
CP GRAPHKEY
JR Z,LOCKTOGGLE
CP ALPHAKEY
JR Z,ALPHATOGGLE
ISRKEYRPT: LD A,(KEYCOUNT) ; Get current count of bytes in the keyboard buffer.
CP KEYBUFSIZE - 1
JR NC, ISREXIT ; Keyboard buffer full, so waste character.
INC A
LD (KEYCOUNT),A
LD HL,(KEYWRITE) ; Get the write buffer pointer.
LD (HL), E ; Store the character.
INC L
LD A,L
AND KEYBUFSIZE-1 ; Circular buffer, keep boundaries.
LD L,A
LD (KEYWRITE),HL ; Store updated pointer.
;
ISREXIT: LD A,(MMCFGVAL) ; Return to the memory mode prior to interrupt call.
OUT (MMCFG),A
;
POP HL
POP DE
POP BC
POP AF
;
LD SP,(SPISRSAVE)
EI
RET
;
; Helper to determine if a key is being held down and autorepeat should be applied.
; The criterion is a timer, if this expires then autorepeat is applied.
;
ISRAUTORPT: LD A,(KEYRPT) ; Increment an initial pause counter.
INC A
CP 10
JR C,ISRAUTO1 ; Once expired we can auto repeat the last key.
LD A,(KEYLAST)
CP 080H
JR NC,ISREXIT ; Dont auto repeat control keys.
LD E,A
JR ISRKEYRPT
ISRAUTO1: LD (KEYRPT),A
JR ISREXIT
;
; Method to alternate through the 3 shift modes, CAPSLOCK=1, SHIFTLOCK=2, NO LOCK=0
;
LOCKTOGGLE: LD HL,FLSDT
LD A,(SFTLK)
INC A
CP 3
JR C,LOCK0
XOR A
LOCK0: LD (SFTLK),A
OR A
LD (HL),043H ; Thick block cursor when lower case.
JR Z,LOCK1
CP 1
LD (HL),03EH ; Thick underscore when CAPS lock.
JR Z,LOCK1
LD (HL),0EFH ; Block cursor when SHIFT lock.
LOCK1: JP ISREXIT
; Method to alternate between NO LOCK and CAPSLOCK.
ALPHATOGGLE:LD HL,FLSDT
LD A,(SFTLK)
INC A
AND 001H
JR LOCK0
ISRKEY2: LD DE,KTBLSL ; KEY TABLE WITH SHIFT LOCK
LD A,B
CP 88H ; BREAK IN (SHIFT & BRK)
JR Z,ISRBRK
LD H,0 ; HL=ROW & COLUMN
LD L,C
BIT 5,A ; CTRL CHECK
JR NZ,ISRKEY15 ; YES, CTRL
LD A,(SFTLK) ; CAPSLOCK=1, SHIFTLOCK=2, NO LOCK=0
RRCA
JR C,ISRKEY3
RRCA
JR C,ISRKEY6
LD A, B
BIT 6, A
LD DE,KTBLSL ; Shift lock.
JR NZ, ISRKEY5
LD DE,KTBLNS ; Lower case.
JR ISRKEY5
; Setup pointer to Control Key mapping.
ISRKEY15: LD DE,KTBLC
; Add in offset.
ISRKEY5: ADD HL,DE
; Get key.
ISRKEY55: LD A,(HL)
JP ISRKEY1
; Setup pointer to Caps Lock mapping.
ISRKEY3: LD A, B
BIT 6, A ; Shift pressed when caps lock on?
LD DE, KTBLSL
JR NZ, ISRKEY5
LD DE,KTBLCL
JR ISRKEY5
; Setup pointer to Shift Lock mapping.
ISRKEY6: LD A, B
BIT 6, A ; Shift pressed when shift lock on?
LD DE, KTBLNS
JR NZ, ISRKEY5
LD DE,KTBLSL
JR ISRKEY5
; Break key pressed, handled in getkey routine.
ISRBRK: LD A,(KEYLAST)
CP BREAKKEY
JP Z,ISREXIT
XOR A ; Reset the keyboard buffer.
LD (KEYCOUNT),A
LD HL,KEYBUF
LD (KEYWRITE),HL
LD (KEYREAD),HL
LD A,BREAKKEY
JP ISRKEY10
KTBLSL: ; SHIFT LOCK.
;S0 00 - 07
DB 0BFH ; SPARE
DB GRAPHKEY ; GRAPH
DB 58H ;
DB ALPHAKEY ; ALPHA
DB NOKEY ; NO
DB ';' ; ;
DB ':' ; :
DB CR ; CR
;S1 08 - 0F
DB 'Y' ; Y
DB 'Z' ; Z
DB '@' ; @
DB '(' ; [
DB ')' ; ]
DB NOKEY ; NULL
DB NOKEY ; NULL
DB NOKEY ; NULL
;S2 10 - 17
DB 'Q' ; Q
DB 'R' ; R
DB 'S' ; S
DB 'T' ; T
DB 'U' ; U
DB 'V' ; V
DB 'W' ; W
DB 'X' ; X
;S3 18 - 1F
DB 'I' ; I
DB 'J' ; J
DB 'K' ; K
DB 'L' ; L
DB 'M' ; M
DB 'N' ; N
DB 'O' ; O
DB 'P' ; P
;S4 20 - 27
DB 'A' ; A
DB 'B' ; B
DB 'C' ; C
DB 'D' ; D
DB 'E' ; E
DB 'F' ; F
DB 'G' ; G
DB 'H' ; H
;S5 28 - 2F
DB '!' ; !
DB '"' ; "
DB '#' ; #
DB '$' ; $
DB '%' ; %
DB '&' ; &
DB '\'' ; '
DB '(' ; (
;S6 30 - 37
DB '\\' ; \
DB '#' ; POND MARK
DB 2BH ; YEN
DB ' ' ; SPACE
DB ' ' ; ¶
DB ')' ; )
DB '<' ; <
DB '>' ; >
;S7 38 - 3F
DB INSERT ; INST.
DB DELETE ; DEL.
DB CURSUP ; CURSOR UP
DB CURSDOWN ; CURSOR DOWN
DB CURSRIGHT ; CURSOR RIGHT
DB CURSLEFT ; CURSOR LEFT
DB '?' ; ?
DB '/' ; /
;
;
KTBLNS: ; NO SHIFT
;S0 00 - 07
DB 0BFH ; SPARE
DB GRAPHKEY ; GRAPH
DB 1BH ; POND
DB ALPHAKEY ; ALPHA
DB NOKEY ; NO
DB '+' ; +
DB '*' ; *
DB CR ; CR
;S1 08 - 0F
DB 'y' ; y
DB 'z' ; z
DB '`' ; `
DB '{' ; {
DB '}' ; }
DB NOKEY ; NULL
DB NOKEY ; NULL
DB NOKEY ; NULL
;S2 10 - 17
DB 'q' ; q
DB 'r' ; r
DB 's' ; s
DB 't' ; t
DB 'u' ; u
DB 'v' ; v
DB 'w' ; w
DB 'x' ; x
;S3 18 - 1F
DB 'i' ; i
DB 'j' ; j
DB 'k' ; k
DB 'l' ; l
DB 'm' ; m
DB 'n' ; n
DB 'o' ; o
DB 'p' ; p
;S4 20 - 27
DB 'a' ; a
DB 'b' ; b
DB 'c' ; c
DB 'd' ; d
DB 'e' ; e
DB 'f' ; f
DB 'g' ; g
DB 'h' ; h
;S5 28 - 2F
DB '1' ; 1
DB '2' ; 2
DB '3' ; 3
DB '4' ; 4
DB '5' ; 5
DB '6' ; 6
DB '7' ; 7
DB '8' ; 8
;S6 30 - 37
DB '\\' ; \
DB CURSUP ;
DB '-' ; -
DB ' ' ; SPACE
DB '0' ; 0
DB '9' ; 9
DB ',' ; ,
DB '.' ; .
;S7 38 - 3F
DB CLRKEY ; CLR.
DB HOMEKEY ; HOME.
DB CURSUP ; CURSOR UP
DB CURSDOWN ; CURSOR DOWN
DB CURSRIGHT ; CURSOR RIGHT
DB CURSLEFT ; CURSOR LEFT
DB 0C6H ; CLR
DB 5AH ;
DB 45H ;
;
;
KTBLCL: ; CAPS LOCK
;S0 00 - 07
DB 0BFH ; SPARE
DB GRAPHKEY ; GRAPH
DB 58H ;
DB ALPHAKEY ; ALPHA
DB NOKEY ; NO
DB ';' ; ;
DB ':' ; :
DB CR ; CR
;S1 08 - 0F
DB 'Y' ; Y
DB 'Z' ; Z
DB '@' ; @
DB '(' ; [
DB ')' ; ]
DB NOKEY ; NULL
DB NOKEY ; NULL
DB NOKEY ; NULL
;S2 10 - 17
DB 'Q' ; Q
DB 'R' ; R
DB 'S' ; S
DB 'T' ; T
DB 'U' ; U
DB 'V' ; V
DB 'W' ; W
DB 'X' ; X
;S3 18 - 1F
DB 'I' ; I
DB 'J' ; J
DB 'K' ; K
DB 'L' ; L
DB 'M' ; M
DB 'N' ; N
DB 'O' ; O
DB 'P' ; P
;S4 20 - 27
DB 'A' ; A
DB 'B' ; B
DB 'C' ; C
DB 'D' ; D
DB 'E' ; E
DB 'F' ; F
DB 'G' ; G
DB 'H' ; H
;S5 28 - 2F
DB '1' ; 1
DB '2' ; 2
DB '3' ; 3
DB '4' ; 4
DB '5' ; 5
DB '6' ; 6
DB '7' ; 7
DB '8' ; 8
;S6 30 - 37
DB '\\' ; \
DB CURSUP ;
DB '-' ; -
DB ' ' ; SPACE
DB '0' ; 0
DB '9' ; 9
DB ',' ; ,
DB '.' ; .
;S7 38 - 3F
DB INSERT ; INST.
DB DELETE ; DEL.
DB CURSUP ; CURSOR UP
DB CURSDOWN ; CURSOR DOWN
DB CURSRIGHT ; CURSOR RIGHT
DB CURSLEFT ; CURSOR LEFT
DB '?' ; ?
DB '/' ; /
;
;
KTBLC: ; CONTROL CODE
;S0 00 - 07
DB NOKEY
DB NOKEY
DB CTRL_CAPPA ; ^
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
;S1 08 - 0F
DB CTRL_Y ; ^Y E3
DB CTRL_Z ; ^Z E4 (CHECKER)
DB CTRL_AT ; ^@
DB CTRL_LB ; ^[ EB/E5
DB CTRL_RB ; ^] EA/E7
DB NOKEY ; #NULL
DB NOKEY ; #NULL
DB NOKEY ; #NULL
;S2 10 - 17
DB CTRL_Q ; ^Q
DB CTRL_R ; ^R
DB CTRL_S ; ^S
DB CTRL_T ; ^T
DB CTRL_U ; ^U
DB CTRL_V ; ^V
DB CTRL_W ; ^W E1
DB CTRL_X ; ^X E2
;S3 18 - 1F
DB CTRL_I ; ^I F9
DB CTRL_J ; ^J FA
DB CTRL_K ; ^K FB
DB CTRL_L ; ^L FC
DB CTRL_M ; ^M CD
DB CTRL_N ; ^N FE
DB CTRL_O ; ^O FF
DB CTRL_P ; ^P E0
;S4 20 - 27
DB CTRL_A ; ^A F1
DB CTRL_B ; ^B F2
DB CTRL_C ; ^C F3
DB CTRL_D ; ^D F4
DB CTRL_E ; ^E F5
DB CTRL_F ; ^F F6
DB CTRL_G ; ^G F7
DB CTRL_H ; ^H F8
;S5 28 - 2F
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
;S6 30 - 37 (ERROR? 7 VALUES ONLY!!)
DB NOKEY ; ^YEN E6
DB CTRL_CAPPA ; ^ EF
DB NOKEY
DB NOKEY
DB NOKEY
DB CTRL_UNDSCR ; ^,
DB NOKEY
;S7 38 - 3F
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB NOKEY
DB CTRL_SLASH ; ^/ EE
ENDIF
;-------------------------------------------------------------------------------
; END OF TIMER INTERRUPT
;-------------------------------------------------------------------------------
;------------------------------------------------------------------------------------------
; Bank switching code, allows a call to code in another bank.
; For TZFS, the area E800-EFFF is locked and the area F000-FFFF is paged as needed.
;------------------------------------------------------------------------------------------
; Methods to access public functions in paged area F000-FFFF. The memory mode is switched
; which means any access to F000-FFFF will be directed to a different portion of the 512K
; static RAM - this is coded into the FlashRAM decoder. Once the memory mode is switched a
; call is made to the required function and upon return the memory mode is returned to the
; previous value. The memory mode is stored on the stack and all registers are preserved for
; full re-entrant functionality.
BANKTOBANK_:JMPTOBNK2
;------------------------------------------------------------------------------------------
; Enhanced function Jump table.
; This table is generally used by a banked page to call a function within another banked
; page. The name is the same as the original function but prefixed by a ?. The original is
; prefixed by a Q.
; All registers are preserved going to the called function and returning from it.
;------------------------------------------------------------------------------------------
?BOOT_: JMPBNK QBOOT_, TZMM_CPM2 ;
?WBOOT_: JMPBNK QWBOOT_, TZMM_CPM2 ;
?CONST_: CALLBNK QCONST_, TZMM_CPM2 ;
?CONIN_: CALLBNK QCONIN_, TZMM_CPM2 ;
?CONOUT_: CALLBNK QCONOUT_, TZMM_CPM2 ;
?LIST_: CALLBNK QLIST_, TZMM_CPM2 ;
?PUNCH_: CALLBNK QPUNCH_, TZMM_CPM2 ;
?READER_: CALLBNK QREADER_, TZMM_CPM2 ;
?HOME_: CALLBNK QHOME_, TZMM_CPM2 ;
?SELDSK_: CALLBNK QSELDSK_, TZMM_CPM2 ;
?SETTRK_: CALLBNK QSETTRK_, TZMM_CPM2 ;
?SETSEC_: CALLBNK QSETSEC_, TZMM_CPM2 ;
?SETDMA_: CALLBNK QSETDMA_, TZMM_CPM2 ;
?READ_: CALLBNK QREAD_, TZMM_CPM2 ;
?WRITE_: CALLBNK QWRITE_, TZMM_CPM2 ;
;-------------------------------------------------------------------------------
; The FDC controller uses it's busy/wait signal as a ROM address line input, this
; causes a jump in the code dependent on the signal status. It gets around the 2MHz
; Z80 not being quick enough to process the signal by polling.
;------------ 0xF3C0 -----------------------------------------------------------
IF $ > FDCJMP1
ERROR "Code overlaps the FDC Jump Vector 1, need to move or optimise code. Addr=%s, required=%s"; % $, FDCJMP1BLK
ENDIF
; ALIGN_NOPS FDCJMP1BLK
ALIGN_NOPS FDCJMP1
FDCJMPL: JP (IX)
;------------ 0xF400 -----------------------------------------------------------
;------------------------------------------------------------------------------------------
; Enhanced function Jump table (continued).
;------------------------------------------------------------------------------------------
?LISTST_: CALLBNK QLISTST_, TZMM_CPM2 ;
?SECTRN_: CALLBNK QSECTRN_, TZMM_CPM2 ;
?DEBUG_: CALLBNK DEBUG, TZMM_CPM2
;-----------------------------------------
;------------------------------------------------------------------------------------------
; Cold boot takes place in memory mode 7 bank and once initialised passes control to
; this fixed point to switch into memory mode 6 and start CPM.
;------------------------------------------------------------------------------------------
BOOT_: EX AF,AF'
;
LD A,05H ; Enable interrupts at hardware level, this must be done before switching memory mode.
LD (KEYPF),A
;
LD A,TZMM_CPM ; Switch to primary CPM memory.
LD (MMCFGVAL),A
OUT (MMCFG),A
;
EX AF,AF'
;
GOCPM: EI
JP CCP ; Start the CCP.
; Method to copy a block of memory from the common shared RAM into CPM memory in mode 6.
; This method is called by code running in memory mode 7 which needs to copy data into the potentially
; same location but in another RAM block.
; This is the inverted copy routine, used for FDC copies where the data is inverted.
;
; Inputs:
; DE = Source memory address (common area).
; HL = Destination memory address (memory in mode 6).
; C = Number of bytes to copy.
; Outputs:
;
MEMCPYINV: DI ; Disable interrupts, TIMIN switches bank to memory mode 7 which we dont want during the copy and returns to the original bank which may be 7.
LD A,TZMM_CPM
OUT (MMCFG),A
MEMCPYINV1: LD A, (DE) ; source character
CPL ; Change to positive values.
INC DE
LD (HL), A ; to dest
INC HL
DEC C ; loop 128 times
JR NZ, MEMCPYINV1
MEMCPYINV2: LD A,TZMM_CPM2
OUT (MMCFG),A
EI
RET
; Method to copy a block of memory from the common shared RAM into CPM memory in mode 6.
; This method is called by code running in memory mode 7 which needs to copy data into the potentially
; same location but in another RAM block.
;
; Inputs:
; DE = Source memory address (common area).
; HL = Destination memory address (memory in mode 6).
; C = Number of bytes to copy.
; Outputs:
;
MEMCPY: DI ; Disable interrupts, TIMIN switches bank to memory mode 7 which we dont want during the copy and returns to the original bank which may be 7.
LD A,TZMM_CPM
OUT (MMCFG),A
MEMCPY1: LD A, (DE) ; source character
INC DE
LD (HL), A ; to dest
INC HL
DEC C ; loop 128 times
JR NZ, MEMCPY1
JR MEMCPYINV2
;-----------------------------------------------------------------------------------------------------------------------------------------
; RAM STORAGE AREA
;-----------------------------------------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; VARIABLES AND STACK SPACE
;-------------------------------------------------------------------------------
IF $ > TZVARMEM
ERROR "Global var not aligned, addr=%s, required=%s"; % $, TZVARMEM
ENDIF
ALIGN_NOPS TZVARMEM
GVARSTART EQU $ ; Start of variables.
MMCFGVAL: DS 1 ; Current memory model value.
FNADDR: DS 2 ; Function to be called address.
SPISRSAVE: DS 2
; Stack space for the Interrupt Service Routine.
DS 16 ; Max 8 stack pushes.
ISRSTACK EQU $
GVAREND EQU $ ; End of common variables
;-------------------------------------------------------------------------------
; END OF VARIABLES AND STACK SPACE
;-------------------------------------------------------------------------------
;------------------------------------------------------------------------------------------------------------
; DISK PARAMETER HEADER
;
; Disk parameter headers for disk 0 to 3
;
; +-------+------+------+------+----------+-------+-------+-------+
; | XLT | 0000 | 0000 | 0000 |DIRBUF | DPB | CSV | ALV |
; +------+------+------+-------+----------+-------+-------+-------+
; 16B 16B 16B 16B 16B 16B 16B 16B
;
; -XLT Address of the logical-to-physical translation vector, if used for this particular drive,
; or the value 0000H if no sector translation takes place (that is, the physical and
; logical sectornumbers are the same). Disk drives with identical sector skew factors share
; the same translatetables.
; -0000 Scratch pad values for use within the BDOS, initial value is unimportant.
; -DIRBUF Address of a 128-byte scratch pad area for directory operations within BDOS. All DPHs
; address the same scratch pad area.
; -DPB Address of a disk parameter block for this drive. Drives with identical disk characteristics
; address the same disk parameter block.
; -CSV Address of a scratch pad area used for software check for changed disks. This address is
; different for each DPH.
; -ALV Address of a scratch pad area used by the BDOS to keep disk storage allocation information.
; This address is different for each DPH.
;------------------------------------------------------------------------------------------------------------
; NB. The Disk Parameter Blocks are stored in CBIOS ROM to save RAM space.
; Space for 2xFD, 3xSD or upto 8 drives total.
; These entries are created dynamically based on hardware available.
DPBASE:
DPBLOCK0: DS DPSIZE ; Location of the 1st DPB in the CBIOS Rom.
DPBLOCK1: DS DPSIZE
DPBLOCK2: DS DPSIZE
DPBLOCK3: DS DPSIZE
DPBLOCK4: DS DPSIZE
DPBLOCK5: DS DPSIZE
DPBLOCK6: DS DPSIZE
;DPBLOCK7: DS DPSIZE
;-------------------------------------------------------------------------------
; TZ SERVICE STRUCTURE AND VARIABLES
;-------------------------------------------------------------------------------
IF $ > TZSVCMEM
ERROR "TZ Service Record not aligned, addr=%s, required=%s"; % $, TZSVCMEM
ENDIF
ALIGN TZSVCMEM
TZSVCCMD: DS 1,0aah ; Service command.
TZSVCRESULT: DS 1 ; Service command result.
TZSVCDIRSEC: DS 1 ; Storage for the directory sector number.
TZSVC_FILE_SEC: EQU TZSVC_DIR_SEC ; Union of the file and directory sector as only one can be used at a time.
TZSVC_TRACK_NO: DS 2 ; Storage for the virtual drive track number.
TZSVC_SECTOR_NO:DS 2 ; Storage for the virtual drive sector number.
TZSVC_FILE_NO: DS 1 ; File number to be opened in a file service command.
TZSVC_FILE_TYPE:DS 1 ; Type of file being accessed to differentiate between Sharp MZF files and other handled files.
TZSVC_LOADADDR DS 2 ; Dynamic load address for rom/images.
TZSVC_SAVEADDR: EQU TZSVC_LOADADDR ; Union of the load address and the cpu frequency change value, the address of data to be saved.
TZSVC_CPU_FREQ: EQU TZSVC_LOADADDR ; Union of the load address and the save address value, only one can be used at a time.
TZSVC_LOADSIZE DS 2 ; Size of file to be loaded.
TZSVC_SAVESIZE: EQU TZSVC_LOADSIZE ; Size of image to be saved.
TZSVC_DIRNAME: DS TZSVCDIRSZ ; Service directory/file name.
TZSVC_FILENAME: DS TZSVCFILESZ ; Filename to be opened/created.
TZSVCWILDC: DS TZSVCWILDSZ ; Directory wildcard for file pattern matching.
HSTBUF: EQU $ ; Host buffer for disk sector storage, shares same space as the service sector as they are the same.
TZSVCSECTOR: DS TZSVCSECSIZE, 0e5h ; Service command sector - to store directory entries, file sector read or writes.
HSTBUFE: EQU $
;-------------------------------------------------------------------------------
; END OF TZ SERVICE STRUCTURE AND VARIABLES
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; The FDC controller uses it's busy/wait signal as a ROM address line input, this
; causes a jump in the code dependent on the signal status. It gets around the 2MHz
; Z80 not being quick enough to process the signal by polling.
;------------ 0xF7C0 -----------------------------------------------------------
IF $ > FDCJMP2
ERROR "Code overlaps the FDC Jump Vector 2, need to move or optimise code. Addr=%s, required=%s"; % $, FDCJMP2BLK
ENDIF
; ALIGN_NOPS FDCJMP2BLK
ALIGN_NOPS FDCJMP2
FDCJMPH: JP (IY)
;------------ 0xF800 -----------------------------------------------------------
;------------------------------------------------------------------------------------------------------------
; CPN Disk work areas.
;------------------------------------------------------------------------------------------------------------
CDIRBUF: DS 128
CSVALVMEM: DS 0680H
CSVALVEND: EQU $
; Allocate space for 8 disk parameter block definitions.
;
;------------------------------------------------------------------------------------------------------------
; DISK PARAMETER BLOCK
;
; +----+----+------+-----+-----+------+----+----+-----+----+
; |SPT |BSH |BLM |EXM |DSM |DRM |AL0 |AL1 |CKS |OFF |
; +----+----+------+-----+-----+------+----+----+-----+----+
; 16B 8B 8B 8B 16B 16B 8B 8B 16B 16B
;
; -SPT is the total number of sectors per track.
; -BSH is the data allocation block shift factor, determined by the data block allocation size.
; -BLM is the data allocation block mask (2[BSH-1]).
; -EXM is the extent mask, determined by the data block allocation size and the number of disk blocks.
; -DSM determines the total storage capacity of the disk drive.
; -DRM determines the total number of directory entries that can be stored on this drive.
; -AL0, AL1 determine reserved directory blocks.
; -CKS is the size of the directory check vector.
; -OFF is the number of reserved tracks at the beginning of the (logical) disk
;
; BLS BSH BLM EXM (DSM < 256) EXM (DSM > 255)
; 1,024 3 7 0 N/A
; 2,048 4 15 1 0
; 4,096 5 31 3 1
; 8,192 6 63 7 3
; 16,384 7 127 15 7
;------------------------------------------------------------------------------------------------------------
; MZ-800 drive but using both heads per track rather than the original
; 1 head for all tracks on side A switching to second head and
; restarting at track 0.
DPB0: DW 64 ; SPT - 128 bytes sectors per track
DB 4 ; BSH - block shift factor
DB 15 ; BLM - block mask
DB 1 ; EXM - Extent mask
DW 155 ; DSM - Storage size (blocks - 1)
DW 63 ; DRM - Number of directory entries - 1
DB 128 ; AL0 - 1 bit set per directory block
DB 0 ; AL1 - "
DW 16 ; CKS - DIR check vector size (DRM+1)/4 (0=fixed disk)
DW 1 ; OFF - Reserved tracks
DB 6 ; CFG - MZ80A Addition, configuration flag:
; Bit 1:0 = FDC: Sector Size, 00 = 128, 10 = 256, 11 = 512, 01 = Unused.
; Bit 2 = Invert, 1 = Invert data, 0 = Use data as read (on MB8866 this is inverted).
; Bit 4:3 = Disk type, 00 = FDC, 11 = SD Card, 10,01 = Unused
; 1.44MB Floppy
DPB3: DW 144 ; SPT - 128 bytes sectors per track (= 36 sectors of 512 bytes)
DB 4 ; BSH - block shift factor
DB 15 ; BLM - block mask
DB 0 ; EXM - Extent mask
DW 719 ; DSM - Storage size (blocks - 1)
DW 127 ; DRM - Number of directory entries - 1
DB 192 ; AL0 - 1 bit set per directory block
DB 0 ; AL1 - "
DW 32 ; CKS - DIR check vector size (DRM+1)/4 (0=fixed disk)
DW 0 ; OFF - Reserved tracks
DB 7 ; CFG - MZ80A Addition, configuration flag:
; Bit 1:0 = FDC: Sector Size, 00 = 128, 10 = 256, 11 = 512, 01 = Unused.
; Bit 2 = Invert, 1 = Invert data, 0 = Use data as read (on MB8866 this is inverted).
; Bit 4:3 = Disk type, 00 = FDC, 11 = SD Card, 10,01 = Unused
; 16Mb SD Hard Disk drives (not hot-swappable).
; This drive has 2048 blocks (small due to size of RAM needed, more blocks more RAM) of 8192 bytes = 16Mb
; There are 1024 directory entries thus AL0/AL1 needs to ave the top four bits set as each block can hold 256 directory entries.
; This implementation limits the sectors per track to 255 (8 bit) even though CPM supports 16bit sectors, so the
; physical drive make up is: 32 Sectors (128 CPM sectors of 128 bytes each) x 1024 tracks, 1 head = 16777216bytes.
; This size has been chosen to maximise the use of the SD Card space and the number of files/programs which can be online
; at the same time. On the MZ80A, memory is more of a premium so keeping the DRM as low as possible saves RAM.
;
DPB4: DW 128 ; SPT - 128 bytes sectors per track (= 36 sectors of 512 bytes)
DB 6 ; BSH - block shift factor
DB 63 ; BLM - block mask
DB 3 ; EXM - Extent mask
DW 2047 ; DSM - Storage size (blocks - 1)
DW 511 ; DRM - Number of directory entries - 1
DB 192 ; AL0 - 1 bit set per directory block
DB 0 ; AL1 - "
DW 0 ; CKS - DIR check vector size (DRM+1)/4 (0=fixed disk)
DW 0 ; OFF - Reserved tracks
DB 27 ; CFG - MZ80A Addition, configuration flag:
; Bit 1:0 = FDC: Sector Size, 00 = 128, 10 = 256, 11 = 512, 01 = Unused.
; Bit 2 = Invert, 1 = Invert data, 0 = Use data as read (on MB8866 this is inverted).
; Bit 4:3 = Disk type, 00 = FDC, 11 = SD Card, 10,01 = Unused
FILL: DS 10000H - $, 0aaH
STKSAVE: EQU 0FFFEH
CBIOSSTACK: EQU 0FFF8H ; Bios stack at top of RAM - 8 = allows room for stack errors and can be viewed when debugging.
;-----------------------------------------------------------------------------------------------------------------------------------------
; END OF RAM STORAGE AREA
;-----------------------------------------------------------------------------------------------------------------------------------------
; Include all other banks which make up the CBIOS system.
;
INCLUDE "cbiosII.asm"