;-------------------------------------------------------------------------------------------------------- ;- ;- 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 ;- ;- 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 . ;-------------------------------------------------------------------------------------------------------- ; 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 RETI ; ; 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 RETI ; ; 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"