From f4953e6394ba0e2082095ce4ce26ad8a907724af Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sat, 6 Oct 2018 23:53:11 +0800 Subject: [PATCH 01/18] Framework for Parallel port driver for ECB-Zilog-Peripherals & ECB-4PIO --- Source/HBIOS/cfg_sbc.asm | 3 + Source/HBIOS/hbios.asm | 34 +++- Source/HBIOS/pio.asm | 336 +++++++++++++++++++++++++++++++++++++++ Source/HBIOS/std.asm | 8 +- 4 files changed, 377 insertions(+), 4 deletions(-) create mode 100644 Source/HBIOS/pio.asm diff --git a/Source/HBIOS/cfg_sbc.asm b/Source/HBIOS/cfg_sbc.asm index 450294e0..8023fa6f 100644 --- a/Source/HBIOS/cfg_sbc.asm +++ b/Source/HBIOS/cfg_sbc.asm @@ -92,3 +92,6 @@ ANSITRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF ANSIENABL BOOTTYPE .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE BOOT_DEFAULT .EQU 'Z' ; SELECTION TO INVOKE AT TIMEOUT + +PIOENABLE .EQU TRUE ; TRUE FOR ZILOG PIO SUPPORT +PIOMODE .EQU PIOMODE_ZP ; PIOMODE_ZP=ECB-ZILOG PERIPHERALS BOARD PIOMODE_4P=ECB-4PIO diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 36916770..b0b765d1 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -546,6 +546,13 @@ INT_SIO: ; SIO INTERRUPT HANDLER LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK JR HBX_INT ; GO TO ROUTING CODE #ENDIF + + #IF (PIOENABLE) +INT_PIO: ; SIO INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,PIO_INT ; HL := PIO INT HANDLER IN BIOS BANK + JR HBX_INT ; GO TO ROUTING CODE + #ENDIF ; #ENDIF ; @@ -860,6 +867,10 @@ HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK #IF (ACIAENABLE) CALL ACIA_PREINIT #ENDIF +#IF (PIOENABLE) + CALL PIO_PREINIT +#ENDIF + ; DIAG(%01111111) ; @@ -1206,6 +1217,9 @@ HB_INITTBL: #IF (PPPENABLE) .DW PPP_INIT #ENDIF +#IF (PIOENABLE) + .DW PIO_INIT +#ENDIF ; HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) ; @@ -1322,7 +1336,7 @@ CIO_ADDENT: ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) -CIO_MAX .EQU 16 ; UP TO 16 UNITS +CIO_MAX .EQU 32 ; UP TO 16 UNITS CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) @@ -2386,6 +2400,15 @@ SIZ_AY .EQU $ - ORG_AY .ECHO SIZ_AY .ECHO " bytes.\n" #ENDIF + +#IF (PIOENABLE) +ORG_PIO .EQU $ + #INCLUDE "pio.asm" +SIZ_PIO .EQU $ - ORG_PIO + .ECHO "PIO occupies " + .ECHO SIZ_PIO + .ECHO " bytes.\n" +#ENDIF ; #DEFINE USEDELAY #INCLUDE "util.asm" @@ -2785,7 +2808,7 @@ PS_SERIAL: PUSH BC ; SAVE UNIT INDEX FOR LATER ; ; UNIT COLUMN - PRTS("Serial $") + PRTS("Char. $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT PRTS(" $") ; PAD TO NEXT COLUMN @@ -2907,6 +2930,9 @@ PS_PRTSC2: PRTS("ANSI$") RET ; +PS_PRTPC0: + RET + ; ; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C ; PS_VIDEO: @@ -3069,7 +3095,7 @@ PS_FLPED .TEXT "ED$" ; PS_SDSTRREF: .DW PS_SDUART, PS_SDASCI, PS_SDTERM, - .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA + .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO ; PS_SDUART .TEXT "UART$" PS_SDASCI .TEXT "ASCI$" @@ -3078,11 +3104,13 @@ PS_SDPRPCON .TEXT "PRPCON$" PS_SDPPPCON .TEXT "PPPCON$" PS_SDSIO .TEXT "SIO$" PS_SDACIA .TEXT "ACIA$" +PS_SDPIO .TEXT "PORT$" ; ; SERIAL TYPE STRINGS ; PS_STRS232 .TEXT "RS-232$" PS_STTERM .TEXT "Terminal$" +PS_STPPT .TEXT "Parallel$" ; PS_STPARMAP .DB "NONENMNS" diff --git a/Source/HBIOS/pio.asm b/Source/HBIOS/pio.asm new file mode 100644 index 00000000..87a3d0ec --- /dev/null +++ b/Source/HBIOS/pio.asm @@ -0,0 +1,336 @@ + +PIO0A .EQU ; ECB-ZP +PIO0B .EQU ; ECB-ZP +PIO1A .EQU ; ECB-ZP +PIO1B .EQU ; ECB-ZP + +PIO2A .EQU ; ECB-4PIO +PIO2B .EQU ; ECB-4PIO +PIO3A .EQU ; ECB-4PIO +PIO3B .EQU ; ECB-4PIO +PIO4A .EQU ; ECB-4PIO +PIO4B .EQU ; ECB-4PIO +PIO5A .EQU ; ECB-4PIO +PIO5B .EQU ; ECB-4PIO + +PIO_NONE .EQU 0 +PIO_ZPIO .EQU 1 +PIO_8255 .EQU 2 +; +PIO_PREINIT: +; +; SETUP THE DISPATCH TABLE ENTRIES +; + LD B,PIO_CNT ; LOOP CONTROL + LD C,0 ; PHYSICAL UNIT INDEX + XOR A ; ZERO TO ACCUM + LD (PIO_DEV),A ; CURRENT DEVICE NUMBER +PIO_PREINIT0: + PUSH BC ; SAVE LOOP CONTROL + LD A,C ; PHYSICAL UNIT TO A + RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) + RLCA ; ... + RLCA ; ... TO GET OFFSET INTO CFG TABLE + LD HL,PIO_CFG ; POINT TO START OF CFG TABLE + CALL ADDHLA ; HL := ENTRY ADDRESS + PUSH HL ; SAVE IT + PUSH HL ; COPY CFG DATA PTR + POP IY ; ... TO IY + CALL PIO_INITUNIT ; HAND OFF TO GENERIC INIT CODE + POP DE ; GET ENTRY ADDRESS BACK, BUT PUT IN DE + POP BC ; RESTORE LOOP CONTROL +; + LD A,(IY+1) ; GET THE PIO TYPE DETECTED + OR A ; SET FLAGS + JR Z,PIO_PREINIT2 ; SKIP IT IF NOTHING FOUND +; + PUSH BC ; SAVE LOOP CONTROL + LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS + CALL NZ,CIO_ADDENT ; ADD ENTRY IF PIO FOUND, BC:DE + POP BC ; RESTORE LOOP CONTROL +; +PIO_PREINIT2: + INC C ; NEXT PHYSICAL UNIT + DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE +; +;#IF (INTMODE == 1) +; ; ADD IM1 INT CALL LIST ENTRY IF APPROPRIATE +; LD A,(SIO_DEV) ; GET NEXT DEVICE NUM +; OR A ; SET FLAGS +; JR Z,PIO_PREINIT3 ; IF ZERO, NO SIO DEVICES +; LD HL,PIO_INT ; GET INT VECTOR +; CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST +;#ENDIF +; +;#IF (INTMODE == 2) +; ; SETUP SIO INTERRUPT VECTOR IN IVT +; LD HL,INT_PIO +; LD (HBX_IVT + IVT_SER0),HL +;#ENDIF +; +PIO_PREINIT3: + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +PIO_INITUNIT: + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +PIO_INIT: + LD B,PIO_CNT ; COUNT OF POSSIBLE SIO UNITS + LD C,0 ; INDEX INTO SIO CONFIG TABLE +PIO_INIT1: + PUSH BC ; SAVE LOOP CONTROL + + LD A,C ; PHYSICAL UNIT TO A + RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) + RLCA ; ... + RLCA ; ... TO GET OFFSET INTO CFG TABLE + LD HL,PIO_CFG ; POINT TO START OF CFG TABLE + CALL ADDHLA ; HL := ENTRY ADDRESS + PUSH HL ; COPY CFG DATA PTR + POP IY ; ... TO IY + + LD A,(IY+1) ; GET PIO TYPE + OR A ; SET FLAGS + CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO + + POP BC ; RESTORE LOOP CONTROL + INC C ; NEXT UNIT + DJNZ PIO_INIT1 ; LOOP TILL DONE +; + XOR A ; SIGNAL SUCCESS + RET ; DONE + +; +PIO_LPT: + IN A,($F6) ; get device status + AND $20 ; device ready? + JR Z,PIO_LPT ; no, busy wait + IN A,($F5) ; get transmit buffer register status ready? + AND $20 ; ready? + JR Z,PIO_LPT ; no, busy wait + LD A,C ; ready, char A for output through data port + OUT ($F0),A ; output char + RET +; +; PIO PORT TABLE +; +PIO_CFG: + ; PIO CHANNEL A + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB PIOBASE+2 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 1 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB PIOBASE+3 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 2 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB PIOBASE+6 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 3 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB PIOBASE+7 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT + ; PIO CHANNEL A + .DB 4 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+2 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 5 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+3 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 6 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+6 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 7 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+7 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 8 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+10 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 9 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+11 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 10 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 11 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 12 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) + .DW DEFSIOACFG ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 13 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_8255 ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) + .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT + ; +; +PIO_CNT .EQU ($ - PIO_CFG) / 8 +; +; DRIVER FUNCTION TABLE +; +PIO_FNTBL: + .DW PIO_IN + .DW PIO_OUT + .DW PIO_IST + .DW PIO_OST + .DW PIO_INITDEV + .DW PIO_QUERY + .DW PIO_DEVICE +#IF (($ - PIO_FNTBL) != (CIO_FNCNT * 2)) + .ECHO "*** INVALID SIO FUNCTION TABLE ***\n" +#ENDIF +; +PIO_OUT: + XOR A ; SIGNAL SUCCESS + RET +; +PIO_IN: + XOR A ; SIGNAL SUCCESS + RET +; +PIO_IST: + RET +; +PIO_OST: + RET +; +PIO_INITDEV: + XOR A ; SIGNAL SUCCESS + RET +; +PIO_QUERY: + LD E,(IY+4) ; FIRST CONFIG BYTE TO E + LD D,(IY+5) ; SECOND CONFIG BYTE TO D + XOR A ; SIGNAL SUCCESS + RET +; +; +;TTY_DEVICE: +; LD D,CIODEV_TERM ; TYPE IS TERMINAL +; LD A,(TTY_DEVNUM) ; GET DEVICE NUMBER +; LD E,A ; PUT IT IN E +; LD A,(TTY_VDAUNIT) ; GET VDA UNIT NUM +; SET 7,A ; SET BIT 7 TO INDICATE TERMINAL TYPE +; LD C,A ; PUT IT IN C +; XOR A ; SIGNAL SUCCESS +; RET +; +; +PIO_DEVICE: + LD D,CIODEV_PIO ; D := DEVICE TYPE + LD E,(IY) ; E := PHYSICAL UNIT + LD C,$80 + XOR A ; SIGNAL SUCCESS + RET +; +PIO_PRTCFG: + ; ANNOUNCE PORT + CALL NEWLINE ; FORMATTING + PRTS("PIO$") ; FORMATTING + LD A,(IY) ; DEVICE NUM + CALL PRTDECB ; PRINT DEVICE NUM + PRTS(": IO=0x$") ; FORMATTING + LD A,(IY+3) ; GET BASE PORT + CALL PRTHEXBYTE ; PRINT BASE PORT +; + ; PRINT THE PIO TYPE + CALL PC_SPACE ; FORMATTING + LD A,(IY+1) ; GET PIO TYPE BYTE + RLCA ; MAKE IT A WORD OFFSET + LD HL,PIO_TYPE_MAP ; POINT HL TO TYPE MAP TABLE + CALL ADDHLA ; HL := ENTRY + LD E,(HL) ; DEREFERENCE + INC HL ; ... + LD D,(HL) ; ... TO GET STRING POINTER + CALL WRITESTR ; PRINT IT +; + ; ALL DONE IF NO PIO WAS DETECTED + LD A,(IY+1) ; GET SIO TYPE BYTE + OR A ; SET FLAGS + RET Z ; IF ZERO, NOT PRESENT +; + PRTS(" MODE=$") ; FORMATTING + LD E,(IY+4) ; LOAD CONFIG + LD D,(IY+5) ; ... WORD TO DE + CALL PS_PRTPC0 ; PRINT CONFIG +; + XOR A + RET +; +; WORKING VARIABLES +; +PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT +; +PIO_TYPE_MAP: + .DW PIO_STR_NONE + .DW PIO_STR_PIO + .DW PIO_STR_8255 + +PIO_STR_NONE .DB "$" +PIO_STR_PIO .DB "Zilog PIO$" +PIO_STR_8255 .DB "i8255 PIO$" \ No newline at end of file diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index f8b72695..8e483c04 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -77,7 +77,13 @@ DSRTCMODE_MFPIC .EQU 2 ; MF/PIC VARIANT SIOMODE_NONE .EQU 0 SIOMODE_RC .EQU 1 ; RC2014 SIO MODULE (SPENCER OWEN) SIOMODE_SMB .EQU 2 ; RC2014 SIO MODULE (SCOTT BAKER) -SIOMODE_ZP .EQU 3 ; ZILOG PERIPHERALS BOARD +SIOMODE_ZP .EQU 3 ; ECB-ZILOG PERIPHERALS BOARD +; +; PIO MODE SELECTIONS +; +PIOMODE_NONE .EQU 0 +PIOMODE_4P .EQU 1 ; ECB-4PIO BOARD +PIOMODE_ZP .EQU 2 ; ECB-ZILOG PERIPHERALS BOARD ; ; TYPE OF CONSOLE BELL TO USE ; From a69218877c9a2fdddabb7e16c73547021ef8bc4c Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 7 Oct 2018 15:45:46 +0800 Subject: [PATCH 02/18] Extend serial device type to support 4 devices including parallel port device. --- Source/HBIOS/hbios.asm | 52 ++++++++++++++++++++++++++++++++++-------- Source/HBIOS/pio.asm | 43 ++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index b0b765d1..59f40d5f 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -2808,7 +2808,7 @@ PS_SERIAL: PUSH BC ; SAVE UNIT INDEX FOR LATER ; ; UNIT COLUMN - PRTS("Char. $") + PRTS("CharIO $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT PRTS(" $") ; PAD TO NEXT COLUMN @@ -2833,10 +2833,17 @@ PS_SERIAL: ; PS_PRTST: LD HL,PS_STRS232 ; ASSUME RS-232 - BIT 7,C ; 0=RS-232, 1=TERMINAL - JR Z,PS_PRTST1 ; HANDLE TERMINAL TYPE - LD HL,PS_STTERM ; TYPE IS TERMINAL -; + LD A,C + AND $C0 + JR Z,PS_PRTST1 ; 00 TYPE 0 - RS-232 + LD HL,PS_STTERM + CP $40 + JR Z,PS_PRTST1 ; 40 TYPE 1 - Terminal + LD HL,PS_STPPT + CP $80 + JR Z,PS_PRTST1 ; 80 TYPE 2 - Parallel + LD HL,PS_STUDEF +; ; C0 TYPE 3 - Undefined PS_PRTST1: CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED LD A,18 ; 18 CHAR FIELD @@ -2847,9 +2854,15 @@ PS_PRTST1: ; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) ; PS_PRTSC: - BIT 7,C ; 0=RS-232, 1=TERMINAL - JR NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG -; + LD A,C + AND $C0 + JR Z,PS_PRTSC0_1 ; 00 TYPE 0 - RS-232 + CP $40 + JR Z,PS_PRTSC1 ; 40 TYPE 1 - Terminal + CP $80 + JR Z,PS_PRTSC2_1 ; 80 TYPE 2 - Parallel +; ; C0 TYPE 3 - Undefined +PS_PRTSC0_1: ; PRINT RS-232 CONFIG LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG LD C,E ; SET SERIAL UNIT NUM @@ -2907,6 +2920,23 @@ PS_PRTSC0: ; RET ; +PS_PRTSC2_1: + ; PRINT PARALLEL CONFIG + LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG + LD C,E ; SET SERIAL UNIT NUM + RST 08 ; DE:HL := I/O CONFIG + LD A,D ; TEST FOR $FF + AND E + INC A ; SET Z IF DE == $FF + JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED + LD A,E + OR A + LD HL,PS_STPPTIN + JR Z,PS_PRTST1 + LD HL,PS_STPPTOUT + JR PS_PRTST1 + RET +; PS_PRTSC1: ; PRINT TERMINAL CONFIG LD A,C ; GET ATTRIBUTE VALUE @@ -3111,12 +3141,14 @@ PS_SDPIO .TEXT "PORT$" PS_STRS232 .TEXT "RS-232$" PS_STTERM .TEXT "Terminal$" PS_STPPT .TEXT "Parallel$" +PS_STUDEF .TEXT "Undefined$" ; PS_STPARMAP .DB "NONENMNS" - ; -; SERIAL TYPE STRINGS +; PARALLEL TYPE STRINGS ; +PS_STPPTIN .TEXT "Input$" +PS_STPPTOUT .TEXT "Output$" ; ; VIDEO DEVICE STRINGS ; diff --git a/Source/HBIOS/pio.asm b/Source/HBIOS/pio.asm index 87a3d0ec..d9e2af85 100644 --- a/Source/HBIOS/pio.asm +++ b/Source/HBIOS/pio.asm @@ -13,6 +13,13 @@ PIO4B .EQU ; ECB-4PIO PIO5A .EQU ; ECB-4PIO PIO5B .EQU ; ECB-4PIO +PIO_Input .EQU $0000 +PIO_Output .EQU $0001 + + +DEFPIOCFGA .EQU $8000 + PIO_Input +DEFPIOCFGB .EQU $8000 + PIO_Output + PIO_NONE .EQU 0 PIO_ZPIO .EQU 1 PIO_8255 .EQU 2 @@ -122,7 +129,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB PIOBASE+2 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -130,7 +137,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB PIOBASE+3 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL A @@ -138,7 +145,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB PIOBASE+6 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -146,14 +153,14 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB PIOBASE+7 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; PIO CHANNEL A .DB 4 ; DEVICE NUMBER (SET DURING INIT) .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB 4PIOBASE+2 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -161,7 +168,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB 4PIOBASE+3 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL A @@ -169,7 +176,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB 4PIOBASE+6 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -177,7 +184,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB 4PIOBASE+7 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL A @@ -185,7 +192,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB 4PIOBASE+10 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -193,7 +200,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB 4PIOBASE+11 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL A @@ -201,7 +208,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -209,7 +216,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL A @@ -217,7 +224,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) - .DW DEFSIOACFG ; LINE CONFIGURATION + .DW DEFPIOCFGA ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B @@ -225,7 +232,7 @@ PIO_CFG: .DB PIO_8255 ; PIO TYPE (SET DURING INIT) .DB 1 ; PIO CHANNEL (B) .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) - .DW DEFSIOBCFG ; LINE CONFIGURATION + .DW DEFPIOCFGB ; LINE CONFIGURATION .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; @@ -259,6 +266,10 @@ PIO_IST: PIO_OST: RET ; +; PIO_INITDEV - Configure device. +; If DE = FFFF then extract the configuratio information from the table of devices and program the device using those settings. +; Otherwise use the configuration information in DE to program those settings and save them in the device table + PIO_INITDEV: XOR A ; SIGNAL SUCCESS RET @@ -284,7 +295,9 @@ PIO_QUERY: PIO_DEVICE: LD D,CIODEV_PIO ; D := DEVICE TYPE LD E,(IY) ; E := PHYSICAL UNIT - LD C,$80 + LD A,E + SET 7,A + LD C,A XOR A ; SIGNAL SUCCESS RET ; From e15c2201ee75eed0ef372d54ac9700509f13cd8b Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 7 Oct 2018 16:53:01 +0800 Subject: [PATCH 03/18] Add Bi-Directional port type to CharIO Parallel port type --- Source/hbios.asm | 3351 ++++++++++++++++++++++++++++++++++++++++++++++ Source/hbios.inc | 187 +++ Source/pio.asm | 350 +++++ 3 files changed, 3888 insertions(+) create mode 100644 Source/hbios.asm create mode 100644 Source/hbios.inc create mode 100644 Source/pio.asm diff --git a/Source/hbios.asm b/Source/hbios.asm new file mode 100644 index 00000000..b52ded07 --- /dev/null +++ b/Source/hbios.asm @@ -0,0 +1,3351 @@ +; +;================================================================================================== +; HBIOS +;================================================================================================== +; +; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS +; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512 +; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE +; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP +; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE +; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN +; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF +; THE BANK SWITCHING THAT OCCURS. +; +; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED +; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS: +; +; - ROMBOOT: BOOT FROM A ROM BANK +; +; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM +; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL +; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK +; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY. +; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY +; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL +; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS +; IS INSTALLED. +; +; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE +; +; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING +; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN +; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE +; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE USER RAM +; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. +; +; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK +; +; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED +; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES +; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT +; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE +; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED +; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED +; AFTER HBIOS IS INSTALLED. +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. +; +MODCNT .EQU 0 +#IFDEF ROMBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IFDEF APPBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IFDEF IMGBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IF (MODCNT != 1) + .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT, IMGBOOT!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +; +; +#IF ((PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) +#DEFINE DIAGP $00 +#ENDIF +; +#IFDEF DIAGP +#DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,N + #DEFCONT \ OUT (DIAGP),A + #DEFCONT \ POP AF +#ELSE +#DEFINE DIAG(N) \; +#ENDIF +; +; +; +#IF (INTMODE == 0) +; NO INTERRUPT HANDLING +#DEFINE HB_DI DI +#DEFINE HB_EI ; +#ELSE +; MODE 1 OR 2 INTERRUPT HANDLING +#DEFINE HB_DI DI +#DEFINE HB_EI EI +#ENDIF +; +; +; +#IFNDEF APPBOOT +; + .ORG 0 +; +;================================================================================================== +; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED +;================================================================================================== +; + .FILL (000H - $),0FFH ; RST 0 + JP HB_START + .DW ROM_SIG + .FILL (008H - $),0FFH ; RST 8 + JP HB_INVOKE ; INVOKE HBIOS FUNCTION + .FILL (010H - $),0FFH ; RST 10 + RET + .FILL (018H - $),0FFH ; RST 18 + RET + .FILL (020H - $),0FFH ; RST 20 + RET + .FILL (028H - $),0FFH ; RST 28 + RET + .FILL (030H - $),0FFH ; RST 30 + RET + .FILL (038H - $),0FFH ; RST 38 / IM1 INT +#IF (INTMODE == 1) + JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM +#ELSE + RETI ; RETURN W/ INTS DISABLED +#ENDIF + .FILL (066H - $),0FFH ; NMI + RETN +; + .FILL (070H - $),0FFH ; SIG STARTS AT $80 +; +ROM_SIG: + .DB $76, $B5 ; 2 SIGNATURE BYTES + .DB 1 ; STRUCTURE VERSION NUMBER + .DB 7 ; ROM SIZE (IN MULTIPLES OF 4KB, MINUS ONE) + .DW NAME ; POINTER TO HUMAN-READABLE ROM NAME + .DW AUTH ; POINTER TO AUTHOR INITIALS + .DW DESC ; POINTER TO LONGER DESCRIPTION OF ROM + .DB 0, 0, 0, 0, 0, 0 ; RESERVED FOR FUTURE USE; MUST BE ZERO +; +NAME .DB "ROMWBW v", BIOSVER, ", ", TIMESTAMP, 0 +AUTH .DB "WBW",0 +DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2015, Wayne Warthen, GNU GPL v3", 0 +; + .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO +; +#ENDIF +; +;================================================================================================== +; HBIOS CONFIGURATION BLOCK (HCB) +;================================================================================================== +; + .ORG HCB_LOC +HCB: + JP HB_START +; +CB_MARKER .DB 'W',~'W' ; MARKER +CB_VERSION .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO +; +CB_PLATFORM .DB PLATFORM +CB_CPUMHZ .DB CPUMHZ +CB_CPUKHZ .DW CPUKHZ +CB_RAMBANKS .DB RAMSIZE / 32 +CB_ROMBANKS .DB ROMSIZE / 32 +; +CB_BOOTVOL .DW 0 ; BOOT VOLUME IS UNIT/SLICE, SET BY LOADER +CB_BOOTBID .DB 0 ; BOOT BANK ID, SET BY LOADER +CB_SERDEV .DB 0 ; PRIMARY SERIAL UNIT IS UNIT #0 BY FIAT +CB_CRTDEV .DB $FF ; PRIMARY CRT UNIT, $FF UNTIL AFTER HBIOS INIT +CB_CONDEV .DB $FF ; CONSOLE UNIT, $FF UNTIL AFTER HBIOS INIT +; +; MEMORY MANAGEMENT VARIABLES START AT $20 +; + .FILL (HCB + $20 - $),0 +; +CB_HEAP .DW 0 +CB_HEAPTOP .DW 0 +; +; STANDARD BANK ID'S START AT $D8 +; + .FILL (HCB + $D8 - $),0 +; +CB_BIDCOM .DB BID_COM +CB_BIDUSR .DB BID_USR +CB_BIDBIOS .DB BID_BIOS +CB_BIDAUX .DB BID_AUX +CB_BIDRAMD0 .DB BID_RAMD0 +CB_BIDRAMDN .DB BID_RAMDN +CB_BIDROMD0 .DB BID_ROMD0 +CB_BIDROMDN .DB BID_ROMDN +; + .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB +; +;================================================================================================== +; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) +;================================================================================================== +; +; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING +; + .FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START + .ORG HBX_LOC ; ADJUST FOR RELOCATION +; +; MEMORY LAYOUT: +; +; HBIOS PROXY CODE $FE00 (256 BYTES) +; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) +; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) +; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) +; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) +; +; DEFINITIONS +; +HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BUFFER SIZE +; +; HBIOS IDENTIFICATION DATA BLOCK +; +HBX_IDENT: + .DB 'W',~'W' ; MARKER + .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO +; +;================================================================================================== +; HBIOS ENTRY FOR RST 08 PROCESSING +;================================================================================================== +; +HBX_INVOKE: + LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME + LD A,(HB_CURBNK) ; GET CURRENT BANK + LD (HB_INVBNK),A ; SAVE INVOCATION BANK + + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH + LD A,BID_BIOS ; HBIOS BANK + CALL HBX_BNKSEL ; SELECT IT + LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK + + CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER + + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH + PUSH AF ; SAVE AF (FUNCTION RETURN) + + LD A,(HB_INVBNK) ; LOAD ORIGINAL BANK + CALL HBX_BNKSEL ; SELECT IT + POP AF ; RESTORE AF + LD SP,0 ; RESTORE ORIGINAL STACK FRAME +HBX_INVSP .EQU $ - 2 + + RET ; RETURN TO CALLER +; +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +;; BNKSEL - Switch Memory Bank to Bank in A. +;; Preserve all Registers including Flags. +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKSEL: + ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, + ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT + ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE + ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT + ; OCCURS DURING PROCESSING. + LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK +; +HBX_BNKSEL_INT: +; +#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA)) + #IF (INTMODE == 1) + ; THIS BIT OF ABSURDITY HANDLES A RARE (BUT FATAL) SITUATION + ; WHERE AN IM1 INTERRUPT OCCURS BETWEEN SETTING THE RAM AND + ; ROM SELECTORS. BRACKETING THE INSTRUCTIONS WITH DI/EI + ; IS CONTRAINDICATED BECAUSE THIS ROUTINE IS CALLED BY + ; OTHER ROUTINES THAT MUST CONTROL INT ENABLE AT A HIGHER + ; LEVEL. THE FOLLOWING TECHNIQUE ENSURES THAT YOU ALWAYS + ; SWITCH DIRECTLY FROM THE PREVIOUS BANK TO THE TARGET BANK + ; WITHOUT AN "ERRANT" BANK BEING ACTIVE BETWEEN THE TWO + ; BANK SELECTION I/O INSTRUCTIONS. THE TECHNIQUE IS ONLY + ; NEEDED WHEN USING INT MODE 1 BECAUSE THAT MODE REQUIRES + ; PAGE ONE TO HAVE A VALID INT HANDLER WHENEVER INTS ARE + ; ENABLED. + ;BIT 7,A ; [8] TEST RAM BIT + ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM + OR A ; [4] SET FLAGS + JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM + #ENDIF + OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR +HBX_ROM: + OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR + RET ; DONE +#ENDIF +#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) + BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE + JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE + RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT + ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K +; +HBX_ROM: + RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K + OUT (MPGSEL_0),A ; BANK_0: 0K - 16K + INC A ; + OUT (MPGSEL_1),A ; BANK_1: 16K - 32K + RET ; DONE +#ENDIF +#IF (PLATFORM == PLT_N8) + BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM + JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE +; +HBX_RAM: + RES 7,A ; CLEAR BIT 7 FROM ABOVE + RLCA ; SCALE SELECTOR TO + RLCA ; ... GO FROM Z180 4K PAGE SIZE + RLCA ; ... TO DESIRED 32K PAGE SIZE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +; +HBX_ROM: + OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER + XOR A ; ZERO ACCUM + OUT0 (Z180_BBR),A ; ZERO BANK BASE + LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +; +#ENDIF +#IF (PLATFORM == PLT_MK4) + RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0 + JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD + XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 +HBX_BNKSEL1: + RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR + RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + RET ; DONE +#ENDIF +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Copy Data - Possibly between banks. This resembles CP/M 3, but +; usage of the HL and DE registers is reversed. +; Caller MUST ensure stack is already in high memory. +; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. +; Caller MUST disable ints if IM1 active +; Enter: +; HL = Source Address +; DE = Destination Address +; BC = Number of bytes to copy +; Exit : None +; Uses : AF,BC,DE,HL +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKCPY: + LD (HBX_BC_SP),SP ; PUT STACK + LD SP,HBX_TMPSTK ; ... IN HI MEM + + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; AND SAVE TO RESTORE LATER + PUSH BC ; CUR LEN -> (SP) +; +HBX_BC_LOOP: + EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC + LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE + OR A ; CLEAR CARRY FLAG + SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE + JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT + EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN + CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK + JR HBX_BC_LOOP ; AND REPEAT TILL DONE +; +HBX_BC_LAST: + ; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE + OR A ; CLEAR CARRY + ADC HL,BC ; HL := REM LEN (0 - 127) + EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN + POP BC ; BC := REM LEN + CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES + POP AF ; RECOVER ORIGINAL BANK + CALL HBX_BNKSEL ; SWITCH + + LD SP,$FFFF ; RESTORE STACK +HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE + RET +; +HBX_BC_ITER: + ; HL = SRC ADR, DE = DEST ADR, BC = LEN + PUSH BC ; SAVE COPY LEN + PUSH DE ; FINAL DEST ON STACK + LD DE,HBX_BUF ; SET DEST TO BUF + LD A,(HB_SRCBNK) ; GET SOURCE BANK + CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK + LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR + POP DE ; DE := FINAL DEST + POP BC ; GET LEN BACK IN BC + PUSH HL ; SAVE UPDATED SRC ADR + LD HL,HBX_BUF ; SET SRC ADR TO BUF + LD A,(HB_DSTBNK) ; GET DEST BANK + CALL HBX_BNKSEL ; SWITCH TO DEST BANK + LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR + POP HL ; RECOVER UPDATED SRC ADR + ; HL = UPD SRC, DE = UPD DEST, BC = 0 + RET +; +; CALL A ROUTINE IN ANOTHER BANK. +; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE. +; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO +; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGTET BANK IS PREPARED FOR THEM. +; ON INPUT A=TARGET BANK, HL=TARGET ADDRESS +; +HBX_BNKCALL: + LD (HBX_TGTBNK),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW + LD (HBX_TGTADR),HL ; STUFF ADDRESS TO CALL INTO CODE BELOW + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; SAVE FOR RETURN +HBX_TGTBNK .EQU $ + 1 + LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) + CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK + +HBX_TGTADR .EQU $ + 1 + CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE) + + EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL + PUSH AF ; SAVE AF + LD A,H ; BANK TO RESTORE TO A + CALL HBX_BNKSEL ; RESTORE IT + POP AF ; RECOVER AF + POP HL ; RECOVER HL + RET +; +; PEEK & POKE ROUTINES +; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED +; CALLER MUST DISABLE INTS IF IM1 AND ACCESSING PAGE W/O IM1 INT VECTOR +; +HBX_PEEK: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD E,(HL) + JR HBX_PPRET +; +HBX_POKE: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD (HL),E +; +HBX_PPRET: + POP AF + CALL HBX_BNKSEL + LD SP,0 ; RESTORE ORIGINAL STACK FRAME +HBX_PPSP .EQU $ - 2 + RET +; +; SMALL TEMPORARY STACK FOR USE BY INVOKE, PEEK, AND POKE +; + .FILL 20,$CC ; 10 LEVEL STACK +HBX_TMPSTK .EQU $ +; +; PRIVATE STACK AT END OF HBIOS CODE +; OCCUPIES SPACE BEFORE IVT +; +HBX_STKSIZ .EQU $FF00 - $ + .ECHO "HBIOS PROXY STACK space: " + .ECHO HBX_STKSIZ + .ECHO " bytes.\n" + .FILL HBX_STKSIZ,$FF +HBX_STACK .EQU $ +; +#IF (INTMODE == 2) +; +; HBIOS INTERRUPT VECTOR TABLE (16 ENTRIES) +; +HBX_IVT: + .DW INT_BAD ; IVT_INT1 + .DW INT_BAD ; IVT_INT2 + .DW INT_BAD ; IVT_TIM0 + .DW INT_BAD ; IVT_TIM1 + .DW INT_BAD ; IVT_DMA0 + .DW INT_BAD ; IVT_DMA1 + .DW INT_BAD ; IVT_CSIO + .DW INT_BAD ; IVT_SER0 + .DW INT_BAD ; IVT_SER1 + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; +; +HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 +; +HBX_ITBL: + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT +#ENDIF +; +; INTERRUPT HANDLER STUBS +; +; THE FOLLOWING INTERRUPT STUBS RECEIVE CONTROL FROM THE +; INTERRUPT, SETUP A HANDLER VECTOR IN HBIOS AND THEN +; BRANCH TO THE COMMON INTERRUPT DISPATCHER +; +; +INT_IM1: +#IF (INTMODE == 1) + PUSH HL ; SAVE HL + LD HL,HB_IM1INT ; HL := IM1 INT HANDLER IN BIOS BANK + JR HBX_INT ; TO TO ROUTING CODE +#ELSE + RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED +#ENDIF +; +#IF (INTMODE == 2) +; +INT_BAD: ; BAD INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,HB_BADINT ; HL := INT HANDLER IN BIOS BANK + JR HBX_INT ; GO TO ROUTING CODE +; +INT_TIMER: ; TIMER INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,HB_TIMINT ; HL := INT ADR IN BIOS + JR HBX_INT ; GO TO ROUTING CODE +; + #IF (SIOENABLE) +INT_SIO: ; SIO INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK + JR HBX_INT ; GO TO ROUTING CODE + #ENDIF + + #IF (PIOENABLE) +INT_PIO: ; SIO INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,PIO_INT ; HL := PIO INT HANDLER IN BIOS BANK + JR HBX_INT ; GO TO ROUTING CODE + #ENDIF +; +#ENDIF +; +#IF (INTMODE > 0) +; +; COMMON INTERRUPT DISPATCHING CODE +; SETUP AND CALL HANDLER IN BIOS BANK +; +HBX_INT: ; COMMON INTERRUPT ROUTING CODE +; + LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_STACK ; USE STACK FRAME IN HI MEM + + ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) + PUSH AF ; SAVE AF + PUSH BC ; SAVE BC + PUSH DE ; SAVE DE + PUSH IY ; SAVE IY + + LD A,BID_BIOS ; HBIOS BANK + CALL HBX_BNKSEL_INT ; SELECT IT + + CALL JPHL ; CALL INTERRUPT ROUTINE + + LD A,(HB_CURBNK) ; GET PRE-INT BANK + CALL HBX_BNKSEL ; SELECT IT + + ; RESTORE STATE + POP IY ; RESTORE IY + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF + + LD SP,$FFFF ; RESTORE ORIGINAL STACK FRAME +HBX_INT_SP .EQU $ - 2 + + POP HL ; RESTORE HL + + EI ; ENABLE INTERRUPTS + RETI ; AND RETURN +; +#ENDIF +; +; FILL TO START OF BOUNCE BUFFER +; +HBX_INTFILL .EQU (HBX_XFC - HBX_BUFSIZ - $) + .ECHO "HBIOS INT space remaining: " + .ECHO HBX_INTFILL + .ECHO " bytes.\n" + .FILL HBX_INTFILL,$FF +; +; INTERBANK COPY BUFFER (64 BYTES) +; +HBX_BUF .FILL HBX_BUFSIZ,0 +; +; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) +; +#IFDEF ROMBOOT + .DB BID_BOOT ; CURRENTLY ACTIVE LOW MEMORY BANK ID +#ELSE + .DB BID_USR ; CURRENTLY ACTIVE LOW MEMORY BANK ID +#ENDIF + .DB 0 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION + .DW 0 ; BNKCPY SOURCE ADDRESS + .DB BID_USR ; BNKCPY SOURCE BANK ID + .DW 0 ; BNKCPY DESTINATION ADDRESS + .DB BID_USR ; BNKCPY DESTINATION BANK ID + .DW 0 ; BNKCPY LENGTH + .FILL 6,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE + JP HBX_INVOKE ; FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) + JP HBX_BNKSEL ; FIXED ADR ENTRY FOR HBX_BNKSEL + JP HBX_BNKCPY ; FIXED ADR ENTRY FOR HBX_BNKCPY + JP HBX_BNKCALL ; FIXED ADR ENTRY FOR HBX_BNKCALL + .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) + .DW HBX_IDENT ; ADDRESS OF HBIOS IDENT INFO DATA BLOCK +; + .FILL $MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) + .ORG HBX_IMG + HBX_SIZ ; RESET ORG +; +;================================================================================================== +; HBIOS CORE +;================================================================================================== +; +;================================================================================================== +; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK +;================================================================================================== +; +HB_ENTRYTBL .EQU $ +; + JP HB_START ; HBIOS INITIALIZATION + JP HB_DISPATCH ; VECTOR TO DISPATCHER +; +HB_STKSIZ .EQU HB_ENTRYTBL + 256 - $ +; + .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK +HB_STACK .EQU $ ; TOP OF HBIOS STACK + +; +;================================================================================================== +; SYSTEM INITIALIZATION +;================================================================================================== +; +HB_START: + DI ; NO INTERRUPTS + IM 1 ; INTERRUPT MODE 1 +; +#IFDEF DIAGP + LD A,%00000001 + OUT (DIAGP),A +#ENDIF +; + LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; SET BASE FOR CPU IO REGISTERS + LD A,Z180_BASE + OUT0 (Z180_ICR),A + + DIAG(%00000010) + + ; DISABLE REFRESH + XOR A + OUT0 (Z180_RCR),A + + ; MASK OFF TIMER INTERRUPTS + XOR A + OUT0 (Z180_TCR),A + + ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) + XOR A + OUT0 (Z180_CCR),A + OUT0 (Z180_CMR),A + + ; SET DEFAULT WAIT STATES + LD A,$F0 + OUT0 (Z180_DCNTL),A + +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4)) + ; MMU SETUP + LD A,$80 + OUT0 (Z180_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG +;#IFDEF ROMBOOT +; XOR A +; OUT0 (Z180_BBR),A ; BANK BASE = 0 +;#ENDIF + LD A,(RAMSIZE + RAMBIAS - 64) >> 2 + OUT0 (Z180_CBR),A ; COMMON BASE = LAST (TOP) BANK +#ENDIF + +#IF (Z180_CLKDIV >= 1) + ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED + LD A,$80 + OUT0 (Z180_CCR),A +#ENDIF + +#IF (Z180_CLKDIV >= 2) + ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED + LD A,$80 + OUT0 (Z180_CMR),A +#ENDIF + +#ENDIF +; +#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) + ; SET PAGING REGISTERS +#IFDEF ROMBOOT + XOR A + OUT (MPGSEL_0),A + INC A + OUT (MPGSEL_1),A +#ENDIF + LD A,62 + OUT (MPGSEL_2),A + INC A + OUT (MPGSEL_3),A + ; ENABLE PAGING + LD A,1 + OUT (MPGENA),A +#ENDIF +; + DIAG(%00000011) +; +; INSTALL PROXY IN UPPER MEMORY +; + +;X1 .EQU $8000 +;X2 .EQU X1 + 2 +;X3 .EQU X2 + 2 +;X4 .EQU X3 + 2 + +; LD HL,(HBX_IMG) +; LD (X1),HL + +; LD HL,(HBX_IMG) +; LD (X2),HL + + LD HL,HBX_IMG + LD DE,HBX_LOC + LD BC,HBX_SIZ + LDIR + +; LD HL,(HBX_IMG) +; LD (X3),HL + +; LD HL,(HBX_LOC) +; LD (X4),HL + +; +; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION +; + LD A,(HB_RAMFLAG) + OR A + JR NZ,HB_START1 +; +; INSTALL HBIOS IN RAM BANK +; + LD A,(HB_CURBNK) + LD (HB_SRCBNK),A + LD A,BID_BIOS + LD (HB_DSTBNK),A + LD HL,0 + LD DE,0 + LD BC,$8000 + CALL HBX_BNKCPY +; +; TRANSITION TO HBIOS IN RAM BANK +; + LD A,BID_BIOS ; BIOS BANK ID + LD HL,HB_START1 ; EXECUTION RESUMES HERE + CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN + HALT ; WE SHOULD NOT COME BACK HERE! +; +HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION +; +; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK +; +HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK +; + DIAG(%00000111) +; + LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN + LD A,TRUE ; ACCUM := TRUE + LD (HB_RAMFLAG),A ; SET RAMFLAG +; +; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO +; +#IFDEF APPBOOT + ; MAKE SURE RST 08 VECTOR IS RIGHT + LD A,$C3 + LD ($0008),A + LD HL,HB_INVOKE + LD ($0009),HL +; + ; MAKE SURE IM1 INT VECTOR IS RIGHT + #IF (INTMODE == 1) + ; JP INT_IM1 IF INTERRUPT MODE ACTIVE + LD A,$C3 + LD ($0038),A + LD HL,INT_IM1 + LD ($0039),HL + #ELSE + ; RETI ($ED, $4D) IF NON-INTERRUPT MODE + LD HL,($0038) + LD (HL),$ED + INC HL + LD (HL),$4D + #ENDIF +#ENDIF +; + DIAG(%00001111) +; +; PERFORM DYNAMIC CPU SPEED DERIVATION +; + CALL HB_CPUSPD ; CPU SPEED DETECTION +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) +; + ; SET DESIRED WAIT STATES + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (Z180_DCNTL),A +; +#ENDIF +; + CALL DELAY_INIT ; INITIALIZE SPEED COMPENSATED DELAY FUNCTIONS +; + DIAG(%00011111) +; +; INITIALIZE HEAP STORAGE +; + ; INITIALIZE POINTERS + LD HL,HB_END ; HEAP FOLLOWS HBIOS CODE + LD (CB_HEAP),HL ; INIT HEAP BASE ADDRESS + LD (CB_HEAPTOP),HL ; INIT HEAP TOP ADDRESS + ; CLEAR HEAP + LD BC,BNKTOP - HB_END ; MAX SIZE OF HEAP + LD A,$FF ; FILL WITH $FF + CALL FILL ; DO IT +; + DIAG(%00111111) +; +; PRE-CONSOLE INITIALIZATION +; +#IF (ASCIENABLE) + CALL ASCI_PREINIT +#ENDIF +#IF (UARTENABLE) + CALL UART_PREINIT +#ENDIF +#IF (SIOENABLE) + CALL SIO_PREINIT +#ENDIF +#IF (ACIAENABLE) + CALL ACIA_PREINIT +#ENDIF +#IF (PIOENABLE) + CALL PIO_PREINIT +#ENDIF + +; + DIAG(%01111111) +; +; PRIOR TO THIS POINT, CONSOLE I/O WAS DIRECTED TO HARDWARE (XIO.ASM). +; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O +; VIA HBIOS. +; + XOR A ; INITIALLY, FIRST SERIAL UNIT IS CONSOLE + LD (CB_CONDEV),A ; SAVE IT, ACTIVATES CONSOLE ON HBIOS +; +; ANNOUNCE HBIOS +; + CALL NEWLINE2 + PRTX(STR_BANNER) +; + DIAG(%11111111) +; +; IO PORT SCAN +; +#IF 0 +PSCN: + LD C,0 ; IO PORT NUMBER + LD B,0 ; LOOP COUNTER + CALL NEWLINE +PSCN1: + CALL NEWLINE + LD A,C + CALL PRTHEXBYTE + CALL PC_COLON + CALL PC_SPACE + CALL DELAY + LD A,C + LD (PSCNX),A +PSCNX .EQU $ + 1 + IN A,(0) + CALL PRTHEXBYTE + CALL PC_COMMA + PUSH BC + LD B,0 + IN A,(C) + POP BC + CALL PRTHEXBYTE + INC C + DJNZ PSCN1 +#ENDIF +; +; SETUP INTERRUPT VECTORS, AS APPROPRIATE +; +;#IF (INTMODE == 1) +; ; OVERLAY $0038 WITH JP INT_IM1 +; LD A,$C3 ; JP INSTRUCTION +; LD ($0038),A ; INSTALL IT +; LD HL,INT_IM1 ; DESTINATION ADDRESS +; LD ($0039),HL ; INSTALL IT +;#ENDIF +; +#IF (INTMODE == 2) + ; SETUP Z80 IVT AND INT MODE 2 + LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS + LD I,A ; ... AND PLACE IT IN I REGISTER + + #IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; SETUP Z180 IVT + XOR A ; SETUP LO BYTE OF IVT ADDRESS + OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER + #ENDIF + + IM 2 ; SWITCH TO INT MODE 2 +#ENDIF + +#IF (PLATFORM == PLT_SBC) +; + #IF (HTIMENABLE) ; SIMH TIMER +; + #IF (INTMODE == 1) + LD HL,HB_TIMINT + CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST + #ENDIF +; + #IF (INTMODE == 2) + ;LD HL,INT_TIMER + ;LD (HBX_IVT),HL + #ENDIF +; + #ENDIF +; +#ENDIF +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) +; + #IF (INTMODE == 2) +; + ; MASK ALL EXTERNAL INTERRUPTS FOR NOW + ;XOR A ; INT0-2 DISABLED + LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED + OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER +; + ; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT + LD HL,INT_TIMER + LD (HBX_IVT + IVT_TIM0),HL + + ; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0 + LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ + LD B,0 + LD C,Z180_RLDR0L ; INITIALIZE TIMER 0 RELOAD REGISTER + OUT (C),L + INC C + OUT (C),H + LD C,Z180_TMDR0L ; INITIALIZE TIMER 0 DATA REGISTER + OUT (C),L + INC C + OUT (C),H + LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING + OUT0 (Z180_TCR),A +; + #ENDIF +; +#ENDIF +; + HB_EI ; INTERRUPTS SHOULD BE OK NOW +; +; DISPLAY PLATFORM INFORMATION +; + CALL NEWLINE2 + PRTX(STR_PLATFORM) + PRTS(" @ $") + LD HL,(CB_CPUKHZ) + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA + PRTS("MHz$") +; +; DISPLAY CPU CONFIG +; + ;CALL PRTSTRD + ;.TEXT ", $" + CALL NEWLINE +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + LD A,Z180_MEMWAIT +#ELSE + LD A,0 +#ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " MEM W/S, $" +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + LD A,Z180_IOWAIT + 1 +#ELSE + LD A,1 +#ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " I/O W/S$" +#IF (INTMODE > 0) + CALL PRTSTRD + .TEXT ", INT MODE $" + LD A,INTMODE + CALL PRTDECB +#ENDIF +; +; DISPLAY MEMORY CONFIG +; + CALL NEWLINE + ;CALL PRTSTRD + ;.TEXT "MEMORY CONFIG: $" + LD HL,ROMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB ROM, $" + LD HL,RAMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB RAM$" +; +; PERFORM DEVICE INITIALIZATION +; + CALL NEWLINE + LD B,HB_INITTBLLEN + LD DE,HB_INITTBL +INITSYS1: + LD A,(DE) + LD L,A + INC DE + LD A,(DE) + LD H,A + INC DE + PUSH DE + PUSH BC + CALL JPHL + POP BC + POP DE + DJNZ INITSYS1 +; +; RECORD HEAP CURB AT THE CURRENT VALUE OF HEAP TOP. HEAP CURB +; MARKS THE POINT IN THE HEAP AFTER WHICH MEMORY IS RELEASED +; WHEN AN HBIOS RESET IS PEFORMED. +; + LD HL,(CB_HEAPTOP) + LD (HEAPCURB),HL +; +; NOW SWITCH TO CRT CONSOLE IF CONFIGURED +; +#IF CRTACT +; +; BIOS IS CONFIGURED TO AUTO ACTIVATE CRT DEVICE. FIRST, +; CHECK TO SEE IF WE HAVE A VALID CRT DEVICE TO USE. +; + LD A,(CB_CRTDEV) ; GET THE CRT DEVICE + INC A ; INCREMENT TO TEST FOR $FF + JR Z,INITSYS3 ; IF NO CRT DEVICE, BYPASS CONSOLE SWITCH +; +; IF PLATFORM HAS A CONFIG JUMPER, CHECK TO SEE IF IT IS JUMPERED. +; IF SO, BYPASS SWITCH TO CRT CONSOLE (FAILSAFE MODE) +; +#IF ((PLATFORM != PLT_N8) & (PLATFORM != PLT_MK4) & (PLATFORM != PLT_RC) & (PLATFORM != PLT_RC180)) + IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER + BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE + JR Z,INITSYS3 ; Z=SHORTED, BYPASS CONSOLE SWITCH +#ENDIF +; + ; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE + CALL NEWLINE2 + PRTX(STR_SWITCH) + CALL NEWLINE +; + ; SWITCH TO CRT CONSOLE + LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE + LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE +; + ; DISPLAY HBIOS BANNER ON NEW CONSOLE + PRTX(STR_BANNER) +#ENDIF +; +INITSYS3: +; + CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE +; +; CHAIN TO OS LOADER +; +#IFDEF ROMBOOT + ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM + LD A,BID_OSIMG ; CHAIN TO OS IMAGES BANK + LD HL,0 ; ENTER AT ADDRESS 0 + CALL HBX_BNKCALL ; GO THERE + HALT ; WE SHOULD NEVER COME BACK! +#ELSE + ; COPY OS IMAGE: BID_USR: --> BID_USR:0 + ;LD A,BID_USR + ;LD (HB_SRCBNK),A + ;LD (HB_DSTBNK),A + ;LD HL,HB_END + ;LD DE,0 + ;LD BC,$8000 + ;CALL HBX_BNKCPY + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_USR ; E = SRC BANK = USER BANK + LD HL,$8000 ; HL = COPY LEN = ENTIRE BANK + RST 08 ; DO IT + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,HB_END ; COPY FROM END OF OF HBIOS + LD DE,0 ; TO USER ADDRESS 0 + RST 08 ; DO IT +; + ; PERFORM BANK CALL TO USER BANK + LD A,BID_USR ; CHAIN TO OS IMAGES BANK + LD HL,0 ; ENTER AT ADDRESS 0 + CALL HBX_BNKCALL ; GO THERE + HALT ; WE SHOULD NEVER COME BACK! +; +#ENDIF +; + RET +; +;================================================================================================== +; TABLE OF INITIALIZATION ENTRY POINTS +;================================================================================================== +; +HB_INITTBL: +#IF (SPKENABLE) + .DW SPK_INIT ; AUDIBLE INDICATOR OF BOOT START +#ENDIF +#IF (AYENABLE) + .DW AY_INIT ; AUDIBLE INDICATOR OF BOOT START +#ENDIF +#IF (ASCIENABLE) + .DW ASCI_INIT +#ENDIF +#IF (UARTENABLE) + .DW UART_INIT +#ENDIF +#IF (SIOENABLE) + .DW SIO_INIT +#ENDIF +#IF (ACIAENABLE) + .DW ACIA_INIT +#ENDIF +#IF (SIMRTCENABLE) + .DW SIMRTC_INIT +#ENDIF +#IF (DSRTCENABLE) + .DW DSRTC_INIT +#ENDIF +#IF (VDUENABLE) + .DW VDU_INIT +#ENDIF +#IF (CVDUENABLE) + .DW CVDU_INIT +#ENDIF +#IF (VGAENABLE) + .DW VGA_INIT +#ENDIF +#IF (NECENABLE) + .DW NEC_INIT +#ENDIF +#IF (TMSENABLE) + .DW TMS_INIT +#ENDIF +#IF (DSKYENABLE) + .DW DSKY_INIT +#ENDIF +#IF (MDENABLE) + .DW MD_INIT +#ENDIF +#IF (FDENABLE) + .DW FD_INIT +#ENDIF +#IF (RFENABLE) + .DW RF_INIT +#ENDIF +#IF (IDEENABLE) + .DW IDE_INIT +#ENDIF +#IF (PPIDEENABLE) + .DW PPIDE_INIT +#ENDIF +#IF (SDENABLE) + .DW SD_INIT +#ENDIF +#IF (HDSKENABLE) + .DW HDSK_INIT +#ENDIF +#IF (PRPENABLE) + .DW PRP_INIT +#ENDIF +#IF (PPPENABLE) + .DW PPP_INIT +#ENDIF +#IF (PIOENABLE) + .DW PIO_INIT +#ENDIF +; +HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) +; +;================================================================================================== +; IDLE +;================================================================================================== +; +;__________________________________________________________________________________________________ +; +IDLE: + PUSH AF + PUSH BC + PUSH DE + PUSH HL + PUSH IY +#IF (FDENABLE) + CALL FD_IDLE +#ENDIF + POP IY + POP HL + POP DE + POP BC + POP AF + RET +; +;================================================================================================== +; BIOS FUNCTION DISPATCHER +;================================================================================================== +; +; MAIN BIOS FUNCTION +; B: FUNCTION +;__________________________________________________________________________________________________ +; +HB_DISPATCH: +; +#IF 0 ; *DEBUG* START +; + CALL HB_DISPCALL ; DO THE WORK +; + ; CHECK STACK INTEGRITY + PUSH AF + LD A,(HB_STACK - HB_STKSIZ + $08) + CP $FF + CALL NZ,PANIC + LD A,$FF + LD (HB_STACK - HB_STKSIZ + $08),A + POP AF + RET +HB_DISPCALL: +; +#ENDIF ; *DEBUG* END +; + LD A,B ; REQUESTED FUNCTION IS IN B + CP BF_CIO + $10 ; $00-$0F: CHARACTER I/O + JP C,CIO_DISPATCH + CP BF_DIO + $10 ; $10-$1F: DISK I/O + JP C,DIO_DISPATCH + CP BF_RTC + $10 ; $20-$2F: REAL TIME CLOCK (RTC) + JP C,RTC_DISPATCH + CP BF_EMU + $10 ; $30-$3F: EMULATION + CALL C,PANIC ; OBSOLETE! + CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER + JP C,VDA_DISPATCH + CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 + CALL C,PANIC ; PANIC IF LESS THAN BF_SYS + JP SYS_DISPATCH ; OTHERWISE SYS CALL + CALL PANIC ; THIS SHOULD NEVER BE REACHED + RET +; +;================================================================================================== +; CHARACTER I/O DEVICE FUNCTION DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +CIO_DISPATCH: + BIT 7,C ; CHECK FOR SPECIAL UNIT CODE + CALL NZ,CIO_SPECIAL ; IF SO, HANDLE IT + + PUSH IY ; SAVE INCOMING IY + + LD IY,CIO_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; SPECIAL HANDLING FOR DEDICATED UNIT CODES +; +CIO_SPECIAL: + ; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST + ; SO JUST SWAP IN ACTIVE CONSOLE UNIT + LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE + LD C,A ; OVERLAY UNIT CODE IN C + RET ; AND REJOIN MAIN DISPATCH FLOW +; +; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS) +; +CIO_ADDENT: + LD HL,CIO_TBL ; POINT TO CIO TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS CHARACTER DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) +CIO_MAX .EQU 32 ; UP TO UNITS +CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) + .DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX +CIO_CNT .DB 0 ; ENTRY COUNT PREFIX +CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES +; +;================================================================================================== +; DISK I/O DEVICE FUNCTION DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO SPECIFIED DISK I/O DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +DIO_DISPATCH: +; +#IF 0 ; *DEBUG* START +; + ; DUMP INCOMING CALL + CALL NEWLINE + PRTS("DIO>$") + CALL REGDMP ; DUMP REGS, NONE DESTROYED +; + ; DO THE ACTUAL DISPATCH PROCESSING + CALL DIO_DISPCALL +; + ; DUMP CALL RESULTS AND RETURN + CALL NEWLINE + PRTS("DIO<$") + CALL REGDMP ; DUMP REGS, NONE DESTROYED + RET +; +#ENDIF ; *DEBUG* END +; +DIO_DISPCALL: + PUSH IY ; SAVE INCOMING IY + + LD IY,DIO_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; ADD AN ENTRY TO THE DIO UNIT TABLE +; +DIO_ADDENT: + LD HL,DIO_TBL ; POINT TO DIO TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS DISK DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF DIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) +DIO_MAX .EQU 16 ; UP TO 32 UNITS +DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) + .DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX +DIO_CNT .DB 0 ; ENTRY COUNT PREFIX +DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES +; +;================================================================================================== +; REAL TIME CLOCK DEVICE DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO REAL TIME CLOCK DRIVER +; B: FUNCTION +; +RTC_DISPATCH: +#IF (SIMRTCENABLE) + JP SIMRTC_DISPATCH +#ENDIF +#IF (DSRTCENABLE) + JP DSRTC_DISPATCH +#ENDIF + CALL PANIC +; +;================================================================================================== +; VIDEO DISPLAY ADAPTER DEVICE DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO SPECIFIED VDA DEVICE DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +VDA_DISPATCH: + PUSH IY ; SAVE INCOMING IY + + LD IY,VDA_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; ADD AN ENTRY TO THE VDA UNIT TABLE (SEE HB_ADDENT FOR DETAILS) +; +VDA_ADDENT: + LD HL,VDA_TBL ; POINT TO VDA TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS VIDEO DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +VDA_FNCNT .EQU 15 ; NUMBER OF VDA FUNCS (FOR RANGE CHECK) +VDA_MAX .EQU 16 ; UP TO 16 UNITS +VDA_SIZ .EQU VDA_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB VDA_FNCNT ; VDA FUNCTION COUNT (FOR RANGE CHECK) + .DB VDA_MAX ; MAX ENTRY COUNT TABLE PREFIX +VDA_CNT .DB 0 ; ENTRY COUNT PREFIX +VDA_TBL .FILL VDA_SIZ,0 ; SPACE FOR ENTRIES +; +;================================================================================================== +; SYSTEM FUNCTION DISPATCHER +;================================================================================================== +; +; B: FUNCTION +; +SYS_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JP Z,SYS_RESET ; $F0 + DEC A + JP Z,SYS_VER ; $F1 + DEC A + JP Z,SYS_SETBNK ; $F2 + DEC A + JP Z,SYS_GETBNK ; $F3 + DEC A + JP Z,SYS_SETCPY ; $F4 + DEC A + JP Z,SYS_BNKCPY ; $F5 + DEC A + JP Z,SYS_ALLOC ; $F6 + DEC A + JP Z,SYS_FREE ; $F7 + DEC A + JP Z,SYS_GET ; $F8 + DEC A + JP Z,SYS_SET ; $F9 + DEC A + JP Z,SYS_PEEK ; $FA + DEC A + JP Z,SYS_POKE ; $FB + DEC A + JP Z,SYS_INT ; $FC + CALL PANIC ; INVALID +; +; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS +; +SYS_RESET: + LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD + LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP + XOR A + RET +; +; GET THE CURRENT HBIOS VERSION +; ON INPUT, C=0 +; RETURNS VERSION IN DE AS BCD +; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS +; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS +; L: PLATFORM ID +; +SYS_VER: + LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP + LD L,PLATFORM + XOR A + RET +; +; SET ACTIVE MEMORY BANK AND RETURN PREVIOUSLY ACTIVE MEMORY BANK +; NOTE THAT IT GOES INTO EFFECT AS HBIOS FUNCTION IS EXITED +; HERE, WE JUST SET THE CURRENT BANK +; CALLER MUST EXTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! +; +SYS_SETBNK: + PUSH HL ; SAVE INCOMING HL + LD HL,HB_INVBNK ; POINT TO HBIOS INVOKE BANK ID ADDRESS + LD A,(HL) ; GET EXISTING BANK ID TO A + LD (HL),C ; UPDATE INVOKE BANK TO NEW BANK ID + LD C,A ; PUT PREVIOUS BANK ID IN C FOR RETURN + POP HL ; RESTORE ORIGINAL HL + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; GET ACTIVE MEMORY BANK +; +SYS_GETBNK: + LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK + LD C,A ; MOVE TO C + XOR A ; SIGNAL SUCCESS + RET +; +; SET BANKS AND LENGTH FOR INTERBANK MEMORY COPY (BNKCPY) +; ENTRY: E=SOURCE BANK ID +; D=DEST BANK ID +; HL=COPY LENGTH (IN BYTES) +; +SYS_SETCPY: + LD A,E + LD (HB_SRCBNK),A ; RECORD THE SOURCE BANK + LD A,D + LD (HB_DSTBNK),A ; RECORD THE DESTINATION BANK + LD (HB_CPYLEN),HL ; RECORD THE COPY LENGTH + XOR A + RET +; +; PERFORM MEMORY COPY POTENTIALLY ACROSS BANKS +; ENTRY: HL=SOURCE ADDRESS +; DE=DESTINATION ADDRESS +; NOTE: SRC/DEST BANK & COPY LENGTH MUST BE SET VIA SETCPY +; +SYS_BNKCPY: + PUSH HL ; SAVE INCOMING HL + LD HL,(HB_CPYLEN) ; HL := COPY LEN (SAVED IN SETCPY) + EX (SP),HL ; RESTORE HL & SET (SP) TO COPY LEN + POP BC ; BC := COPY LEN +#IF (INTMODE == 1) + DI +#ENDIF + CALL HB_BNKCPY +#IF (INTMODE == 1) + EI +#ENDIF + XOR A + RET +; +; ALLOCATE HL BYTES OF MEMORY FROM HBIOS HEAP +; RETURNS POINTER TO ALLOCATED MEMORY IN HL +; ON SUCCESS RETURN A == 0, AND Z SET +; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED +; ALL OTHER REGISTERS PRESERVED +; +SYS_ALLOC: + JP HB_ALLOC +; +; FREE HEAP MEMORY BY SIMPLY RELEASING ALL +; MEMORY BEYOND POINTER IN HL. +; ON SUCCESS RETURN A == 0, AND Z SET +; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED +; ALL OTHER REGISTERS PRESERVED +; +SYS_FREE: + CALL PANIC ; NOT YET IMPLEMENTED + OR $FF + RET +; +; GET SYSTEM INFORMATION +; ITEM TO RETURN INDICATED IN C +; +SYS_GET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSGET_CIOCNT + JR Z,SYS_GETCIOCNT + CP BF_SYSGET_DIOCNT + JR Z,SYS_GETDIOCNT + CP BF_SYSGET_VDACNT + JR Z,SYS_GETVDACNT + CP BF_SYSGET_TIMER + JR Z,SYS_GETTIMER + CP BF_SYSGET_BOOTINFO + JR Z,SYS_GETBOOTINFO + CP BF_SYSGET_CPUINFO + JR Z,SYS_GETCPUINFO + CP BF_SYSGET_MEMINFO + JR Z,SYS_GETMEMINFO + CP BF_SYSGET_BNKINFO + JR Z,SYS_GETBNKINFO + OR $FF ; SIGNAL ERROR + RET +; +; GET TIMER +; RETURNS: +; DE:HL: TIMER VALUE (32 BIT) +; +SYS_GETTIMER: + LD HL,HB_TICKS + HB_DI + CALL LD32 + HB_EI + XOR A + RET +; +; GET BOOT INFORMATION +; RETURNS: +; L: BOOT BANK ID +; DE: BOOT DISK VOLUME (UNIT/SLICE) +; +SYS_GETBOOTINFO: + LD A,(CB_BOOTBID) + LD L,A + LD DE,(CB_BOOTVOL) + XOR A + RET +; +; GET CPU INFORMATION +; RETURNS: +; H: Z80 CPU VARIANT +; L: CPU SPEED IN MHZ +; DE: CPU SPEED IN KHZ +; +SYS_GETCPUINFO: + LD H,0 ; NOT YET DEFINED + LD A,(CB_CPUMHZ) + LD L,A + LD DE,(CB_CPUKHZ) + XOR A + RET +; +; GET MEMORY INFORMATION +; RETURNS: +; D: COUNT OF ROM BANKS +; E: COUNT OF RAM BANKS +; +SYS_GETMEMINFO: + LD D,ROMSIZE / 32 + LD E,RAMSIZE / 32 + XOR A + RET +; +; GET BANK CONFIGURATION INFORMATION +; RETURNS: +; D: HBIOS BANK ID +; E: USER BANK ID +; +SYS_GETBNKINFO: + LD A,(CB_BIDBIOS) + LD D,A + LD A,(CB_BIDUSR) + LD E,A + XOR A + RET +; +; GET SERIAL UNIT COUNT +; +SYS_GETCIOCNT: + LD A,(CIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; GET DISK UNIT COUNT +; +SYS_GETDIOCNT: + LD A,(DIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; GET VIDEO UNIT COUNT +; +SYS_GETVDACNT: + LD A,(VDA_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; SET SYSTEM PARAMETERS +; PARAMETER(S) TO SET INDICATED IN C +; +SYS_SET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSSET_TIMER + JR Z,SYS_SETTIMER + CP BF_SYSSET_BOOTINFO + JR Z,SYS_SETBOOTINFO + OR $FF ; SIGNAL ERROR + RET +; +; SET BOOT INFORMATION +; ON ENTRY: +; L: BOOT BANK ID +; DE: BOOT DISK VOLUME (UNIT/SLICE) +; +SYS_SETBOOTINFO: + LD A,L + LD (CB_BOOTBID),A + LD (CB_BOOTVOL),DE + XOR A + RET +; +; SET TIMER +; ON ENTRY: +; DE:HL: TIMER VALUE (32 BIT) +; +SYS_SETTIMER: + LD BC,HB_TICKS + HB_DI + CALL ST32 + HB_EI + XOR A + RET +; +; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK +; ENTRY: D=BANK ID, HL=ADDRESS +; RETURN: E=BYTE VALUE +; +SYS_PEEK: +#IF (INTMODE == 1) + DI +#ENDIF + CALL HBX_PEEK ; IMPLEMENTED IN PROXY +#IF (INTMODE == 1) + EI +#ENDIF + XOR A + RET +; +; WRITE A BYTE OF MEMORY TO SPECIFIED BANK +; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE +; +SYS_POKE: +#IF (INTMODE == 1) + DI +#ENDIF + CALL HBX_POKE ; IMPLEMENTED IN PROXY +#IF (INTMODE == 1) + EI +#ENDIF + XOR A + RET +; +; INTERRUPT MANAGEMENT FUNCTIONS +; SUBFUNCTION IN C +; +SYS_INT: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSINT_INFO + JR Z,SYS_INTINFO + CP BF_SYSINT_GET + JR Z,SYS_INTGET + CP BF_SYSINT_SET + JR Z,SYS_INTSET + OR $FF ; SIGNAL ERROR + RET +; +; GET INTERRUPT SYSTEM INFORMATION +; RETURN D:=INTERRUPT MODE, E:=INT VEC TABLE SIZE +; +SYS_INTINFO: + LD D,INTMODE ; D := ACTIVE INTERRUPT MODE +#IF (INTMODE == 0) + LD E,0 ; 0 ENTRIES IF INTERRUPTS DISABLED +#ENDIF +#IF (INTMODE == 1) + LD A,(HB_IM1CNT) ; RETURN IM1 CALL LIST SIZE + LD E,A +#ENDIF +#IF (INTMODE == 2) + LD E,HBX_IVTCNT ; RETURN INT VEC TABLE SIZE +#ENDIF + XOR A ; INDICATE SUCCESS + RET ; AND DONE +; +; ROUTINE SHARED BY INT GET/SET. RETURNS ADDRESS OF VECTOR FOR SPECIFIED LIST / TABLE +; POSITION. ZF SET ON RETURN FOR SUCCESS, ELSE ERROR. +; +SYS_INTVECADR: +#IF (INTMODE == 0) + CALL PANIC ; INVALID FOR INT MODE 0 + OR $FF + RET +#ENDIF +#IF (INTMODE == 1) + LD A,(HB_IM1CNT) ; GET CURRENT ENTRY COUNT + INC A ; ALLOW FOR EXTRA ENTRY TO APPEND AT END + LD C,A ; SAVE IN C FOR COMPARE +#ENDIF +#IF (INTMODE == 2) + LD C,HBX_IVTCNT ; GET CURRENT ENTRY COUNT +#ENDIF + LD A,E ; INCOMING INDEX POSITION TO A + CP C ; COMPARE TO VECTOR COUNT + JR C,SYS_INTGET1 ; CONTINUE IF POSITION IN RANGE + CALL PANIC ; ELSE ERROR + OR $FF + RET +SYS_INTGET1: + OR A + RLA ; HL := (A * 2) FOR IM2 +#IF (INTMODE == 1) + RLA ; ... HL := (A * 4) + 1 FOR IM1 + INC A +#ENDIF + LD H,0 + LD L,A +#IF (INTMODE == 1) + LD DE,HB_IM1INT ; DE := START OF CALL LIST +#ENDIF +#IF (INTMODE == 2) + LD DE,HBX_IVT ; DE := START OF VECTOR TABLE +#ENDIF + ADD HL,DE ; HL := ADR OF VECTOR + XOR A ; INDICATE SUCCESS + RET +; +; RETURN THE INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE +; ENTRY: E=LIST/TABLE POSITION +; RETURN: HL=INTERRUPT VECTOR +; +SYS_INTGET: + CALL SYS_INTVECADR ; GET VECTOR ADDRESS + RET NZ ; BAIL OUT ON ERROR + LD A,(HL) ; DEREF HL TO GET VECTOR + INC HL + LD H,(HL) + LD L,A + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; SET AN INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE +; ENTRY: E=LIST/TABLE POSITION, HL=NEW INTERRUPT VECTOR +; RETURN: HL=PREVIOUS INTERRUPT VECTOR, DE=ADR OF INT ROUTING ENGINE FOR IM2 +; +SYS_INTSET: + PUSH HL ; SAVE NEW VECTOR + CALL SYS_INTVECADR ; GET VECTOR ADDRESS + JR Z,SYS_INTSET1 ; CONTINUE IF OK + POP HL ; FIX STACK + RET NZ ; BAIL OUT ON ERROR +SYS_INTSET1: + PUSH HL ; SAVE VECTOR ADDRESS + LD A,(HL) ; DEREF HL TO GET PREV VECTOR + INC HL + LD H,(HL) + LD L,A + EX (SP),HL ; (SP) := PREV VEC, HL := VEC ADR + POP DE ; DE := PREV VEC + POP BC ; BC := NEW VEC + LD (HL),C ; SAVE LSB + INC HL + LD (HL),B ; SAVE MSB + EX DE,HL ; HL := PREV VEC +#IF (INTMODE == 2) + LD DE,HBX_INT ; DE := IM2 INT ROUTING ENGINE +#ENDIF + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +;================================================================================================== +; GLOBAL HBIOS FUNCTIONS +;================================================================================================== +; +; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN +; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT) +; +CIO_IDLE: + PUSH AF ; PRESERVE AF + LD A,(IDLECOUNT) ; GET CURRENT IDLE COUNT + DEC A ; DECREMENT + LD (IDLECOUNT),A ; SAVE UPDATED VALUE + CALL Z,IDLE ; IF ZERO, DO IDLE PROCESSING + POP AF ; RECOVER AF + RET +; +#IF (INTMODE == 1) +; +; IM1 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK +; LIST OF IM1 INT CALLS IS BUILT DYNAMICALLY BELOW +; SEE HB_ADDIM1 ROUTINE +; EACH ENTRY WILL LOOK LIKE: +; CALL XXXX ; CALL INT HANDLER +; RET NZ ; RETURN IF HANDLED +; +; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. +; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID +; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. +; +; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. +; +HB_IM1INT: ; IM1 DEVICE INTERRUPT HANDLER CALL LIST + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ +; +; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 +; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS +; +HB_ADDIM1: + EX DE,HL ; VECTOR ADDRESS TO DE + LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY + INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE + LD (HL),E ; ADD VECTOR ADDRESS + INC HL ; ... + LD (HL),D ; ... + INC HL ; BUMP PTR + INC HL ; BUMP PTR + LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER + LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT + INC (HL) ; INCREMENT + RET ; DONE +; +HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST +HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST +HB_IM1PTR .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY +; +#ENDIF +; +; TIMER INTERRUPT +; +HB_TIMINT: + ; INCREMENT TICK COUNTER (32 BIT) + LD HL,HB_TICKS ; POINT TO TICK COUNTER + INC (HL) + JR NZ,HB_TIMINT1 + INC HL + INC (HL) + JR NZ,HB_TIMINT1 + INC HL + INC (HL) + JR NZ,HB_TIMINT1 + INC HL + INC (HL) +; +HB_TIMINT1: +; +#IF 0 +; + LD HL,TEMPCNT + DEC (HL) + JR NZ,HB_TIMINT2 + LD (HL),250 +; + LD A,'*' + CALL COUT + JR HB_TIMINT2 +; +TEMPCNT .DB 250 +; +#ENDIF +; +HB_TIMINT2: +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; ACK/RESET Z180 TIMER INTERRUPT + IN0 A,(Z180_TCR) + IN0 A,(Z180_TMDR0L) +#ENDIF +; + OR $FF ; NZ SET TO INDICATE INT HANDLED + RET +; +; BAD INTERRUPT HANDLER +; +HB_BADINT: + CALL NEWLINE2 + PRTS("+++ BAD INT: $") + CALL _REGDMP + CALL CONTINUE + OR $FF ; SIGNAL INTERRUPT HANDLED + RET +; +; COMMON API FUNCTION DISPATCH CODE +; +; ON ENTRY C IS UNIT # (INDEX INTO XXX_TBL OF UNITS) +; AND IY POINTS TO START OF UNIT TABLE. +; USE UNIT # IN C TO LOOKUP XXX_TBL ENTRY. THE XXX_TBL +; ENTRY CONTAINS THE START OF THE DRIVER FUNCTION TABLE AND +; THE DEVICE SPECIFIC INSTANCE DATA (BLOB). SET IY TO BLOB ADDRESS +; AND CALL THE SPECIFIC FUNCTION REQUESTED IN THE DRIVER. +; +HB_DISPCALL: + ; CHECK INCOMING UNIT INDEX IN C FOR VAILIDITY + LD A,C ; A := INCOMING DISK UNIT INDEX + CP (IY-1) ; COMPARE TO COUNT + JR NC,HB_DISPERR ; HANDLE INVALID UNIT INDEX + + ; CHECK FUNCTION INDEX FOR VALIDITY + LD A,B ; A := INCOMING FUNCTION NUMBER + AND $0F ; LOW NIBBLE ONLY FOR FUNC INDEX + CP (IY-3) ; CHECK FN NUM AGAINST MAX + JR NC,HB_DISPERR ; HANDLE FN NUM OUT OF RANGE ERROR + + ; BUMP IY TO ACTUAL XXX_TBL ENTRY FOR INCOMING UNIT INDEX + LD B,0 ; MSB IS ALWAYS ZERO + RLC C ; MULTIPLY UNIT INDEX + RLC C ; ... BY 4 FOR TABLE ENTRY OFFSET + ADD IY,BC ; SET IY TO ENTRY ADDRESS + + ; DERIVE DRIVER FUNC ADR TO CALL + PUSH HL ; SAVE INCOMING HL + LD L,(IY+0) ; COPY DRIVER FUNC TABLE + LD H,(IY+1) ; ... START TO HL + RLCA ; CONV UNIT (STILL IN A) TO FN ADR OFFSET + CALL ADDHLA ; HL NOW HAS DRIVER FUNC TBL START ADR + LD A,(HL) ; DEREFERENCE HL + INC HL ; ... TO GET + LD H,(HL) ; ... ACTUAL + LD L,A ; ... TARGET FUNCTION ADDRESS + EX (SP),HL ; RESTORE HL, FUNC ADR ON STACK + + ; GET UNIT INSTANCE DATA BLOB ADDRESS TO IY + PUSH HL ; SAVE INCOMING HL + LD L,(IY+2) ; HL := DATA BLOB ADDRESS + LD H,(IY+3) ; ... + EX (SP),HL ; RESTORE HL, BLOB ADR ON TOS + POP IY ; IY := BLOB ADR + + RET ; JUMP TO DRIVER FUNC ADR ON TOS +; +HB_DISPERR: + CALL PANIC ; PANIC + OR $FF ; SIGNAL ERROR + RET ; AND RETURN VIA DISPEXIT +; +; ADD AN ENTRY TO THE UNIT TABLE AT ADDRESS IN HL +; BC: DRIVER FUNCTION TABLE +; DE: ADDRESS OF UNIT INSTANCE DATA +; RETURN +; A: UNIT NUMBER ASSIGNED +; +HB_ADDENT: + DEC HL ; POINT TO ENTRY COUNT + LD A,(HL) ; GET ENTRY COUNT + PUSH AF ; SAVE VALUE TO RETURN AS ENTRY NUM AT END + INC A ; INCREMENT TO ACCOUNT FOR NEW ENTRY + DEC HL ; POINT TO ENTRY MAX + CP (HL) ; COMPARE MAX TO CURRENT COUNT (COUNT - MAX) + CALL NC,PANIC ; OVERFLOW + INC HL ; POINT TO COUNT + LD (HL),A ; SAVE NEW COUNT + INC HL ; POINT TO START OF TABLE + DEC A ; CONVERT A FROM ENTRY COUNT TO ENTRY INDEX + RLCA ; MULTIPLY BY 4 + RLCA ; ... TO GET BYTE OFFSET OF ENTRY + CALL ADDHLA ; MAKE HL POINT TO ACTUAL ENTRY ADDRESS + PUSH BC ; GET TABLE ENTRY ADDRESS TO BC + EX (SP),HL ; ... AND DISPATCH ADDRESS TO HL + POP BC ; ... SO THAT DE:HL HAS 32 BIT ENTRY + CALL ST32 ; LD (BC),DE:HL STORES THE ENTRY + POP AF ; RETURN ENTRY INDEX (UNIT NUMBER ASSIGNED) + RET +; +; ALLOCATE HL BYTES OF MEMORY ON THE HEAP +; RETURNS POINTER TO ALLOCATED SPACE IN HL +; ON SUCCESS RETURN A == 0, AND Z SET +; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED +; ALL OTHER REGISTERS PRESERVED +; +; A 4 BYTE HEADER IS PLACED IN FRONT OF THE ALLOCATED MEMORY +; - DWORD: SIZE OF MEMROY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) +; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) +; +HB_ALLOC: + ; SAVE ALLOC SIZE AND REFERENCE ADR FOR SUBSEQUENT HEADER CONSTRUCTION + LD (HB_TMPSZ),HL ; SAVE INCOMING SIZE REQUESTED + ; USE EX (SP),HL INSTEAD???? + POP HL ; GET RETURN ADDRESS + LD (HB_TMPREF),HL ; SAVE AS REFERENCE + ; USE EX (SP),HL INSTEAD???? + PUSH HL ; PUT IT BACK ON STACK + LD HL,(HB_TMPSZ) ; RECOVER INCOMING MEM SIZE PARM +; + ; CALC NEW HEAP TOP AND HANDLE OUT-OF-SPACE ERROR + PUSH DE ; SAVE INCOMING DE + LD DE,4 ; SIZE OF HEADER + ADD HL,DE ; ADD IT IN + JR C,HB_ALLOC1 ; ERROR ON OVERFLOW + LD DE,(CB_HEAPTOP) ; CURRENT HEAP TOP + ADD HL,DE ; ADD IT IN, HL := NEW HEAP TOP + JR C,HB_ALLOC1 ; ERROR ON OVERFLOW + BIT 7,H ; TEST PAST END OF BANK (>= 32K) + JR NZ,HB_ALLOC1 ; ERROR IF PAST END +; + ; SAVE NEW HEAP TOP + LD DE,(CB_HEAPTOP) ; GET ORIGINAL HEAP TOP + LD (CB_HEAPTOP),HL ; SAVE NEW HEAP TOP +; + ; SET HEADER VALUES + EX DE,HL ; HEADER ADR TO HL + LD DE,(HB_TMPSZ) ; GET THE ORIG SIZE REQUESTED + LD (HL),E ; SAVE SIZE (LSB) + INC HL ; BUMP HEADER POINTER + LD (HL),D ; SAVE SIZE (MSB) + INC HL ; BUMP HEADER POINTER + LD DE,(HB_TMPREF) ; GET THE REFERENCE ADR + LD (HL),E ; SAVE REF ADR (LSB) + INC HL ; BUMP HEADER POINTER + LD (HL),D ; SAVE REF ADR (MSB) + INC HL ; BUMP HEADER POINTER +; + ; RETURN SUCCESS, HL POINTS TO START OF ALLOCATED MEMORY (PAST HEADER) + POP DE ; RESTORE INCOMING DE + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +HB_ALLOC1: + ; ERROR RETURN + POP DE ; RESTORE INCOMING DE + OR $FF ; SIGNAL ERROR + RET ; AND RETURN +; +HB_TMPSZ .DW 0 +HB_TMPREF .DW 0 +; +;================================================================================================== +; DEVICE DRIVERS +;================================================================================================== +; +#IF (SIMRTCENABLE) +ORG_SIMRTC .EQU $ + #INCLUDE "simrtc.asm" +SIZ_SIMRTC .EQU $ - ORG_SIMRTC + .ECHO "SIMRTC occupies " + .ECHO SIZ_SIMRTC + .ECHO " bytes.\n" +#ENDIF +; +#IF (DSRTCENABLE) +ORG_DSRTC .EQU $ + #INCLUDE "dsrtc.asm" +SIZ_DSRTC .EQU $ - ORG_DSRTC + .ECHO "DSRTC occupies " + .ECHO SIZ_DSRTC + .ECHO " bytes.\n" +#ENDIF +; +#IF (ASCIENABLE) +ORG_ASCI .EQU $ + #INCLUDE "asci.asm" +SIZ_ASCI .EQU $ - ORG_ASCI + .ECHO "ASCI occupies " + .ECHO SIZ_ASCI + .ECHO " bytes.\n" +#ENDIF +; +#IF (UARTENABLE) +ORG_UART .EQU $ + #INCLUDE "uart.asm" +SIZ_UART .EQU $ - ORG_UART + .ECHO "UART occupies " + .ECHO SIZ_UART + .ECHO " bytes.\n" +#ENDIF +; +#IF (SIOENABLE) +ORG_SIO .EQU $ + #INCLUDE "sio.asm" +SIZ_SIO .EQU $ - ORG_SIO + .ECHO "SIO occupies " + .ECHO SIZ_SIO + .ECHO " bytes.\n" +#ENDIF +; +#IF (ACIAENABLE) +ORG_ACIA .EQU $ + #INCLUDE "acia.asm" +SIZ_ACIA .EQU $ - ORG_ACIA + .ECHO "ACIA occupies " + .ECHO SIZ_ACIA + .ECHO " bytes.\n" +#ENDIF +; +#IF (VGAENABLE) +ORG_VGA .EQU $ + #INCLUDE "vga.asm" +SIZ_VGA .EQU $ - ORG_VGA + .ECHO "VGA occupies " + .ECHO SIZ_VGA + .ECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE) +ORG_CVDU .EQU $ + #INCLUDE "cvdu.asm" +SIZ_CVDU .EQU $ - ORG_CVDU + .ECHO "CVDU occupies " + .ECHO SIZ_CVDU + .ECHO " bytes.\n" +#ENDIF +; +#IF (VDUENABLE) +ORG_VDU .EQU $ + #INCLUDE "vdu.asm" +SIZ_VDU .EQU $ - ORG_VDU + .ECHO "VDU occupies " + .ECHO SIZ_VDU + .ECHO " bytes.\n" +#ENDIF +; +#IF (TMSENABLE) +ORG_TMS .EQU $ + #INCLUDE "tms.asm" +SIZ_TMS .EQU $ - ORG_TMS + .ECHO "TMS occupies " + .ECHO SIZ_TMS + .ECHO " bytes.\n" +#ENDIF +; +#IF (NECENABLE) +ORG_NEC .EQU $ + ;#INCLUDE "nec.asm" +SIZ_NEC .EQU $ - ORG_NEC + .ECHO "NEC occupies " + .ECHO SIZ_NEC + .ECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE | VGAENABLE) +ORG_FONTHI .EQU $ + #INCLUDE "font_hi.asm" +SIZ_FONTHI .EQU $ - ORG_FONTHI + .ECHO "FONTHI occupies " + .ECHO SIZ_FONTHI + .ECHO " bytes.\n" +#ENDIF +; +#IF (TMSENABLE) +ORG_FONTTMS .EQU $ + #INCLUDE "font_tms.asm" +SIZ_FONTTMS .EQU $ - ORG_FONTTMS + .ECHO "FONTTMS occupies " + .ECHO SIZ_FONTTMS + .ECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE | VGAENABLE) +ORG_KBD .EQU $ + #INCLUDE "kbd.asm" +SIZ_KBD .EQU $ - ORG_KBD + .ECHO "KBD occupies " + .ECHO SIZ_KBD + .ECHO " bytes.\n" +#ENDIF +; +#IF (VDUENABLE | (TMSENABLE & (PLATFORM == PLT_N8))) +ORG_PPK .EQU $ + #INCLUDE "ppk.asm" +SIZ_PPK .EQU $ - ORG_PPK + .ECHO "PPK occupies " + .ECHO SIZ_PPK + .ECHO " bytes.\n" +#ENDIF +; +#IF (PRPENABLE) +ORG_PRP .EQU $ + #INCLUDE "prp.asm" +SIZ_PRP .EQU $ - ORG_PRP + .ECHO "PRP occupies " + .ECHO SIZ_PRP + .ECHO " bytes.\n" +#ENDIF +; +#IF (PPPENABLE) +ORG_PPP .EQU $ + #INCLUDE "ppp.asm" +SIZ_PPP .EQU $ - ORG_PPP + .ECHO "PPP occupies " + .ECHO SIZ_PPP + .ECHO " bytes.\n" +#ENDIF +; +#IF (MDENABLE) +ORG_MD .EQU $ + #INCLUDE "md.asm" +SIZ_MD .EQU $ - ORG_MD + .ECHO "MD occupies " + .ECHO SIZ_MD + .ECHO " bytes.\n" +#ENDIF + +#IF (FDENABLE) +ORG_FD .EQU $ + #INCLUDE "fd.asm" +SIZ_FD .EQU $ - ORG_FD + .ECHO "FD occupies " + .ECHO SIZ_FD + .ECHO " bytes.\n" +#ENDIF + +#IF (RFENABLE) +ORG_RF .EQU $ + #INCLUDE "rf.asm" +SIZ_RF .EQU $ - ORG_RF + .ECHO "RF occupies " + .ECHO SIZ_RF + .ECHO " bytes.\n" +#ENDIF + +#IF (IDEENABLE) +ORG_IDE .EQU $ + #INCLUDE "ide.asm" +SIZ_IDE .EQU $ - ORG_IDE + .ECHO "IDE occupies " + .ECHO SIZ_IDE + .ECHO " bytes.\n" +#ENDIF + +#IF (PPIDEENABLE) +ORG_PPIDE .EQU $ + #INCLUDE "ppide.asm" +SIZ_PPIDE .EQU $ - ORG_PPIDE + .ECHO "PPIDE occupies " + .ECHO SIZ_PPIDE + .ECHO " bytes.\n" +#ENDIF + +#IF (SDENABLE) +ORG_SD .EQU $ + #INCLUDE "sd.asm" +SIZ_SD .EQU $ - ORG_SD + .ECHO "SD occupies " + .ECHO SIZ_SD + .ECHO " bytes.\n" +#ENDIF + +#IF (HDSKENABLE) +ORG_HDSK .EQU $ + #INCLUDE "hdsk.asm" +SIZ_HDSK .EQU $ - ORG_HDSK + .ECHO "HDSK occupies " + .ECHO SIZ_HDSK + .ECHO " bytes.\n" +#ENDIF + +#IF (TERMENABLE) +ORG_TERM .EQU $ + #INCLUDE "term.asm" +SIZ_TERM .EQU $ - ORG_TERM + .ECHO "TERM occupies " + .ECHO SIZ_TERM + .ECHO " bytes.\n" +#ENDIF +; +#IF (SPKENABLE) +ORG_SPK .EQU $ + #INCLUDE "spk.asm" +SIZ_SPK .EQU $ - ORG_SPK + .ECHO "SPK occupies " + .ECHO SIZ_SPK + .ECHO " bytes.\n" +#ENDIF +; +#IF (AYENABLE) +ORG_AY .EQU $ + #INCLUDE "ay.asm" +SIZ_AY .EQU $ - ORG_AY + .ECHO "AY occupies " + .ECHO SIZ_AY + .ECHO " bytes.\n" +#ENDIF + +#IF (PIOENABLE) +ORG_PIO .EQU $ + #INCLUDE "pio.asm" +SIZ_PIO .EQU $ - ORG_PIO + .ECHO "PIO occupies " + .ECHO SIZ_PIO + .ECHO " bytes.\n" +#ENDIF +; +#DEFINE USEDELAY +#INCLUDE "util.asm" +#INCLUDE "time.asm" +#INCLUDE "bcd.asm" +#INCLUDE "decode.asm" +;#INCLUDE "xio.asm" +; +#IF (DSKYENABLE) +#DEFINE DSKY_KBD +#INCLUDE "dsky.asm" +#ENDIF +; +; DETECT CPU SPEED USING DS-1302 RTC +; +HB_CPUSPD: +; +#IF (DSRTCENABLE) +; + CALL DSRTC_TSTCLK ; IS CLOCK RUNNING? + JR Z,HB_CPUSPD1 ; YES, CONTINUE + ; MAKE SURE CLOCK IS RUNNING + LD HL,DSRTC_TIMDEF + CALL DSRTC_TIM2CLK + LD HL,DSRTC_BUF + CALL DSRTC_WRCLK + CALL DSRTC_TSTCLK ; NOW IS CLOCK RUNNING? + RET NZ +; +HB_CPUSPD1: +; LD B,8 +;HB_CPUSPDX: +; PUSH BC + + ; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT + ; FOR SECOND TICK AND TO GET A FULL ONE SECOND LOOP COUNT + + CALL HB_RDSEC ; GET SECONDS + LD (HB_CURSEC),A ; AND INIT CURSEC + CALL HB_WAITSEC ; WAIT FOR SECONDS TICK + LD (HB_CURSEC),A ; SAVE NEW VALUE + CALL HB_WAITSEC ; WAIT FOR SECONDS TICK + +; PUSH DE +; POP BC +; CALL NEWLINE +; CALL PRTHEXWORD + +; POP BC +; DJNZ HB_CPUSPDX +; + LD A,H + OR L + RET Z ; FAILURE, USE DEFAULT CPU SPEED + +; + ; MOVE LOOP COUNT TO HL + PUSH DE + POP HL +; + ; TIMES 4 FOR CPU SPEED IN KHZ + RES 0,L ; GRANULARITY +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + SLA L + RL H +#ENDIF + SLA L + RL H + SLA L + RL H +; + LD (CB_CPUKHZ),HL + LD DE,1000 + CALL DIV16 + LD A,C + LD (CB_CPUMHZ),A +; + RET +; +HB_WAITSEC: + ; WAIT FOR SECONDS TICK + ; RETURN SECS VALUE IN A, LOOP COUNT IN DE + LD DE,0 ; INIT LOOP COUNTER +HB_WAITSEC1: +#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2)| (PLATFORM == PLT_RC)) + ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 + CALL DLY32 + CALL DLY8 + CALL DLY2 + JP $ + 3 ; 10 TSTATES + JP $ + 3 ; 10 TSTATES + JP $ + 3 ; 10 TSTATES + JP $ + 3 ; 10 TSTATES + ;LD A,R ; 9 TSTATES + INC BC ; 6 TSTATES + ;LD A,(BC) ; 7 TSTATES + ;NOP ; 4 TSTATES + NOP ; 4 TSTATES +#ENDIF + +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; LOOP TARGET IS 8000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 8 + ;CALL DLY64 + CALL DLY32 + CALL DLY16 + CALL DLY8 + CALL DLY4 + CALL DLY2 + CALL DLY1 ; CALL (25TS) & RET (18TS) = 43TS + OR A ; 7 TSTATES + OR A ; 7 TSTATES + ;OR A ; 7 TSTATES + ;OR A ; 7 TSTATES + NOP ; 6 TSTATES + ;NOP ; 6 TSTATES + ;NOP ; 6 TSTATES + ;NOP ; 6 TSTATES + ;NOP ; 6 TSTATES +#ENDIF +; + PUSH DE + CALL HB_RDSEC ; GET SECONDS + POP DE + INC DE ; BUMP COUNTER + LD HL,HB_CURSEC ; POINT TO COMP VALUE + CP (HL) ; TEST FOR CHANGE + RET NZ ; DONE IF TICK OCCURRED + LD A,D ; CHECK HL + OR E ; ... FOR OVERFLOW + RET Z ; TIMEOUT, SOMETHING IS WRONG + JR HB_WAITSEC1 ; LOOP +; +HB_RDSEC: + ; READ SECONDS BYTE INTO A + LD C,$81 ; SECONDS REGISTER + CALL DSRTC_CMD ; SEND THE COMMAND + CALL DSRTC_GET ; READ THE REGISTER + CALL DSRTC_END ; FINISH IT + RET +; +#ELSE +; + RET ; NO RTC, ABORT +; +#ENDIF +; +; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 +; +PRTD3M: + PUSH BC + PUSH DE + PUSH HL + LD E,'0' + LD BC,-10000 + CALL PRTD3M1 + LD E,0 + LD BC,-1000 + CALL PRTD3M1 + CALL PC_PERIOD + LD BC,-100 + CALL PRTD3M1 + LD C,-10 + CALL PRTD3M1 + LD C,-1 + CALL PRTD3M1 + POP HL + POP DE + POP BC + RET +PRTD3M1: + LD A,'0' - 1 +PRTD3M2: + INC A + ADD HL,BC + JR C,PRTD3M2 + SBC HL,BC + CP E + JR Z,PRTD3M3 + LD E,0 + CALL COUT +PRTD3M3: + RET +; +;================================================================================================== +; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES +;================================================================================================== +; +PRTSUM: + CALL NEWLINE2 ; SKIP A LINE + LD DE,PS_STRHDR ; POINT TO HEADER + CALL WRITESTR ; PRINT IT +; + ; PRINT DISK DEVICES + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + LD C,BF_SYSGET_DIOCNT ; SUBFUNC: DISK UNIT COUNT + RST 08 ; E := DISK UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + JR Z,PRTSUM1A ; IF NONE, BYPASS + LD C,0 ; C WILL BE UNIT INDEX +PRTSUM1: + PUSH BC ; SAVE LOOP CONTROL + CALL PS_DISK ; PRINT DISK INFO + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP DISK UNIT INDEX + DJNZ PRTSUM1 ; LOOP THRU ALL DISK DEVICES +; +PRTSUM1A: + ; PRINT SERIAL DEVICES + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + LD C,BF_SYSGET_CIOCNT ; SUBFUNC: SERIAL UNIT COUNT + RST 08 ; E := SERIAL UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + JR Z,PRTSUM2A ; IF NONE, BYPASS + LD C,0 ; C WILL BE UNIT INDEX +PRTSUM2: + PUSH BC ; SAVE LOOP CONTROL + CALL PS_SERIAL ; PRINT SERIAL INFO + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP SERIAL UNIT INDEX + DJNZ PRTSUM2 ; LOOP THRU ALL SERIAL DEVICES +; +PRTSUM2A: + ; PRINT VIDEO DEVICES + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + LD C,BF_SYSGET_VDACNT ; SUBFUNC: VIDEO UNIT COUNT + RST 08 ; E := SERIAL UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + JR Z,PRTSUM3A ; IF NONE, BYPASS + LD C,0 ; C WILL BE UNIT INDEX +PRTSUM3: + PUSH BC ; SAVE LOOP CONTROL + CALL PS_VIDEO ; PRINT VIDEO INFO + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP VIDEO UNIT INDEX + DJNZ PRTSUM3 ; LOOP THRU ALL VIDEO DEVICES +; +PRTSUM3A: + RET ; DONE +; +; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C +; +PS_DISK: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("Disk $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_DDSTRREF ; POINT TO DISK DEVICE TYPE NAME TABLE + CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH + POP DE ; RECOVER ATTRIBUTES TO DE + PUSH DE ; SAVE ATTRIBUTES AGAIN + CALL PS_PRTDT ; PRINT DISK TYPE + POP DE ; RESTORE ATTRIBUTES + POP BC ; RESTORE UNIT NUM + CALL PS_PRTDC ; PRINT DISK CAPACITY +; + CALL NEWLINE + RET +; +; PRINT DISK TYPE (DISK ATTRIBUTE IN E) +; +PS_PRTDT: + LD A,E ; ATTRIBUTES TO A + BIT 7,A ; FLOPPY BIT SET? + LD HL,PS_DTFLOP ; ASSUME FLOPPY + JR NZ,PS_PRTDT1 ; IF FLOPPY, JUMP AHEAD + RRCA ; SHIFT TYPE BITS + RRCA + RRCA + AND $07 ; AND ISOLATE THEM + RLCA ; X2 FOR WORD OFFSET IN STRING TABLE + LD HL,PS_DTSTRREF + 2 ; POINT TO STR REF TABLE (SKIP FLOPPY STRING) + CALL ADDHLA + LD A,(HL) + INC HL + LD H,(HL) + LD L,A +; +PS_PRTDT1: + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,18 ; 18 CHAR FIELD + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E) +; +PS_PRTDC: +; + LD A,E ; ATTRIBUTE TO ACCUM + BIT 7,A ; TEST FOR FLOPPY + JR NZ,PS_PRTDC2 ; HANDLE FLOPPY + RRCA ; ISOLATE TYPE BITS + RRCA + RRCA + AND $07 + CP 4 ; ROM DISK? + JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB + CP 5 ; RAM DISK? + JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB +; + ; PRINT HARD DISK STORAGE SIZE IN MB + LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY + RST 08 ; DE:HL := BLOCKS + JP NZ,PS_PRTNUL ; MEDIA PROBLEM + RES 7,D ; CLEAR LBA BIT + LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB + CALL SRL32 ; RIGHT SHIFT + CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) + PRTS("MB$") ; PRINT SUFFIX + CALL PC_COMMA + PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA + RET ; DONE +; +PS_PRTDC1: + ; PRINT ROM/ROM DISK CAPACITY IN KB + LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY + RST 08 ; DE:HL := BLOCKS + JP NZ,PS_PRTNUL ; MEDIA PROBLEM + RES 7,D ; CLEAR LBA BIT + LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB + CALL SRL32 ; RIGHT SHIFT + CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) + PRTS("KB$") ; PRINT SUFFIX + CALL PC_COMMA + PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA + RET ; DONE +; +PS_PRTDC2: + LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING + ; PRINT FLOPPY TYPE + LD A,C ; ATTRIBUTE TO ACCUM + RLCA ; ISOLATE FORM FACTOR BITS + RLCA + RLCA + AND $03 + LD DE,PS_FLP8 ; ASSUME 8" + CP 0 + JR Z,PS_PRTDC2A + LD DE,PS_FLP5 ; ASSUME 5.25" + CP 1 + JR Z,PS_PRTDC2A + LD DE,PS_FLP3 ; ASSUME 3.5" + CP 2 + JR Z,PS_PRTDC2A + LD DE,PS_FLPN ; ASSUME OTHER" +PS_PRTDC2A: + CALL WRITESTR + ; PRINT FLOPPY SIDES + LD A,C ; ATTRIBUTE TO ACCUM + LD DE,PS_FLPSS ; ASSUME SINGLE SIDED + BIT 4,A ; DS? + JR Z,PS_PRTDC2B + LD DE,PS_FLPDS ; DOUBLE SIDED +PS_PRTDC2B: + CALL WRITESTR + ; PRINT FLOPPY DENSITY + LD A,C ; ATTRIBUTE TO ACCUM + RRCA ; ISOLATE DENSITY BITS + RRCA + AND $03 + LD DE,PS_FLPSD ; SINGLE DENSITY + CP 0 + JR Z,PS_PRTDC2C + LD DE,PS_FLPDD ; DOUBLE DENSITY + CP 1 + JR Z,PS_PRTDC2C + LD DE,PS_FLPHD ; HIGH DENSITY + CP 2 + JR Z,PS_PRTDC2C + LD DE,PS_FLPED ; EXTENDED DENSITY + CP 3 + JR Z,PS_PRTDC2C +PS_PRTDC2C: + CALL WRITESTR + CALL PC_COMMA + PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA +; + RET ; DONE +; +; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C +; +PS_SERIAL: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("CharIO $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, C:=DEVICE ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_SDSTRREF ; POINT TO SERIAL DEVICE TYPE NAME TABLE + CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH + POP BC ; RECOVER ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES AGAIN + CALL PS_PRTST ; PRINT SERIAL TYPE + POP BC ; RESTORE ATTRIBUTES + POP DE ; RESTORE UNIT NUM TO E + CALL PS_PRTSC ; PRINT SERIAL CONFIG +; + CALL NEWLINE + RET +; +; PRINT SERIAL TYPE (SERIAL ATTRIBUTE IN E) +; +PS_PRTST: + LD HL,PS_STRS232 ; ASSUME RS-232 + LD A,C + AND $C0 + JR Z,PS_PRTST1 ; 00 TYPE 0 - RS-232 + LD HL,PS_STTERM + CP $40 + JR Z,PS_PRTST1 ; 40 TYPE 1 - Terminal + LD HL,PS_STPPT + CP $80 + JR Z,PS_PRTST1 ; 80 TYPE 2 - Parallel + LD HL,PS_STUDEF +; ; C0 TYPE 3 - Undefined +PS_PRTST1: + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,18 ; 18 CHAR FIELD + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) +; +PS_PRTSC: + LD A,C + AND $C0 + JR Z,PS_PRTSC0_1 ; 00 TYPE 0 - RS-232 + CP $40 + JR Z,PS_PRTSC1 ; 40 TYPE 1 - Terminal + CP $80 + JR Z,PS_PRTSC2_1 ; 80 TYPE 2 - Parallel +; ; C0 TYPE 3 - Undefined +PS_PRTSC0_1: + ; PRINT RS-232 CONFIG + LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG + LD C,E ; SET SERIAL UNIT NUM + RST 08 ; DE:HL := BAUD RATE + LD A,D ; TEST FOR $FF + AND E + INC A ; SET Z IF DE == $FF + JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED +; +PS_PRTSC0: + ; PRINT BAUD RATE + PUSH DE ; PRESERVE DE + LD A,D + AND $1F ; ISOLATE ENCODED BAUD RATE + LD L,A ; PUT IN L + LD H,0 ; H IS ALWAYS ZERO + LD DE,75 ; BAUD RATE DECODE CONSTANT + CALL DECODE ; DE:HL := BAUD RATE + LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF + CALL BIN2BCD ; CONVERT TO BCD + CALL PRTBCD ; AND PRINT IN DECIMAL + POP DE ; RESTORE DE +; + ; PRINT DATA BITS + PUSH DE ; PRESERVE DE + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + AND $03 ; ISOLATE DATA BITS VALUE + ADD A,'5' ; CONVERT TO CHARACTER + CALL COUT ; AND PRINT + POP DE ; RESTORE DE +; + ; PRINT PARITY + PUSH DE ; PRESERVE DE + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + RRCA ; SHIFT RELEVANT BITS + RRCA ; ... + RRCA ; ... + AND $07 ; AND ISOLATE DATA BITS VALUE + LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE + CALL ADDHLA ; APPLY OFFSET + LD A,(HL) ; GET CHARACTER + CALL COUT ; AND PRINT + POP DE ; RESTORE DE +; + ; PRINT STOP BITS + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + RRCA ; SHIFT RELEVANT BITS + RRCA ; ... + AND $01 ; AND ISOLATE DATA BITS VALUE + ADD A,'1' ; MAKE IT A CHARACTER + CALL COUT ; AND PRINT +; + RET +; +PS_PRTSC2_1: + ; PRINT PARALLEL CONFIG + LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG + LD C,E ; SET SERIAL UNIT NUM + RST 08 ; DE:HL := I/O CONFIG + LD A,D ; TEST FOR $FF + AND E + INC A ; SET Z IF DE == $FF + JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED + LD A,E + OR A + LD HL,PS_STPPTIN ; Parallel Input + JR Z,PS_PRTST1 + LD HL,PS_STPPTOUT ; Parallel Output + DEC A + JR Z,PS_PRTST1 + LD HL,PS_STRPPTBD ; Parallel BiDirectional + DEC A + JP Z,PS_PRTST1 + JP PS_PRTNUL + RET +; +PS_PRTSC1: + ; PRINT TERMINAL CONFIG + LD A,C ; GET ATTRIBUTE VALUE + CP $FF ; NO ATTACHED VDA + JR Z,PS_PRTSC2 + PRTS("Video $") ; FORMATTING + AND $0F ; ISOLATE VIDEO UNIT NUM + CALL PRTDECB ; PRINT IT + CALL PC_COMMA +#IF (VDAEMU == EMUTYP_TTY) + PRTS("TTY$") +#ENDIF +#IF (VDAEMU == EMUTYP_ANSI) + PRTS("ANSI$") +#ENDIF + RET +; +PS_PRTSC2: + PRTS("PropTerm$") ; ASSUME PROPELLER + CALL PC_COMMA + PRTS("ANSI$") + RET +; +PS_PRTPC0: + RET + ; +; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C +; +PS_VIDEO: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("Video $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_VDSTRREF ; POINT TO VIDEO DEVICE TYPE NAME TABLE + CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH + POP DE ; RECOVER ATTRIBUTES + PUSH DE ; SAVE ATTRIBUTES AGAIN + CALL PS_PRTVT ; PRINT VIDEO TYPE + POP DE ; RESTORE ATTRIBUTES + POP BC ; RESTORE UNIT NUM + CALL PS_PRTVC ; PRINT VIDEO CONFIG +; + CALL NEWLINE + RET +; +; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E) +; +PS_PRTVT: + LD HL,PS_VTCRT ; ASSUME CRT + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,18 ; 18 CHAR FIELD + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E) +; +PS_PRTVC: + PRTS("Text$") + CALL PC_COMMA + LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG + RST 08 ; D:=ROWS, E:=COLS + LD A,E + CALL PRTDECB + LD A,'x' + CALL COUT + LD A,D + CALL PRTDECB + RET +; +; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE +; +PS_PRTDEV: + LD A,D + RRCA ; TYPE IS IN UPPER NIBBLE, MOVE TO LOWER NIBBLE + RRCA + RRCA + RRCA + RLCA ; X2 FOR WORD OFFSET IN STRING TABLE + CALL ADDHLA + LD A,(HL) + INC HL + LD H,(HL) + LD L,A + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,E ; NUM + CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR + CALL PC_COLON ; PRINT COLON + LD A,12 - 2 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE +; +PS_PRTNUL: + LD HL,PS_STRNUL + ; FALL THRU TO PS_PRT +; +; +; +PS_PRT: + ; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C + LD C,0 ; INIT CHAR COUNT +PS_PRT1: + LD A,(HL) ; GET CHAR + INC HL ; BUMP INDEX + CP '$' ; TERM? + RET Z ; IF SO, DONE + CALL COUT ; PRINT IT + INC C ; BUMP COUNTER + JR PS_PRT1 ; AND LOOP +; +; +; +PS_PAD: + ; PAD N SPACES SPECIFIED IN A + LD B,A + LD A,' ' +PS_PAD1: + CALL COUT + DJNZ PS_PAD1 + RET +; +; +; +PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE +; +; DISK DEVICE STRINGS +; +PS_DDSTRREF: + .DW PS_DDMD, PS_DDFD, PS_DDRF, PS_DDIDE, PS_DDATAPI, PS_DDPPIDE + .DW PS_DDSD, PS_DDPRPSD, PS_DDPPPSD, PS_DDHDSK +; +PS_DDMD .TEXT "MD$" +PS_DDFD .TEXT "FD$" +PS_DDRF .TEXT "RF$" +PS_DDIDE .TEXT "IDE$" +PS_DDATAPI .TEXT "ATAPI$" +PS_DDPPIDE .TEXT "PPIDE$" +PS_DDSD .TEXT "SD$" +PS_DDPRPSD .TEXT "PRPSD$" +PS_DDPPPSD .TEXT "PPPSD$" +PS_DDHDSK .TEXT "HDSK$" +; +; DISK TYPE STRINGS +; +PS_DTSTRREF: + .DW PS_DTFLOP, PS_DTHARD, PS_DTCF, PS_DTSD + .DW PS_DTUSB, PS_DTROM, PS_DTRAM, PS_DTRF +; +PS_DTFLOP .TEXT "Floppy Disk$" +PS_DTHARD .TEXT "Hard Disk$" +PS_DTCF .TEXT "CompactFlash$" +PS_DTSD .TEXT "SD Card$" +PS_DTUSB .TEXT "USB Drive$" +PS_DTROM .TEXT "ROM Disk$" +PS_DTRAM .TEXT "RAM Disk$" +PS_DTRF .TEXT "RAM Floppy$" +PS_DTOTHER .TEXT "???$" +; +; FLOPPY ATTRIBUTE STRINGS +; +PS_FLP8 .TEXT "8\",$" +PS_FLP5 .TEXT "5.25\",$" +PS_FLP3 .TEXT "3.5\",$" +PS_FLPN .TEXT "???\",$" +; +PS_FLPSS .TEXT "SS/$" +PS_FLPDS .TEXT "DS/$" +; +PS_FLPSD .TEXT "SD$" +PS_FLPDD .TEXT "DD$" +PS_FLPHD .TEXT "HD$" +PS_FLPED .TEXT "ED$" +; +; SERIAL DEVICE STRINGS +; +PS_SDSTRREF: + .DW PS_SDUART, PS_SDASCI, PS_SDTERM, + .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO +; +PS_SDUART .TEXT "UART$" +PS_SDASCI .TEXT "ASCI$" +PS_SDTERM .TEXT "TERM$" +PS_SDPRPCON .TEXT "PRPCON$" +PS_SDPPPCON .TEXT "PPPCON$" +PS_SDSIO .TEXT "SIO$" +PS_SDACIA .TEXT "ACIA$" +PS_SDPIO .TEXT "PORT$" +; +; SERIAL TYPE STRINGS +; +PS_STRS232 .TEXT "RS-232$" +PS_STTERM .TEXT "Terminal$" +PS_STPPT .TEXT "Parallel$" +PS_STUDEF .TEXT "Undefined$" +; +PS_STPARMAP .DB "NONENMNS" +; +; PARALLEL TYPE STRINGS +; +PS_STPPTIN .TEXT "Input$" +PS_STPPTOUT .TEXT "Output$" +PS_STRPPTBD .TEXT "Bi-Directional$" +; +; VIDEO DEVICE STRINGS +; +PS_VDSTRREF: + .DW PS_VDVDU, PS_VDCVDU, PS_VDNEC, PS_VDTMS, PS_VDVGA +; +PS_VDVDU .TEXT "VDU$" +PS_VDCVDU .TEXT "CVDU$" +PS_VDNEC .TEXT "NEC$" +PS_VDTMS .TEXT "TMS$" +PS_VDVGA .TEXT "VGA$" +; +; VIDEO TYPE STRINGS +; +PS_VTCRT .TEXT "CRT$" +; +; VIDEO CONFIG STRINGS +; +; +; +; 0 1 2 3 4 5 6 7 +; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 +PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" + .TEXT "---------- ---------- ---------------- --------------------\r\n$" +; +;================================================================================================== +; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) +;================================================================================================== +; +; OUTPUT CHARACTER FROM A +; +COUT: + ; SAVE ALL INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL +; + ; GET CURRENT CONSOLE UNIT + LD E,A ; TEMPORARILY STASH OUTPUT CHAR IN E + LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE + CP $FF ; TEST FOR $FF (HBIOS NOT READY) + JR Z,COUT1 ; IF NOT READY, USE XIO +; + ; USE HBIOS + LD C,A ; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY + JR COUT2 ; CONTINUE +; +COUT1: + ;; USE XIO + ;LD A,E ; GET OUTPUT CHAR BACK TO ACCUM + ;CALL XIO_OUTC ; OUTPUT VIA XIO +; +COUT2: + ; RESTORE ALL REGISTERS + POP HL + POP DE + POP BC + POP AF + RET +; +; INPUT CHARACTER TO A +; +CIN: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE + CP $FF ; TEST FOR $FF (HBIOS NOT READY) + JR Z,CIN1 ; IF NOT READY, USE XIO +; + ; USE HBIOS + LD C,A ; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY + LD A,E ; RESULTANT CHAR TO A + JR CIN2 ; CONTINUE +; +CIN1: + ;; USE XIO + ;CALL XIO_INC ; GET CHAR +; +CIN2: +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) +; +CST: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE + CP $FF ; TEST FOR $FF (HBIOS NOT READY) + JR Z,CST1 ; IF NOT READY, USE XIO +; + ; USE HBIOS + LD C,A ; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY + JR CST2 ; CONTINUE +; +CST1: + ;; USE XIO + ;CALL XIO_IST ; GET STATUS +; +CST2: + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +;================================================================================================== +; MISCELLANEOUS UTILITY FUNCTIONS +;================================================================================================== +; +; SET HL TO IY+A, A IS TRASHED +; +LDHLIYA: + PUSH IY ; COPY INSTANCE DATA PTR + POP HL ; ... TO HL + ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN + ADD A,L ; ADD OFFSET TO LSB + LD L,A ; ... PUT BACK IN L + RET NC ; DONE IF CF NOT SET + INC H ; IF CF SET, BUMP MSB + RET ; ... AND RETURN +; +; CONVERT AN HBIOS STANDARD HARD DISK CHS ADDRESS TO +; AN LBA ADDRESS. A STANDARD HBIOS HARD DISK IS ASSUMED +; TO HAVE 16 SECTORS PER TRACK AND 16 HEADS PER CYLINDER. +; +; INPUT: HL=TRACK, D=HEAD, E=SECTOR +; OUTPUT: DE:HL=32 BIT LBA ADDRESS (D:7 IS NOT SET IN THE RESULT) +; +HB_CHS2LBA: +; + LD A,D ; HEAD TO A + RLCA ; LEFT SHIFT TO HIGH NIBBLE + RLCA ; ... DEPENDS ON HIGH + RLCA ; ... NIBBLE BEING 0 SINCE + RLCA ; ... IT ROTATES INTO LOW NIBBLE + OR E ; COMBINE WITH SECTOR (HIGH NIBBLE MUST BE ZERO) + LD D,0 + LD E,H + LD H,L + LD L,A + XOR A + RET +; +;================================================================================================== +; HBIOS GLOBAL DATA +;================================================================================================== +; +IDLECOUNT .DB 0 +; +HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION +; +HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER +; +STR_BANNER .DB "RetroBrew HBIOS v", BIOSVER, ", ", TIMESTAMP, "$" +STR_PLATFORM .DB PLATFORM_NAME, "$" +STR_SWITCH .DB "*** Activating CRT Console ***$" +STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" +; +HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) +; +HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) +; +HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER +; +HB_END .EQU $ +; +SLACK .EQU BNKTOP - $ + .ECHO "HBIOS space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +#IFDEF ROMBOOT + .FILL SLACK +#ENDIF +; + .END diff --git a/Source/hbios.inc b/Source/hbios.inc new file mode 100644 index 00000000..50e06531 --- /dev/null +++ b/Source/hbios.inc @@ -0,0 +1,187 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; HBIOS FUNCTIONS +; +BF_CIO .EQU $00 +BF_CIOIN .EQU BF_CIO + 0 ; CHARACTER INPUT +BF_CIOOUT .EQU BF_CIO + 1 ; CHARACTER OUTPUT +BF_CIOIST .EQU BF_CIO + 2 ; CHARACTER INPUT STATUS +BF_CIOOST .EQU BF_CIO + 3 ; CHARACTER OUTPUT STATUS +BF_CIOINIT .EQU BF_CIO + 4 ; INIT/RESET DEVICE/LINE CONFIG +BF_CIOQUERY .EQU BF_CIO + 5 ; REPORT DEVICE/LINE CONFIG +BF_CIODEVICE .EQU BF_CIO + 6 ; REPORT DEVICE INFO +; +BF_DIO .EQU $10 +BF_DIOSTATUS .EQU BF_DIO + 0 ; DISK STATUS +BF_DIORESET .EQU BF_DIO + 1 ; DISK RESET +BF_DIOSEEK .EQU BF_DIO + 2 ; DISK SEEK +BF_DIOREAD .EQU BF_DIO + 3 ; DISK READ SECTORS +BF_DIOWRITE .EQU BF_DIO + 4 ; DISK WRITE SECTORS +BF_DIOVERIFY .EQU BF_DIO + 5 ; DISK VERIFY SECTORS +BF_DIOFORMAT .EQU BF_DIO + 6 ; DISK FORMAT TRACK +BF_DIODEVICE .EQU BF_DIO + 7 ; DISK DEVICE INFO REPORT +BF_DIOMEDIA .EQU BF_DIO + 8 ; DISK MEDIA REPORT +BF_DIODEFMED .EQU BF_DIO + 9 ; DEFINE DISK MEDIA +BF_DIOCAP .EQU BF_DIO + 10 ; DISK CAPACITY REPORT +BF_DIOGEOM .EQU BF_DIO + 11 ; DISK GEOMETRY REPORT +; +BF_RTC .EQU $20 +BF_RTCGETTIM .EQU BF_RTC + 0 ; GET TIME +BF_RTCSETTIM .EQU BF_RTC + 1 ; SET TIME +BF_RTCGETBYT .EQU BF_RTC + 2 ; GET NVRAM BYTE BY INDEX +BF_RTCSETBYT .EQU BF_RTC + 3 ; SET NVRAM BYTE BY INDEX +BF_RTCGETBLK .EQU BF_RTC + 4 ; GET NVRAM DATA BLOCK +BF_RTCSETBLK .EQU BF_RTC + 5 ; SET NVRAM DATA BLOCK +; +BF_EMU .EQU $30 ; DEPRECATED +; +BF_VDA .EQU $40 +BF_VDAINI .EQU BF_VDA + 0 ; INITIALIZE VDU +BF_VDAQRY .EQU BF_VDA + 1 ; QUERY VDU STATUS +BF_VDARES .EQU BF_VDA + 2 ; SOFT RESET VDU +BF_VDADEV .EQU BF_VDA + 3 ; DEVICE INFO +BF_VDASCS .EQU BF_VDA + 4 ; SET CURSOR STYLE +BF_VDASCP .EQU BF_VDA + 5 ; SET CURSOR POSITION +BF_VDASAT .EQU BF_VDA + 6 ; SET CHARACTER ATTRIBUTE +BF_VDASCO .EQU BF_VDA + 7 ; SET CHARACTER COLOR +BF_VDAWRC .EQU BF_VDA + 8 ; WRITE CHARACTER +BF_VDAFIL .EQU BF_VDA + 9 ; FILL +BF_VDACPY .EQU BF_VDA + 10 ; COPY +BF_VDASCR .EQU BF_VDA + 11 ; SCROLL +BF_VDAKST .EQU BF_VDA + 12 ; GET KEYBOARD STATUS +BF_VDAKFL .EQU BF_VDA + 13 ; FLUSH KEYBOARD BUFFER +BF_VDAKRD .EQU BF_VDA + 14 ; READ KEYBOARD +; +BF_SYS .EQU $F0 +BF_SYSRESET .EQU BF_SYS + 0 ; SOFT RESET HBIOS +BF_SYSVER .EQU BF_SYS + 1 ; GET HBIOS VERSION +BF_SYSSETBNK .EQU BF_SYS + 2 ; SET CURRENT BANK +BF_SYSGETBNK .EQU BF_SYS + 3 ; GET CURRENT BANK +BF_SYSSETCPY .EQU BF_SYS + 4 ; BANK MEMORY COPY SETUP +BF_SYSBNKCPY .EQU BF_SYS + 5 ; BANK MEMORY COPY +BF_SYSALLOC .EQU BF_SYS + 6 ; ALLOC HBIOS HEAP MEMORY +BF_SYSFREE .EQU BF_SYS + 7 ; FREE HBIOS HEAP MEMORY +BF_SYSGET .EQU BF_SYS + 8 ; GET HBIOS INFO +BF_SYSSET .EQU BF_SYS + 9 ; SET HBIOS PARAMETERS +BF_SYSPEEK .EQU BF_SYS + 10 ; GET A BYTE VALUE FROM ALT BANK +BF_SYSPOKE .EQU BF_SYS + 11 ; SET A BYTE VALUE IN ALT BANK +BF_SYSINT .EQU BF_SYS + 12 ; MANAGE INTERRUPT VECTORS +; +BF_SYSGET_CIOCNT .EQU $00 ; GET CHAR UNIT COUNT +BF_SYSGET_DIOCNT .EQU $10 ; GET DISK UNIT COUNT +BF_SYSGET_VDACNT .EQU $40 ; GET VDA UNIT COUNT +BF_SYSGET_TIMER .EQU $D0 ; GET CURRENT TIMER VALUE +BF_SYSGET_BOOTINFO .EQU $E0 ; GET BOOT INFORMATION +BF_SYSGET_CPUINFO .EQU $F0 ; GET CPU INFORMATION +BF_SYSGET_MEMINFO .EQU $F1 ; GET MEMORY CAPACTITY INFO +BF_SYSGET_BNKINFO .EQU $F2 ; GET BANK ASSIGNMENT INFO +; +BF_SYSSET_TIMER .EQU $D0 ; SET TIMER VALUE +BF_SYSSET_BOOTINFO .EQU $E0 ; SET BOOT INFORMATION +; +BF_SYSINT_INFO .EQU $00 ; GET INTERRUPT SYSTEM INFO +BF_SYSINT_GET .EQU $10 ; GET INT VECTOR ADDRESS +BF_SYSINT_SET .EQU $20 ; SET INT VECTOR ADDRESS +; +; CHAR DEVICE IDS +; +CIODEV_UART .EQU $00 +CIODEV_ASCI .EQU $10 +CIODEV_TERM .EQU $20 +CIODEV_PRPCON .EQU $30 +CIODEV_PPPCON .EQU $40 +CIODEV_SIO .EQU $50 +CIODEV_ACIA .EQU $60 +CIODEV_CONSOLE .EQU $D0 +CIODEV_PIO .EQU $70 +; +; SUB TYPES OF CHAR DEVICES +; +;00 RS-232 +;01 TERMINAL +;02 PARALLEL PORT +;03 UNUSED +; +; DISK DEVICE IDS +; +DIODEV_MD .EQU $00 +DIODEV_FD .EQU $10 +DIODEV_RF .EQU $20 +DIODEV_IDE .EQU $30 +DIODEV_ATAPI .EQU $40 +DIODEV_PPIDE .EQU $50 +DIODEV_SD .EQU $60 +DIODEV_PRPSD .EQU $70 +DIODEV_PPPSD .EQU $80 +DIODEV_HDSK .EQU $90 +; +; VIDEO DEVICE IDS +; +VDADEV_VDU .EQU $00 ; ECB VDU - MOTOROLA 6545 +VDADEV_CVDU .EQU $10 ; ECB COLOR VDU - MOS 8563 +VDADEV_NEC .EQU $20 ; ECB UPD7220 - NEC UPD7220 +VDADEV_TMS .EQU $30 ; N8 ONBOARD VDA SUBSYSTEM - TMS 9918 +VDADEV_VGA .EQU $40 ; VGA +; +; EMULATION TYPES +; +EMUTYP_NONE .EQU 0 ; NONE +EMUTYP_TTY .EQU 1 ; TTY +EMUTYP_ANSI .EQU 2 ; ANSI +; +; HBIOS CONTROL BLOCK OFFSETS +; WARNING: THESE OFFSETS WILL CHANGE SIGNIFICANTLY BETWEEN RELEASES +; IT IS STRONGLY RECOMMENDED THAT YOU DO NOT USE THEM! +; +HCB_LOC .EQU $100 ; LOCATION OF HCB IN HBIOS BANK +HCB_SIZ .EQU $100 ; SIZE OF HCB DATA BLOCK +; +HCB_MARKER .EQU $03 ; MARKER ('W',~'W') (WORD) +HCB_VERSION .EQU $05 ; HBIOS VERSION NUM +HCB_PLATFORM .EQU $07 ; PLATFORM ID +HCB_CPUMHZ .EQU $08 ; CPU SPEED IN MHZ (BYTE) +HCB_CPUKHZ .EQU $09 ; CPU SPEED IN KHZ (WORD) +HCB_RAMBANKS .EQU $0B ; TOTAL SIZE OF RAM IN 32K BANKS (BYTE) +HCB_ROMBANKS .EQU $0C ; TOTAL SIZE OF ROM IN 32K BANKS (BYTE) +HCB_BOOTVOL .EQU $0D ; BOOT VOLUME, MSB=DEV/UNIT, LSB=LU (WORD) +HCB_BOOTBID .EQU $0F ; BANK ID OF ROM PAGE BOOTED (BYTE) +HCB_SERDEV .EQU $10 ; PRIMARY SERIAL DEVICE/UNIT (BYTE) +HCB_CRTDEV .EQU $11 ; CRT DISPLAY DEVICE/UNIT (BYTE) +HCB_CONDEV .EQU $12 ; ACTIVE CONSOLE DEVICE/UNIT (BYTE) +;HCB_CUREMU .EQU $13 ; CURRENT VDA TERMINAL EMULATION (DEPRECATED) +;HCB_CURVDA .EQU $14 ; CURRENT VDA TARGET FOR EMULATION (DEPRECATED) +; +HCB_HEAP .EQU $20 ; DWORD ADDRESS OF START OF HEAP +HCB_HEAPTOP .EQU $22 ; DWORD ADDRESS OF TOP OF HEAP +; +; MEMORY BANK IDS (ONE BYTE EACH) +HCB_BIDCOM .EQU $D8 ; COMMON BANK (UPPER 32K) +HCB_BIDUSR .EQU $D9 ; USER BANK (TPA) +HCB_BIDBIOS .EQU $DA ; BIOS BANK (HBIOS, UBIOS) +HCB_BIDAUX .EQU $DB ; AUX BANK (BPBIOS) +HCB_BIDRAMD0 .EQU $DC ; FIRST BANK OF RAM DRIVE +HCB_BIDRAMDN .EQU $DD ; LAST BANK OF RAM DRIVE +HCB_BIDROMD0 .EQU $DE ; FIRST BANK OF ROM DRIVE +HCB_BIDROMDN .EQU $DF ; LAST BANK OF ROM DRIVE +; +; HBIOS PROXY COMMON DATA BLOCK +; EXACTLY 32 BYTES AT $FFE0-$FFFF +; +HBX_XFC .EQU $10000 - $20 ; HBIOS PROXY INTERFACE AREA, 32 BYTES FIXED +; +HBX_XFCDAT .EQU HBX_XFC ; DATA PORTION OF HBIOS PROXY INTERFACE AREA +HB_CURBNK .EQU HBX_XFCDAT + 0 ; CURRENTLY ACTIVE LOW MEMORY BANK ID +HB_INVBNK .EQU HBX_XFCDAT + 1 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION +HB_SRCADR .EQU HBX_XFCDAT + 2 ; BNKCPY: DESTINATION BANK ID +HB_SRCBNK .EQU HBX_XFCDAT + 4 ; BNKCPY: SOURCE BANK ID +HB_DSTADR .EQU HBX_XFCDAT + 5 ; BNKCPY: DESTINATION ADDRESS +HB_DSTBNK .EQU HBX_XFCDAT + 7 ; BNKCPY: SOURCE ADDRESS +HB_CPYLEN .EQU HBX_XFCDAT + 8 ; BNKCPY: COPY LENGTH +; +HBX_XFCFNS .EQU HBX_XFC + $10 ; JUMP TABLE PORTION OF HBIOS PROXY INTERFACE AREA +HB_INVOKE .EQU HBX_XFCFNS + (0 * 3) ; INVOKE HBIOS FUNCTION +HB_BNKSEL .EQU HBX_XFCFNS + (1 * 3) ; SELECT LOW MEMORY BANK ID +HB_BNKCPY .EQU HBX_XFCFNS + (2 * 3) ; INTERBANK MEMORY COPY +HB_BNKCALL .EQU HBX_XFCFNS + (3 * 3) ; INTERBANK FUNCTION CALL +;HB_LOC .EQU HBX_XFCFNS + 12 ; ADDRESS OF HBIOS PROXY START (DEPRECATED) +HB_IDENT .EQU HBX_XFCFNS + 14 ; POINTER TO HBIOS IDENT DATA BLOCK diff --git a/Source/pio.asm b/Source/pio.asm new file mode 100644 index 00000000..580f0f73 --- /dev/null +++ b/Source/pio.asm @@ -0,0 +1,350 @@ + +PIO0A .EQU ; ECB-ZP +PIO0B .EQU ; ECB-ZP +PIO1A .EQU ; ECB-ZP +PIO1B .EQU ; ECB-ZP + +PIO2A .EQU ; ECB-4PIO +PIO2B .EQU ; ECB-4PIO +PIO3A .EQU ; ECB-4PIO +PIO3B .EQU ; ECB-4PIO +PIO4A .EQU ; ECB-4PIO +PIO4B .EQU ; ECB-4PIO +PIO5A .EQU ; ECB-4PIO +PIO5B .EQU ; ECB-4PIO + +PIO_Input .EQU $0000 +PIO_Output .EQU $0001 +PIO_BiDir .Equ $0002 + +DEFPIOCFGA .EQU $8000 + PIO_Input +DEFPIOCFGB .EQU $8000 + PIO_Output +DEFPIOCFGX .EQU $8000 + PIO_BiDir + +PIO_NONE .EQU 0 +PIO_ZPIO .EQU 1 +PIO_8255 .EQU 2 +; +PIO_PREINIT: +; +; SETUP THE DISPATCH TABLE ENTRIES +; + LD B,PIO_CNT ; LOOP CONTROL + LD C,0 ; PHYSICAL UNIT INDEX + XOR A ; ZERO TO ACCUM + LD (PIO_DEV),A ; CURRENT DEVICE NUMBER +PIO_PREINIT0: + PUSH BC ; SAVE LOOP CONTROL + LD A,C ; PHYSICAL UNIT TO A + RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) + RLCA ; ... + RLCA ; ... TO GET OFFSET INTO CFG TABLE + LD HL,PIO_CFG ; POINT TO START OF CFG TABLE + CALL ADDHLA ; HL := ENTRY ADDRESS + PUSH HL ; SAVE IT + PUSH HL ; COPY CFG DATA PTR + POP IY ; ... TO IY + CALL PIO_INITUNIT ; HAND OFF TO GENERIC INIT CODE + POP DE ; GET ENTRY ADDRESS BACK, BUT PUT IN DE + POP BC ; RESTORE LOOP CONTROL +; + LD A,(IY+1) ; GET THE PIO TYPE DETECTED + OR A ; SET FLAGS + JR Z,PIO_PREINIT2 ; SKIP IT IF NOTHING FOUND +; + PUSH BC ; SAVE LOOP CONTROL + LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS + CALL NZ,CIO_ADDENT ; ADD ENTRY IF PIO FOUND, BC:DE + POP BC ; RESTORE LOOP CONTROL +; +PIO_PREINIT2: + INC C ; NEXT PHYSICAL UNIT + DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE +; +;#IF (INTMODE == 1) +; ; ADD IM1 INT CALL LIST ENTRY IF APPROPRIATE +; LD A,(SIO_DEV) ; GET NEXT DEVICE NUM +; OR A ; SET FLAGS +; JR Z,PIO_PREINIT3 ; IF ZERO, NO SIO DEVICES +; LD HL,PIO_INT ; GET INT VECTOR +; CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST +;#ENDIF +; +;#IF (INTMODE == 2) +; ; SETUP SIO INTERRUPT VECTOR IN IVT +; LD HL,INT_PIO +; LD (HBX_IVT + IVT_SER0),HL +;#ENDIF +; +PIO_PREINIT3: + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +PIO_INITUNIT: + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +PIO_INIT: + LD B,PIO_CNT ; COUNT OF POSSIBLE SIO UNITS + LD C,0 ; INDEX INTO SIO CONFIG TABLE +PIO_INIT1: + PUSH BC ; SAVE LOOP CONTROL + + LD A,C ; PHYSICAL UNIT TO A + RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) + RLCA ; ... + RLCA ; ... TO GET OFFSET INTO CFG TABLE + LD HL,PIO_CFG ; POINT TO START OF CFG TABLE + CALL ADDHLA ; HL := ENTRY ADDRESS + PUSH HL ; COPY CFG DATA PTR + POP IY ; ... TO IY + + LD A,(IY+1) ; GET PIO TYPE + OR A ; SET FLAGS + CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO + + POP BC ; RESTORE LOOP CONTROL + INC C ; NEXT UNIT + DJNZ PIO_INIT1 ; LOOP TILL DONE +; + XOR A ; SIGNAL SUCCESS + RET ; DONE + +; +PIO_LPT: + IN A,($F6) ; get device status + AND $20 ; device ready? + JR Z,PIO_LPT ; no, busy wait + IN A,($F5) ; get transmit buffer register status ready? + AND $20 ; ready? + JR Z,PIO_LPT ; no, busy wait + LD A,C ; ready, char A for output through data port + OUT ($F0),A ; output char + RET +; +; PIO PORT TABLE +; +PIO_CFG: + ; PIO CHANNEL A + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB PIOBASE+2 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 1 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB PIOBASE+3 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 2 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB PIOBASE+6 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 3 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB PIOBASE+7 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT + ; PIO CHANNEL A + .DB 4 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+2 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGX ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 5 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+3 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 6 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+6 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 7 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+7 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 8 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+10 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 9 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+11 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 10 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 11 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL A + .DB 12 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) + .DB 0 ; PIO CHANNEL (A) + .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO CHANNEL B + .DB 13 ; DEVICE NUMBER (SET DURING INIT) + .DB PIO_8255 ; PIO TYPE (SET DURING INIT) + .DB 1 ; PIO CHANNEL (B) + .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) + .DW DEFPIOCFGB ; LINE CONFIGURATION + .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT + ; +; +PIO_CNT .EQU ($ - PIO_CFG) / 8 +; +; DRIVER FUNCTION TABLE +; +PIO_FNTBL: + .DW PIO_IN + .DW PIO_OUT + .DW PIO_IST + .DW PIO_OST + .DW PIO_INITDEV + .DW PIO_QUERY + .DW PIO_DEVICE +#IF (($ - PIO_FNTBL) != (CIO_FNCNT * 2)) + .ECHO "*** INVALID SIO FUNCTION TABLE ***\n" +#ENDIF +; +PIO_OUT: + XOR A ; SIGNAL SUCCESS + RET +; +PIO_IN: + XOR A ; SIGNAL SUCCESS + RET +; +PIO_IST: + RET +; +PIO_OST: + RET +; +; PIO_INITDEV - Configure device. +; If DE = FFFF then extract the configuratio information from the table of devices and program the device using those settings. +; Otherwise use the configuration information in DE to program those settings and save them in the device table + +PIO_INITDEV: + XOR A ; SIGNAL SUCCESS + RET +; +PIO_QUERY: + LD E,(IY+4) ; FIRST CONFIG BYTE TO E + LD D,(IY+5) ; SECOND CONFIG BYTE TO D + XOR A ; SIGNAL SUCCESS + RET +; +; +;TTY_DEVICE: +; LD D,CIODEV_TERM ; TYPE IS TERMINAL +; LD A,(TTY_DEVNUM) ; GET DEVICE NUMBER +; LD E,A ; PUT IT IN E +; LD A,(TTY_VDAUNIT) ; GET VDA UNIT NUM +; SET 7,A ; SET BIT 7 TO INDICATE TERMINAL TYPE +; LD C,A ; PUT IT IN C +; XOR A ; SIGNAL SUCCESS +; RET +; +; +PIO_DEVICE: + LD D,CIODEV_PIO ; D := DEVICE TYPE + LD E,(IY) ; E := PHYSICAL UNIT + LD A,E + SET 7,A + LD C,A + XOR A ; SIGNAL SUCCESS + RET +; +PIO_PRTCFG: + ; ANNOUNCE PORT + CALL NEWLINE ; FORMATTING + PRTS("PIO$") ; FORMATTING + LD A,(IY) ; DEVICE NUM + CALL PRTDECB ; PRINT DEVICE NUM + PRTS(": IO=0x$") ; FORMATTING + LD A,(IY+3) ; GET BASE PORT + CALL PRTHEXBYTE ; PRINT BASE PORT +; + ; PRINT THE PIO TYPE + CALL PC_SPACE ; FORMATTING + LD A,(IY+1) ; GET PIO TYPE BYTE + RLCA ; MAKE IT A WORD OFFSET + LD HL,PIO_TYPE_MAP ; POINT HL TO TYPE MAP TABLE + CALL ADDHLA ; HL := ENTRY + LD E,(HL) ; DEREFERENCE + INC HL ; ... + LD D,(HL) ; ... TO GET STRING POINTER + CALL WRITESTR ; PRINT IT +; + ; ALL DONE IF NO PIO WAS DETECTED + LD A,(IY+1) ; GET SIO TYPE BYTE + OR A ; SET FLAGS + RET Z ; IF ZERO, NOT PRESENT +; + PRTS(" MODE=$") ; FORMATTING + LD E,(IY+4) ; LOAD CONFIG + LD D,(IY+5) ; ... WORD TO DE + CALL PS_PRTPC0 ; PRINT CONFIG +; + XOR A + RET +; +; WORKING VARIABLES +; +PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT +; +PIO_TYPE_MAP: + .DW PIO_STR_NONE + .DW PIO_STR_PIO + .DW PIO_STR_8255 + +PIO_STR_NONE .DB "$" +PIO_STR_PIO .DB "Zilog PIO$" +PIO_STR_8255 .DB "i8255 PIO$" \ No newline at end of file From f7fc9dc5644c4ab1916c39ab97b1e42afc2177f8 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 7 Oct 2018 17:10:15 +0800 Subject: [PATCH 04/18] Delete pio.asm --- Source/pio.asm | 350 ------------------------------------------------- 1 file changed, 350 deletions(-) delete mode 100644 Source/pio.asm diff --git a/Source/pio.asm b/Source/pio.asm deleted file mode 100644 index 580f0f73..00000000 --- a/Source/pio.asm +++ /dev/null @@ -1,350 +0,0 @@ - -PIO0A .EQU ; ECB-ZP -PIO0B .EQU ; ECB-ZP -PIO1A .EQU ; ECB-ZP -PIO1B .EQU ; ECB-ZP - -PIO2A .EQU ; ECB-4PIO -PIO2B .EQU ; ECB-4PIO -PIO3A .EQU ; ECB-4PIO -PIO3B .EQU ; ECB-4PIO -PIO4A .EQU ; ECB-4PIO -PIO4B .EQU ; ECB-4PIO -PIO5A .EQU ; ECB-4PIO -PIO5B .EQU ; ECB-4PIO - -PIO_Input .EQU $0000 -PIO_Output .EQU $0001 -PIO_BiDir .Equ $0002 - -DEFPIOCFGA .EQU $8000 + PIO_Input -DEFPIOCFGB .EQU $8000 + PIO_Output -DEFPIOCFGX .EQU $8000 + PIO_BiDir - -PIO_NONE .EQU 0 -PIO_ZPIO .EQU 1 -PIO_8255 .EQU 2 -; -PIO_PREINIT: -; -; SETUP THE DISPATCH TABLE ENTRIES -; - LD B,PIO_CNT ; LOOP CONTROL - LD C,0 ; PHYSICAL UNIT INDEX - XOR A ; ZERO TO ACCUM - LD (PIO_DEV),A ; CURRENT DEVICE NUMBER -PIO_PREINIT0: - PUSH BC ; SAVE LOOP CONTROL - LD A,C ; PHYSICAL UNIT TO A - RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) - RLCA ; ... - RLCA ; ... TO GET OFFSET INTO CFG TABLE - LD HL,PIO_CFG ; POINT TO START OF CFG TABLE - CALL ADDHLA ; HL := ENTRY ADDRESS - PUSH HL ; SAVE IT - PUSH HL ; COPY CFG DATA PTR - POP IY ; ... TO IY - CALL PIO_INITUNIT ; HAND OFF TO GENERIC INIT CODE - POP DE ; GET ENTRY ADDRESS BACK, BUT PUT IN DE - POP BC ; RESTORE LOOP CONTROL -; - LD A,(IY+1) ; GET THE PIO TYPE DETECTED - OR A ; SET FLAGS - JR Z,PIO_PREINIT2 ; SKIP IT IF NOTHING FOUND -; - PUSH BC ; SAVE LOOP CONTROL - LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS - CALL NZ,CIO_ADDENT ; ADD ENTRY IF PIO FOUND, BC:DE - POP BC ; RESTORE LOOP CONTROL -; -PIO_PREINIT2: - INC C ; NEXT PHYSICAL UNIT - DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE -; -;#IF (INTMODE == 1) -; ; ADD IM1 INT CALL LIST ENTRY IF APPROPRIATE -; LD A,(SIO_DEV) ; GET NEXT DEVICE NUM -; OR A ; SET FLAGS -; JR Z,PIO_PREINIT3 ; IF ZERO, NO SIO DEVICES -; LD HL,PIO_INT ; GET INT VECTOR -; CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST -;#ENDIF -; -;#IF (INTMODE == 2) -; ; SETUP SIO INTERRUPT VECTOR IN IVT -; LD HL,INT_PIO -; LD (HBX_IVT + IVT_SER0),HL -;#ENDIF -; -PIO_PREINIT3: - XOR A ; SIGNAL SUCCESS - RET ; AND RETURN -; -PIO_INITUNIT: - XOR A ; SIGNAL SUCCESS - RET ; AND RETURN -; -PIO_INIT: - LD B,PIO_CNT ; COUNT OF POSSIBLE SIO UNITS - LD C,0 ; INDEX INTO SIO CONFIG TABLE -PIO_INIT1: - PUSH BC ; SAVE LOOP CONTROL - - LD A,C ; PHYSICAL UNIT TO A - RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (8 BYTES) - RLCA ; ... - RLCA ; ... TO GET OFFSET INTO CFG TABLE - LD HL,PIO_CFG ; POINT TO START OF CFG TABLE - CALL ADDHLA ; HL := ENTRY ADDRESS - PUSH HL ; COPY CFG DATA PTR - POP IY ; ... TO IY - - LD A,(IY+1) ; GET PIO TYPE - OR A ; SET FLAGS - CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO - - POP BC ; RESTORE LOOP CONTROL - INC C ; NEXT UNIT - DJNZ PIO_INIT1 ; LOOP TILL DONE -; - XOR A ; SIGNAL SUCCESS - RET ; DONE - -; -PIO_LPT: - IN A,($F6) ; get device status - AND $20 ; device ready? - JR Z,PIO_LPT ; no, busy wait - IN A,($F5) ; get transmit buffer register status ready? - AND $20 ; ready? - JR Z,PIO_LPT ; no, busy wait - LD A,C ; ready, char A for output through data port - OUT ($F0),A ; output char - RET -; -; PIO PORT TABLE -; -PIO_CFG: - ; PIO CHANNEL A - .DB 0 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB PIOBASE+2 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 1 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB PIOBASE+3 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL A - .DB 2 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB PIOBASE+6 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 3 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB PIOBASE+7 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT - ; PIO CHANNEL A - .DB 4 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB 4PIOBASE+2 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGX ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 5 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB 4PIOBASE+3 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL A - .DB 6 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB 4PIOBASE+6 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 7 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB 4PIOBASE+7 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL A - .DB 8 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB 4PIOBASE+10 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 9 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB 4PIOBASE+11 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL A - .DB 10 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 11 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL A - .DB 12 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) - .DB 0 ; PIO CHANNEL (A) - .DB 4PIOBASE+14 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION - .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT -; - ; PIO CHANNEL B - .DB 13 ; DEVICE NUMBER (SET DURING INIT) - .DB PIO_8255 ; PIO TYPE (SET DURING INIT) - .DB 1 ; PIO CHANNEL (B) - .DB 4PIOBASE+15 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGB ; LINE CONFIGURATION - .DW SIOB_RCVBUF ; POINTER TO RCV BUFFER STRUCT - ; -; -PIO_CNT .EQU ($ - PIO_CFG) / 8 -; -; DRIVER FUNCTION TABLE -; -PIO_FNTBL: - .DW PIO_IN - .DW PIO_OUT - .DW PIO_IST - .DW PIO_OST - .DW PIO_INITDEV - .DW PIO_QUERY - .DW PIO_DEVICE -#IF (($ - PIO_FNTBL) != (CIO_FNCNT * 2)) - .ECHO "*** INVALID SIO FUNCTION TABLE ***\n" -#ENDIF -; -PIO_OUT: - XOR A ; SIGNAL SUCCESS - RET -; -PIO_IN: - XOR A ; SIGNAL SUCCESS - RET -; -PIO_IST: - RET -; -PIO_OST: - RET -; -; PIO_INITDEV - Configure device. -; If DE = FFFF then extract the configuratio information from the table of devices and program the device using those settings. -; Otherwise use the configuration information in DE to program those settings and save them in the device table - -PIO_INITDEV: - XOR A ; SIGNAL SUCCESS - RET -; -PIO_QUERY: - LD E,(IY+4) ; FIRST CONFIG BYTE TO E - LD D,(IY+5) ; SECOND CONFIG BYTE TO D - XOR A ; SIGNAL SUCCESS - RET -; -; -;TTY_DEVICE: -; LD D,CIODEV_TERM ; TYPE IS TERMINAL -; LD A,(TTY_DEVNUM) ; GET DEVICE NUMBER -; LD E,A ; PUT IT IN E -; LD A,(TTY_VDAUNIT) ; GET VDA UNIT NUM -; SET 7,A ; SET BIT 7 TO INDICATE TERMINAL TYPE -; LD C,A ; PUT IT IN C -; XOR A ; SIGNAL SUCCESS -; RET -; -; -PIO_DEVICE: - LD D,CIODEV_PIO ; D := DEVICE TYPE - LD E,(IY) ; E := PHYSICAL UNIT - LD A,E - SET 7,A - LD C,A - XOR A ; SIGNAL SUCCESS - RET -; -PIO_PRTCFG: - ; ANNOUNCE PORT - CALL NEWLINE ; FORMATTING - PRTS("PIO$") ; FORMATTING - LD A,(IY) ; DEVICE NUM - CALL PRTDECB ; PRINT DEVICE NUM - PRTS(": IO=0x$") ; FORMATTING - LD A,(IY+3) ; GET BASE PORT - CALL PRTHEXBYTE ; PRINT BASE PORT -; - ; PRINT THE PIO TYPE - CALL PC_SPACE ; FORMATTING - LD A,(IY+1) ; GET PIO TYPE BYTE - RLCA ; MAKE IT A WORD OFFSET - LD HL,PIO_TYPE_MAP ; POINT HL TO TYPE MAP TABLE - CALL ADDHLA ; HL := ENTRY - LD E,(HL) ; DEREFERENCE - INC HL ; ... - LD D,(HL) ; ... TO GET STRING POINTER - CALL WRITESTR ; PRINT IT -; - ; ALL DONE IF NO PIO WAS DETECTED - LD A,(IY+1) ; GET SIO TYPE BYTE - OR A ; SET FLAGS - RET Z ; IF ZERO, NOT PRESENT -; - PRTS(" MODE=$") ; FORMATTING - LD E,(IY+4) ; LOAD CONFIG - LD D,(IY+5) ; ... WORD TO DE - CALL PS_PRTPC0 ; PRINT CONFIG -; - XOR A - RET -; -; WORKING VARIABLES -; -PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT -; -PIO_TYPE_MAP: - .DW PIO_STR_NONE - .DW PIO_STR_PIO - .DW PIO_STR_8255 - -PIO_STR_NONE .DB "$" -PIO_STR_PIO .DB "Zilog PIO$" -PIO_STR_8255 .DB "i8255 PIO$" \ No newline at end of file From b5b29fcb324af51afcf4f2ebeeebb3b87b37fcf3 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 7 Oct 2018 17:10:41 +0800 Subject: [PATCH 05/18] Delete hbios.inc --- Source/hbios.inc | 187 ----------------------------------------------- 1 file changed, 187 deletions(-) delete mode 100644 Source/hbios.inc diff --git a/Source/hbios.inc b/Source/hbios.inc deleted file mode 100644 index 50e06531..00000000 --- a/Source/hbios.inc +++ /dev/null @@ -1,187 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; HBIOS FUNCTIONS -; -BF_CIO .EQU $00 -BF_CIOIN .EQU BF_CIO + 0 ; CHARACTER INPUT -BF_CIOOUT .EQU BF_CIO + 1 ; CHARACTER OUTPUT -BF_CIOIST .EQU BF_CIO + 2 ; CHARACTER INPUT STATUS -BF_CIOOST .EQU BF_CIO + 3 ; CHARACTER OUTPUT STATUS -BF_CIOINIT .EQU BF_CIO + 4 ; INIT/RESET DEVICE/LINE CONFIG -BF_CIOQUERY .EQU BF_CIO + 5 ; REPORT DEVICE/LINE CONFIG -BF_CIODEVICE .EQU BF_CIO + 6 ; REPORT DEVICE INFO -; -BF_DIO .EQU $10 -BF_DIOSTATUS .EQU BF_DIO + 0 ; DISK STATUS -BF_DIORESET .EQU BF_DIO + 1 ; DISK RESET -BF_DIOSEEK .EQU BF_DIO + 2 ; DISK SEEK -BF_DIOREAD .EQU BF_DIO + 3 ; DISK READ SECTORS -BF_DIOWRITE .EQU BF_DIO + 4 ; DISK WRITE SECTORS -BF_DIOVERIFY .EQU BF_DIO + 5 ; DISK VERIFY SECTORS -BF_DIOFORMAT .EQU BF_DIO + 6 ; DISK FORMAT TRACK -BF_DIODEVICE .EQU BF_DIO + 7 ; DISK DEVICE INFO REPORT -BF_DIOMEDIA .EQU BF_DIO + 8 ; DISK MEDIA REPORT -BF_DIODEFMED .EQU BF_DIO + 9 ; DEFINE DISK MEDIA -BF_DIOCAP .EQU BF_DIO + 10 ; DISK CAPACITY REPORT -BF_DIOGEOM .EQU BF_DIO + 11 ; DISK GEOMETRY REPORT -; -BF_RTC .EQU $20 -BF_RTCGETTIM .EQU BF_RTC + 0 ; GET TIME -BF_RTCSETTIM .EQU BF_RTC + 1 ; SET TIME -BF_RTCGETBYT .EQU BF_RTC + 2 ; GET NVRAM BYTE BY INDEX -BF_RTCSETBYT .EQU BF_RTC + 3 ; SET NVRAM BYTE BY INDEX -BF_RTCGETBLK .EQU BF_RTC + 4 ; GET NVRAM DATA BLOCK -BF_RTCSETBLK .EQU BF_RTC + 5 ; SET NVRAM DATA BLOCK -; -BF_EMU .EQU $30 ; DEPRECATED -; -BF_VDA .EQU $40 -BF_VDAINI .EQU BF_VDA + 0 ; INITIALIZE VDU -BF_VDAQRY .EQU BF_VDA + 1 ; QUERY VDU STATUS -BF_VDARES .EQU BF_VDA + 2 ; SOFT RESET VDU -BF_VDADEV .EQU BF_VDA + 3 ; DEVICE INFO -BF_VDASCS .EQU BF_VDA + 4 ; SET CURSOR STYLE -BF_VDASCP .EQU BF_VDA + 5 ; SET CURSOR POSITION -BF_VDASAT .EQU BF_VDA + 6 ; SET CHARACTER ATTRIBUTE -BF_VDASCO .EQU BF_VDA + 7 ; SET CHARACTER COLOR -BF_VDAWRC .EQU BF_VDA + 8 ; WRITE CHARACTER -BF_VDAFIL .EQU BF_VDA + 9 ; FILL -BF_VDACPY .EQU BF_VDA + 10 ; COPY -BF_VDASCR .EQU BF_VDA + 11 ; SCROLL -BF_VDAKST .EQU BF_VDA + 12 ; GET KEYBOARD STATUS -BF_VDAKFL .EQU BF_VDA + 13 ; FLUSH KEYBOARD BUFFER -BF_VDAKRD .EQU BF_VDA + 14 ; READ KEYBOARD -; -BF_SYS .EQU $F0 -BF_SYSRESET .EQU BF_SYS + 0 ; SOFT RESET HBIOS -BF_SYSVER .EQU BF_SYS + 1 ; GET HBIOS VERSION -BF_SYSSETBNK .EQU BF_SYS + 2 ; SET CURRENT BANK -BF_SYSGETBNK .EQU BF_SYS + 3 ; GET CURRENT BANK -BF_SYSSETCPY .EQU BF_SYS + 4 ; BANK MEMORY COPY SETUP -BF_SYSBNKCPY .EQU BF_SYS + 5 ; BANK MEMORY COPY -BF_SYSALLOC .EQU BF_SYS + 6 ; ALLOC HBIOS HEAP MEMORY -BF_SYSFREE .EQU BF_SYS + 7 ; FREE HBIOS HEAP MEMORY -BF_SYSGET .EQU BF_SYS + 8 ; GET HBIOS INFO -BF_SYSSET .EQU BF_SYS + 9 ; SET HBIOS PARAMETERS -BF_SYSPEEK .EQU BF_SYS + 10 ; GET A BYTE VALUE FROM ALT BANK -BF_SYSPOKE .EQU BF_SYS + 11 ; SET A BYTE VALUE IN ALT BANK -BF_SYSINT .EQU BF_SYS + 12 ; MANAGE INTERRUPT VECTORS -; -BF_SYSGET_CIOCNT .EQU $00 ; GET CHAR UNIT COUNT -BF_SYSGET_DIOCNT .EQU $10 ; GET DISK UNIT COUNT -BF_SYSGET_VDACNT .EQU $40 ; GET VDA UNIT COUNT -BF_SYSGET_TIMER .EQU $D0 ; GET CURRENT TIMER VALUE -BF_SYSGET_BOOTINFO .EQU $E0 ; GET BOOT INFORMATION -BF_SYSGET_CPUINFO .EQU $F0 ; GET CPU INFORMATION -BF_SYSGET_MEMINFO .EQU $F1 ; GET MEMORY CAPACTITY INFO -BF_SYSGET_BNKINFO .EQU $F2 ; GET BANK ASSIGNMENT INFO -; -BF_SYSSET_TIMER .EQU $D0 ; SET TIMER VALUE -BF_SYSSET_BOOTINFO .EQU $E0 ; SET BOOT INFORMATION -; -BF_SYSINT_INFO .EQU $00 ; GET INTERRUPT SYSTEM INFO -BF_SYSINT_GET .EQU $10 ; GET INT VECTOR ADDRESS -BF_SYSINT_SET .EQU $20 ; SET INT VECTOR ADDRESS -; -; CHAR DEVICE IDS -; -CIODEV_UART .EQU $00 -CIODEV_ASCI .EQU $10 -CIODEV_TERM .EQU $20 -CIODEV_PRPCON .EQU $30 -CIODEV_PPPCON .EQU $40 -CIODEV_SIO .EQU $50 -CIODEV_ACIA .EQU $60 -CIODEV_CONSOLE .EQU $D0 -CIODEV_PIO .EQU $70 -; -; SUB TYPES OF CHAR DEVICES -; -;00 RS-232 -;01 TERMINAL -;02 PARALLEL PORT -;03 UNUSED -; -; DISK DEVICE IDS -; -DIODEV_MD .EQU $00 -DIODEV_FD .EQU $10 -DIODEV_RF .EQU $20 -DIODEV_IDE .EQU $30 -DIODEV_ATAPI .EQU $40 -DIODEV_PPIDE .EQU $50 -DIODEV_SD .EQU $60 -DIODEV_PRPSD .EQU $70 -DIODEV_PPPSD .EQU $80 -DIODEV_HDSK .EQU $90 -; -; VIDEO DEVICE IDS -; -VDADEV_VDU .EQU $00 ; ECB VDU - MOTOROLA 6545 -VDADEV_CVDU .EQU $10 ; ECB COLOR VDU - MOS 8563 -VDADEV_NEC .EQU $20 ; ECB UPD7220 - NEC UPD7220 -VDADEV_TMS .EQU $30 ; N8 ONBOARD VDA SUBSYSTEM - TMS 9918 -VDADEV_VGA .EQU $40 ; VGA -; -; EMULATION TYPES -; -EMUTYP_NONE .EQU 0 ; NONE -EMUTYP_TTY .EQU 1 ; TTY -EMUTYP_ANSI .EQU 2 ; ANSI -; -; HBIOS CONTROL BLOCK OFFSETS -; WARNING: THESE OFFSETS WILL CHANGE SIGNIFICANTLY BETWEEN RELEASES -; IT IS STRONGLY RECOMMENDED THAT YOU DO NOT USE THEM! -; -HCB_LOC .EQU $100 ; LOCATION OF HCB IN HBIOS BANK -HCB_SIZ .EQU $100 ; SIZE OF HCB DATA BLOCK -; -HCB_MARKER .EQU $03 ; MARKER ('W',~'W') (WORD) -HCB_VERSION .EQU $05 ; HBIOS VERSION NUM -HCB_PLATFORM .EQU $07 ; PLATFORM ID -HCB_CPUMHZ .EQU $08 ; CPU SPEED IN MHZ (BYTE) -HCB_CPUKHZ .EQU $09 ; CPU SPEED IN KHZ (WORD) -HCB_RAMBANKS .EQU $0B ; TOTAL SIZE OF RAM IN 32K BANKS (BYTE) -HCB_ROMBANKS .EQU $0C ; TOTAL SIZE OF ROM IN 32K BANKS (BYTE) -HCB_BOOTVOL .EQU $0D ; BOOT VOLUME, MSB=DEV/UNIT, LSB=LU (WORD) -HCB_BOOTBID .EQU $0F ; BANK ID OF ROM PAGE BOOTED (BYTE) -HCB_SERDEV .EQU $10 ; PRIMARY SERIAL DEVICE/UNIT (BYTE) -HCB_CRTDEV .EQU $11 ; CRT DISPLAY DEVICE/UNIT (BYTE) -HCB_CONDEV .EQU $12 ; ACTIVE CONSOLE DEVICE/UNIT (BYTE) -;HCB_CUREMU .EQU $13 ; CURRENT VDA TERMINAL EMULATION (DEPRECATED) -;HCB_CURVDA .EQU $14 ; CURRENT VDA TARGET FOR EMULATION (DEPRECATED) -; -HCB_HEAP .EQU $20 ; DWORD ADDRESS OF START OF HEAP -HCB_HEAPTOP .EQU $22 ; DWORD ADDRESS OF TOP OF HEAP -; -; MEMORY BANK IDS (ONE BYTE EACH) -HCB_BIDCOM .EQU $D8 ; COMMON BANK (UPPER 32K) -HCB_BIDUSR .EQU $D9 ; USER BANK (TPA) -HCB_BIDBIOS .EQU $DA ; BIOS BANK (HBIOS, UBIOS) -HCB_BIDAUX .EQU $DB ; AUX BANK (BPBIOS) -HCB_BIDRAMD0 .EQU $DC ; FIRST BANK OF RAM DRIVE -HCB_BIDRAMDN .EQU $DD ; LAST BANK OF RAM DRIVE -HCB_BIDROMD0 .EQU $DE ; FIRST BANK OF ROM DRIVE -HCB_BIDROMDN .EQU $DF ; LAST BANK OF ROM DRIVE -; -; HBIOS PROXY COMMON DATA BLOCK -; EXACTLY 32 BYTES AT $FFE0-$FFFF -; -HBX_XFC .EQU $10000 - $20 ; HBIOS PROXY INTERFACE AREA, 32 BYTES FIXED -; -HBX_XFCDAT .EQU HBX_XFC ; DATA PORTION OF HBIOS PROXY INTERFACE AREA -HB_CURBNK .EQU HBX_XFCDAT + 0 ; CURRENTLY ACTIVE LOW MEMORY BANK ID -HB_INVBNK .EQU HBX_XFCDAT + 1 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION -HB_SRCADR .EQU HBX_XFCDAT + 2 ; BNKCPY: DESTINATION BANK ID -HB_SRCBNK .EQU HBX_XFCDAT + 4 ; BNKCPY: SOURCE BANK ID -HB_DSTADR .EQU HBX_XFCDAT + 5 ; BNKCPY: DESTINATION ADDRESS -HB_DSTBNK .EQU HBX_XFCDAT + 7 ; BNKCPY: SOURCE ADDRESS -HB_CPYLEN .EQU HBX_XFCDAT + 8 ; BNKCPY: COPY LENGTH -; -HBX_XFCFNS .EQU HBX_XFC + $10 ; JUMP TABLE PORTION OF HBIOS PROXY INTERFACE AREA -HB_INVOKE .EQU HBX_XFCFNS + (0 * 3) ; INVOKE HBIOS FUNCTION -HB_BNKSEL .EQU HBX_XFCFNS + (1 * 3) ; SELECT LOW MEMORY BANK ID -HB_BNKCPY .EQU HBX_XFCFNS + (2 * 3) ; INTERBANK MEMORY COPY -HB_BNKCALL .EQU HBX_XFCFNS + (3 * 3) ; INTERBANK FUNCTION CALL -;HB_LOC .EQU HBX_XFCFNS + 12 ; ADDRESS OF HBIOS PROXY START (DEPRECATED) -HB_IDENT .EQU HBX_XFCFNS + 14 ; POINTER TO HBIOS IDENT DATA BLOCK From 9d372a54ccd6e60979b8f61855fe5535624df265 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 7 Oct 2018 17:10:55 +0800 Subject: [PATCH 06/18] Delete hbios.asm --- Source/hbios.asm | 3351 ---------------------------------------------- 1 file changed, 3351 deletions(-) delete mode 100644 Source/hbios.asm diff --git a/Source/hbios.asm b/Source/hbios.asm deleted file mode 100644 index b52ded07..00000000 --- a/Source/hbios.asm +++ /dev/null @@ -1,3351 +0,0 @@ -; -;================================================================================================== -; HBIOS -;================================================================================================== -; -; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS -; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512 -; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE -; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP -; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE -; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN -; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF -; THE BANK SWITCHING THAT OCCURS. -; -; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED -; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS: -; -; - ROMBOOT: BOOT FROM A ROM BANK -; -; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM -; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL -; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK -; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY. -; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY -; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL -; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS -; IS INSTALLED. -; -; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE -; -; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING -; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN -; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE -; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE USER RAM -; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. -; -; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK -; -; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED -; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES -; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT -; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE -; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED -; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED -; AFTER HBIOS IS INSTALLED. -; -; INCLUDE GENERIC STUFF -; -#INCLUDE "std.asm" -; -; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. -; -MODCNT .EQU 0 -#IFDEF ROMBOOT -MODCNT .SET MODCNT + 1 -#ENDIF -#IFDEF APPBOOT -MODCNT .SET MODCNT + 1 -#ENDIF -#IFDEF IMGBOOT -MODCNT .SET MODCNT + 1 -#ENDIF -#IF (MODCNT != 1) - .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT, IMGBOOT!!!\n" - !!! ; FORCE AN ASSEMBLY ERROR -#ENDIF -; -; -; -#IF ((PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) -#DEFINE DIAGP $00 -#ENDIF -; -#IFDEF DIAGP -#DEFINE DIAG(N) PUSH AF - #DEFCONT \ LD A,N - #DEFCONT \ OUT (DIAGP),A - #DEFCONT \ POP AF -#ELSE -#DEFINE DIAG(N) \; -#ENDIF -; -; -; -#IF (INTMODE == 0) -; NO INTERRUPT HANDLING -#DEFINE HB_DI DI -#DEFINE HB_EI ; -#ELSE -; MODE 1 OR 2 INTERRUPT HANDLING -#DEFINE HB_DI DI -#DEFINE HB_EI EI -#ENDIF -; -; -; -#IFNDEF APPBOOT -; - .ORG 0 -; -;================================================================================================== -; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED -;================================================================================================== -; - .FILL (000H - $),0FFH ; RST 0 - JP HB_START - .DW ROM_SIG - .FILL (008H - $),0FFH ; RST 8 - JP HB_INVOKE ; INVOKE HBIOS FUNCTION - .FILL (010H - $),0FFH ; RST 10 - RET - .FILL (018H - $),0FFH ; RST 18 - RET - .FILL (020H - $),0FFH ; RST 20 - RET - .FILL (028H - $),0FFH ; RST 28 - RET - .FILL (030H - $),0FFH ; RST 30 - RET - .FILL (038H - $),0FFH ; RST 38 / IM1 INT -#IF (INTMODE == 1) - JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM -#ELSE - RETI ; RETURN W/ INTS DISABLED -#ENDIF - .FILL (066H - $),0FFH ; NMI - RETN -; - .FILL (070H - $),0FFH ; SIG STARTS AT $80 -; -ROM_SIG: - .DB $76, $B5 ; 2 SIGNATURE BYTES - .DB 1 ; STRUCTURE VERSION NUMBER - .DB 7 ; ROM SIZE (IN MULTIPLES OF 4KB, MINUS ONE) - .DW NAME ; POINTER TO HUMAN-READABLE ROM NAME - .DW AUTH ; POINTER TO AUTHOR INITIALS - .DW DESC ; POINTER TO LONGER DESCRIPTION OF ROM - .DB 0, 0, 0, 0, 0, 0 ; RESERVED FOR FUTURE USE; MUST BE ZERO -; -NAME .DB "ROMWBW v", BIOSVER, ", ", TIMESTAMP, 0 -AUTH .DB "WBW",0 -DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2015, Wayne Warthen, GNU GPL v3", 0 -; - .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO -; -#ENDIF -; -;================================================================================================== -; HBIOS CONFIGURATION BLOCK (HCB) -;================================================================================================== -; - .ORG HCB_LOC -HCB: - JP HB_START -; -CB_MARKER .DB 'W',~'W' ; MARKER -CB_VERSION .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO - .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO -; -CB_PLATFORM .DB PLATFORM -CB_CPUMHZ .DB CPUMHZ -CB_CPUKHZ .DW CPUKHZ -CB_RAMBANKS .DB RAMSIZE / 32 -CB_ROMBANKS .DB ROMSIZE / 32 -; -CB_BOOTVOL .DW 0 ; BOOT VOLUME IS UNIT/SLICE, SET BY LOADER -CB_BOOTBID .DB 0 ; BOOT BANK ID, SET BY LOADER -CB_SERDEV .DB 0 ; PRIMARY SERIAL UNIT IS UNIT #0 BY FIAT -CB_CRTDEV .DB $FF ; PRIMARY CRT UNIT, $FF UNTIL AFTER HBIOS INIT -CB_CONDEV .DB $FF ; CONSOLE UNIT, $FF UNTIL AFTER HBIOS INIT -; -; MEMORY MANAGEMENT VARIABLES START AT $20 -; - .FILL (HCB + $20 - $),0 -; -CB_HEAP .DW 0 -CB_HEAPTOP .DW 0 -; -; STANDARD BANK ID'S START AT $D8 -; - .FILL (HCB + $D8 - $),0 -; -CB_BIDCOM .DB BID_COM -CB_BIDUSR .DB BID_USR -CB_BIDBIOS .DB BID_BIOS -CB_BIDAUX .DB BID_AUX -CB_BIDRAMD0 .DB BID_RAMD0 -CB_BIDRAMDN .DB BID_RAMDN -CB_BIDROMD0 .DB BID_ROMD0 -CB_BIDROMDN .DB BID_ROMDN -; - .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB -; -;================================================================================================== -; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) -;================================================================================================== -; -; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING -; - .FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START - .ORG HBX_LOC ; ADJUST FOR RELOCATION -; -; MEMORY LAYOUT: -; -; HBIOS PROXY CODE $FE00 (256 BYTES) -; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) -; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) -; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) -; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) -; -; DEFINITIONS -; -HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BUFFER SIZE -; -; HBIOS IDENTIFICATION DATA BLOCK -; -HBX_IDENT: - .DB 'W',~'W' ; MARKER - .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO - .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO -; -;================================================================================================== -; HBIOS ENTRY FOR RST 08 PROCESSING -;================================================================================================== -; -HBX_INVOKE: - LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME - LD A,(HB_CURBNK) ; GET CURRENT BANK - LD (HB_INVBNK),A ; SAVE INVOCATION BANK - - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH - LD A,BID_BIOS ; HBIOS BANK - CALL HBX_BNKSEL ; SELECT IT - LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK - - CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER - - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH - PUSH AF ; SAVE AF (FUNCTION RETURN) - - LD A,(HB_INVBNK) ; LOAD ORIGINAL BANK - CALL HBX_BNKSEL ; SELECT IT - POP AF ; RESTORE AF - LD SP,0 ; RESTORE ORIGINAL STACK FRAME -HBX_INVSP .EQU $ - 2 - - RET ; RETURN TO CALLER -; -;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -;; BNKSEL - Switch Memory Bank to Bank in A. -;; Preserve all Registers including Flags. -;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -; -HBX_BNKSEL: - ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, - ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT - ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE - ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT - ; OCCURS DURING PROCESSING. - LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK -; -HBX_BNKSEL_INT: -; -#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA)) - #IF (INTMODE == 1) - ; THIS BIT OF ABSURDITY HANDLES A RARE (BUT FATAL) SITUATION - ; WHERE AN IM1 INTERRUPT OCCURS BETWEEN SETTING THE RAM AND - ; ROM SELECTORS. BRACKETING THE INSTRUCTIONS WITH DI/EI - ; IS CONTRAINDICATED BECAUSE THIS ROUTINE IS CALLED BY - ; OTHER ROUTINES THAT MUST CONTROL INT ENABLE AT A HIGHER - ; LEVEL. THE FOLLOWING TECHNIQUE ENSURES THAT YOU ALWAYS - ; SWITCH DIRECTLY FROM THE PREVIOUS BANK TO THE TARGET BANK - ; WITHOUT AN "ERRANT" BANK BEING ACTIVE BETWEEN THE TWO - ; BANK SELECTION I/O INSTRUCTIONS. THE TECHNIQUE IS ONLY - ; NEEDED WHEN USING INT MODE 1 BECAUSE THAT MODE REQUIRES - ; PAGE ONE TO HAVE A VALID INT HANDLER WHENEVER INTS ARE - ; ENABLED. - ;BIT 7,A ; [8] TEST RAM BIT - ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM - OR A ; [4] SET FLAGS - JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM - #ENDIF - OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR -HBX_ROM: - OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR - RET ; DONE -#ENDIF -#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) - BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE - JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE - RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT - ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K -; -HBX_ROM: - RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K - OUT (MPGSEL_0),A ; BANK_0: 0K - 16K - INC A ; - OUT (MPGSEL_1),A ; BANK_1: 16K - 32K - RET ; DONE -#ENDIF -#IF (PLATFORM == PLT_N8) - BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM - JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE -; -HBX_RAM: - RES 7,A ; CLEAR BIT 7 FROM ABOVE - RLCA ; SCALE SELECTOR TO - RLCA ; ... GO FROM Z180 4K PAGE SIZE - RLCA ; ... TO DESIRED 32K PAGE SIZE - OUT0 (Z180_BBR),A ; WRITE TO BANK BASE - LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 - OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER - RET ; DONE -; -HBX_ROM: - OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER - XOR A ; ZERO ACCUM - OUT0 (Z180_BBR),A ; ZERO BANK BASE - LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 - OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER - RET ; DONE -; -#ENDIF -#IF (PLATFORM == PLT_MK4) - RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0 - JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD - XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 -HBX_BNKSEL1: - RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR - RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE - OUT0 (Z180_BBR),A ; WRITE TO BANK BASE - RET ; DONE -#ENDIF -; -;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -; Copy Data - Possibly between banks. This resembles CP/M 3, but -; usage of the HL and DE registers is reversed. -; Caller MUST ensure stack is already in high memory. -; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. -; Caller MUST disable ints if IM1 active -; Enter: -; HL = Source Address -; DE = Destination Address -; BC = Number of bytes to copy -; Exit : None -; Uses : AF,BC,DE,HL -; -;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -; -HBX_BNKCPY: - LD (HBX_BC_SP),SP ; PUT STACK - LD SP,HBX_TMPSTK ; ... IN HI MEM - - LD A,(HB_CURBNK) ; GET CURRENT BANK - PUSH AF ; AND SAVE TO RESTORE LATER - PUSH BC ; CUR LEN -> (SP) -; -HBX_BC_LOOP: - EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC - LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE - OR A ; CLEAR CARRY FLAG - SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE - JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT - EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN - CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK - JR HBX_BC_LOOP ; AND REPEAT TILL DONE -; -HBX_BC_LAST: - ; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE - OR A ; CLEAR CARRY - ADC HL,BC ; HL := REM LEN (0 - 127) - EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN - POP BC ; BC := REM LEN - CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES - POP AF ; RECOVER ORIGINAL BANK - CALL HBX_BNKSEL ; SWITCH - - LD SP,$FFFF ; RESTORE STACK -HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE - RET -; -HBX_BC_ITER: - ; HL = SRC ADR, DE = DEST ADR, BC = LEN - PUSH BC ; SAVE COPY LEN - PUSH DE ; FINAL DEST ON STACK - LD DE,HBX_BUF ; SET DEST TO BUF - LD A,(HB_SRCBNK) ; GET SOURCE BANK - CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK - LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR - POP DE ; DE := FINAL DEST - POP BC ; GET LEN BACK IN BC - PUSH HL ; SAVE UPDATED SRC ADR - LD HL,HBX_BUF ; SET SRC ADR TO BUF - LD A,(HB_DSTBNK) ; GET DEST BANK - CALL HBX_BNKSEL ; SWITCH TO DEST BANK - LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR - POP HL ; RECOVER UPDATED SRC ADR - ; HL = UPD SRC, DE = UPD DEST, BC = 0 - RET -; -; CALL A ROUTINE IN ANOTHER BANK. -; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE. -; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO -; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGTET BANK IS PREPARED FOR THEM. -; ON INPUT A=TARGET BANK, HL=TARGET ADDRESS -; -HBX_BNKCALL: - LD (HBX_TGTBNK),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW - LD (HBX_TGTADR),HL ; STUFF ADDRESS TO CALL INTO CODE BELOW - LD A,(HB_CURBNK) ; GET CURRENT BANK - PUSH AF ; SAVE FOR RETURN -HBX_TGTBNK .EQU $ + 1 - LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) - CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK - -HBX_TGTADR .EQU $ + 1 - CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE) - - EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL - PUSH AF ; SAVE AF - LD A,H ; BANK TO RESTORE TO A - CALL HBX_BNKSEL ; RESTORE IT - POP AF ; RECOVER AF - POP HL ; RECOVER HL - RET -; -; PEEK & POKE ROUTINES -; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED -; CALLER MUST DISABLE INTS IF IM1 AND ACCESSING PAGE W/O IM1 INT VECTOR -; -HBX_PEEK: - LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM - LD A,(HB_CURBNK) - PUSH AF - LD A,D - CALL HBX_BNKSEL - LD E,(HL) - JR HBX_PPRET -; -HBX_POKE: - LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM - LD A,(HB_CURBNK) - PUSH AF - LD A,D - CALL HBX_BNKSEL - LD (HL),E -; -HBX_PPRET: - POP AF - CALL HBX_BNKSEL - LD SP,0 ; RESTORE ORIGINAL STACK FRAME -HBX_PPSP .EQU $ - 2 - RET -; -; SMALL TEMPORARY STACK FOR USE BY INVOKE, PEEK, AND POKE -; - .FILL 20,$CC ; 10 LEVEL STACK -HBX_TMPSTK .EQU $ -; -; PRIVATE STACK AT END OF HBIOS CODE -; OCCUPIES SPACE BEFORE IVT -; -HBX_STKSIZ .EQU $FF00 - $ - .ECHO "HBIOS PROXY STACK space: " - .ECHO HBX_STKSIZ - .ECHO " bytes.\n" - .FILL HBX_STKSIZ,$FF -HBX_STACK .EQU $ -; -#IF (INTMODE == 2) -; -; HBIOS INTERRUPT VECTOR TABLE (16 ENTRIES) -; -HBX_IVT: - .DW INT_BAD ; IVT_INT1 - .DW INT_BAD ; IVT_INT2 - .DW INT_BAD ; IVT_TIM0 - .DW INT_BAD ; IVT_TIM1 - .DW INT_BAD ; IVT_DMA0 - .DW INT_BAD ; IVT_DMA1 - .DW INT_BAD ; IVT_CSIO - .DW INT_BAD ; IVT_SER0 - .DW INT_BAD ; IVT_SER1 - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; -; -HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 -; -HBX_ITBL: - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT -#ENDIF -; -; INTERRUPT HANDLER STUBS -; -; THE FOLLOWING INTERRUPT STUBS RECEIVE CONTROL FROM THE -; INTERRUPT, SETUP A HANDLER VECTOR IN HBIOS AND THEN -; BRANCH TO THE COMMON INTERRUPT DISPATCHER -; -; -INT_IM1: -#IF (INTMODE == 1) - PUSH HL ; SAVE HL - LD HL,HB_IM1INT ; HL := IM1 INT HANDLER IN BIOS BANK - JR HBX_INT ; TO TO ROUTING CODE -#ELSE - RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED -#ENDIF -; -#IF (INTMODE == 2) -; -INT_BAD: ; BAD INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,HB_BADINT ; HL := INT HANDLER IN BIOS BANK - JR HBX_INT ; GO TO ROUTING CODE -; -INT_TIMER: ; TIMER INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,HB_TIMINT ; HL := INT ADR IN BIOS - JR HBX_INT ; GO TO ROUTING CODE -; - #IF (SIOENABLE) -INT_SIO: ; SIO INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK - JR HBX_INT ; GO TO ROUTING CODE - #ENDIF - - #IF (PIOENABLE) -INT_PIO: ; SIO INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,PIO_INT ; HL := PIO INT HANDLER IN BIOS BANK - JR HBX_INT ; GO TO ROUTING CODE - #ENDIF -; -#ENDIF -; -#IF (INTMODE > 0) -; -; COMMON INTERRUPT DISPATCHING CODE -; SETUP AND CALL HANDLER IN BIOS BANK -; -HBX_INT: ; COMMON INTERRUPT ROUTING CODE -; - LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME - LD SP,HBX_STACK ; USE STACK FRAME IN HI MEM - - ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) - PUSH AF ; SAVE AF - PUSH BC ; SAVE BC - PUSH DE ; SAVE DE - PUSH IY ; SAVE IY - - LD A,BID_BIOS ; HBIOS BANK - CALL HBX_BNKSEL_INT ; SELECT IT - - CALL JPHL ; CALL INTERRUPT ROUTINE - - LD A,(HB_CURBNK) ; GET PRE-INT BANK - CALL HBX_BNKSEL ; SELECT IT - - ; RESTORE STATE - POP IY ; RESTORE IY - POP DE ; RESTORE DE - POP BC ; RESTORE BC - POP AF ; RESTORE AF - - LD SP,$FFFF ; RESTORE ORIGINAL STACK FRAME -HBX_INT_SP .EQU $ - 2 - - POP HL ; RESTORE HL - - EI ; ENABLE INTERRUPTS - RETI ; AND RETURN -; -#ENDIF -; -; FILL TO START OF BOUNCE BUFFER -; -HBX_INTFILL .EQU (HBX_XFC - HBX_BUFSIZ - $) - .ECHO "HBIOS INT space remaining: " - .ECHO HBX_INTFILL - .ECHO " bytes.\n" - .FILL HBX_INTFILL,$FF -; -; INTERBANK COPY BUFFER (64 BYTES) -; -HBX_BUF .FILL HBX_BUFSIZ,0 -; -; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) -; -#IFDEF ROMBOOT - .DB BID_BOOT ; CURRENTLY ACTIVE LOW MEMORY BANK ID -#ELSE - .DB BID_USR ; CURRENTLY ACTIVE LOW MEMORY BANK ID -#ENDIF - .DB 0 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION - .DW 0 ; BNKCPY SOURCE ADDRESS - .DB BID_USR ; BNKCPY SOURCE BANK ID - .DW 0 ; BNKCPY DESTINATION ADDRESS - .DB BID_USR ; BNKCPY DESTINATION BANK ID - .DW 0 ; BNKCPY LENGTH - .FILL 6,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE - JP HBX_INVOKE ; FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) - JP HBX_BNKSEL ; FIXED ADR ENTRY FOR HBX_BNKSEL - JP HBX_BNKCPY ; FIXED ADR ENTRY FOR HBX_BNKCPY - JP HBX_BNKCALL ; FIXED ADR ENTRY FOR HBX_BNKCALL - .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) - .DW HBX_IDENT ; ADDRESS OF HBIOS IDENT INFO DATA BLOCK -; - .FILL $MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) - .ORG HBX_IMG + HBX_SIZ ; RESET ORG -; -;================================================================================================== -; HBIOS CORE -;================================================================================================== -; -;================================================================================================== -; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK -;================================================================================================== -; -HB_ENTRYTBL .EQU $ -; - JP HB_START ; HBIOS INITIALIZATION - JP HB_DISPATCH ; VECTOR TO DISPATCHER -; -HB_STKSIZ .EQU HB_ENTRYTBL + 256 - $ -; - .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK -HB_STACK .EQU $ ; TOP OF HBIOS STACK - -; -;================================================================================================== -; SYSTEM INITIALIZATION -;================================================================================================== -; -HB_START: - DI ; NO INTERRUPTS - IM 1 ; INTERRUPT MODE 1 -; -#IFDEF DIAGP - LD A,%00000001 - OUT (DIAGP),A -#ENDIF -; - LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; SET BASE FOR CPU IO REGISTERS - LD A,Z180_BASE - OUT0 (Z180_ICR),A - - DIAG(%00000010) - - ; DISABLE REFRESH - XOR A - OUT0 (Z180_RCR),A - - ; MASK OFF TIMER INTERRUPTS - XOR A - OUT0 (Z180_TCR),A - - ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) - XOR A - OUT0 (Z180_CCR),A - OUT0 (Z180_CMR),A - - ; SET DEFAULT WAIT STATES - LD A,$F0 - OUT0 (Z180_DCNTL),A - -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4)) - ; MMU SETUP - LD A,$80 - OUT0 (Z180_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG -;#IFDEF ROMBOOT -; XOR A -; OUT0 (Z180_BBR),A ; BANK BASE = 0 -;#ENDIF - LD A,(RAMSIZE + RAMBIAS - 64) >> 2 - OUT0 (Z180_CBR),A ; COMMON BASE = LAST (TOP) BANK -#ENDIF - -#IF (Z180_CLKDIV >= 1) - ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED - LD A,$80 - OUT0 (Z180_CCR),A -#ENDIF - -#IF (Z180_CLKDIV >= 2) - ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED - LD A,$80 - OUT0 (Z180_CMR),A -#ENDIF - -#ENDIF -; -#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) - ; SET PAGING REGISTERS -#IFDEF ROMBOOT - XOR A - OUT (MPGSEL_0),A - INC A - OUT (MPGSEL_1),A -#ENDIF - LD A,62 - OUT (MPGSEL_2),A - INC A - OUT (MPGSEL_3),A - ; ENABLE PAGING - LD A,1 - OUT (MPGENA),A -#ENDIF -; - DIAG(%00000011) -; -; INSTALL PROXY IN UPPER MEMORY -; - -;X1 .EQU $8000 -;X2 .EQU X1 + 2 -;X3 .EQU X2 + 2 -;X4 .EQU X3 + 2 - -; LD HL,(HBX_IMG) -; LD (X1),HL - -; LD HL,(HBX_IMG) -; LD (X2),HL - - LD HL,HBX_IMG - LD DE,HBX_LOC - LD BC,HBX_SIZ - LDIR - -; LD HL,(HBX_IMG) -; LD (X3),HL - -; LD HL,(HBX_LOC) -; LD (X4),HL - -; -; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION -; - LD A,(HB_RAMFLAG) - OR A - JR NZ,HB_START1 -; -; INSTALL HBIOS IN RAM BANK -; - LD A,(HB_CURBNK) - LD (HB_SRCBNK),A - LD A,BID_BIOS - LD (HB_DSTBNK),A - LD HL,0 - LD DE,0 - LD BC,$8000 - CALL HBX_BNKCPY -; -; TRANSITION TO HBIOS IN RAM BANK -; - LD A,BID_BIOS ; BIOS BANK ID - LD HL,HB_START1 ; EXECUTION RESUMES HERE - CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN - HALT ; WE SHOULD NOT COME BACK HERE! -; -HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION -; -; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK -; -HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK -; - DIAG(%00000111) -; - LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN - LD A,TRUE ; ACCUM := TRUE - LD (HB_RAMFLAG),A ; SET RAMFLAG -; -; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO -; -#IFDEF APPBOOT - ; MAKE SURE RST 08 VECTOR IS RIGHT - LD A,$C3 - LD ($0008),A - LD HL,HB_INVOKE - LD ($0009),HL -; - ; MAKE SURE IM1 INT VECTOR IS RIGHT - #IF (INTMODE == 1) - ; JP INT_IM1 IF INTERRUPT MODE ACTIVE - LD A,$C3 - LD ($0038),A - LD HL,INT_IM1 - LD ($0039),HL - #ELSE - ; RETI ($ED, $4D) IF NON-INTERRUPT MODE - LD HL,($0038) - LD (HL),$ED - INC HL - LD (HL),$4D - #ENDIF -#ENDIF -; - DIAG(%00001111) -; -; PERFORM DYNAMIC CPU SPEED DERIVATION -; - CALL HB_CPUSPD ; CPU SPEED DETECTION -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) -; - ; SET DESIRED WAIT STATES - LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) - OUT0 (Z180_DCNTL),A -; -#ENDIF -; - CALL DELAY_INIT ; INITIALIZE SPEED COMPENSATED DELAY FUNCTIONS -; - DIAG(%00011111) -; -; INITIALIZE HEAP STORAGE -; - ; INITIALIZE POINTERS - LD HL,HB_END ; HEAP FOLLOWS HBIOS CODE - LD (CB_HEAP),HL ; INIT HEAP BASE ADDRESS - LD (CB_HEAPTOP),HL ; INIT HEAP TOP ADDRESS - ; CLEAR HEAP - LD BC,BNKTOP - HB_END ; MAX SIZE OF HEAP - LD A,$FF ; FILL WITH $FF - CALL FILL ; DO IT -; - DIAG(%00111111) -; -; PRE-CONSOLE INITIALIZATION -; -#IF (ASCIENABLE) - CALL ASCI_PREINIT -#ENDIF -#IF (UARTENABLE) - CALL UART_PREINIT -#ENDIF -#IF (SIOENABLE) - CALL SIO_PREINIT -#ENDIF -#IF (ACIAENABLE) - CALL ACIA_PREINIT -#ENDIF -#IF (PIOENABLE) - CALL PIO_PREINIT -#ENDIF - -; - DIAG(%01111111) -; -; PRIOR TO THIS POINT, CONSOLE I/O WAS DIRECTED TO HARDWARE (XIO.ASM). -; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O -; VIA HBIOS. -; - XOR A ; INITIALLY, FIRST SERIAL UNIT IS CONSOLE - LD (CB_CONDEV),A ; SAVE IT, ACTIVATES CONSOLE ON HBIOS -; -; ANNOUNCE HBIOS -; - CALL NEWLINE2 - PRTX(STR_BANNER) -; - DIAG(%11111111) -; -; IO PORT SCAN -; -#IF 0 -PSCN: - LD C,0 ; IO PORT NUMBER - LD B,0 ; LOOP COUNTER - CALL NEWLINE -PSCN1: - CALL NEWLINE - LD A,C - CALL PRTHEXBYTE - CALL PC_COLON - CALL PC_SPACE - CALL DELAY - LD A,C - LD (PSCNX),A -PSCNX .EQU $ + 1 - IN A,(0) - CALL PRTHEXBYTE - CALL PC_COMMA - PUSH BC - LD B,0 - IN A,(C) - POP BC - CALL PRTHEXBYTE - INC C - DJNZ PSCN1 -#ENDIF -; -; SETUP INTERRUPT VECTORS, AS APPROPRIATE -; -;#IF (INTMODE == 1) -; ; OVERLAY $0038 WITH JP INT_IM1 -; LD A,$C3 ; JP INSTRUCTION -; LD ($0038),A ; INSTALL IT -; LD HL,INT_IM1 ; DESTINATION ADDRESS -; LD ($0039),HL ; INSTALL IT -;#ENDIF -; -#IF (INTMODE == 2) - ; SETUP Z80 IVT AND INT MODE 2 - LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS - LD I,A ; ... AND PLACE IT IN I REGISTER - - #IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; SETUP Z180 IVT - XOR A ; SETUP LO BYTE OF IVT ADDRESS - OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER - #ENDIF - - IM 2 ; SWITCH TO INT MODE 2 -#ENDIF - -#IF (PLATFORM == PLT_SBC) -; - #IF (HTIMENABLE) ; SIMH TIMER -; - #IF (INTMODE == 1) - LD HL,HB_TIMINT - CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST - #ENDIF -; - #IF (INTMODE == 2) - ;LD HL,INT_TIMER - ;LD (HBX_IVT),HL - #ENDIF -; - #ENDIF -; -#ENDIF -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) -; - #IF (INTMODE == 2) -; - ; MASK ALL EXTERNAL INTERRUPTS FOR NOW - ;XOR A ; INT0-2 DISABLED - LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED - OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER -; - ; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT - LD HL,INT_TIMER - LD (HBX_IVT + IVT_TIM0),HL - - ; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0 - LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ - LD B,0 - LD C,Z180_RLDR0L ; INITIALIZE TIMER 0 RELOAD REGISTER - OUT (C),L - INC C - OUT (C),H - LD C,Z180_TMDR0L ; INITIALIZE TIMER 0 DATA REGISTER - OUT (C),L - INC C - OUT (C),H - LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING - OUT0 (Z180_TCR),A -; - #ENDIF -; -#ENDIF -; - HB_EI ; INTERRUPTS SHOULD BE OK NOW -; -; DISPLAY PLATFORM INFORMATION -; - CALL NEWLINE2 - PRTX(STR_PLATFORM) - PRTS(" @ $") - LD HL,(CB_CPUKHZ) - CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA - PRTS("MHz$") -; -; DISPLAY CPU CONFIG -; - ;CALL PRTSTRD - ;.TEXT ", $" - CALL NEWLINE -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - LD A,Z180_MEMWAIT -#ELSE - LD A,0 -#ENDIF - CALL PRTDECB - CALL PRTSTRD - .TEXT " MEM W/S, $" -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - LD A,Z180_IOWAIT + 1 -#ELSE - LD A,1 -#ENDIF - CALL PRTDECB - CALL PRTSTRD - .TEXT " I/O W/S$" -#IF (INTMODE > 0) - CALL PRTSTRD - .TEXT ", INT MODE $" - LD A,INTMODE - CALL PRTDECB -#ENDIF -; -; DISPLAY MEMORY CONFIG -; - CALL NEWLINE - ;CALL PRTSTRD - ;.TEXT "MEMORY CONFIG: $" - LD HL,ROMSIZE - CALL PRTDEC - CALL PRTSTRD - .TEXT "KB ROM, $" - LD HL,RAMSIZE - CALL PRTDEC - CALL PRTSTRD - .TEXT "KB RAM$" -; -; PERFORM DEVICE INITIALIZATION -; - CALL NEWLINE - LD B,HB_INITTBLLEN - LD DE,HB_INITTBL -INITSYS1: - LD A,(DE) - LD L,A - INC DE - LD A,(DE) - LD H,A - INC DE - PUSH DE - PUSH BC - CALL JPHL - POP BC - POP DE - DJNZ INITSYS1 -; -; RECORD HEAP CURB AT THE CURRENT VALUE OF HEAP TOP. HEAP CURB -; MARKS THE POINT IN THE HEAP AFTER WHICH MEMORY IS RELEASED -; WHEN AN HBIOS RESET IS PEFORMED. -; - LD HL,(CB_HEAPTOP) - LD (HEAPCURB),HL -; -; NOW SWITCH TO CRT CONSOLE IF CONFIGURED -; -#IF CRTACT -; -; BIOS IS CONFIGURED TO AUTO ACTIVATE CRT DEVICE. FIRST, -; CHECK TO SEE IF WE HAVE A VALID CRT DEVICE TO USE. -; - LD A,(CB_CRTDEV) ; GET THE CRT DEVICE - INC A ; INCREMENT TO TEST FOR $FF - JR Z,INITSYS3 ; IF NO CRT DEVICE, BYPASS CONSOLE SWITCH -; -; IF PLATFORM HAS A CONFIG JUMPER, CHECK TO SEE IF IT IS JUMPERED. -; IF SO, BYPASS SWITCH TO CRT CONSOLE (FAILSAFE MODE) -; -#IF ((PLATFORM != PLT_N8) & (PLATFORM != PLT_MK4) & (PLATFORM != PLT_RC) & (PLATFORM != PLT_RC180)) - IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER - BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE - JR Z,INITSYS3 ; Z=SHORTED, BYPASS CONSOLE SWITCH -#ENDIF -; - ; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE - CALL NEWLINE2 - PRTX(STR_SWITCH) - CALL NEWLINE -; - ; SWITCH TO CRT CONSOLE - LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE - LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE -; - ; DISPLAY HBIOS BANNER ON NEW CONSOLE - PRTX(STR_BANNER) -#ENDIF -; -INITSYS3: -; - CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE -; -; CHAIN TO OS LOADER -; -#IFDEF ROMBOOT - ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM - LD A,BID_OSIMG ; CHAIN TO OS IMAGES BANK - LD HL,0 ; ENTER AT ADDRESS 0 - CALL HBX_BNKCALL ; GO THERE - HALT ; WE SHOULD NEVER COME BACK! -#ELSE - ; COPY OS IMAGE: BID_USR: --> BID_USR:0 - ;LD A,BID_USR - ;LD (HB_SRCBNK),A - ;LD (HB_DSTBNK),A - ;LD HL,HB_END - ;LD DE,0 - ;LD BC,$8000 - ;CALL HBX_BNKCPY - LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY - LD D,BID_USR ; D = DEST BANK = USER BANK - LD E,BID_USR ; E = SRC BANK = USER BANK - LD HL,$8000 ; HL = COPY LEN = ENTIRE BANK - RST 08 ; DO IT - LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY - LD HL,HB_END ; COPY FROM END OF OF HBIOS - LD DE,0 ; TO USER ADDRESS 0 - RST 08 ; DO IT -; - ; PERFORM BANK CALL TO USER BANK - LD A,BID_USR ; CHAIN TO OS IMAGES BANK - LD HL,0 ; ENTER AT ADDRESS 0 - CALL HBX_BNKCALL ; GO THERE - HALT ; WE SHOULD NEVER COME BACK! -; -#ENDIF -; - RET -; -;================================================================================================== -; TABLE OF INITIALIZATION ENTRY POINTS -;================================================================================================== -; -HB_INITTBL: -#IF (SPKENABLE) - .DW SPK_INIT ; AUDIBLE INDICATOR OF BOOT START -#ENDIF -#IF (AYENABLE) - .DW AY_INIT ; AUDIBLE INDICATOR OF BOOT START -#ENDIF -#IF (ASCIENABLE) - .DW ASCI_INIT -#ENDIF -#IF (UARTENABLE) - .DW UART_INIT -#ENDIF -#IF (SIOENABLE) - .DW SIO_INIT -#ENDIF -#IF (ACIAENABLE) - .DW ACIA_INIT -#ENDIF -#IF (SIMRTCENABLE) - .DW SIMRTC_INIT -#ENDIF -#IF (DSRTCENABLE) - .DW DSRTC_INIT -#ENDIF -#IF (VDUENABLE) - .DW VDU_INIT -#ENDIF -#IF (CVDUENABLE) - .DW CVDU_INIT -#ENDIF -#IF (VGAENABLE) - .DW VGA_INIT -#ENDIF -#IF (NECENABLE) - .DW NEC_INIT -#ENDIF -#IF (TMSENABLE) - .DW TMS_INIT -#ENDIF -#IF (DSKYENABLE) - .DW DSKY_INIT -#ENDIF -#IF (MDENABLE) - .DW MD_INIT -#ENDIF -#IF (FDENABLE) - .DW FD_INIT -#ENDIF -#IF (RFENABLE) - .DW RF_INIT -#ENDIF -#IF (IDEENABLE) - .DW IDE_INIT -#ENDIF -#IF (PPIDEENABLE) - .DW PPIDE_INIT -#ENDIF -#IF (SDENABLE) - .DW SD_INIT -#ENDIF -#IF (HDSKENABLE) - .DW HDSK_INIT -#ENDIF -#IF (PRPENABLE) - .DW PRP_INIT -#ENDIF -#IF (PPPENABLE) - .DW PPP_INIT -#ENDIF -#IF (PIOENABLE) - .DW PIO_INIT -#ENDIF -; -HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) -; -;================================================================================================== -; IDLE -;================================================================================================== -; -;__________________________________________________________________________________________________ -; -IDLE: - PUSH AF - PUSH BC - PUSH DE - PUSH HL - PUSH IY -#IF (FDENABLE) - CALL FD_IDLE -#ENDIF - POP IY - POP HL - POP DE - POP BC - POP AF - RET -; -;================================================================================================== -; BIOS FUNCTION DISPATCHER -;================================================================================================== -; -; MAIN BIOS FUNCTION -; B: FUNCTION -;__________________________________________________________________________________________________ -; -HB_DISPATCH: -; -#IF 0 ; *DEBUG* START -; - CALL HB_DISPCALL ; DO THE WORK -; - ; CHECK STACK INTEGRITY - PUSH AF - LD A,(HB_STACK - HB_STKSIZ + $08) - CP $FF - CALL NZ,PANIC - LD A,$FF - LD (HB_STACK - HB_STKSIZ + $08),A - POP AF - RET -HB_DISPCALL: -; -#ENDIF ; *DEBUG* END -; - LD A,B ; REQUESTED FUNCTION IS IN B - CP BF_CIO + $10 ; $00-$0F: CHARACTER I/O - JP C,CIO_DISPATCH - CP BF_DIO + $10 ; $10-$1F: DISK I/O - JP C,DIO_DISPATCH - CP BF_RTC + $10 ; $20-$2F: REAL TIME CLOCK (RTC) - JP C,RTC_DISPATCH - CP BF_EMU + $10 ; $30-$3F: EMULATION - CALL C,PANIC ; OBSOLETE! - CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER - JP C,VDA_DISPATCH - CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 - CALL C,PANIC ; PANIC IF LESS THAN BF_SYS - JP SYS_DISPATCH ; OTHERWISE SYS CALL - CALL PANIC ; THIS SHOULD NEVER BE REACHED - RET -; -;================================================================================================== -; CHARACTER I/O DEVICE FUNCTION DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER -; B: FUNCTION -; C: UNIT NUMBER -; -CIO_DISPATCH: - BIT 7,C ; CHECK FOR SPECIAL UNIT CODE - CALL NZ,CIO_SPECIAL ; IF SO, HANDLE IT - - PUSH IY ; SAVE INCOMING IY - - LD IY,CIO_TBL ; POINT IY TO START OF DIO TABLE - CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE - - POP IY ; RESTORE IY - RET ; AND DONE -; -; SPECIAL HANDLING FOR DEDICATED UNIT CODES -; -CIO_SPECIAL: - ; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST - ; SO JUST SWAP IN ACTIVE CONSOLE UNIT - LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE - LD C,A ; OVERLAY UNIT CODE IN C - RET ; AND REJOIN MAIN DISPATCH FLOW -; -; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS) -; -CIO_ADDENT: - LD HL,CIO_TBL ; POINT TO CIO TABLE - JP HB_ADDENT ; ... AND GO TO COMMON CODE -; -; HBIOS CHARACTER DEVICE UNIT TABLE -; -; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. -; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT -; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. -; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS -; EACH ENTRY IS DEFINED AS: -; -; WORD DRIVER FUNCTION TABLE ADDRESS -; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) -; -CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) -CIO_MAX .EQU 32 ; UP TO UNITS -CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES -; - .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) - .DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX -CIO_CNT .DB 0 ; ENTRY COUNT PREFIX -CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES -; -;================================================================================================== -; DISK I/O DEVICE FUNCTION DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO SPECIFIED DISK I/O DRIVER -; B: FUNCTION -; C: UNIT NUMBER -; -DIO_DISPATCH: -; -#IF 0 ; *DEBUG* START -; - ; DUMP INCOMING CALL - CALL NEWLINE - PRTS("DIO>$") - CALL REGDMP ; DUMP REGS, NONE DESTROYED -; - ; DO THE ACTUAL DISPATCH PROCESSING - CALL DIO_DISPCALL -; - ; DUMP CALL RESULTS AND RETURN - CALL NEWLINE - PRTS("DIO<$") - CALL REGDMP ; DUMP REGS, NONE DESTROYED - RET -; -#ENDIF ; *DEBUG* END -; -DIO_DISPCALL: - PUSH IY ; SAVE INCOMING IY - - LD IY,DIO_TBL ; POINT IY TO START OF DIO TABLE - CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE - - POP IY ; RESTORE IY - RET ; AND DONE -; -; ADD AN ENTRY TO THE DIO UNIT TABLE -; -DIO_ADDENT: - LD HL,DIO_TBL ; POINT TO DIO TABLE - JP HB_ADDENT ; ... AND GO TO COMMON CODE -; -; HBIOS DISK DEVICE UNIT TABLE -; -; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. -; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT -; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. -; TABLE - 3 CONTAINS THE NUMBER OF DIO FUNCTION IDS -; EACH ENTRY IS DEFINED AS: -; -; WORD DRIVER FUNCTION TABLE ADDRESS -; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) -; -DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) -DIO_MAX .EQU 16 ; UP TO 32 UNITS -DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES -; - .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) - .DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX -DIO_CNT .DB 0 ; ENTRY COUNT PREFIX -DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES -; -;================================================================================================== -; REAL TIME CLOCK DEVICE DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO REAL TIME CLOCK DRIVER -; B: FUNCTION -; -RTC_DISPATCH: -#IF (SIMRTCENABLE) - JP SIMRTC_DISPATCH -#ENDIF -#IF (DSRTCENABLE) - JP DSRTC_DISPATCH -#ENDIF - CALL PANIC -; -;================================================================================================== -; VIDEO DISPLAY ADAPTER DEVICE DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO SPECIFIED VDA DEVICE DRIVER -; B: FUNCTION -; C: UNIT NUMBER -; -VDA_DISPATCH: - PUSH IY ; SAVE INCOMING IY - - LD IY,VDA_TBL ; POINT IY TO START OF DIO TABLE - CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE - - POP IY ; RESTORE IY - RET ; AND DONE -; -; ADD AN ENTRY TO THE VDA UNIT TABLE (SEE HB_ADDENT FOR DETAILS) -; -VDA_ADDENT: - LD HL,VDA_TBL ; POINT TO VDA TABLE - JP HB_ADDENT ; ... AND GO TO COMMON CODE -; -; HBIOS VIDEO DEVICE UNIT TABLE -; -; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. -; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT -; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. -; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS -; EACH ENTRY IS DEFINED AS: -; -; WORD DRIVER FUNCTION TABLE ADDRESS -; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) -; -VDA_FNCNT .EQU 15 ; NUMBER OF VDA FUNCS (FOR RANGE CHECK) -VDA_MAX .EQU 16 ; UP TO 16 UNITS -VDA_SIZ .EQU VDA_MAX * 4 ; EACH ENTRY IS 4 BYTES -; - .DB VDA_FNCNT ; VDA FUNCTION COUNT (FOR RANGE CHECK) - .DB VDA_MAX ; MAX ENTRY COUNT TABLE PREFIX -VDA_CNT .DB 0 ; ENTRY COUNT PREFIX -VDA_TBL .FILL VDA_SIZ,0 ; SPACE FOR ENTRIES -; -;================================================================================================== -; SYSTEM FUNCTION DISPATCHER -;================================================================================================== -; -; B: FUNCTION -; -SYS_DISPATCH: - LD A,B ; GET REQUESTED FUNCTION - AND $0F ; ISOLATE SUB-FUNCTION - JP Z,SYS_RESET ; $F0 - DEC A - JP Z,SYS_VER ; $F1 - DEC A - JP Z,SYS_SETBNK ; $F2 - DEC A - JP Z,SYS_GETBNK ; $F3 - DEC A - JP Z,SYS_SETCPY ; $F4 - DEC A - JP Z,SYS_BNKCPY ; $F5 - DEC A - JP Z,SYS_ALLOC ; $F6 - DEC A - JP Z,SYS_FREE ; $F7 - DEC A - JP Z,SYS_GET ; $F8 - DEC A - JP Z,SYS_SET ; $F9 - DEC A - JP Z,SYS_PEEK ; $FA - DEC A - JP Z,SYS_POKE ; $FB - DEC A - JP Z,SYS_INT ; $FC - CALL PANIC ; INVALID -; -; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS -; -SYS_RESET: - LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD - LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP - XOR A - RET -; -; GET THE CURRENT HBIOS VERSION -; ON INPUT, C=0 -; RETURNS VERSION IN DE AS BCD -; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS -; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS -; L: PLATFORM ID -; -SYS_VER: - LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP - LD L,PLATFORM - XOR A - RET -; -; SET ACTIVE MEMORY BANK AND RETURN PREVIOUSLY ACTIVE MEMORY BANK -; NOTE THAT IT GOES INTO EFFECT AS HBIOS FUNCTION IS EXITED -; HERE, WE JUST SET THE CURRENT BANK -; CALLER MUST EXTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! -; -SYS_SETBNK: - PUSH HL ; SAVE INCOMING HL - LD HL,HB_INVBNK ; POINT TO HBIOS INVOKE BANK ID ADDRESS - LD A,(HL) ; GET EXISTING BANK ID TO A - LD (HL),C ; UPDATE INVOKE BANK TO NEW BANK ID - LD C,A ; PUT PREVIOUS BANK ID IN C FOR RETURN - POP HL ; RESTORE ORIGINAL HL - XOR A ; SIGNAL SUCCESS - RET ; DONE -; -; GET ACTIVE MEMORY BANK -; -SYS_GETBNK: - LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK - LD C,A ; MOVE TO C - XOR A ; SIGNAL SUCCESS - RET -; -; SET BANKS AND LENGTH FOR INTERBANK MEMORY COPY (BNKCPY) -; ENTRY: E=SOURCE BANK ID -; D=DEST BANK ID -; HL=COPY LENGTH (IN BYTES) -; -SYS_SETCPY: - LD A,E - LD (HB_SRCBNK),A ; RECORD THE SOURCE BANK - LD A,D - LD (HB_DSTBNK),A ; RECORD THE DESTINATION BANK - LD (HB_CPYLEN),HL ; RECORD THE COPY LENGTH - XOR A - RET -; -; PERFORM MEMORY COPY POTENTIALLY ACROSS BANKS -; ENTRY: HL=SOURCE ADDRESS -; DE=DESTINATION ADDRESS -; NOTE: SRC/DEST BANK & COPY LENGTH MUST BE SET VIA SETCPY -; -SYS_BNKCPY: - PUSH HL ; SAVE INCOMING HL - LD HL,(HB_CPYLEN) ; HL := COPY LEN (SAVED IN SETCPY) - EX (SP),HL ; RESTORE HL & SET (SP) TO COPY LEN - POP BC ; BC := COPY LEN -#IF (INTMODE == 1) - DI -#ENDIF - CALL HB_BNKCPY -#IF (INTMODE == 1) - EI -#ENDIF - XOR A - RET -; -; ALLOCATE HL BYTES OF MEMORY FROM HBIOS HEAP -; RETURNS POINTER TO ALLOCATED MEMORY IN HL -; ON SUCCESS RETURN A == 0, AND Z SET -; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED -; ALL OTHER REGISTERS PRESERVED -; -SYS_ALLOC: - JP HB_ALLOC -; -; FREE HEAP MEMORY BY SIMPLY RELEASING ALL -; MEMORY BEYOND POINTER IN HL. -; ON SUCCESS RETURN A == 0, AND Z SET -; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED -; ALL OTHER REGISTERS PRESERVED -; -SYS_FREE: - CALL PANIC ; NOT YET IMPLEMENTED - OR $FF - RET -; -; GET SYSTEM INFORMATION -; ITEM TO RETURN INDICATED IN C -; -SYS_GET: - LD A,C ; GET REQUESTED SUB-FUNCTION - CP BF_SYSGET_CIOCNT - JR Z,SYS_GETCIOCNT - CP BF_SYSGET_DIOCNT - JR Z,SYS_GETDIOCNT - CP BF_SYSGET_VDACNT - JR Z,SYS_GETVDACNT - CP BF_SYSGET_TIMER - JR Z,SYS_GETTIMER - CP BF_SYSGET_BOOTINFO - JR Z,SYS_GETBOOTINFO - CP BF_SYSGET_CPUINFO - JR Z,SYS_GETCPUINFO - CP BF_SYSGET_MEMINFO - JR Z,SYS_GETMEMINFO - CP BF_SYSGET_BNKINFO - JR Z,SYS_GETBNKINFO - OR $FF ; SIGNAL ERROR - RET -; -; GET TIMER -; RETURNS: -; DE:HL: TIMER VALUE (32 BIT) -; -SYS_GETTIMER: - LD HL,HB_TICKS - HB_DI - CALL LD32 - HB_EI - XOR A - RET -; -; GET BOOT INFORMATION -; RETURNS: -; L: BOOT BANK ID -; DE: BOOT DISK VOLUME (UNIT/SLICE) -; -SYS_GETBOOTINFO: - LD A,(CB_BOOTBID) - LD L,A - LD DE,(CB_BOOTVOL) - XOR A - RET -; -; GET CPU INFORMATION -; RETURNS: -; H: Z80 CPU VARIANT -; L: CPU SPEED IN MHZ -; DE: CPU SPEED IN KHZ -; -SYS_GETCPUINFO: - LD H,0 ; NOT YET DEFINED - LD A,(CB_CPUMHZ) - LD L,A - LD DE,(CB_CPUKHZ) - XOR A - RET -; -; GET MEMORY INFORMATION -; RETURNS: -; D: COUNT OF ROM BANKS -; E: COUNT OF RAM BANKS -; -SYS_GETMEMINFO: - LD D,ROMSIZE / 32 - LD E,RAMSIZE / 32 - XOR A - RET -; -; GET BANK CONFIGURATION INFORMATION -; RETURNS: -; D: HBIOS BANK ID -; E: USER BANK ID -; -SYS_GETBNKINFO: - LD A,(CB_BIDBIOS) - LD D,A - LD A,(CB_BIDUSR) - LD E,A - XOR A - RET -; -; GET SERIAL UNIT COUNT -; -SYS_GETCIOCNT: - LD A,(CIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) - LD E,A ; PUT IT IN E - XOR A ; SIGNALS SUCCESS - RET -; -; GET DISK UNIT COUNT -; -SYS_GETDIOCNT: - LD A,(DIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) - LD E,A ; PUT IT IN E - XOR A ; SIGNALS SUCCESS - RET -; -; GET VIDEO UNIT COUNT -; -SYS_GETVDACNT: - LD A,(VDA_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) - LD E,A ; PUT IT IN E - XOR A ; SIGNALS SUCCESS - RET -; -; SET SYSTEM PARAMETERS -; PARAMETER(S) TO SET INDICATED IN C -; -SYS_SET: - LD A,C ; GET REQUESTED SUB-FUNCTION - CP BF_SYSSET_TIMER - JR Z,SYS_SETTIMER - CP BF_SYSSET_BOOTINFO - JR Z,SYS_SETBOOTINFO - OR $FF ; SIGNAL ERROR - RET -; -; SET BOOT INFORMATION -; ON ENTRY: -; L: BOOT BANK ID -; DE: BOOT DISK VOLUME (UNIT/SLICE) -; -SYS_SETBOOTINFO: - LD A,L - LD (CB_BOOTBID),A - LD (CB_BOOTVOL),DE - XOR A - RET -; -; SET TIMER -; ON ENTRY: -; DE:HL: TIMER VALUE (32 BIT) -; -SYS_SETTIMER: - LD BC,HB_TICKS - HB_DI - CALL ST32 - HB_EI - XOR A - RET -; -; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK -; ENTRY: D=BANK ID, HL=ADDRESS -; RETURN: E=BYTE VALUE -; -SYS_PEEK: -#IF (INTMODE == 1) - DI -#ENDIF - CALL HBX_PEEK ; IMPLEMENTED IN PROXY -#IF (INTMODE == 1) - EI -#ENDIF - XOR A - RET -; -; WRITE A BYTE OF MEMORY TO SPECIFIED BANK -; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE -; -SYS_POKE: -#IF (INTMODE == 1) - DI -#ENDIF - CALL HBX_POKE ; IMPLEMENTED IN PROXY -#IF (INTMODE == 1) - EI -#ENDIF - XOR A - RET -; -; INTERRUPT MANAGEMENT FUNCTIONS -; SUBFUNCTION IN C -; -SYS_INT: - LD A,C ; GET REQUESTED SUB-FUNCTION - CP BF_SYSINT_INFO - JR Z,SYS_INTINFO - CP BF_SYSINT_GET - JR Z,SYS_INTGET - CP BF_SYSINT_SET - JR Z,SYS_INTSET - OR $FF ; SIGNAL ERROR - RET -; -; GET INTERRUPT SYSTEM INFORMATION -; RETURN D:=INTERRUPT MODE, E:=INT VEC TABLE SIZE -; -SYS_INTINFO: - LD D,INTMODE ; D := ACTIVE INTERRUPT MODE -#IF (INTMODE == 0) - LD E,0 ; 0 ENTRIES IF INTERRUPTS DISABLED -#ENDIF -#IF (INTMODE == 1) - LD A,(HB_IM1CNT) ; RETURN IM1 CALL LIST SIZE - LD E,A -#ENDIF -#IF (INTMODE == 2) - LD E,HBX_IVTCNT ; RETURN INT VEC TABLE SIZE -#ENDIF - XOR A ; INDICATE SUCCESS - RET ; AND DONE -; -; ROUTINE SHARED BY INT GET/SET. RETURNS ADDRESS OF VECTOR FOR SPECIFIED LIST / TABLE -; POSITION. ZF SET ON RETURN FOR SUCCESS, ELSE ERROR. -; -SYS_INTVECADR: -#IF (INTMODE == 0) - CALL PANIC ; INVALID FOR INT MODE 0 - OR $FF - RET -#ENDIF -#IF (INTMODE == 1) - LD A,(HB_IM1CNT) ; GET CURRENT ENTRY COUNT - INC A ; ALLOW FOR EXTRA ENTRY TO APPEND AT END - LD C,A ; SAVE IN C FOR COMPARE -#ENDIF -#IF (INTMODE == 2) - LD C,HBX_IVTCNT ; GET CURRENT ENTRY COUNT -#ENDIF - LD A,E ; INCOMING INDEX POSITION TO A - CP C ; COMPARE TO VECTOR COUNT - JR C,SYS_INTGET1 ; CONTINUE IF POSITION IN RANGE - CALL PANIC ; ELSE ERROR - OR $FF - RET -SYS_INTGET1: - OR A - RLA ; HL := (A * 2) FOR IM2 -#IF (INTMODE == 1) - RLA ; ... HL := (A * 4) + 1 FOR IM1 - INC A -#ENDIF - LD H,0 - LD L,A -#IF (INTMODE == 1) - LD DE,HB_IM1INT ; DE := START OF CALL LIST -#ENDIF -#IF (INTMODE == 2) - LD DE,HBX_IVT ; DE := START OF VECTOR TABLE -#ENDIF - ADD HL,DE ; HL := ADR OF VECTOR - XOR A ; INDICATE SUCCESS - RET -; -; RETURN THE INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE -; ENTRY: E=LIST/TABLE POSITION -; RETURN: HL=INTERRUPT VECTOR -; -SYS_INTGET: - CALL SYS_INTVECADR ; GET VECTOR ADDRESS - RET NZ ; BAIL OUT ON ERROR - LD A,(HL) ; DEREF HL TO GET VECTOR - INC HL - LD H,(HL) - LD L,A - XOR A ; SIGNAL SUCCESS - RET ; DONE -; -; SET AN INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE -; ENTRY: E=LIST/TABLE POSITION, HL=NEW INTERRUPT VECTOR -; RETURN: HL=PREVIOUS INTERRUPT VECTOR, DE=ADR OF INT ROUTING ENGINE FOR IM2 -; -SYS_INTSET: - PUSH HL ; SAVE NEW VECTOR - CALL SYS_INTVECADR ; GET VECTOR ADDRESS - JR Z,SYS_INTSET1 ; CONTINUE IF OK - POP HL ; FIX STACK - RET NZ ; BAIL OUT ON ERROR -SYS_INTSET1: - PUSH HL ; SAVE VECTOR ADDRESS - LD A,(HL) ; DEREF HL TO GET PREV VECTOR - INC HL - LD H,(HL) - LD L,A - EX (SP),HL ; (SP) := PREV VEC, HL := VEC ADR - POP DE ; DE := PREV VEC - POP BC ; BC := NEW VEC - LD (HL),C ; SAVE LSB - INC HL - LD (HL),B ; SAVE MSB - EX DE,HL ; HL := PREV VEC -#IF (INTMODE == 2) - LD DE,HBX_INT ; DE := IM2 INT ROUTING ENGINE -#ENDIF - XOR A ; SIGNAL SUCCESS - RET ; DONE -; -;================================================================================================== -; GLOBAL HBIOS FUNCTIONS -;================================================================================================== -; -; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN -; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT) -; -CIO_IDLE: - PUSH AF ; PRESERVE AF - LD A,(IDLECOUNT) ; GET CURRENT IDLE COUNT - DEC A ; DECREMENT - LD (IDLECOUNT),A ; SAVE UPDATED VALUE - CALL Z,IDLE ; IF ZERO, DO IDLE PROCESSING - POP AF ; RECOVER AF - RET -; -#IF (INTMODE == 1) -; -; IM1 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK -; LIST OF IM1 INT CALLS IS BUILT DYNAMICALLY BELOW -; SEE HB_ADDIM1 ROUTINE -; EACH ENTRY WILL LOOK LIKE: -; CALL XXXX ; CALL INT HANDLER -; RET NZ ; RETURN IF HANDLED -; -; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. -; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID -; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. -; -; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. -; -HB_IM1INT: ; IM1 DEVICE INTERRUPT HANDLER CALL LIST - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ -; -; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 -; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS -; -HB_ADDIM1: - EX DE,HL ; VECTOR ADDRESS TO DE - LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY - INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE - LD (HL),E ; ADD VECTOR ADDRESS - INC HL ; ... - LD (HL),D ; ... - INC HL ; BUMP PTR - INC HL ; BUMP PTR - LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER - LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT - INC (HL) ; INCREMENT - RET ; DONE -; -HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST -HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST -HB_IM1PTR .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY -; -#ENDIF -; -; TIMER INTERRUPT -; -HB_TIMINT: - ; INCREMENT TICK COUNTER (32 BIT) - LD HL,HB_TICKS ; POINT TO TICK COUNTER - INC (HL) - JR NZ,HB_TIMINT1 - INC HL - INC (HL) - JR NZ,HB_TIMINT1 - INC HL - INC (HL) - JR NZ,HB_TIMINT1 - INC HL - INC (HL) -; -HB_TIMINT1: -; -#IF 0 -; - LD HL,TEMPCNT - DEC (HL) - JR NZ,HB_TIMINT2 - LD (HL),250 -; - LD A,'*' - CALL COUT - JR HB_TIMINT2 -; -TEMPCNT .DB 250 -; -#ENDIF -; -HB_TIMINT2: -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; ACK/RESET Z180 TIMER INTERRUPT - IN0 A,(Z180_TCR) - IN0 A,(Z180_TMDR0L) -#ENDIF -; - OR $FF ; NZ SET TO INDICATE INT HANDLED - RET -; -; BAD INTERRUPT HANDLER -; -HB_BADINT: - CALL NEWLINE2 - PRTS("+++ BAD INT: $") - CALL _REGDMP - CALL CONTINUE - OR $FF ; SIGNAL INTERRUPT HANDLED - RET -; -; COMMON API FUNCTION DISPATCH CODE -; -; ON ENTRY C IS UNIT # (INDEX INTO XXX_TBL OF UNITS) -; AND IY POINTS TO START OF UNIT TABLE. -; USE UNIT # IN C TO LOOKUP XXX_TBL ENTRY. THE XXX_TBL -; ENTRY CONTAINS THE START OF THE DRIVER FUNCTION TABLE AND -; THE DEVICE SPECIFIC INSTANCE DATA (BLOB). SET IY TO BLOB ADDRESS -; AND CALL THE SPECIFIC FUNCTION REQUESTED IN THE DRIVER. -; -HB_DISPCALL: - ; CHECK INCOMING UNIT INDEX IN C FOR VAILIDITY - LD A,C ; A := INCOMING DISK UNIT INDEX - CP (IY-1) ; COMPARE TO COUNT - JR NC,HB_DISPERR ; HANDLE INVALID UNIT INDEX - - ; CHECK FUNCTION INDEX FOR VALIDITY - LD A,B ; A := INCOMING FUNCTION NUMBER - AND $0F ; LOW NIBBLE ONLY FOR FUNC INDEX - CP (IY-3) ; CHECK FN NUM AGAINST MAX - JR NC,HB_DISPERR ; HANDLE FN NUM OUT OF RANGE ERROR - - ; BUMP IY TO ACTUAL XXX_TBL ENTRY FOR INCOMING UNIT INDEX - LD B,0 ; MSB IS ALWAYS ZERO - RLC C ; MULTIPLY UNIT INDEX - RLC C ; ... BY 4 FOR TABLE ENTRY OFFSET - ADD IY,BC ; SET IY TO ENTRY ADDRESS - - ; DERIVE DRIVER FUNC ADR TO CALL - PUSH HL ; SAVE INCOMING HL - LD L,(IY+0) ; COPY DRIVER FUNC TABLE - LD H,(IY+1) ; ... START TO HL - RLCA ; CONV UNIT (STILL IN A) TO FN ADR OFFSET - CALL ADDHLA ; HL NOW HAS DRIVER FUNC TBL START ADR - LD A,(HL) ; DEREFERENCE HL - INC HL ; ... TO GET - LD H,(HL) ; ... ACTUAL - LD L,A ; ... TARGET FUNCTION ADDRESS - EX (SP),HL ; RESTORE HL, FUNC ADR ON STACK - - ; GET UNIT INSTANCE DATA BLOB ADDRESS TO IY - PUSH HL ; SAVE INCOMING HL - LD L,(IY+2) ; HL := DATA BLOB ADDRESS - LD H,(IY+3) ; ... - EX (SP),HL ; RESTORE HL, BLOB ADR ON TOS - POP IY ; IY := BLOB ADR - - RET ; JUMP TO DRIVER FUNC ADR ON TOS -; -HB_DISPERR: - CALL PANIC ; PANIC - OR $FF ; SIGNAL ERROR - RET ; AND RETURN VIA DISPEXIT -; -; ADD AN ENTRY TO THE UNIT TABLE AT ADDRESS IN HL -; BC: DRIVER FUNCTION TABLE -; DE: ADDRESS OF UNIT INSTANCE DATA -; RETURN -; A: UNIT NUMBER ASSIGNED -; -HB_ADDENT: - DEC HL ; POINT TO ENTRY COUNT - LD A,(HL) ; GET ENTRY COUNT - PUSH AF ; SAVE VALUE TO RETURN AS ENTRY NUM AT END - INC A ; INCREMENT TO ACCOUNT FOR NEW ENTRY - DEC HL ; POINT TO ENTRY MAX - CP (HL) ; COMPARE MAX TO CURRENT COUNT (COUNT - MAX) - CALL NC,PANIC ; OVERFLOW - INC HL ; POINT TO COUNT - LD (HL),A ; SAVE NEW COUNT - INC HL ; POINT TO START OF TABLE - DEC A ; CONVERT A FROM ENTRY COUNT TO ENTRY INDEX - RLCA ; MULTIPLY BY 4 - RLCA ; ... TO GET BYTE OFFSET OF ENTRY - CALL ADDHLA ; MAKE HL POINT TO ACTUAL ENTRY ADDRESS - PUSH BC ; GET TABLE ENTRY ADDRESS TO BC - EX (SP),HL ; ... AND DISPATCH ADDRESS TO HL - POP BC ; ... SO THAT DE:HL HAS 32 BIT ENTRY - CALL ST32 ; LD (BC),DE:HL STORES THE ENTRY - POP AF ; RETURN ENTRY INDEX (UNIT NUMBER ASSIGNED) - RET -; -; ALLOCATE HL BYTES OF MEMORY ON THE HEAP -; RETURNS POINTER TO ALLOCATED SPACE IN HL -; ON SUCCESS RETURN A == 0, AND Z SET -; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED -; ALL OTHER REGISTERS PRESERVED -; -; A 4 BYTE HEADER IS PLACED IN FRONT OF THE ALLOCATED MEMORY -; - DWORD: SIZE OF MEMROY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) -; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) -; -HB_ALLOC: - ; SAVE ALLOC SIZE AND REFERENCE ADR FOR SUBSEQUENT HEADER CONSTRUCTION - LD (HB_TMPSZ),HL ; SAVE INCOMING SIZE REQUESTED - ; USE EX (SP),HL INSTEAD???? - POP HL ; GET RETURN ADDRESS - LD (HB_TMPREF),HL ; SAVE AS REFERENCE - ; USE EX (SP),HL INSTEAD???? - PUSH HL ; PUT IT BACK ON STACK - LD HL,(HB_TMPSZ) ; RECOVER INCOMING MEM SIZE PARM -; - ; CALC NEW HEAP TOP AND HANDLE OUT-OF-SPACE ERROR - PUSH DE ; SAVE INCOMING DE - LD DE,4 ; SIZE OF HEADER - ADD HL,DE ; ADD IT IN - JR C,HB_ALLOC1 ; ERROR ON OVERFLOW - LD DE,(CB_HEAPTOP) ; CURRENT HEAP TOP - ADD HL,DE ; ADD IT IN, HL := NEW HEAP TOP - JR C,HB_ALLOC1 ; ERROR ON OVERFLOW - BIT 7,H ; TEST PAST END OF BANK (>= 32K) - JR NZ,HB_ALLOC1 ; ERROR IF PAST END -; - ; SAVE NEW HEAP TOP - LD DE,(CB_HEAPTOP) ; GET ORIGINAL HEAP TOP - LD (CB_HEAPTOP),HL ; SAVE NEW HEAP TOP -; - ; SET HEADER VALUES - EX DE,HL ; HEADER ADR TO HL - LD DE,(HB_TMPSZ) ; GET THE ORIG SIZE REQUESTED - LD (HL),E ; SAVE SIZE (LSB) - INC HL ; BUMP HEADER POINTER - LD (HL),D ; SAVE SIZE (MSB) - INC HL ; BUMP HEADER POINTER - LD DE,(HB_TMPREF) ; GET THE REFERENCE ADR - LD (HL),E ; SAVE REF ADR (LSB) - INC HL ; BUMP HEADER POINTER - LD (HL),D ; SAVE REF ADR (MSB) - INC HL ; BUMP HEADER POINTER -; - ; RETURN SUCCESS, HL POINTS TO START OF ALLOCATED MEMORY (PAST HEADER) - POP DE ; RESTORE INCOMING DE - XOR A ; SIGNAL SUCCESS - RET ; AND RETURN -; -HB_ALLOC1: - ; ERROR RETURN - POP DE ; RESTORE INCOMING DE - OR $FF ; SIGNAL ERROR - RET ; AND RETURN -; -HB_TMPSZ .DW 0 -HB_TMPREF .DW 0 -; -;================================================================================================== -; DEVICE DRIVERS -;================================================================================================== -; -#IF (SIMRTCENABLE) -ORG_SIMRTC .EQU $ - #INCLUDE "simrtc.asm" -SIZ_SIMRTC .EQU $ - ORG_SIMRTC - .ECHO "SIMRTC occupies " - .ECHO SIZ_SIMRTC - .ECHO " bytes.\n" -#ENDIF -; -#IF (DSRTCENABLE) -ORG_DSRTC .EQU $ - #INCLUDE "dsrtc.asm" -SIZ_DSRTC .EQU $ - ORG_DSRTC - .ECHO "DSRTC occupies " - .ECHO SIZ_DSRTC - .ECHO " bytes.\n" -#ENDIF -; -#IF (ASCIENABLE) -ORG_ASCI .EQU $ - #INCLUDE "asci.asm" -SIZ_ASCI .EQU $ - ORG_ASCI - .ECHO "ASCI occupies " - .ECHO SIZ_ASCI - .ECHO " bytes.\n" -#ENDIF -; -#IF (UARTENABLE) -ORG_UART .EQU $ - #INCLUDE "uart.asm" -SIZ_UART .EQU $ - ORG_UART - .ECHO "UART occupies " - .ECHO SIZ_UART - .ECHO " bytes.\n" -#ENDIF -; -#IF (SIOENABLE) -ORG_SIO .EQU $ - #INCLUDE "sio.asm" -SIZ_SIO .EQU $ - ORG_SIO - .ECHO "SIO occupies " - .ECHO SIZ_SIO - .ECHO " bytes.\n" -#ENDIF -; -#IF (ACIAENABLE) -ORG_ACIA .EQU $ - #INCLUDE "acia.asm" -SIZ_ACIA .EQU $ - ORG_ACIA - .ECHO "ACIA occupies " - .ECHO SIZ_ACIA - .ECHO " bytes.\n" -#ENDIF -; -#IF (VGAENABLE) -ORG_VGA .EQU $ - #INCLUDE "vga.asm" -SIZ_VGA .EQU $ - ORG_VGA - .ECHO "VGA occupies " - .ECHO SIZ_VGA - .ECHO " bytes.\n" -#ENDIF -; -#IF (CVDUENABLE) -ORG_CVDU .EQU $ - #INCLUDE "cvdu.asm" -SIZ_CVDU .EQU $ - ORG_CVDU - .ECHO "CVDU occupies " - .ECHO SIZ_CVDU - .ECHO " bytes.\n" -#ENDIF -; -#IF (VDUENABLE) -ORG_VDU .EQU $ - #INCLUDE "vdu.asm" -SIZ_VDU .EQU $ - ORG_VDU - .ECHO "VDU occupies " - .ECHO SIZ_VDU - .ECHO " bytes.\n" -#ENDIF -; -#IF (TMSENABLE) -ORG_TMS .EQU $ - #INCLUDE "tms.asm" -SIZ_TMS .EQU $ - ORG_TMS - .ECHO "TMS occupies " - .ECHO SIZ_TMS - .ECHO " bytes.\n" -#ENDIF -; -#IF (NECENABLE) -ORG_NEC .EQU $ - ;#INCLUDE "nec.asm" -SIZ_NEC .EQU $ - ORG_NEC - .ECHO "NEC occupies " - .ECHO SIZ_NEC - .ECHO " bytes.\n" -#ENDIF -; -#IF (CVDUENABLE | VGAENABLE) -ORG_FONTHI .EQU $ - #INCLUDE "font_hi.asm" -SIZ_FONTHI .EQU $ - ORG_FONTHI - .ECHO "FONTHI occupies " - .ECHO SIZ_FONTHI - .ECHO " bytes.\n" -#ENDIF -; -#IF (TMSENABLE) -ORG_FONTTMS .EQU $ - #INCLUDE "font_tms.asm" -SIZ_FONTTMS .EQU $ - ORG_FONTTMS - .ECHO "FONTTMS occupies " - .ECHO SIZ_FONTTMS - .ECHO " bytes.\n" -#ENDIF -; -#IF (CVDUENABLE | VGAENABLE) -ORG_KBD .EQU $ - #INCLUDE "kbd.asm" -SIZ_KBD .EQU $ - ORG_KBD - .ECHO "KBD occupies " - .ECHO SIZ_KBD - .ECHO " bytes.\n" -#ENDIF -; -#IF (VDUENABLE | (TMSENABLE & (PLATFORM == PLT_N8))) -ORG_PPK .EQU $ - #INCLUDE "ppk.asm" -SIZ_PPK .EQU $ - ORG_PPK - .ECHO "PPK occupies " - .ECHO SIZ_PPK - .ECHO " bytes.\n" -#ENDIF -; -#IF (PRPENABLE) -ORG_PRP .EQU $ - #INCLUDE "prp.asm" -SIZ_PRP .EQU $ - ORG_PRP - .ECHO "PRP occupies " - .ECHO SIZ_PRP - .ECHO " bytes.\n" -#ENDIF -; -#IF (PPPENABLE) -ORG_PPP .EQU $ - #INCLUDE "ppp.asm" -SIZ_PPP .EQU $ - ORG_PPP - .ECHO "PPP occupies " - .ECHO SIZ_PPP - .ECHO " bytes.\n" -#ENDIF -; -#IF (MDENABLE) -ORG_MD .EQU $ - #INCLUDE "md.asm" -SIZ_MD .EQU $ - ORG_MD - .ECHO "MD occupies " - .ECHO SIZ_MD - .ECHO " bytes.\n" -#ENDIF - -#IF (FDENABLE) -ORG_FD .EQU $ - #INCLUDE "fd.asm" -SIZ_FD .EQU $ - ORG_FD - .ECHO "FD occupies " - .ECHO SIZ_FD - .ECHO " bytes.\n" -#ENDIF - -#IF (RFENABLE) -ORG_RF .EQU $ - #INCLUDE "rf.asm" -SIZ_RF .EQU $ - ORG_RF - .ECHO "RF occupies " - .ECHO SIZ_RF - .ECHO " bytes.\n" -#ENDIF - -#IF (IDEENABLE) -ORG_IDE .EQU $ - #INCLUDE "ide.asm" -SIZ_IDE .EQU $ - ORG_IDE - .ECHO "IDE occupies " - .ECHO SIZ_IDE - .ECHO " bytes.\n" -#ENDIF - -#IF (PPIDEENABLE) -ORG_PPIDE .EQU $ - #INCLUDE "ppide.asm" -SIZ_PPIDE .EQU $ - ORG_PPIDE - .ECHO "PPIDE occupies " - .ECHO SIZ_PPIDE - .ECHO " bytes.\n" -#ENDIF - -#IF (SDENABLE) -ORG_SD .EQU $ - #INCLUDE "sd.asm" -SIZ_SD .EQU $ - ORG_SD - .ECHO "SD occupies " - .ECHO SIZ_SD - .ECHO " bytes.\n" -#ENDIF - -#IF (HDSKENABLE) -ORG_HDSK .EQU $ - #INCLUDE "hdsk.asm" -SIZ_HDSK .EQU $ - ORG_HDSK - .ECHO "HDSK occupies " - .ECHO SIZ_HDSK - .ECHO " bytes.\n" -#ENDIF - -#IF (TERMENABLE) -ORG_TERM .EQU $ - #INCLUDE "term.asm" -SIZ_TERM .EQU $ - ORG_TERM - .ECHO "TERM occupies " - .ECHO SIZ_TERM - .ECHO " bytes.\n" -#ENDIF -; -#IF (SPKENABLE) -ORG_SPK .EQU $ - #INCLUDE "spk.asm" -SIZ_SPK .EQU $ - ORG_SPK - .ECHO "SPK occupies " - .ECHO SIZ_SPK - .ECHO " bytes.\n" -#ENDIF -; -#IF (AYENABLE) -ORG_AY .EQU $ - #INCLUDE "ay.asm" -SIZ_AY .EQU $ - ORG_AY - .ECHO "AY occupies " - .ECHO SIZ_AY - .ECHO " bytes.\n" -#ENDIF - -#IF (PIOENABLE) -ORG_PIO .EQU $ - #INCLUDE "pio.asm" -SIZ_PIO .EQU $ - ORG_PIO - .ECHO "PIO occupies " - .ECHO SIZ_PIO - .ECHO " bytes.\n" -#ENDIF -; -#DEFINE USEDELAY -#INCLUDE "util.asm" -#INCLUDE "time.asm" -#INCLUDE "bcd.asm" -#INCLUDE "decode.asm" -;#INCLUDE "xio.asm" -; -#IF (DSKYENABLE) -#DEFINE DSKY_KBD -#INCLUDE "dsky.asm" -#ENDIF -; -; DETECT CPU SPEED USING DS-1302 RTC -; -HB_CPUSPD: -; -#IF (DSRTCENABLE) -; - CALL DSRTC_TSTCLK ; IS CLOCK RUNNING? - JR Z,HB_CPUSPD1 ; YES, CONTINUE - ; MAKE SURE CLOCK IS RUNNING - LD HL,DSRTC_TIMDEF - CALL DSRTC_TIM2CLK - LD HL,DSRTC_BUF - CALL DSRTC_WRCLK - CALL DSRTC_TSTCLK ; NOW IS CLOCK RUNNING? - RET NZ -; -HB_CPUSPD1: -; LD B,8 -;HB_CPUSPDX: -; PUSH BC - - ; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT - ; FOR SECOND TICK AND TO GET A FULL ONE SECOND LOOP COUNT - - CALL HB_RDSEC ; GET SECONDS - LD (HB_CURSEC),A ; AND INIT CURSEC - CALL HB_WAITSEC ; WAIT FOR SECONDS TICK - LD (HB_CURSEC),A ; SAVE NEW VALUE - CALL HB_WAITSEC ; WAIT FOR SECONDS TICK - -; PUSH DE -; POP BC -; CALL NEWLINE -; CALL PRTHEXWORD - -; POP BC -; DJNZ HB_CPUSPDX -; - LD A,H - OR L - RET Z ; FAILURE, USE DEFAULT CPU SPEED - -; - ; MOVE LOOP COUNT TO HL - PUSH DE - POP HL -; - ; TIMES 4 FOR CPU SPEED IN KHZ - RES 0,L ; GRANULARITY -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - SLA L - RL H -#ENDIF - SLA L - RL H - SLA L - RL H -; - LD (CB_CPUKHZ),HL - LD DE,1000 - CALL DIV16 - LD A,C - LD (CB_CPUMHZ),A -; - RET -; -HB_WAITSEC: - ; WAIT FOR SECONDS TICK - ; RETURN SECS VALUE IN A, LOOP COUNT IN DE - LD DE,0 ; INIT LOOP COUNTER -HB_WAITSEC1: -#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2)| (PLATFORM == PLT_RC)) - ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 - CALL DLY32 - CALL DLY8 - CALL DLY2 - JP $ + 3 ; 10 TSTATES - JP $ + 3 ; 10 TSTATES - JP $ + 3 ; 10 TSTATES - JP $ + 3 ; 10 TSTATES - ;LD A,R ; 9 TSTATES - INC BC ; 6 TSTATES - ;LD A,(BC) ; 7 TSTATES - ;NOP ; 4 TSTATES - NOP ; 4 TSTATES -#ENDIF - -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; LOOP TARGET IS 8000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 8 - ;CALL DLY64 - CALL DLY32 - CALL DLY16 - CALL DLY8 - CALL DLY4 - CALL DLY2 - CALL DLY1 ; CALL (25TS) & RET (18TS) = 43TS - OR A ; 7 TSTATES - OR A ; 7 TSTATES - ;OR A ; 7 TSTATES - ;OR A ; 7 TSTATES - NOP ; 6 TSTATES - ;NOP ; 6 TSTATES - ;NOP ; 6 TSTATES - ;NOP ; 6 TSTATES - ;NOP ; 6 TSTATES -#ENDIF -; - PUSH DE - CALL HB_RDSEC ; GET SECONDS - POP DE - INC DE ; BUMP COUNTER - LD HL,HB_CURSEC ; POINT TO COMP VALUE - CP (HL) ; TEST FOR CHANGE - RET NZ ; DONE IF TICK OCCURRED - LD A,D ; CHECK HL - OR E ; ... FOR OVERFLOW - RET Z ; TIMEOUT, SOMETHING IS WRONG - JR HB_WAITSEC1 ; LOOP -; -HB_RDSEC: - ; READ SECONDS BYTE INTO A - LD C,$81 ; SECONDS REGISTER - CALL DSRTC_CMD ; SEND THE COMMAND - CALL DSRTC_GET ; READ THE REGISTER - CALL DSRTC_END ; FINISH IT - RET -; -#ELSE -; - RET ; NO RTC, ABORT -; -#ENDIF -; -; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 -; -PRTD3M: - PUSH BC - PUSH DE - PUSH HL - LD E,'0' - LD BC,-10000 - CALL PRTD3M1 - LD E,0 - LD BC,-1000 - CALL PRTD3M1 - CALL PC_PERIOD - LD BC,-100 - CALL PRTD3M1 - LD C,-10 - CALL PRTD3M1 - LD C,-1 - CALL PRTD3M1 - POP HL - POP DE - POP BC - RET -PRTD3M1: - LD A,'0' - 1 -PRTD3M2: - INC A - ADD HL,BC - JR C,PRTD3M2 - SBC HL,BC - CP E - JR Z,PRTD3M3 - LD E,0 - CALL COUT -PRTD3M3: - RET -; -;================================================================================================== -; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES -;================================================================================================== -; -PRTSUM: - CALL NEWLINE2 ; SKIP A LINE - LD DE,PS_STRHDR ; POINT TO HEADER - CALL WRITESTR ; PRINT IT -; - ; PRINT DISK DEVICES - LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET - LD C,BF_SYSGET_DIOCNT ; SUBFUNC: DISK UNIT COUNT - RST 08 ; E := DISK UNIT COUNT - LD B,E ; MOVE TO B FOR LOOP COUNT - LD A,E ; MOVE TO ACCUM - OR A ; SET FLAGS - JR Z,PRTSUM1A ; IF NONE, BYPASS - LD C,0 ; C WILL BE UNIT INDEX -PRTSUM1: - PUSH BC ; SAVE LOOP CONTROL - CALL PS_DISK ; PRINT DISK INFO - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP DISK UNIT INDEX - DJNZ PRTSUM1 ; LOOP THRU ALL DISK DEVICES -; -PRTSUM1A: - ; PRINT SERIAL DEVICES - LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET - LD C,BF_SYSGET_CIOCNT ; SUBFUNC: SERIAL UNIT COUNT - RST 08 ; E := SERIAL UNIT COUNT - LD B,E ; MOVE TO B FOR LOOP COUNT - LD A,E ; MOVE TO ACCUM - OR A ; SET FLAGS - JR Z,PRTSUM2A ; IF NONE, BYPASS - LD C,0 ; C WILL BE UNIT INDEX -PRTSUM2: - PUSH BC ; SAVE LOOP CONTROL - CALL PS_SERIAL ; PRINT SERIAL INFO - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP SERIAL UNIT INDEX - DJNZ PRTSUM2 ; LOOP THRU ALL SERIAL DEVICES -; -PRTSUM2A: - ; PRINT VIDEO DEVICES - LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET - LD C,BF_SYSGET_VDACNT ; SUBFUNC: VIDEO UNIT COUNT - RST 08 ; E := SERIAL UNIT COUNT - LD B,E ; MOVE TO B FOR LOOP COUNT - LD A,E ; MOVE TO ACCUM - OR A ; SET FLAGS - JR Z,PRTSUM3A ; IF NONE, BYPASS - LD C,0 ; C WILL BE UNIT INDEX -PRTSUM3: - PUSH BC ; SAVE LOOP CONTROL - CALL PS_VIDEO ; PRINT VIDEO INFO - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP VIDEO UNIT INDEX - DJNZ PRTSUM3 ; LOOP THRU ALL VIDEO DEVICES -; -PRTSUM3A: - RET ; DONE -; -; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C -; -PS_DISK: - PUSH BC ; SAVE UNIT INDEX FOR LATER -; - ; UNIT COLUMN - PRTS("Disk $") - LD A,C ; MOVE UNIT NUM TO A - CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT - PRTS(" $") ; PAD TO NEXT COLUMN -; - ; DEVICE COLUMN - LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C - RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES - LD HL,PS_DDSTRREF ; POINT TO DISK DEVICE TYPE NAME TABLE - CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH - POP DE ; RECOVER ATTRIBUTES TO DE - PUSH DE ; SAVE ATTRIBUTES AGAIN - CALL PS_PRTDT ; PRINT DISK TYPE - POP DE ; RESTORE ATTRIBUTES - POP BC ; RESTORE UNIT NUM - CALL PS_PRTDC ; PRINT DISK CAPACITY -; - CALL NEWLINE - RET -; -; PRINT DISK TYPE (DISK ATTRIBUTE IN E) -; -PS_PRTDT: - LD A,E ; ATTRIBUTES TO A - BIT 7,A ; FLOPPY BIT SET? - LD HL,PS_DTFLOP ; ASSUME FLOPPY - JR NZ,PS_PRTDT1 ; IF FLOPPY, JUMP AHEAD - RRCA ; SHIFT TYPE BITS - RRCA - RRCA - AND $07 ; AND ISOLATE THEM - RLCA ; X2 FOR WORD OFFSET IN STRING TABLE - LD HL,PS_DTSTRREF + 2 ; POINT TO STR REF TABLE (SKIP FLOPPY STRING) - CALL ADDHLA - LD A,(HL) - INC HL - LD H,(HL) - LD L,A -; -PS_PRTDT1: - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,18 ; 18 CHAR FIELD - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E) -; -PS_PRTDC: -; - LD A,E ; ATTRIBUTE TO ACCUM - BIT 7,A ; TEST FOR FLOPPY - JR NZ,PS_PRTDC2 ; HANDLE FLOPPY - RRCA ; ISOLATE TYPE BITS - RRCA - RRCA - AND $07 - CP 4 ; ROM DISK? - JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB - CP 5 ; RAM DISK? - JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB -; - ; PRINT HARD DISK STORAGE SIZE IN MB - LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY - RST 08 ; DE:HL := BLOCKS - JP NZ,PS_PRTNUL ; MEDIA PROBLEM - RES 7,D ; CLEAR LBA BIT - LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB - CALL SRL32 ; RIGHT SHIFT - CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) - PRTS("MB$") ; PRINT SUFFIX - CALL PC_COMMA - PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA - RET ; DONE -; -PS_PRTDC1: - ; PRINT ROM/ROM DISK CAPACITY IN KB - LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY - RST 08 ; DE:HL := BLOCKS - JP NZ,PS_PRTNUL ; MEDIA PROBLEM - RES 7,D ; CLEAR LBA BIT - LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB - CALL SRL32 ; RIGHT SHIFT - CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) - PRTS("KB$") ; PRINT SUFFIX - CALL PC_COMMA - PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA - RET ; DONE -; -PS_PRTDC2: - LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING - ; PRINT FLOPPY TYPE - LD A,C ; ATTRIBUTE TO ACCUM - RLCA ; ISOLATE FORM FACTOR BITS - RLCA - RLCA - AND $03 - LD DE,PS_FLP8 ; ASSUME 8" - CP 0 - JR Z,PS_PRTDC2A - LD DE,PS_FLP5 ; ASSUME 5.25" - CP 1 - JR Z,PS_PRTDC2A - LD DE,PS_FLP3 ; ASSUME 3.5" - CP 2 - JR Z,PS_PRTDC2A - LD DE,PS_FLPN ; ASSUME OTHER" -PS_PRTDC2A: - CALL WRITESTR - ; PRINT FLOPPY SIDES - LD A,C ; ATTRIBUTE TO ACCUM - LD DE,PS_FLPSS ; ASSUME SINGLE SIDED - BIT 4,A ; DS? - JR Z,PS_PRTDC2B - LD DE,PS_FLPDS ; DOUBLE SIDED -PS_PRTDC2B: - CALL WRITESTR - ; PRINT FLOPPY DENSITY - LD A,C ; ATTRIBUTE TO ACCUM - RRCA ; ISOLATE DENSITY BITS - RRCA - AND $03 - LD DE,PS_FLPSD ; SINGLE DENSITY - CP 0 - JR Z,PS_PRTDC2C - LD DE,PS_FLPDD ; DOUBLE DENSITY - CP 1 - JR Z,PS_PRTDC2C - LD DE,PS_FLPHD ; HIGH DENSITY - CP 2 - JR Z,PS_PRTDC2C - LD DE,PS_FLPED ; EXTENDED DENSITY - CP 3 - JR Z,PS_PRTDC2C -PS_PRTDC2C: - CALL WRITESTR - CALL PC_COMMA - PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA -; - RET ; DONE -; -; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C -; -PS_SERIAL: - PUSH BC ; SAVE UNIT INDEX FOR LATER -; - ; UNIT COLUMN - PRTS("CharIO $") - LD A,C ; MOVE UNIT NUM TO A - CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT - PRTS(" $") ; PAD TO NEXT COLUMN -; - ; DEVICE COLUMN - LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C - RST 08 ; DE:=DEVTYP/NUM, C:=DEVICE ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES - LD HL,PS_SDSTRREF ; POINT TO SERIAL DEVICE TYPE NAME TABLE - CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH - POP BC ; RECOVER ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES AGAIN - CALL PS_PRTST ; PRINT SERIAL TYPE - POP BC ; RESTORE ATTRIBUTES - POP DE ; RESTORE UNIT NUM TO E - CALL PS_PRTSC ; PRINT SERIAL CONFIG -; - CALL NEWLINE - RET -; -; PRINT SERIAL TYPE (SERIAL ATTRIBUTE IN E) -; -PS_PRTST: - LD HL,PS_STRS232 ; ASSUME RS-232 - LD A,C - AND $C0 - JR Z,PS_PRTST1 ; 00 TYPE 0 - RS-232 - LD HL,PS_STTERM - CP $40 - JR Z,PS_PRTST1 ; 40 TYPE 1 - Terminal - LD HL,PS_STPPT - CP $80 - JR Z,PS_PRTST1 ; 80 TYPE 2 - Parallel - LD HL,PS_STUDEF -; ; C0 TYPE 3 - Undefined -PS_PRTST1: - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,18 ; 18 CHAR FIELD - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) -; -PS_PRTSC: - LD A,C - AND $C0 - JR Z,PS_PRTSC0_1 ; 00 TYPE 0 - RS-232 - CP $40 - JR Z,PS_PRTSC1 ; 40 TYPE 1 - Terminal - CP $80 - JR Z,PS_PRTSC2_1 ; 80 TYPE 2 - Parallel -; ; C0 TYPE 3 - Undefined -PS_PRTSC0_1: - ; PRINT RS-232 CONFIG - LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG - LD C,E ; SET SERIAL UNIT NUM - RST 08 ; DE:HL := BAUD RATE - LD A,D ; TEST FOR $FF - AND E - INC A ; SET Z IF DE == $FF - JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED -; -PS_PRTSC0: - ; PRINT BAUD RATE - PUSH DE ; PRESERVE DE - LD A,D - AND $1F ; ISOLATE ENCODED BAUD RATE - LD L,A ; PUT IN L - LD H,0 ; H IS ALWAYS ZERO - LD DE,75 ; BAUD RATE DECODE CONSTANT - CALL DECODE ; DE:HL := BAUD RATE - LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF - CALL BIN2BCD ; CONVERT TO BCD - CALL PRTBCD ; AND PRINT IN DECIMAL - POP DE ; RESTORE DE -; - ; PRINT DATA BITS - PUSH DE ; PRESERVE DE - CALL PC_COMMA ; FORMATTING - LD A,E ; GET CONFIG BYTE - AND $03 ; ISOLATE DATA BITS VALUE - ADD A,'5' ; CONVERT TO CHARACTER - CALL COUT ; AND PRINT - POP DE ; RESTORE DE -; - ; PRINT PARITY - PUSH DE ; PRESERVE DE - CALL PC_COMMA ; FORMATTING - LD A,E ; GET CONFIG BYTE - RRCA ; SHIFT RELEVANT BITS - RRCA ; ... - RRCA ; ... - AND $07 ; AND ISOLATE DATA BITS VALUE - LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE - CALL ADDHLA ; APPLY OFFSET - LD A,(HL) ; GET CHARACTER - CALL COUT ; AND PRINT - POP DE ; RESTORE DE -; - ; PRINT STOP BITS - CALL PC_COMMA ; FORMATTING - LD A,E ; GET CONFIG BYTE - RRCA ; SHIFT RELEVANT BITS - RRCA ; ... - AND $01 ; AND ISOLATE DATA BITS VALUE - ADD A,'1' ; MAKE IT A CHARACTER - CALL COUT ; AND PRINT -; - RET -; -PS_PRTSC2_1: - ; PRINT PARALLEL CONFIG - LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG - LD C,E ; SET SERIAL UNIT NUM - RST 08 ; DE:HL := I/O CONFIG - LD A,D ; TEST FOR $FF - AND E - INC A ; SET Z IF DE == $FF - JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED - LD A,E - OR A - LD HL,PS_STPPTIN ; Parallel Input - JR Z,PS_PRTST1 - LD HL,PS_STPPTOUT ; Parallel Output - DEC A - JR Z,PS_PRTST1 - LD HL,PS_STRPPTBD ; Parallel BiDirectional - DEC A - JP Z,PS_PRTST1 - JP PS_PRTNUL - RET -; -PS_PRTSC1: - ; PRINT TERMINAL CONFIG - LD A,C ; GET ATTRIBUTE VALUE - CP $FF ; NO ATTACHED VDA - JR Z,PS_PRTSC2 - PRTS("Video $") ; FORMATTING - AND $0F ; ISOLATE VIDEO UNIT NUM - CALL PRTDECB ; PRINT IT - CALL PC_COMMA -#IF (VDAEMU == EMUTYP_TTY) - PRTS("TTY$") -#ENDIF -#IF (VDAEMU == EMUTYP_ANSI) - PRTS("ANSI$") -#ENDIF - RET -; -PS_PRTSC2: - PRTS("PropTerm$") ; ASSUME PROPELLER - CALL PC_COMMA - PRTS("ANSI$") - RET -; -PS_PRTPC0: - RET - ; -; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C -; -PS_VIDEO: - PUSH BC ; SAVE UNIT INDEX FOR LATER -; - ; UNIT COLUMN - PRTS("Video $") - LD A,C ; MOVE UNIT NUM TO A - CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT - PRTS(" $") ; PAD TO NEXT COLUMN -; - ; DEVICE COLUMN - LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C - RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES - LD HL,PS_VDSTRREF ; POINT TO VIDEO DEVICE TYPE NAME TABLE - CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH - POP DE ; RECOVER ATTRIBUTES - PUSH DE ; SAVE ATTRIBUTES AGAIN - CALL PS_PRTVT ; PRINT VIDEO TYPE - POP DE ; RESTORE ATTRIBUTES - POP BC ; RESTORE UNIT NUM - CALL PS_PRTVC ; PRINT VIDEO CONFIG -; - CALL NEWLINE - RET -; -; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E) -; -PS_PRTVT: - LD HL,PS_VTCRT ; ASSUME CRT - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,18 ; 18 CHAR FIELD - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E) -; -PS_PRTVC: - PRTS("Text$") - CALL PC_COMMA - LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG - RST 08 ; D:=ROWS, E:=COLS - LD A,E - CALL PRTDECB - LD A,'x' - CALL COUT - LD A,D - CALL PRTDECB - RET -; -; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE -; -PS_PRTDEV: - LD A,D - RRCA ; TYPE IS IN UPPER NIBBLE, MOVE TO LOWER NIBBLE - RRCA - RRCA - RRCA - RLCA ; X2 FOR WORD OFFSET IN STRING TABLE - CALL ADDHLA - LD A,(HL) - INC HL - LD H,(HL) - LD L,A - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,E ; NUM - CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR - CALL PC_COLON ; PRINT COLON - LD A,12 - 2 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE -; -PS_PRTNUL: - LD HL,PS_STRNUL - ; FALL THRU TO PS_PRT -; -; -; -PS_PRT: - ; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C - LD C,0 ; INIT CHAR COUNT -PS_PRT1: - LD A,(HL) ; GET CHAR - INC HL ; BUMP INDEX - CP '$' ; TERM? - RET Z ; IF SO, DONE - CALL COUT ; PRINT IT - INC C ; BUMP COUNTER - JR PS_PRT1 ; AND LOOP -; -; -; -PS_PAD: - ; PAD N SPACES SPECIFIED IN A - LD B,A - LD A,' ' -PS_PAD1: - CALL COUT - DJNZ PS_PAD1 - RET -; -; -; -PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE -; -; DISK DEVICE STRINGS -; -PS_DDSTRREF: - .DW PS_DDMD, PS_DDFD, PS_DDRF, PS_DDIDE, PS_DDATAPI, PS_DDPPIDE - .DW PS_DDSD, PS_DDPRPSD, PS_DDPPPSD, PS_DDHDSK -; -PS_DDMD .TEXT "MD$" -PS_DDFD .TEXT "FD$" -PS_DDRF .TEXT "RF$" -PS_DDIDE .TEXT "IDE$" -PS_DDATAPI .TEXT "ATAPI$" -PS_DDPPIDE .TEXT "PPIDE$" -PS_DDSD .TEXT "SD$" -PS_DDPRPSD .TEXT "PRPSD$" -PS_DDPPPSD .TEXT "PPPSD$" -PS_DDHDSK .TEXT "HDSK$" -; -; DISK TYPE STRINGS -; -PS_DTSTRREF: - .DW PS_DTFLOP, PS_DTHARD, PS_DTCF, PS_DTSD - .DW PS_DTUSB, PS_DTROM, PS_DTRAM, PS_DTRF -; -PS_DTFLOP .TEXT "Floppy Disk$" -PS_DTHARD .TEXT "Hard Disk$" -PS_DTCF .TEXT "CompactFlash$" -PS_DTSD .TEXT "SD Card$" -PS_DTUSB .TEXT "USB Drive$" -PS_DTROM .TEXT "ROM Disk$" -PS_DTRAM .TEXT "RAM Disk$" -PS_DTRF .TEXT "RAM Floppy$" -PS_DTOTHER .TEXT "???$" -; -; FLOPPY ATTRIBUTE STRINGS -; -PS_FLP8 .TEXT "8\",$" -PS_FLP5 .TEXT "5.25\",$" -PS_FLP3 .TEXT "3.5\",$" -PS_FLPN .TEXT "???\",$" -; -PS_FLPSS .TEXT "SS/$" -PS_FLPDS .TEXT "DS/$" -; -PS_FLPSD .TEXT "SD$" -PS_FLPDD .TEXT "DD$" -PS_FLPHD .TEXT "HD$" -PS_FLPED .TEXT "ED$" -; -; SERIAL DEVICE STRINGS -; -PS_SDSTRREF: - .DW PS_SDUART, PS_SDASCI, PS_SDTERM, - .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO -; -PS_SDUART .TEXT "UART$" -PS_SDASCI .TEXT "ASCI$" -PS_SDTERM .TEXT "TERM$" -PS_SDPRPCON .TEXT "PRPCON$" -PS_SDPPPCON .TEXT "PPPCON$" -PS_SDSIO .TEXT "SIO$" -PS_SDACIA .TEXT "ACIA$" -PS_SDPIO .TEXT "PORT$" -; -; SERIAL TYPE STRINGS -; -PS_STRS232 .TEXT "RS-232$" -PS_STTERM .TEXT "Terminal$" -PS_STPPT .TEXT "Parallel$" -PS_STUDEF .TEXT "Undefined$" -; -PS_STPARMAP .DB "NONENMNS" -; -; PARALLEL TYPE STRINGS -; -PS_STPPTIN .TEXT "Input$" -PS_STPPTOUT .TEXT "Output$" -PS_STRPPTBD .TEXT "Bi-Directional$" -; -; VIDEO DEVICE STRINGS -; -PS_VDSTRREF: - .DW PS_VDVDU, PS_VDCVDU, PS_VDNEC, PS_VDTMS, PS_VDVGA -; -PS_VDVDU .TEXT "VDU$" -PS_VDCVDU .TEXT "CVDU$" -PS_VDNEC .TEXT "NEC$" -PS_VDTMS .TEXT "TMS$" -PS_VDVGA .TEXT "VGA$" -; -; VIDEO TYPE STRINGS -; -PS_VTCRT .TEXT "CRT$" -; -; VIDEO CONFIG STRINGS -; -; -; -; 0 1 2 3 4 5 6 7 -; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 -PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" - .TEXT "---------- ---------- ---------------- --------------------\r\n$" -; -;================================================================================================== -; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) -;================================================================================================== -; -; OUTPUT CHARACTER FROM A -; -COUT: - ; SAVE ALL INCOMING REGISTERS - PUSH AF - PUSH BC - PUSH DE - PUSH HL -; - ; GET CURRENT CONSOLE UNIT - LD E,A ; TEMPORARILY STASH OUTPUT CHAR IN E - LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE - CP $FF ; TEST FOR $FF (HBIOS NOT READY) - JR Z,COUT1 ; IF NOT READY, USE XIO -; - ; USE HBIOS - LD C,A ; CONSOLE UNIT TO C - LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR - CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY - JR COUT2 ; CONTINUE -; -COUT1: - ;; USE XIO - ;LD A,E ; GET OUTPUT CHAR BACK TO ACCUM - ;CALL XIO_OUTC ; OUTPUT VIA XIO -; -COUT2: - ; RESTORE ALL REGISTERS - POP HL - POP DE - POP BC - POP AF - RET -; -; INPUT CHARACTER TO A -; -CIN: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE - CP $FF ; TEST FOR $FF (HBIOS NOT READY) - JR Z,CIN1 ; IF NOT READY, USE XIO -; - ; USE HBIOS - LD C,A ; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY - LD A,E ; RESULTANT CHAR TO A - JR CIN2 ; CONTINUE -; -CIN1: - ;; USE XIO - ;CALL XIO_INC ; GET CHAR -; -CIN2: -; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) -; -CST: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE - CP $FF ; TEST FOR $FF (HBIOS NOT READY) - JR Z,CST1 ; IF NOT READY, USE XIO -; - ; USE HBIOS - LD C,A ; CONSOLE UNIT TO C - LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS - CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY - JR CST2 ; CONTINUE -; -CST1: - ;; USE XIO - ;CALL XIO_IST ; GET STATUS -; -CST2: - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -;================================================================================================== -; MISCELLANEOUS UTILITY FUNCTIONS -;================================================================================================== -; -; SET HL TO IY+A, A IS TRASHED -; -LDHLIYA: - PUSH IY ; COPY INSTANCE DATA PTR - POP HL ; ... TO HL - ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN - ADD A,L ; ADD OFFSET TO LSB - LD L,A ; ... PUT BACK IN L - RET NC ; DONE IF CF NOT SET - INC H ; IF CF SET, BUMP MSB - RET ; ... AND RETURN -; -; CONVERT AN HBIOS STANDARD HARD DISK CHS ADDRESS TO -; AN LBA ADDRESS. A STANDARD HBIOS HARD DISK IS ASSUMED -; TO HAVE 16 SECTORS PER TRACK AND 16 HEADS PER CYLINDER. -; -; INPUT: HL=TRACK, D=HEAD, E=SECTOR -; OUTPUT: DE:HL=32 BIT LBA ADDRESS (D:7 IS NOT SET IN THE RESULT) -; -HB_CHS2LBA: -; - LD A,D ; HEAD TO A - RLCA ; LEFT SHIFT TO HIGH NIBBLE - RLCA ; ... DEPENDS ON HIGH - RLCA ; ... NIBBLE BEING 0 SINCE - RLCA ; ... IT ROTATES INTO LOW NIBBLE - OR E ; COMBINE WITH SECTOR (HIGH NIBBLE MUST BE ZERO) - LD D,0 - LD E,H - LD H,L - LD L,A - XOR A - RET -; -;================================================================================================== -; HBIOS GLOBAL DATA -;================================================================================================== -; -IDLECOUNT .DB 0 -; -HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION -; -HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER -; -STR_BANNER .DB "RetroBrew HBIOS v", BIOSVER, ", ", TIMESTAMP, "$" -STR_PLATFORM .DB PLATFORM_NAME, "$" -STR_SWITCH .DB "*** Activating CRT Console ***$" -STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" -; -HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) -; -HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) -; -HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER -; -HB_END .EQU $ -; -SLACK .EQU BNKTOP - $ - .ECHO "HBIOS space remaining: " - .ECHO SLACK - .ECHO " bytes.\n" -; -#IFDEF ROMBOOT - .FILL SLACK -#ENDIF -; - .END From a28bfc157bb79c9e8006d65fa87ed69bc9dc16d9 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 7 Oct 2018 17:11:52 +0800 Subject: [PATCH 07/18] Extend serial device type to support 4 devices including parallel port device. --- Source/HBIOS/hbios.asm | 16 +++++++++++----- Source/HBIOS/hbios.inc | 10 +++++++++- Source/HBIOS/pio.asm | 5 +++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 59f40d5f..b52ded07 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -1336,7 +1336,7 @@ CIO_ADDENT: ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) -CIO_MAX .EQU 32 ; UP TO 16 UNITS +CIO_MAX .EQU 32 ; UP TO UNITS CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) @@ -1399,7 +1399,7 @@ DIO_ADDENT: ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) -DIO_MAX .EQU 16 ; UP TO 16 UNITS +DIO_MAX .EQU 16 ; UP TO 32 UNITS DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) @@ -2931,10 +2931,15 @@ PS_PRTSC2_1: JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED LD A,E OR A - LD HL,PS_STPPTIN + LD HL,PS_STPPTIN ; Parallel Input JR Z,PS_PRTST1 - LD HL,PS_STPPTOUT - JR PS_PRTST1 + LD HL,PS_STPPTOUT ; Parallel Output + DEC A + JR Z,PS_PRTST1 + LD HL,PS_STRPPTBD ; Parallel BiDirectional + DEC A + JP Z,PS_PRTST1 + JP PS_PRTNUL RET ; PS_PRTSC1: @@ -3149,6 +3154,7 @@ PS_STPARMAP .DB "NONENMNS" ; PS_STPPTIN .TEXT "Input$" PS_STPPTOUT .TEXT "Output$" +PS_STRPPTBD .TEXT "Bi-Directional$" ; ; VIDEO DEVICE STRINGS ; diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index ad64b3b5..50e06531 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -83,7 +83,7 @@ BF_SYSINT_INFO .EQU $00 ; GET INTERRUPT SYSTEM INFO BF_SYSINT_GET .EQU $10 ; GET INT VECTOR ADDRESS BF_SYSINT_SET .EQU $20 ; SET INT VECTOR ADDRESS ; -; SERIAL DEVICE IDS +; CHAR DEVICE IDS ; CIODEV_UART .EQU $00 CIODEV_ASCI .EQU $10 @@ -93,6 +93,14 @@ CIODEV_PPPCON .EQU $40 CIODEV_SIO .EQU $50 CIODEV_ACIA .EQU $60 CIODEV_CONSOLE .EQU $D0 +CIODEV_PIO .EQU $70 +; +; SUB TYPES OF CHAR DEVICES +; +;00 RS-232 +;01 TERMINAL +;02 PARALLEL PORT +;03 UNUSED ; ; DISK DEVICE IDS ; diff --git a/Source/HBIOS/pio.asm b/Source/HBIOS/pio.asm index d9e2af85..580f0f73 100644 --- a/Source/HBIOS/pio.asm +++ b/Source/HBIOS/pio.asm @@ -15,10 +15,11 @@ PIO5B .EQU ; ECB-4PIO PIO_Input .EQU $0000 PIO_Output .EQU $0001 - +PIO_BiDir .Equ $0002 DEFPIOCFGA .EQU $8000 + PIO_Input DEFPIOCFGB .EQU $8000 + PIO_Output +DEFPIOCFGX .EQU $8000 + PIO_BiDir PIO_NONE .EQU 0 PIO_ZPIO .EQU 1 @@ -160,7 +161,7 @@ PIO_CFG: .DB PIO_ZPIO ; PIO TYPE (SET DURING INIT) .DB 0 ; PIO CHANNEL (A) .DB 4PIOBASE+2 ; BASE PORT (CMD PORT) - .DW DEFPIOCFGA ; LINE CONFIGURATION + .DW DEFPIOCFGX ; LINE CONFIGURATION .DW SIOA_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; ; PIO CHANNEL B From 40b40b7fa51011a1c2330a7d6344e76e4e85ae7d Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 28 Oct 2018 14:39:20 +0800 Subject: [PATCH 08/18] Support for additional rom options including Nascom and Tasty BASIC --- Source/HBIOS/hbios.asm | 94 +- Source/HBIOS/imgpad.asm | 12 + Source/HBIOS/imgpad0.asm | 12 + Source/HBIOS/nascom.asm | 4424 +++++++++++++++++++++++++++++++++++ Source/HBIOS/romldr.asm | 153 +- Source/HBIOS/std.asm | 12 +- Source/HBIOS/tastybasic.asm | 1813 ++++++++++++++ 7 files changed, 6415 insertions(+), 105 deletions(-) create mode 100644 Source/HBIOS/imgpad.asm create mode 100644 Source/HBIOS/imgpad0.asm create mode 100644 Source/HBIOS/nascom.asm create mode 100644 Source/HBIOS/tastybasic.asm diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index b52ded07..7311ac95 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -546,13 +546,6 @@ INT_SIO: ; SIO INTERRUPT HANDLER LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK JR HBX_INT ; GO TO ROUTING CODE #ENDIF - - #IF (PIOENABLE) -INT_PIO: ; SIO INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,PIO_INT ; HL := PIO INT HANDLER IN BIOS BANK - JR HBX_INT ; GO TO ROUTING CODE - #ENDIF ; #ENDIF ; @@ -867,10 +860,6 @@ HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK #IF (ACIAENABLE) CALL ACIA_PREINIT #ENDIF -#IF (PIOENABLE) - CALL PIO_PREINIT -#ENDIF - ; DIAG(%01111111) ; @@ -1110,7 +1099,7 @@ INITSYS3: ; #IFDEF ROMBOOT ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM - LD A,BID_OSIMG ; CHAIN TO OS IMAGES BANK + LD A,BID_BIOSIMG ; CHAIN TO OS IMAGES BANK LD HL,0 ; ENTER AT ADDRESS 0 CALL HBX_BNKCALL ; GO THERE HALT ; WE SHOULD NEVER COME BACK! @@ -1217,9 +1206,6 @@ HB_INITTBL: #IF (PPPENABLE) .DW PPP_INIT #ENDIF -#IF (PIOENABLE) - .DW PIO_INIT -#ENDIF ; HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) ; @@ -1336,7 +1322,7 @@ CIO_ADDENT: ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) -CIO_MAX .EQU 32 ; UP TO UNITS +CIO_MAX .EQU 16 ; UP TO 16 UNITS CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) @@ -1399,7 +1385,7 @@ DIO_ADDENT: ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) -DIO_MAX .EQU 16 ; UP TO 32 UNITS +DIO_MAX .EQU 16 ; UP TO 16 UNITS DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) @@ -2400,15 +2386,6 @@ SIZ_AY .EQU $ - ORG_AY .ECHO SIZ_AY .ECHO " bytes.\n" #ENDIF - -#IF (PIOENABLE) -ORG_PIO .EQU $ - #INCLUDE "pio.asm" -SIZ_PIO .EQU $ - ORG_PIO - .ECHO "PIO occupies " - .ECHO SIZ_PIO - .ECHO " bytes.\n" -#ENDIF ; #DEFINE USEDELAY #INCLUDE "util.asm" @@ -2808,7 +2785,7 @@ PS_SERIAL: PUSH BC ; SAVE UNIT INDEX FOR LATER ; ; UNIT COLUMN - PRTS("CharIO $") + PRTS("Serial $") LD A,C ; MOVE UNIT NUM TO A CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT PRTS(" $") ; PAD TO NEXT COLUMN @@ -2833,17 +2810,10 @@ PS_SERIAL: ; PS_PRTST: LD HL,PS_STRS232 ; ASSUME RS-232 - LD A,C - AND $C0 - JR Z,PS_PRTST1 ; 00 TYPE 0 - RS-232 - LD HL,PS_STTERM - CP $40 - JR Z,PS_PRTST1 ; 40 TYPE 1 - Terminal - LD HL,PS_STPPT - CP $80 - JR Z,PS_PRTST1 ; 80 TYPE 2 - Parallel - LD HL,PS_STUDEF -; ; C0 TYPE 3 - Undefined + BIT 7,C ; 0=RS-232, 1=TERMINAL + JR Z,PS_PRTST1 ; HANDLE TERMINAL TYPE + LD HL,PS_STTERM ; TYPE IS TERMINAL +; PS_PRTST1: CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED LD A,18 ; 18 CHAR FIELD @@ -2854,15 +2824,9 @@ PS_PRTST1: ; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) ; PS_PRTSC: - LD A,C - AND $C0 - JR Z,PS_PRTSC0_1 ; 00 TYPE 0 - RS-232 - CP $40 - JR Z,PS_PRTSC1 ; 40 TYPE 1 - Terminal - CP $80 - JR Z,PS_PRTSC2_1 ; 80 TYPE 2 - Parallel -; ; C0 TYPE 3 - Undefined -PS_PRTSC0_1: + BIT 7,C ; 0=RS-232, 1=TERMINAL + JR NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG +; ; PRINT RS-232 CONFIG LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG LD C,E ; SET SERIAL UNIT NUM @@ -2920,28 +2884,6 @@ PS_PRTSC0: ; RET ; -PS_PRTSC2_1: - ; PRINT PARALLEL CONFIG - LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG - LD C,E ; SET SERIAL UNIT NUM - RST 08 ; DE:HL := I/O CONFIG - LD A,D ; TEST FOR $FF - AND E - INC A ; SET Z IF DE == $FF - JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED - LD A,E - OR A - LD HL,PS_STPPTIN ; Parallel Input - JR Z,PS_PRTST1 - LD HL,PS_STPPTOUT ; Parallel Output - DEC A - JR Z,PS_PRTST1 - LD HL,PS_STRPPTBD ; Parallel BiDirectional - DEC A - JP Z,PS_PRTST1 - JP PS_PRTNUL - RET -; PS_PRTSC1: ; PRINT TERMINAL CONFIG LD A,C ; GET ATTRIBUTE VALUE @@ -2965,9 +2907,6 @@ PS_PRTSC2: PRTS("ANSI$") RET ; -PS_PRTPC0: - RET - ; ; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C ; PS_VIDEO: @@ -3130,7 +3069,7 @@ PS_FLPED .TEXT "ED$" ; PS_SDSTRREF: .DW PS_SDUART, PS_SDASCI, PS_SDTERM, - .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA, PS_SDPIO + .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA ; PS_SDUART .TEXT "UART$" PS_SDASCI .TEXT "ASCI$" @@ -3139,22 +3078,17 @@ PS_SDPRPCON .TEXT "PRPCON$" PS_SDPPPCON .TEXT "PPPCON$" PS_SDSIO .TEXT "SIO$" PS_SDACIA .TEXT "ACIA$" -PS_SDPIO .TEXT "PORT$" ; ; SERIAL TYPE STRINGS ; PS_STRS232 .TEXT "RS-232$" PS_STTERM .TEXT "Terminal$" -PS_STPPT .TEXT "Parallel$" -PS_STUDEF .TEXT "Undefined$" ; PS_STPARMAP .DB "NONENMNS" + ; -; PARALLEL TYPE STRINGS +; SERIAL TYPE STRINGS ; -PS_STPPTIN .TEXT "Input$" -PS_STPPTOUT .TEXT "Output$" -PS_STRPPTBD .TEXT "Bi-Directional$" ; ; VIDEO DEVICE STRINGS ; diff --git a/Source/HBIOS/imgpad.asm b/Source/HBIOS/imgpad.asm new file mode 100644 index 00000000..972ba3b9 --- /dev/null +++ b/Source/HBIOS/imgpad.asm @@ -0,0 +1,12 @@ +#INCLUDE "std.asm" +; +SLACK .EQU ($8000-LDR_SIZ-MON_SIZ-SYS_SIZ-SYS_SIZ) + .FILL SLACK,00H +; +MON_STACK .EQU $ +; + .ECHO "Padspace space created: " + .ECHO SLACK + .ECHO " bytes.\n" + + .END \ No newline at end of file diff --git a/Source/HBIOS/imgpad0.asm b/Source/HBIOS/imgpad0.asm new file mode 100644 index 00000000..31ef6b96 --- /dev/null +++ b/Source/HBIOS/imgpad0.asm @@ -0,0 +1,12 @@ +#INCLUDE "std.asm" +; +SLACK .EQU ($8000-BAS_SIZ-TBC_SIZ) + .FILL SLACK,00H +; +MON_STACK .EQU $ +; + .ECHO "Padspace space created: " + .ECHO SLACK + .ECHO " bytes.\n" + + .END \ No newline at end of file diff --git a/Source/HBIOS/nascom.asm b/Source/HBIOS/nascom.asm new file mode 100644 index 00000000..c83a33e1 --- /dev/null +++ b/Source/HBIOS/nascom.asm @@ -0,0 +1,4424 @@ +;================================================================================== +; The updates to the original BASIC within this file are copyright Grant Searle +; +; You have permission to use this for NON COMMERCIAL USE ONLY +; If you wish to use it elsewhere, please include an acknowledgement to myself. +; +; http://searle.hostei.com/grant/index.html +; +; eMail: home.micros01@btinternet.com +; +; If the above don't work, please perform an Internet search to see if I have +; updated the web page hosting service. +; +;================================================================================== + +; NASCOM ROM BASIC Ver 4.7, (C) 1978 Microsoft +; Scanned from source published in 80-BUS NEWS from Vol 2, Issue 3 +; (May-June 1983) to Vol 3, Issue 3 (May-June 1984) +; Adapted for the freeware Zilog Macro Assembler 2.10 to produce +; the original ROM code (checksum A934H). PA +; +; SBC V2 BOOTROM VERSION 27/10/2018 +; difficultylevelhigh@gmail.com +; +#INCLUDE "std.asm" +; +; GENERAL EQUATES + +CTRLC .EQU 03H ; Control "C" +CTRLG .EQU 07H ; Control "G" +BKSP .EQU 08H ; Back space +LF .EQU 0AH ; Line feed +CS .EQU 0CH ; Clear screen +CR .EQU 0DH ; Carriage return +CTRLO .EQU 0FH ; Control "O" +CTRLQ .EQU 11H ; Control "Q" +CTRLR .EQU 12H ; Control "R" +CTRLS .EQU 13H ; Control "S" +CTRLU .EQU 15H ; Control "U" +ESC .EQU 1BH ; Escape +DEL .EQU 7FH ; Delete + +; BASIC WORK SPACE LOCATIONS + +WRKSPC .EQU BAS_END+90H ; WAS 4090H ; BASIC Work space +USR .EQU WRKSPC+3H ; "USR (x)" jump +OUTSUB .EQU WRKSPC+6H ; "OUT p,n" +OTPORT .EQU WRKSPC+7H ; Port (p) +DIVSUP .EQU WRKSPC+9H ; Division support routine +DIV1 .EQU WRKSPC+0AH ; <- Values +DIV2 .EQU WRKSPC+0EH ; <- to +DIV3 .EQU WRKSPC+12H ; <- be +DIV4 .EQU WRKSPC+15H ; <-inserted +SEED .EQU WRKSPC+17H ; Random number seed +LSTRND .EQU WRKSPC+3AH ; Last random number +INPSUB .EQU WRKSPC+3EH ; #INP (x)" Routine +INPORT .EQU WRKSPC+3FH ; PORT (x) +NULLS .EQU WRKSPC+41H ; Number of nulls +LWIDTH .EQU WRKSPC+42H ; Terminal width +COMMAN .EQU WRKSPC+43H ; Width for commas +NULFLG .EQU WRKSPC+44H ; Null after input byte flag +CTLOFG .EQU WRKSPC+45H ; Control "O" flag +LINESC .EQU WRKSPC+46H ; Lines counter +LINESN .EQU WRKSPC+48H ; Lines number +CHKSUM .EQU WRKSPC+4AH ; Array load/save check sum +NMIFLG .EQU WRKSPC+4CH ; Flag for NMI break routine +BRKFLG .EQU WRKSPC+4DH ; Break flag +RINPUT .EQU WRKSPC+4EH ; Input reflection +POINT .EQU WRKSPC+51H ; "POINT" reflection (unused) +PSET .EQU WRKSPC+54H ; "SET" reflection +RESET .EQU WRKSPC+57H ; "RESET" reflection +STRSPC .EQU WRKSPC+5AH ; Bottom of string space +LINEAT .EQU WRKSPC+5CH ; Current line number +BASTXT .EQU WRKSPC+5EH ; Pointer to start of program +BUFFER .EQU WRKSPC+61H ; Input buffer +STACK .EQU WRKSPC+66H ; Initial stack +CURPOS .EQU WRKSPC+0ABH ; Character position on line +LCRFLG .EQU WRKSPC+0ACH ; Locate/Create flag +TYPE .EQU WRKSPC+0ADH ; Data type flag +DATFLG .EQU WRKSPC+0AEH ; Literal statement flag +LSTRAM .EQU WRKSPC+0AFH ; Last available RAM +TMSTPT .EQU WRKSPC+0B1H ; Temporary string pointer +TMSTPL .EQU WRKSPC+0B3H ; Temporary string pool +TMPSTR .EQU WRKSPC+0BFH ; Temporary string +STRBOT .EQU WRKSPC+0C3H ; Bottom of string space +CUROPR .EQU WRKSPC+0C5H ; Current operator in EVAL +LOOPST .EQU WRKSPC+0C7H ; First statement of loop +DATLIN .EQU WRKSPC+0C9H ; Line of current DATA item +FORFLG .EQU WRKSPC+0CBH ; "FOR" loop flag +LSTBIN .EQU WRKSPC+0CCH ; Last byte entered +READFG .EQU WRKSPC+0CDH ; Read/Input flag +BRKLIN .EQU WRKSPC+0CEH ; Line of break +NXTOPR .EQU WRKSPC+0D0H ; Next operator in EVAL +ERRLIN .EQU WRKSPC+0D2H ; Line of error +CONTAD .EQU WRKSPC+0D4H ; Where to CONTinue +PROGND .EQU WRKSPC+0D6H ; End of program +VAREND .EQU WRKSPC+0D8H ; End of variables +ARREND .EQU WRKSPC+0DAH ; End of arrays +NXTDAT .EQU WRKSPC+0DCH ; Next data item +FNRGNM .EQU WRKSPC+0DEH ; Name of FN argument +FNARG .EQU WRKSPC+0E0H ; FN argument value +FPREG .EQU WRKSPC+0E4H ; Floating point register +FPEXP .EQU FPREG+3 ; Floating point exponent +SGNRES .EQU WRKSPC+0E8H ; Sign of result +PBUFF .EQU WRKSPC+0E9H ; Number print buffer +MULVAL .EQU WRKSPC+0F6H ; Multiplier +PROGST .EQU WRKSPC+0F9H ; Start of program text area +STLOOK .EQU WRKSPC+15DH ; Start of memory test + + +; BASIC ERROR CODE VALUES + +NF .EQU 00H ; NEXT without FOR +SN .EQU 02H ; Syntax error +RG .EQU 04H ; RETURN without GOSUB +OD .EQU 06H ; Out of DATA +FC .EQU 08H ; Function call error +OV .EQU 0AH ; Overflow +OM .EQU 0CH ; Out of memory +UL .EQU 0EH ; Undefined line number +BS .EQU 10H ; Bad subscript +DD .EQU 12H ; Re-DIMensioned array +DZ .EQU 14H ; Division by zero (/0) +ID .EQU 16H ; Illegal direct +TM .EQU 18H ; Type miss-match +OS .EQU 1AH ; Out of string space +LS .EQU 1CH ; String too long +ST .EQU 1EH ; String formula too complex +CN .EQU 20H ; Can't CONTinue +UF .EQU 22H ; UnDEFined FN function +MO .EQU 24H ; Missing operand +HX .EQU 26H ; HEX error +BN .EQU 28H ; BIN error + + .ORG BAS_LOC ; WAS 02000H + +COLD: JP STARTB ; Jump for cold start +WARM: JP WARMST ; Jump for warm start +STARTB: + LD IX,0 ; Flag cold start + JP CSTART ; Jump to initialise + + .WORD DEINT ; Get integer -32768 to 32767 + .WORD ABPASS ; Return integer in AB + + +CSTART: LD HL,WRKSPC ; Start of workspace RAM + LD SP,HL ; Set up a temporary stack + JP INITST ; Go to initialise + +INIT: LD DE,INITAB ; Initialise workspace + LD B,INITBE-INITAB+3; Bytes to copy + LD HL,WRKSPC ; Into workspace RAM +COPY: LD A,(DE) ; Get source + LD (HL),A ; To destination + INC HL ; Next destination + INC DE ; Next source + DEC B ; Count bytes + JP NZ,COPY ; More to move + LD SP,HL ; Temporary stack + + CALL CLREG ; Clear registers and stack + CALL PRNTCRLF ; Output CRLF + LD (BUFFER+72+1),A ; Mark end of buffer + LD (PROGST),A ; Initialise program area +MSIZE: LD HL,MEMMSG ; Point to message + CALL PRS ; Output "Memory size" + CALL PROMPT ; Get input with '?' + CALL GETCHR ; Get next character + OR A ; Set flags + JP NZ,TSTMEM ; If number - Test if RAM there + LD HL,STLOOK ; Point to start of RAM +MLOOP: INC HL ; Next byte +; LD A,H ; Above address FFFF ? +; OR L + LD A,H ; Memory top set below HBIOS Proxy @ FE00 + CP $FD + JP Z,SETTOP ; Yes - 64K RAM + LD A,(HL) ; Get contents + LD B,A ; Save it + CPL ; Flip all bits + LD (HL),A ; Put it back + CP (HL) ; RAM there if same + LD (HL),B ; Restore old contents + JP Z,MLOOP ; If RAM - test next byte + JP SETTOP ; Top of RAM found + +TSTMEM: CALL ATOH ; Get high memory into DE + OR A ; Set flags on last byte + JP NZ,SNERR ; ?SN Error if bad character + EX DE,HL ; Address into HL + DEC HL ; Back one byte + LD A,11011001B ; Test byte + LD B,(HL) ; Get old contents + LD (HL),A ; Load test byte + CP (HL) ; RAM there if same + LD (HL),B ; Restore old contents + JP NZ,MSIZE ; Ask again if no RAM + +SETTOP: DEC HL ; Back one byte + LD DE,STLOOK-1 ; See if enough RAM + CALL CPDEHL ; Compare DE with HL + JP C,MSIZE ; Ask again if not enough RAM + LD DE,0-50 ; 50 Bytes string space + LD (LSTRAM),HL ; Save last available RAM + ADD HL,DE ; Allocate string space + LD (STRSPC),HL ; Save string space + CALL CLRPTR ; Clear program area + LD HL,(STRSPC) ; Get end of memory + LD DE,0-17 ; Offset for free bytes + ADD HL,DE ; Adjust HL + LD DE,PROGST ; Start of program text + LD A,L ; Get LSB + SUB E ; Adjust it + LD L,A ; Re-save + LD A,H ; Get MSB + SBC A,D ; Adjust it + LD H,A ; Re-save + PUSH HL ; Save bytes free + LD HL,SIGNON ; Sign-on message + CALL PRS ; Output string + POP HL ; Get bytes free back + CALL PRNTHL ; Output amount of free memory + LD HL,BFREE ; " Bytes free" message + CALL PRS ; Output string + +WARMST: LD SP,STACK ; Temporary stack +BRKRET: CALL CLREG ; Clear registers and stack + JP PRNTOK ; Go to get command line + +BFREE: .BYTE " Bytes free",CR,LF,0,0 + +SIGNON: .BYTE "Z80 BASIC Ver 4.7b",CR,LF + .BYTE "Copyright ",40,"C",41 + .BYTE " 1978 by Microsoft",CR,LF,0,0 + +MEMMSG: .BYTE "Memory top",0 + +; FUNCTION ADDRESS TABLE + +FNCTAB: .WORD SGN + .WORD INT + .WORD ABS + .WORD USR + .WORD FRE + .WORD INP + .WORD POS + .WORD SQR + .WORD RND + .WORD LOG + .WORD EXP + .WORD COS + .WORD SIN + .WORD TAN + .WORD ATN + .WORD PEEK + .WORD DEEK + .WORD POINT + .WORD LEN + .WORD STR + .WORD VAL + .WORD ASC + .WORD CHR + .WORD HEX + .WORD BIN + .WORD LEFT + .WORD RIGHT + .WORD MID + +; RESERVED WORD LIST + +WORDS: .BYTE 'E'+80H,"ND" + .BYTE 'F'+80H,"OR" + .BYTE 'N'+80H,"EXT" + .BYTE 'D'+80H,"ATA" + .BYTE 'I'+80H,"NPUT" + .BYTE 'D'+80H,"IM" + .BYTE 'R'+80H,"EAD" + .BYTE 'L'+80H,"ET" + .BYTE 'G'+80H,"OTO" + .BYTE 'R'+80H,"UN" + .BYTE 'I'+80H,"F" + .BYTE 'R'+80H,"ESTORE" + .BYTE 'G'+80H,"OSUB" + .BYTE 'R'+80H,"ETURN" + .BYTE 'R'+80H,"EM" + .BYTE 'S'+80H,"TOP" + .BYTE 'O'+80H,"UT" + .BYTE 'O'+80H,"N" + .BYTE 'N'+80H,"ULL" + .BYTE 'W'+80H,"AIT" + .BYTE 'D'+80H,"EF" + .BYTE 'P'+80H,"OKE" + .BYTE 'D'+80H,"OKE" + .BYTE 'S'+80H,"CREEN" + .BYTE 'L'+80H,"INES" + .BYTE 'C'+80H,"LS" + .BYTE 'W'+80H,"IDTH" + .BYTE 'M'+80H,"ONITOR" + .BYTE 'S'+80H,"ET" + .BYTE 'R'+80H,"ESET" + .BYTE 'P'+80H,"RINT" + .BYTE 'C'+80H,"ONT" + .BYTE 'L'+80H,"IST" + .BYTE 'C'+80H,"LEAR" + .BYTE 'C'+80H,"LOAD" + .BYTE 'C'+80H,"SAVE" + .BYTE 'N'+80H,"EW" + + .BYTE 'T'+80H,"AB(" + .BYTE 'T'+80H,"O" + .BYTE 'F'+80H,"N" + .BYTE 'S'+80H,"PC(" + .BYTE 'T'+80H,"HEN" + .BYTE 'N'+80H,"OT" + .BYTE 'S'+80H,"TEP" + + .BYTE '+'+80H + .BYTE '-'+80H + .BYTE '*'+80H + .BYTE '/'+80H + .BYTE '^'+80H + .BYTE 'A'+80H,"ND" + .BYTE 'O'+80H,"R" + .BYTE '>'+80H + .BYTE '='+80H + .BYTE '<'+80H + + .BYTE 'S'+80H,"GN" + .BYTE 'I'+80H,"NT" + .BYTE 'A'+80H,"BS" + .BYTE 'U'+80H,"SR" + .BYTE 'F'+80H,"RE" + .BYTE 'I'+80H,"NP" + .BYTE 'P'+80H,"OS" + .BYTE 'S'+80H,"QR" + .BYTE 'R'+80H,"ND" + .BYTE 'L'+80H,"OG" + .BYTE 'E'+80H,"XP" + .BYTE 'C'+80H,"OS" + .BYTE 'S'+80H,"IN" + .BYTE 'T'+80H,"AN" + .BYTE 'A'+80H,"TN" + .BYTE 'P'+80H,"EEK" + .BYTE 'D'+80H,"EEK" + .BYTE 'P'+80H,"OINT" + .BYTE 'L'+80H,"EN" + .BYTE 'S'+80H,"TR$" + .BYTE 'V'+80H,"AL" + .BYTE 'A'+80H,"SC" + .BYTE 'C'+80H,"HR$" + .BYTE 'H'+80H,"EX$" + .BYTE 'B'+80H,"IN$" + .BYTE 'L'+80H,"EFT$" + .BYTE 'R'+80H,"IGHT$" + .BYTE 'M'+80H,"ID$" + .BYTE 80H ; End of list marker + +; KEYWORD ADDRESS TABLE + +WORDTB: .WORD PEND + .WORD FOR + .WORD NEXT + .WORD DATA + .WORD INPUT + .WORD DIM + .WORD READ + .WORD LET + .WORD GOTO + .WORD RUN + .WORD IF + .WORD RESTOR + .WORD GOSUB + .WORD RETURN + .WORD REM + .WORD STOP + .WORD POUT + .WORD ON + .WORD NULL + .WORD WAIT + .WORD DEF + .WORD POKE + .WORD DOKE + .WORD REM + .WORD LINES + .WORD CLS + .WORD WIDTH + .WORD MONITR + .WORD PSET + .WORD RESET + .WORD PRINT + .WORD CONT + .WORD LIST + .WORD CLEAR + .WORD REM + .WORD REM + .WORD NEW + +; RESERVED WORD TOKEN VALUES + +ZEND .EQU 080H ; END +ZFOR .EQU 081H ; FOR +ZDATA .EQU 083H ; DATA +ZGOTO .EQU 088H ; GOTO +ZGOSUB .EQU 08CH ; GOSUB +ZREM .EQU 08EH ; REM +ZPRINT .EQU 09EH ; PRINT +ZNEW .EQU 0A4H ; NEW + +ZTAB .EQU 0A5H ; TAB +ZTO .EQU 0A6H ; TO +ZFN .EQU 0A7H ; FN +ZSPC .EQU 0A8H ; SPC +ZTHEN .EQU 0A9H ; THEN +ZNOT .EQU 0AAH ; NOT +ZSTEP .EQU 0ABH ; STEP + +ZPLUS .EQU 0ACH ; + +ZMINUS .EQU 0ADH ; - +ZTIMES .EQU 0AEH ; * +ZDIV .EQU 0AFH ; / +ZOR .EQU 0B2H ; OR +ZGTR .EQU 0B3H ; > +ZEQUAL .EQU 0B4H ; M +ZLTH .EQU 0B5H ; < +ZSGN .EQU 0B6H ; SGN +ZPOINT .EQU 0C7H ; POINT +ZLEFT .EQU 0CDH +2 ; LEFT$ + +; ARITHMETIC PRECEDENCE TABLE + +PRITAB: .BYTE 79H ; Precedence value + .WORD PADD ; FPREG = + FPREG + + .BYTE 79H ; Precedence value + .WORD PSUB ; FPREG = - FPREG + + .BYTE 7CH ; Precedence value + .WORD MULT ; PPREG = * FPREG + + .BYTE 7CH ; Precedence value + .WORD DIV ; FPREG = / FPREG + + .BYTE 7FH ; Precedence value + .WORD POWER ; FPREG = ^ FPREG + + .BYTE 50H ; Precedence value + .WORD PAND ; FPREG = AND FPREG + + .BYTE 46H ; Precedence value + .WORD POR ; FPREG = OR FPREG + +; BASIC ERROR CODE LIST + +ERRORS: .BYTE "NF" ; NEXT without FOR + .BYTE "SN" ; Syntax error + .BYTE "RG" ; RETURN without GOSUB + .BYTE "OD" ; Out of DATA + .BYTE "FC" ; Illegal function call + .BYTE "OV" ; Overflow error + .BYTE "OM" ; Out of memory + .BYTE "UL" ; Undefined line + .BYTE "BS" ; Bad subscript + .BYTE "DD" ; Re-DIMensioned array + .BYTE "/0" ; Division by zero + .BYTE "ID" ; Illegal direct + .BYTE "TM" ; Type mis-match + .BYTE "OS" ; Out of string space + .BYTE "LS" ; String too long + .BYTE "ST" ; String formula too complex + .BYTE "CN" ; Can't CONTinue + .BYTE "UF" ; Undefined FN function + .BYTE "MO" ; Missing operand + .BYTE "HX" ; HEX error + .BYTE "BN" ; BIN error + +; INITIALISATION TABLE ------------------------------------------------------- + +INITAB: JP WARMST ; Warm start jump + JP FCERR ; "USR (X)" jump (Set to Error) + OUT (0),A ; "OUT p,n" skeleton + RET + SUB 0 ; Division support routine + LD L,A + LD A,H + SBC A,0 + LD H,A + LD A,B + SBC A,0 + LD B,A + LD A,0 + RET + .BYTE 0,0,0 ; Random number seed table used by RND + .BYTE 035H,04AH,0CAH,099H ;-2.65145E+07 + .BYTE 039H,01CH,076H,098H ; 1.61291E+07 + .BYTE 022H,095H,0B3H,098H ;-1.17691E+07 + .BYTE 00AH,0DDH,047H,098H ; 1.30983E+07 + .BYTE 053H,0D1H,099H,099H ;-2-01612E+07 + .BYTE 00AH,01AH,09FH,098H ;-1.04269E+07 + .BYTE 065H,0BCH,0CDH,098H ;-1.34831E+07 + .BYTE 0D6H,077H,03EH,098H ; 1.24825E+07 + .BYTE 052H,0C7H,04FH,080H ; Last random number + IN A,(0) ; INP (x) skeleton + RET + .BYTE 1 ; POS (x) number (1) + .BYTE 255 ; Terminal width (255 = no auto CRLF) + .BYTE 28 ; Width for commas (3 columns) + .BYTE 0 ; No nulls after input bytes + .BYTE 0 ; Output enabled (^O off) + .WORD 20 ; Initial lines counter + .WORD 20 ; Initial lines number + .WORD 0 ; Array load/save check sum + .BYTE 0 ; Break not by NMI + .BYTE 0 ; Break flag + JP TTYLIN ; Input reflection (set to TTY) + JP $0000 ; POINT reflection unused + JP $0000 ; SET reflection + JP $0000 ; RESET reflection + .WORD STLOOK ; Temp string space + .WORD -2 ; Current line number (cold) + .WORD PROGST+1 ; Start of program text +INITBE: + +; END OF INITIALISATION TABLE --------------------------------------------------- + +ERRMSG: .BYTE " Error",0 +INMSG: .BYTE " in ",0 +ZERBYT .EQU $-1 ; A zero byte +OKMSG: .BYTE "Ok",CR,LF,0,0 +BRKMSG: .BYTE "Break",0 + +BAKSTK: LD HL,4 ; Look for "FOR" block with + ADD HL,SP ; same index as specified +LOKFOR: LD A,(HL) ; Get block ID + INC HL ; Point to index address + CP ZFOR ; Is it a "FOR" token + RET NZ ; No - exit + LD C,(HL) ; BC = Address of "FOR" index + INC HL + LD B,(HL) + INC HL ; Point to sign of STEP + PUSH HL ; Save pointer to sign + LD L,C ; HL = address of "FOR" index + LD H,B + LD A,D ; See if an index was specified + OR E ; DE = 0 if no index specified + EX DE,HL ; Specified index into HL + JP Z,INDFND ; Skip if no index given + EX DE,HL ; Index back into DE + CALL CPDEHL ; Compare index with one given +INDFND: LD BC,16-3 ; Offset to next block + POP HL ; Restore pointer to sign + RET Z ; Return if block found + ADD HL,BC ; Point to next block + JP LOKFOR ; Keep on looking + +MOVUP: CALL ENFMEM ; See if enough memory +MOVSTR: PUSH BC ; Save end of source + EX (SP),HL ; Swap source and dest" end + POP BC ; Get end of destination +MOVLP: CALL CPDEHL ; See if list moved + LD A,(HL) ; Get byte + LD (BC),A ; Move it + RET Z ; Exit if all done + DEC BC ; Next byte to move to + DEC HL ; Next byte to move + JP MOVLP ; Loop until all bytes moved + +CHKSTK: PUSH HL ; Save code string address + LD HL,(ARREND) ; Lowest free memory + LD B,0 ; BC = Number of levels to test + ADD HL,BC ; 2 Bytes for each level + ADD HL,BC + .BYTE 3EH ; Skip "PUSH HL" +ENFMEM: PUSH HL ; Save code string address + LD A,0D0H ;LOW -48 ; 48 Bytes minimum RAM + SUB L + LD L,A + LD A,0FFH; HIGH (-48) ; 48 Bytes minimum RAM + SBC A,H + JP C,OMERR ; Not enough - ?OM Error + LD H,A + ADD HL,SP ; Test if stack is overflowed + POP HL ; Restore code string address + RET C ; Return if enough mmory +OMERR: LD E,OM ; ?OM Error + JP ERROR + +DATSNR: LD HL,(DATLIN) ; Get line of current DATA item + LD (LINEAT),HL ; Save as current line +SNERR: LD E,SN ; ?SN Error + .BYTE 01H ; Skip "LD E,DZ" +DZERR: LD E,DZ ; ?/0 Error + .BYTE 01H ; Skip "LD E,NF" +NFERR: LD E,NF ; ?NF Error + .BYTE 01H ; Skip "LD E,DD" +DDERR: LD E,DD ; ?DD Error + .BYTE 01H ; Skip "LD E,UF" +UFERR: LD E,UF ; ?UF Error + .BYTE 01H ; Skip "LD E,OV +OVERR: LD E,OV ; ?OV Error + .BYTE 01H ; Skip "LD E,TM" +TMERR: LD E,TM ; ?TM Error + +ERROR: CALL CLREG ; Clear registers and stack + LD (CTLOFG),A ; Enable output (A is 0) + CALL STTLIN ; Start new line + LD HL,ERRORS ; Point to error codes + LD D,A ; D = 0 (A is 0) + LD A,'?' + CALL OUTC ; Output '?' + ADD HL,DE ; Offset to correct error code + LD A,(HL) ; First character + CALL OUTC ; Output it + CALL GETCHR ; Get next character + CALL OUTC ; Output it + LD HL,ERRMSG ; "Error" message +ERRIN: CALL PRS ; Output message + LD HL,(LINEAT) ; Get line of error + LD DE,-2 ; Cold start error if -2 + CALL CPDEHL ; See if cold start error + JP Z,CSTART ; Cold start error - Restart + LD A,H ; Was it a direct error? + AND L ; Line = -1 if direct error + INC A + CALL NZ,LINEIN ; No - output line of error + .BYTE 3EH ; Skip "POP BC" +POPNOK: POP BC ; Drop address in input buffer + +PRNTOK: XOR A ; Output "Ok" and get command + LD (CTLOFG),A ; Enable output + CALL STTLIN ; Start new line + LD HL,OKMSG ; "Ok" message + CALL PRS ; Output "Ok" +GETCMD: LD HL,-1 ; Flag direct mode + LD (LINEAT),HL ; Save as current line + CALL GETLIN ; Get an input line + JP C,GETCMD ; Get line again if break + CALL GETCHR ; Get first character + INC A ; Test if end of line + DEC A ; Without affecting Carry + JP Z,GETCMD ; Nothing entered - Get another + PUSH AF ; Save Carry status + CALL ATOH ; Get line number into DE + PUSH DE ; Save line number + CALL CRUNCH ; Tokenise rest of line + LD B,A ; Length of tokenised line + POP DE ; Restore line number + POP AF ; Restore Carry + JP NC,EXCUTE ; No line number - Direct mode + PUSH DE ; Save line number + PUSH BC ; Save length of tokenised line + XOR A + LD (LSTBIN),A ; Clear last byte input + CALL GETCHR ; Get next character + OR A ; Set flags + PUSH AF ; And save them + CALL SRCHLN ; Search for line number in DE + JP C,LINFND ; Jump if line found + POP AF ; Get status + PUSH AF ; And re-save + JP Z,ULERR ; Nothing after number - Error + OR A ; Clear Carry +LINFND: PUSH BC ; Save address of line in prog + JP NC,INEWLN ; Line not found - Insert new + EX DE,HL ; Next line address in DE + LD HL,(PROGND) ; End of program +SFTPRG: LD A,(DE) ; Shift rest of program down + LD (BC),A + INC BC ; Next destination + INC DE ; Next source + CALL CPDEHL ; All done? + JP NZ,SFTPRG ; More to do + LD H,B ; HL - New end of program + LD L,C + LD (PROGND),HL ; Update end of program + +INEWLN: POP DE ; Get address of line, + POP AF ; Get status + JP Z,SETPTR ; No text - Set up pointers + LD HL,(PROGND) ; Get end of program + EX (SP),HL ; Get length of input line + POP BC ; End of program to BC + ADD HL,BC ; Find new end + PUSH HL ; Save new end + CALL MOVUP ; Make space for line + POP HL ; Restore new end + LD (PROGND),HL ; Update end of program pointer + EX DE,HL ; Get line to move up in HL + LD (HL),H ; Save MSB + POP DE ; Get new line number + INC HL ; Skip pointer + INC HL + LD (HL),E ; Save LSB of line number + INC HL + LD (HL),D ; Save MSB of line number + INC HL ; To first byte in line + LD DE,BUFFER ; Copy buffer to program +MOVBUF: LD A,(DE) ; Get source + LD (HL),A ; Save destinations + INC HL ; Next source + INC DE ; Next destination + OR A ; Done? + JP NZ,MOVBUF ; No - Repeat +SETPTR: CALL RUNFST ; Set line pointers + INC HL ; To LSB of pointer + EX DE,HL ; Address to DE +PTRLP: LD H,D ; Address to HL + LD L,E + LD A,(HL) ; Get LSB of pointer + INC HL ; To MSB of pointer + OR (HL) ; Compare with MSB pointer + JP Z,GETCMD ; Get command line if end + INC HL ; To LSB of line number + INC HL ; Skip line number + INC HL ; Point to first byte in line + XOR A ; Looking for 00 byte +FNDEND: CP (HL) ; Found end of line? + INC HL ; Move to next byte + JP NZ,FNDEND ; No - Keep looking + EX DE,HL ; Next line address to HL + LD (HL),E ; Save LSB of pointer + INC HL + LD (HL),D ; Save MSB of pointer + JP PTRLP ; Do next line + +SRCHLN: LD HL,(BASTXT) ; Start of program text +SRCHLP: LD B,H ; BC = Address to look at + LD C,L + LD A,(HL) ; Get address of next line + INC HL + OR (HL) ; End of program found? + DEC HL + RET Z ; Yes - Line not found + INC HL + INC HL + LD A,(HL) ; Get LSB of line number + INC HL + LD H,(HL) ; Get MSB of line number + LD L,A + CALL CPDEHL ; Compare with line in DE + LD H,B ; HL = Start of this line + LD L,C + LD A,(HL) ; Get LSB of next line address + INC HL + LD H,(HL) ; Get MSB of next line address + LD L,A ; Next line to HL + CCF + RET Z ; Lines found - Exit + CCF + RET NC ; Line not found,at line after + JP SRCHLP ; Keep looking + +NEW: RET NZ ; Return if any more on line +CLRPTR: LD HL,(BASTXT) ; Point to start of program + XOR A ; Set program area to empty + LD (HL),A ; Save LSB = 00 + INC HL + LD (HL),A ; Save MSB = 00 + INC HL + LD (PROGND),HL ; Set program end + +RUNFST: LD HL,(BASTXT) ; Clear all variables + DEC HL + +INTVAR: LD (BRKLIN),HL ; Initialise RUN variables + LD HL,(LSTRAM) ; Get end of RAM + LD (STRBOT),HL ; Clear string space + XOR A + CALL RESTOR ; Reset DATA pointers + LD HL,(PROGND) ; Get end of program + LD (VAREND),HL ; Clear variables + LD (ARREND),HL ; Clear arrays + +CLREG: POP BC ; Save return address + LD HL,(STRSPC) ; Get end of working RAN + LD SP,HL ; Set stack + LD HL,TMSTPL ; Temporary string pool + LD (TMSTPT),HL ; Reset temporary string ptr + XOR A ; A = 00 + LD L,A ; HL = 0000 + LD H,A + LD (CONTAD),HL ; No CONTinue + LD (FORFLG),A ; Clear FOR flag + LD (FNRGNM),HL ; Clear FN argument + PUSH HL ; HL = 0000 + PUSH BC ; Put back return +DOAGN: LD HL,(BRKLIN) ; Get address of code to RUN + RET ; Return to execution driver + +PROMPT: LD A,'?' ; '?' + CALL OUTC ; Output character + LD A,' ' ; Space + CALL OUTC ; Output character + JP RINPUT ; Get input line + +CRUNCH: XOR A ; Tokenise line @ HL to BUFFER + LD (DATFLG),A ; Reset literal flag + LD C,2+3 ; 2 byte number and 3 nulls + LD DE,BUFFER ; Start of input buffer +CRNCLP: LD A,(HL) ; Get byte + CP ' ' ; Is it a space? + JP Z,MOVDIR ; Yes - Copy direct + LD B,A ; Save character + CP '"' ; Is it a quote? + JP Z,CPYLIT ; Yes - Copy literal string + OR A ; Is it end of buffer? + JP Z,ENDBUF ; Yes - End buffer + LD A,(DATFLG) ; Get data type + OR A ; Literal? + LD A,(HL) ; Get byte to copy + JP NZ,MOVDIR ; Literal - Copy direct + CP '?' ; Is it '?' short for PRINT + LD A,ZPRINT ; "PRINT" token + JP Z,MOVDIR ; Yes - replace it + LD A,(HL) ; Get byte again + CP '0' ; Is it less than '0' + JP C,FNDWRD ; Yes - Look for reserved words + CP 60; ";"+1 ; Is it "0123456789:;" ? + JP C,MOVDIR ; Yes - copy it direct +FNDWRD: PUSH DE ; Look for reserved words + LD DE,WORDS-1 ; Point to table + PUSH BC ; Save count + LD BC,RETNAD ; Where to return to + PUSH BC ; Save return address + LD B,ZEND-1 ; First token value -1 + LD A,(HL) ; Get byte + CP 'a' ; Less than 'a' ? + JP C,SEARCH ; Yes - search for words + CP 'z'+1 ; Greater than 'z' ? + JP NC,SEARCH ; Yes - search for words + AND 01011111B ; Force upper case + LD (HL),A ; Replace byte +SEARCH: LD C,(HL) ; Search for a word + EX DE,HL +GETNXT: INC HL ; Get next reserved word + OR (HL) ; Start of word? + JP P,GETNXT ; No - move on + INC B ; Increment token value + LD A, (HL) ; Get byte from table + AND 01111111B ; Strip bit 7 + RET Z ; Return if end of list + CP C ; Same character as in buffer? + JP NZ,GETNXT ; No - get next word + EX DE,HL + PUSH HL ; Save start of word + +NXTBYT: INC DE ; Look through rest of word + LD A,(DE) ; Get byte from table + OR A ; End of word ? + JP M,MATCH ; Yes - Match found + LD C,A ; Save it + LD A,B ; Get token value + CP ZGOTO ; Is it "GOTO" token ? + JP NZ,NOSPC ; No - Don't allow spaces + CALL GETCHR ; Get next character + DEC HL ; Cancel increment from GETCHR +NOSPC: INC HL ; Next byte + LD A,(HL) ; Get byte + CP 'a' ; Less than 'a' ? + JP C,NOCHNG ; Yes - don't change + AND 01011111B ; Make upper case +NOCHNG: CP C ; Same as in buffer ? + JP Z,NXTBYT ; Yes - keep testing + POP HL ; Get back start of word + JP SEARCH ; Look at next word + +MATCH: LD C,B ; Word found - Save token value + POP AF ; Throw away return + EX DE,HL + RET ; Return to "RETNAD" +RETNAD: EX DE,HL ; Get address in string + LD A,C ; Get token value + POP BC ; Restore buffer length + POP DE ; Get destination address +MOVDIR: INC HL ; Next source in buffer + LD (DE),A ; Put byte in buffer + INC DE ; Move up buffer + INC C ; Increment length of buffer + SUB ':' ; End of statement? + JP Z,SETLIT ; Jump if multi-statement line + CP ZDATA-3AH ; Is it DATA statement ? + JP NZ,TSTREM ; No - see if REM +SETLIT: LD (DATFLG),A ; Set literal flag +TSTREM: SUB ZREM-3AH ; Is it REM? + JP NZ,CRNCLP ; No - Leave flag + LD B,A ; Copy rest of buffer +NXTCHR: LD A,(HL) ; Get byte + OR A ; End of line ? + JP Z,ENDBUF ; Yes - Terminate buffer + CP B ; End of statement ? + JP Z,MOVDIR ; Yes - Get next one +CPYLIT: INC HL ; Move up source string + LD (DE),A ; Save in destination + INC C ; Increment length + INC DE ; Move up destination + JP NXTCHR ; Repeat + +ENDBUF: LD HL,BUFFER-1 ; Point to start of buffer + LD (DE),A ; Mark end of buffer (A = 00) + INC DE + LD (DE),A ; A = 00 + INC DE + LD (DE),A ; A = 00 + RET + +DODEL: LD A,(NULFLG) ; Get null flag status + OR A ; Is it zero? + LD A,0 ; Zero A - Leave flags + LD (NULFLG),A ; Zero null flag + JP NZ,ECHDEL ; Set - Echo it + DEC B ; Decrement length + JP Z,GETLIN ; Get line again if empty + CALL OUTC ; Output null character + .BYTE 3EH ; Skip "DEC B" +ECHDEL: DEC B ; Count bytes in buffer + DEC HL ; Back space buffer + JP Z,OTKLN ; No buffer - Try again + LD A,(HL) ; Get deleted byte + CALL OUTC ; Echo it + JP MORINP ; Get more input + +DELCHR: DEC B ; Count bytes in buffer + DEC HL ; Back space buffer + CALL OUTC ; Output character in A + JP NZ,MORINP ; Not end - Get more +OTKLN: CALL OUTC ; Output character in A +KILIN: CALL PRNTCRLF ; Output CRLF + JP TTYLIN ; Get line again + +GETLIN: +TTYLIN: LD HL,BUFFER ; Get a line by character + LD B,1 ; Set buffer as empty + XOR A + LD (NULFLG),A ; Clear null flag +MORINP: CALL CLOTST ; Get character and test ^O + LD C,A ; Save character in C + CP DEL ; Delete character? + JP Z,DODEL ; Yes - Process it + LD A,(NULFLG) ; Get null flag + OR A ; Test null flag status + JP Z,PROCES ; Reset - Process character + LD A,0 ; Set a null + CALL OUTC ; Output null + XOR A ; Clear A + LD (NULFLG),A ; Reset null flag +PROCES: LD A,C ; Get character + CP CTRLG ; Bell? + JP Z,PUTCTL ; Yes - Save it + CP CTRLC ; Is it control "C"? + CALL Z,PRNTCRLF ; Yes - Output CRLF + SCF ; Flag break + RET Z ; Return if control "C" + CP CR ; Is it enter? + JP Z,ENDINP ; Yes - Terminate input + CP CTRLU ; Is it control "U"? + JP Z,KILIN ; Yes - Get another line + CP '@' ; Is it "kill line"? + JP Z,OTKLN ; Yes - Kill line + CP '_' ; Is it delete? + JP Z,DELCHR ; Yes - Delete character + CP BKSP ; Is it backspace? + JP Z,DELCHR ; Yes - Delete character + CP CTRLR ; Is it control "R"? + JP NZ,PUTBUF ; No - Put in buffer + PUSH BC ; Save buffer length + PUSH DE ; Save DE + PUSH HL ; Save buffer address + LD (HL),0 ; Mark end of buffer + CALL OUTNCR ; Output and do CRLF + LD HL,BUFFER ; Point to buffer start + CALL PRS ; Output buffer + POP HL ; Restore buffer address + POP DE ; Restore DE + POP BC ; Restore buffer length + JP MORINP ; Get another character + +PUTBUF: CP ' ' ; Is it a control code? + JP C,MORINP ; Yes - Ignore +PUTCTL: LD A,B ; Get number of bytes in buffer + CP 72+1 ; Test for line overflow + LD A,CTRLG ; Set a bell + JP NC,OUTNBS ; Ring bell if buffer full + LD A,C ; Get character + LD (HL),C ; Save in buffer + LD (LSTBIN),A ; Save last input byte + INC HL ; Move up buffer + INC B ; Increment length +OUTIT: CALL OUTC ; Output the character entered + JP MORINP ; Get another character + +OUTNBS: CALL OUTC ; Output bell and back over it + LD A,BKSP ; Set back space + JP OUTIT ; Output it and get more + +CPDEHL: LD A,H ; Get H + SUB D ; Compare with D + RET NZ ; Different - Exit + LD A,L ; Get L + SUB E ; Compare with E + RET ; Return status + +CHKSYN: LD A,(HL) ; Check syntax of character + EX (SP),HL ; Address of test byte + CP (HL) ; Same as in code string? + INC HL ; Return address + EX (SP),HL ; Put it back + JP Z,GETCHR ; Yes - Get next character + JP SNERR ; Different - ?SN Error + +OUTC: PUSH AF ; Save character + LD A,(CTLOFG) ; Get control "O" flag + OR A ; Is it set? + JP NZ,POPAF ; Yes - don't output + POP AF ; Restore character + PUSH BC ; Save buffer length + PUSH AF ; Save character + CP ' ' ; Is it a control code? + JP C,DINPOS ; Yes - Don't INC POS(X) + LD A,(LWIDTH) ; Get line width + LD B,A ; To B + LD A,(CURPOS) ; Get cursor position + INC B ; Width 255? + JP Z,INCLEN ; Yes - No width limit + DEC B ; Restore width + CP B ; At end of line? + CALL Z,PRNTCRLF ; Yes - output CRLF +INCLEN: INC A ; Move on one character + LD (CURPOS),A ; Save new position +DINPOS: POP AF ; Restore character + POP BC ; Restore buffer length + CALL MONOUT ; Send it + RET + +CLOTST: CALL GETINP ; Get input character + AND 01111111B ; Strip bit 7 + CP CTRLO ; Is it control "O"? + RET NZ ; No don't flip flag + LD A,(CTLOFG) ; Get flag + CPL ; Flip it + LD (CTLOFG),A ; Put it back + XOR A ; Null character + RET + +LIST: CALL ATOH ; ASCII number to DE + RET NZ ; Return if anything extra + POP BC ; Rubbish - Not needed + CALL SRCHLN ; Search for line number in DE + PUSH BC ; Save address of line + CALL SETLIN ; Set up lines counter +LISTLP: POP HL ; Restore address of line + LD C,(HL) ; Get LSB of next line + INC HL + LD B,(HL) ; Get MSB of next line + INC HL + LD A,B ; BC = 0 (End of program)? + OR C + JP Z,PRNTOK ; Yes - Go to command mode + CALL COUNT ; Count lines + CALL TSTBRK ; Test for break key + PUSH BC ; Save address of next line + CALL PRNTCRLF ; Output CRLF + LD E,(HL) ; Get LSB of line number + INC HL + LD D,(HL) ; Get MSB of line number + INC HL + PUSH HL ; Save address of line start + EX DE,HL ; Line number to HL + CALL PRNTHL ; Output line number in decimal + LD A,' ' ; Space after line number + POP HL ; Restore start of line address +LSTLP2: CALL OUTC ; Output character in A +LSTLP3: LD A,(HL) ; Get next byte in line + OR A ; End of line? + INC HL ; To next byte in line + JP Z,LISTLP ; Yes - get next line + JP P,LSTLP2 ; No token - output it + SUB ZEND-1 ; Find and output word + LD C,A ; Token offset+1 to C + LD DE,WORDS ; Reserved word list +FNDTOK: LD A,(DE) ; Get character in list + INC DE ; Move on to next + OR A ; Is it start of word? + JP P,FNDTOK ; No - Keep looking for word + DEC C ; Count words + JP NZ,FNDTOK ; Not there - keep looking +OUTWRD: AND 01111111B ; Strip bit 7 + CALL OUTC ; Output first character + LD A,(DE) ; Get next character + INC DE ; Move on to next + OR A ; Is it end of word? + JP P,OUTWRD ; No - output the rest + JP LSTLP3 ; Next byte in line + +SETLIN: PUSH HL ; Set up LINES counter + LD HL,(LINESN) ; Get LINES number + LD (LINESC),HL ; Save in LINES counter + POP HL + RET + +COUNT: PUSH HL ; Save code string address + PUSH DE + LD HL,(LINESC) ; Get LINES counter + LD DE,-1 + ADC HL,DE ; Decrement + LD (LINESC),HL ; Put it back + POP DE + POP HL ; Restore code string address + RET P ; Return if more lines to go + PUSH HL ; Save code string address + LD HL,(LINESN) ; Get LINES number + LD (LINESC),HL ; Reset LINES counter + CALL GETINP ; Get input character + CP CTRLC ; Is it control "C"? + JP Z,RSLNBK ; Yes - Reset LINES and break + POP HL ; Restore code string address + JP COUNT ; Keep on counting + +RSLNBK: LD HL,(LINESN) ; Get LINES number + LD (LINESC),HL ; Reset LINES counter + JP BRKRET ; Go and output "Break" + +FOR: LD A,64H ; Flag "FOR" assignment + LD (FORFLG),A ; Save "FOR" flag + CALL LET ; Set up initial index + POP BC ; Drop RETurn address + PUSH HL ; Save code string address + CALL DATA ; Get next statement address + LD (LOOPST),HL ; Save it for start of loop + LD HL,2 ; Offset for "FOR" block + ADD HL,SP ; Point to it +FORSLP: CALL LOKFOR ; Look for existing "FOR" block + POP DE ; Get code string address + JP NZ,FORFND ; No nesting found + ADD HL,BC ; Move into "FOR" block + PUSH DE ; Save code string address + DEC HL + LD D,(HL) ; Get MSB of loop statement + DEC HL + LD E,(HL) ; Get LSB of loop statement + INC HL + INC HL + PUSH HL ; Save block address + LD HL,(LOOPST) ; Get address of loop statement + CALL CPDEHL ; Compare the FOR loops + POP HL ; Restore block address + JP NZ,FORSLP ; Different FORs - Find another + POP DE ; Restore code string address + LD SP,HL ; Remove all nested loops + +FORFND: EX DE,HL ; Code string address to HL + LD C,8 + CALL CHKSTK ; Check for 8 levels of stack + PUSH HL ; Save code string address + LD HL,(LOOPST) ; Get first statement of loop + EX (SP),HL ; Save and restore code string + PUSH HL ; Re-save code string address + LD HL,(LINEAT) ; Get current line number + EX (SP),HL ; Save and restore code string + CALL TSTNUM ; Make sure it's a number + CALL CHKSYN ; Make sure "TO" is next + .BYTE ZTO ; "TO" token + CALL GETNUM ; Get "TO" expression value + PUSH HL ; Save code string address + CALL BCDEFP ; Move "TO" value to BCDE + POP HL ; Restore code string address + PUSH BC ; Save "TO" value in block + PUSH DE + LD BC,8100H ; BCDE - 1 (default STEP) + LD D,C ; C=0 + LD E,D ; D=0 + LD A,(HL) ; Get next byte in code string + CP ZSTEP ; See if "STEP" is stated + LD A,1 ; Sign of step = 1 + JP NZ,SAVSTP ; No STEP given - Default to 1 + CALL GETCHR ; Jump over "STEP" token + CALL GETNUM ; Get step value + PUSH HL ; Save code string address + CALL BCDEFP ; Move STEP to BCDE + CALL TSTSGN ; Test sign of FPREG + POP HL ; Restore code string address +SAVSTP: PUSH BC ; Save the STEP value in block + PUSH DE + PUSH AF ; Save sign of STEP + INC SP ; Don't save flags + PUSH HL ; Save code string address + LD HL,(BRKLIN) ; Get address of index variable + EX (SP),HL ; Save and restore code string +PUTFID: LD B,ZFOR ; "FOR" block marker + PUSH BC ; Save it + INC SP ; Don't save C + +RUNCNT: CALL TSTBRK ; Execution driver - Test break + LD (BRKLIN),HL ; Save code address for break + LD A,(HL) ; Get next byte in code string + CP ':' ; Multi statement line? + JP Z,EXCUTE ; Yes - Execute it + OR A ; End of line? + JP NZ,SNERR ; No - Syntax error + INC HL ; Point to address of next line + LD A,(HL) ; Get LSB of line pointer + INC HL + OR (HL) ; Is it zero (End of prog)? + JP Z,ENDPRG ; Yes - Terminate execution + INC HL ; Point to line number + LD E,(HL) ; Get LSB of line number + INC HL + LD D,(HL) ; Get MSB of line number + EX DE,HL ; Line number to HL + LD (LINEAT),HL ; Save as current line number + EX DE,HL ; Line number back to DE +EXCUTE: CALL GETCHR ; Get key word + LD DE,RUNCNT ; Where to RETurn to + PUSH DE ; Save for RETurn +IFJMP: RET Z ; Go to RUNCNT if end of STMT +ONJMP: SUB ZEND ; Is it a token? + JP C,LET ; No - try to assign it + CP ZNEW+1-ZEND ; END to NEW ? + JP NC,SNERR ; Not a key word - ?SN Error + RLCA ; Double it + LD C,A ; BC = Offset into table + LD B,0 + EX DE,HL ; Save code string address + LD HL,WORDTB ; Keyword address table + ADD HL,BC ; Point to routine address + LD C,(HL) ; Get LSB of routine address + INC HL + LD B,(HL) ; Get MSB of routine address + PUSH BC ; Save routine address + EX DE,HL ; Restore code string address + +GETCHR: INC HL ; Point to next character + LD A,(HL) ; Get next code string byte + CP ':' ; Z if ':' + RET NC ; NC if > "9" + CP ' ' + JP Z,GETCHR ; Skip over spaces + CP '0' + CCF ; NC if < '0' + INC A ; Test for zero - Leave carry + DEC A ; Z if Null + RET + +RESTOR: EX DE,HL ; Save code string address + LD HL,(BASTXT) ; Point to start of program + JP Z,RESTNL ; Just RESTORE - reset pointer + EX DE,HL ; Restore code string address + CALL ATOH ; Get line number to DE + PUSH HL ; Save code string address + CALL SRCHLN ; Search for line number in DE + LD H,B ; HL = Address of line + LD L,C + POP DE ; Restore code string address + JP NC,ULERR ; ?UL Error if not found +RESTNL: DEC HL ; Byte before DATA statement +UPDATA: LD (NXTDAT),HL ; Update DATA pointer + EX DE,HL ; Restore code string address + RET + + +TSTBRK: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL + ; GET CONSOLE INPUT STATUS VIA HBIOS + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + RST 08 ; HBIOS RETURNS STATUS IN A + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET Z ; No key, go back + PUSH BC + PUSH DE + PUSH HL + ; INPUT CHARACTER FROM CONSOLE VIA HBIOS + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + + CP ESC ; Escape key? + JR Z,BRK ; Yes, break + CP CTRLC ; + JR Z,BRK ; Yes, break + CP CTRLS ; Stop scrolling? + RET NZ ; Other key, ignore +STALL: ; Wait for key + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + ; INPUT CHARACTER FROM CONSOLE VIA HBIOS + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + CP CTRLQ ; Resume scrolling? + RET Z ; Release the chokehold + CP CTRLC ; Second break? + JR Z,STOP ; Break during hold exits prog + JR STALL ; Loop until or + +BRK LD A,$FF ; Set BRKFLG + LD (BRKFLG),A ; Store it + +STOP: RET NZ ; Exit if anything else + .BYTE 0F6H ; Flag "STOP" +PEND: RET NZ ; Exit if anything else + LD (BRKLIN),HL ; Save point of break + .BYTE 21H ; Skip "OR 11111111B" +INPBRK: OR 11111111B ; Flag "Break" wanted + POP BC ; Return not needed and more +ENDPRG: LD HL,(LINEAT) ; Get current line number + PUSH AF ; Save STOP / END status + LD A,L ; Is it direct break? + AND H + INC A ; Line is -1 if direct break + JP Z,NOLIN ; Yes - No line number + LD (ERRLIN),HL ; Save line of break + LD HL,(BRKLIN) ; Get point of break + LD (CONTAD),HL ; Save point to CONTinue +NOLIN: XOR A + LD (CTLOFG),A ; Enable output + CALL STTLIN ; Start a new line + POP AF ; Restore STOP / END status + LD HL,BRKMSG ; "Break" message + JP NZ,ERRIN ; "in line" wanted? + JP PRNTOK ; Go to command mode + +CONT: LD HL,(CONTAD) ; Get CONTinue address + LD A,H ; Is it zero? + OR L + LD E,CN ; ?CN Error + JP Z,ERROR ; Yes - output "?CN Error" + EX DE,HL ; Save code string address + LD HL,(ERRLIN) ; Get line of last break + LD (LINEAT),HL ; Set up current line number + EX DE,HL ; Restore code string address + RET ; CONTinue where left off + +NULL: CALL GETINT ; Get integer 0-255 + RET NZ ; Return if bad value + LD (NULLS),A ; Set nulls number + RET + + +ACCSUM: PUSH HL ; Save address in array + LD HL,(CHKSUM) ; Get check sum + LD B,0 ; BC - Value of byte + LD C,A + ADD HL,BC ; Add byte to check sum + LD (CHKSUM),HL ; Re-save check sum + POP HL ; Restore address in array + RET + +CHKLTR: LD A,(HL) ; Get byte + CP 'A' ; < 'a' ? + RET C ; Carry set if not letter + CP 'Z'+1 ; > 'z' ? + CCF + RET ; Carry set if not letter + +FPSINT: CALL GETCHR ; Get next character +POSINT: CALL GETNUM ; Get integer 0 to 32767 +DEPINT: CALL TSTSGN ; Test sign of FPREG + JP M,FCERR ; Negative - ?FC Error +DEINT: LD A,(FPEXP) ; Get integer value to DE + CP 80H+16 ; Exponent in range (16 bits)? + JP C,FPINT ; Yes - convert it + LD BC,9080H ; BCDE = -32768 + LD DE,0000 + PUSH HL ; Save code string address + CALL CMPNUM ; Compare FPREG with BCDE + POP HL ; Restore code string address + LD D,C ; MSB to D + RET Z ; Return if in range +FCERR: LD E,FC ; ?FC Error + JP ERROR ; Output error- + +ATOH: DEC HL ; ASCII number to DE binary +GETLN: LD DE,0 ; Get number to DE +GTLNLP: CALL GETCHR ; Get next character + RET NC ; Exit if not a digit + PUSH HL ; Save code string address + PUSH AF ; Save digit + LD HL,65529/10 ; Largest number 65529 + CALL CPDEHL ; Number in range? + JP C,SNERR ; No - ?SN Error + LD H,D ; HL = Number + LD L,E + ADD HL,DE ; Times 2 + ADD HL,HL ; Times 4 + ADD HL,DE ; Times 5 + ADD HL,HL ; Times 10 + POP AF ; Restore digit + SUB '0' ; Make it 0 to 9 + LD E,A ; DE = Value of digit + LD D,0 + ADD HL,DE ; Add to number + EX DE,HL ; Number to DE + POP HL ; Restore code string address + JP GTLNLP ; Go to next character + +CLEAR: JP Z,INTVAR ; Just "CLEAR" Keep parameters + CALL POSINT ; Get integer 0 to 32767 to DE + DEC HL ; Cancel increment + CALL GETCHR ; Get next character + PUSH HL ; Save code string address + LD HL,(LSTRAM) ; Get end of RAM + JP Z,STORED ; No value given - Use stored + POP HL ; Restore code string address + CALL CHKSYN ; Check for comma + .BYTE ',' + PUSH DE ; Save number + CALL POSINT ; Get integer 0 to 32767 + DEC HL ; Cancel increment + CALL GETCHR ; Get next character + JP NZ,SNERR ; ?SN Error if more on line + EX (SP),HL ; Save code string address + EX DE,HL ; Number to DE +STORED: LD A,L ; Get LSB of new RAM top + SUB E ; Subtract LSB of string space + LD E,A ; Save LSB + LD A,H ; Get MSB of new RAM top + SBC A,D ; Subtract MSB of string space + LD D,A ; Save MSB + JP C,OMERR ; ?OM Error if not enough mem + PUSH HL ; Save RAM top + LD HL,(PROGND) ; Get program end + LD BC,40 ; 40 Bytes minimum working RAM + ADD HL,BC ; Get lowest address + CALL CPDEHL ; Enough memory? + JP NC,OMERR ; No - ?OM Error + EX DE,HL ; RAM top to HL + LD (STRSPC),HL ; Set new string space + POP HL ; End of memory to use + LD (LSTRAM),HL ; Set new top of RAM + POP HL ; Restore code string address + JP INTVAR ; Initialise variables + +RUN: JP Z,RUNFST ; RUN from start if just RUN + CALL INTVAR ; Initialise variables + LD BC,RUNCNT ; Execution driver loop + JP RUNLIN ; RUN from line number + +GOSUB: LD C,3 ; 3 Levels of stack needed + CALL CHKSTK ; Check for 3 levels of stack + POP BC ; Get return address + PUSH HL ; Save code string for RETURN + PUSH HL ; And for GOSUB routine + LD HL,(LINEAT) ; Get current line + EX (SP),HL ; Into stack - Code string out + LD A,ZGOSUB ; "GOSUB" token + PUSH AF ; Save token + INC SP ; Don't save flags + +RUNLIN: PUSH BC ; Save return address +GOTO: CALL ATOH ; ASCII number to DE binary + CALL REM ; Get end of line + PUSH HL ; Save end of line + LD HL,(LINEAT) ; Get current line + CALL CPDEHL ; Line after current? + POP HL ; Restore end of line + INC HL ; Start of next line + CALL C,SRCHLP ; Line is after current line + CALL NC,SRCHLN ; Line is before current line + LD H,B ; Set up code string address + LD L,C + DEC HL ; Incremented after + RET C ; Line found +ULERR: LD E,UL ; ?UL Error + JP ERROR ; Output error message + +RETURN: RET NZ ; Return if not just RETURN + LD D,-1 ; Flag "GOSUB" search + CALL BAKSTK ; Look "GOSUB" block + LD SP,HL ; Kill all FORs in subroutine + CP ZGOSUB ; Test for "GOSUB" token + LD E,RG ; ?RG Error + JP NZ,ERROR ; Error if no "GOSUB" found + POP HL ; Get RETURN line number + LD (LINEAT),HL ; Save as current + INC HL ; Was it from direct statement? + LD A,H + OR L ; Return to line + JP NZ,RETLIN ; No - Return to line + LD A,(LSTBIN) ; Any INPUT in subroutine? + OR A ; If so buffer is corrupted + JP NZ,POPNOK ; Yes - Go to command mode +RETLIN: LD HL,RUNCNT ; Execution driver loop + EX (SP),HL ; Into stack - Code string out + .BYTE 3EH ; Skip "POP HL" +NXTDTA: POP HL ; Restore code string address + +DATA: .BYTE 01H,3AH ; ':' End of statement +REM: LD C,0 ; 00 End of statement + LD B,0 +NXTSTL: LD A,C ; Statement and byte + LD C,B + LD B,A ; Statement end byte +NXTSTT: LD A,(HL) ; Get byte + OR A ; End of line? + RET Z ; Yes - Exit + CP B ; End of statement? + RET Z ; Yes - Exit + INC HL ; Next byte + CP '"' ; Literal string? + JP Z,NXTSTL ; Yes - Look for another '"' + JP NXTSTT ; Keep looking + +LET: CALL GETVAR ; Get variable name + CALL CHKSYN ; Make sure "=" follows + .BYTE ZEQUAL ; "=" token + PUSH DE ; Save address of variable + LD A,(TYPE) ; Get data type + PUSH AF ; Save type + CALL EVAL ; Evaluate expression + POP AF ; Restore type + EX (SP),HL ; Save code - Get var addr + LD (BRKLIN),HL ; Save address of variable + RRA ; Adjust type + CALL CHKTYP ; Check types are the same + JP Z,LETNUM ; Numeric - Move value +LETSTR: PUSH HL ; Save address of string var + LD HL,(FPREG) ; Pointer to string entry + PUSH HL ; Save it on stack + INC HL ; Skip over length + INC HL + LD E,(HL) ; LSB of string address + INC HL + LD D,(HL) ; MSB of string address + LD HL,(BASTXT) ; Point to start of program + CALL CPDEHL ; Is string before program? + JP NC,CRESTR ; Yes - Create string entry + LD HL,(STRSPC) ; Point to string space + CALL CPDEHL ; Is string literal in program? + POP DE ; Restore address of string + JP NC,MVSTPT ; Yes - Set up pointer + LD HL,TMPSTR ; Temporary string pool + CALL CPDEHL ; Is string in temporary pool? + JP NC,MVSTPT ; No - Set up pointer + .BYTE 3EH ; Skip "POP DE" +CRESTR: POP DE ; Restore address of string + CALL BAKTMP ; Back to last tmp-str entry + EX DE,HL ; Address of string entry + CALL SAVSTR ; Save string in string area +MVSTPT: CALL BAKTMP ; Back to last tmp-str entry + POP HL ; Get string pointer + CALL DETHL4 ; Move string pointer to var + POP HL ; Restore code string address + RET + +LETNUM: PUSH HL ; Save address of variable + CALL FPTHL ; Move value to variable + POP DE ; Restore address of variable + POP HL ; Restore code string address + RET + +ON: CALL GETINT ; Get integer 0-255 + LD A,(HL) ; Get "GOTO" or "GOSUB" token + LD B,A ; Save in B + CP ZGOSUB ; "GOSUB" token? + JP Z,ONGO ; Yes - Find line number + CALL CHKSYN ; Make sure it's "GOTO" + .BYTE ZGOTO ; "GOTO" token + DEC HL ; Cancel increment +ONGO: LD C,E ; Integer of branch value +ONGOLP: DEC C ; Count branches + LD A,B ; Get "GOTO" or "GOSUB" token + JP Z,ONJMP ; Go to that line if right one + CALL GETLN ; Get line number to DE + CP ',' ; Another line number? + RET NZ ; No - Drop through + JP ONGOLP ; Yes - loop + +IF: CALL EVAL ; Evaluate expression + LD A,(HL) ; Get token + CP ZGOTO ; "GOTO" token? + JP Z,IFGO ; Yes - Get line + CALL CHKSYN ; Make sure it's "THEN" + .BYTE ZTHEN ; "THEN" token + DEC HL ; Cancel increment +IFGO: CALL TSTNUM ; Make sure it's numeric + CALL TSTSGN ; Test state of expression + JP Z,REM ; False - Drop through + CALL GETCHR ; Get next character + JP C,GOTO ; Number - GOTO that line + JP IFJMP ; Otherwise do statement + +MRPRNT: DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character +PRINT: JP Z,PRNTCRLF ; CRLF if just PRINT +PRNTLP: RET Z ; End of list - Exit + CP ZTAB ; "TAB(" token? + JP Z,DOTAB ; Yes - Do TAB routine + CP ZSPC ; "SPC(" token? + JP Z,DOTAB ; Yes - Do SPC routine + PUSH HL ; Save code string address + CP ',' ; Comma? + JP Z,DOCOM ; Yes - Move to next zone + CP 59 ;";" ; Semi-colon? + JP Z,NEXITM ; Do semi-colon routine + POP BC ; Code string address to BC + CALL EVAL ; Evaluate expression + PUSH HL ; Save code string address + LD A,(TYPE) ; Get variable type + OR A ; Is it a string variable? + JP NZ,PRNTST ; Yes - Output string contents + CALL NUMASC ; Convert number to text + CALL CRTST ; Create temporary string + LD (HL),' ' ; Followed by a space + LD HL,(FPREG) ; Get length of output + INC (HL) ; Plus 1 for the space + LD HL,(FPREG) ; < Not needed > + LD A,(LWIDTH) ; Get width of line + LD B,A ; To B + INC B ; Width 255 (No limit)? + JP Z,PRNTNB ; Yes - Output number string + INC B ; Adjust it + LD A,(CURPOS) ; Get cursor position + ADD A,(HL) ; Add length of string + DEC A ; Adjust it + CP B ; Will output fit on this line? + CALL NC,PRNTCRLF ; No - CRLF first +PRNTNB: CALL PRS1 ; Output string at (HL) + XOR A ; Skip CALL by setting 'z' flag +PRNTST: CALL NZ,PRS1 ; Output string at (HL) + POP HL ; Restore code string address + JP MRPRNT ; See if more to PRINT + +STTLIN: LD A,(CURPOS) ; Make sure on new line + OR A ; Already at start? + RET Z ; Yes - Do nothing + JP PRNTCRLF ; Start a new line + +ENDINP: LD (HL),0 ; Mark end of buffer + LD HL,BUFFER-1 ; Point to buffer +PRNTCRLF: LD A,CR ; Load a CR + CALL OUTC ; Output character + LD A,LF ; Load a LF + CALL OUTC ; Output character +DONULL: XOR A ; Set to position 0 + LD (CURPOS),A ; Store it + LD A,(NULLS) ; Get number of nulls +NULLP: DEC A ; Count them + RET Z ; Return if done + PUSH AF ; Save count + XOR A ; Load a null + CALL OUTC ; Output it + POP AF ; Restore count + JP NULLP ; Keep counting + +DOCOM: LD A,(COMMAN) ; Get comma width + LD B,A ; Save in B + LD A,(CURPOS) ; Get current position + CP B ; Within the limit? + CALL NC,PRNTCRLF ; No - output CRLF + JP NC,NEXITM ; Get next item +ZONELP: SUB 14 ; Next zone of 14 characters + JP NC,ZONELP ; Repeat if more zones + CPL ; Number of spaces to output + JP ASPCS ; Output them + +DOTAB: PUSH AF ; Save token + CALL FNDNUM ; Evaluate expression + CALL CHKSYN ; Make sure ")" follows + .BYTE ")" + DEC HL ; Back space on to ")" + POP AF ; Restore token + SUB ZSPC ; Was it "SPC(" ? + PUSH HL ; Save code string address + JP Z,DOSPC ; Yes - Do 'E' spaces + LD A,(CURPOS) ; Get current position +DOSPC: CPL ; Number of spaces to print to + ADD A,E ; Total number to print + JP NC,NEXITM ; TAB < Current POS(X) +ASPCS: INC A ; Output A spaces + LD B,A ; Save number to print + LD A,' ' ; Space +SPCLP: CALL OUTC ; Output character in A + DEC B ; Count them + JP NZ,SPCLP ; Repeat if more +NEXITM: POP HL ; Restore code string address + CALL GETCHR ; Get next character + JP PRNTLP ; More to print + +REDO: .BYTE "?Redo from start",CR,LF,0 + +BADINP: LD A,(READFG) ; READ or INPUT? + OR A + JP NZ,DATSNR ; READ - ?SN Error + POP BC ; Throw away code string addr + LD HL,REDO ; "Redo from start" message + CALL PRS ; Output string + JP DOAGN ; Do last INPUT again + +INPUT: CALL IDTEST ; Test for illegal direct + LD A,(HL) ; Get character after "INPUT" + CP '"' ; Is there a prompt string? + LD A,0 ; Clear A and leave flags + LD (CTLOFG),A ; Enable output + JP NZ,NOPMPT ; No prompt - get input + CALL QTSTR ; Get string terminated by '"' + CALL CHKSYN ; Check for ';' after prompt + .BYTE ';' + PUSH HL ; Save code string address + CALL PRS1 ; Output prompt string + .BYTE 3EH ; Skip "PUSH HL" +NOPMPT: PUSH HL ; Save code string address + CALL PROMPT ; Get input with "? " prompt + POP BC ; Restore code string address + JP C,INPBRK ; Break pressed - Exit + INC HL ; Next byte + LD A,(HL) ; Get it + OR A ; End of line? + DEC HL ; Back again + PUSH BC ; Re-save code string address + JP Z,NXTDTA ; Yes - Find next DATA stmt + LD (HL),',' ; Store comma as separator + JP NXTITM ; Get next item + +READ: PUSH HL ; Save code string address + LD HL,(NXTDAT) ; Next DATA statement + .BYTE 0F6H ; Flag "READ" +NXTITM: XOR A ; Flag "INPUT" + LD (READFG),A ; Save "READ"/"INPUT" flag + EX (SP),HL ; Get code str' , Save pointer + JP GTVLUS ; Get values + +NEDMOR: CALL CHKSYN ; Check for comma between items + .BYTE ',' +GTVLUS: CALL GETVAR ; Get variable name + EX (SP),HL ; Save code str" , Get pointer + PUSH DE ; Save variable address + LD A,(HL) ; Get next "INPUT"/"DATA" byte + CP ',' ; Comma? + JP Z,ANTVLU ; Yes - Get another value + LD A,(READFG) ; Is it READ? + OR A + JP NZ,FDTLP ; Yes - Find next DATA stmt + LD A,'?' ; More INPUT needed + CALL OUTC ; Output character + CALL PROMPT ; Get INPUT with prompt + POP DE ; Variable address + POP BC ; Code string address + JP C,INPBRK ; Break pressed + INC HL ; Point to next DATA byte + LD A,(HL) ; Get byte + OR A ; Is it zero (No input) ? + DEC HL ; Back space INPUT pointer + PUSH BC ; Save code string address + JP Z,NXTDTA ; Find end of buffer + PUSH DE ; Save variable address +ANTVLU: LD A,(TYPE) ; Check data type + OR A ; Is it numeric? + JP Z,INPBIN ; Yes - Convert to binary + CALL GETCHR ; Get next character + LD D,A ; Save input character + LD B,A ; Again + CP '"' ; Start of literal sting? + JP Z,STRENT ; Yes - Create string entry + LD A,(READFG) ; "READ" or "INPUT" ? + OR A + LD D,A ; Save 00 if "INPUT" + JP Z,ITMSEP ; "INPUT" - End with 00 + LD D,':' ; "DATA" - End with 00 or ':' +ITMSEP: LD B,',' ; Item separator + DEC HL ; Back space for DTSTR +STRENT: CALL DTSTR ; Get string terminated by D + EX DE,HL ; String address to DE + LD HL,LTSTND ; Where to go after LETSTR + EX (SP),HL ; Save HL , get input pointer + PUSH DE ; Save address of string + JP LETSTR ; Assign string to variable + +INPBIN: CALL GETCHR ; Get next character + CALL ASCTFP ; Convert ASCII to FP number + EX (SP),HL ; Save input ptr, Get var addr + CALL FPTHL ; Move FPREG to variable + POP HL ; Restore input pointer +LTSTND: DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character + JP Z,MORDT ; End of line - More needed? + CP ',' ; Another value? + JP NZ,BADINP ; No - Bad input +MORDT: EX (SP),HL ; Get code string address + DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character + JP NZ,NEDMOR ; More needed - Get it + POP DE ; Restore DATA pointer + LD A,(READFG) ; "READ" or "INPUT" ? + OR A + EX DE,HL ; DATA pointer to HL + JP NZ,UPDATA ; Update DATA pointer if "READ" + PUSH DE ; Save code string address + OR (HL) ; More input given? + LD HL,EXTIG ; "?Extra ignored" message + CALL NZ,PRS ; Output string if extra given + POP HL ; Restore code string address + RET + +EXTIG: .BYTE "?Extra ignored",CR,LF,0 + +FDTLP: CALL DATA ; Get next statement + OR A ; End of line? + JP NZ,FANDT ; No - See if DATA statement + INC HL + LD A,(HL) ; End of program? + INC HL + OR (HL) ; 00 00 Ends program + LD E,OD ; ?OD Error + JP Z,ERROR ; Yes - Out of DATA + INC HL + LD E,(HL) ; LSB of line number + INC HL + LD D,(HL) ; MSB of line number + EX DE,HL + LD (DATLIN),HL ; Set line of current DATA item + EX DE,HL +FANDT: CALL GETCHR ; Get next character + CP ZDATA ; "DATA" token + JP NZ,FDTLP ; No "DATA" - Keep looking + JP ANTVLU ; Found - Convert input + +NEXT: LD DE,0 ; In case no index given +NEXT1: CALL NZ,GETVAR ; Get index address + LD (BRKLIN),HL ; Save code string address + CALL BAKSTK ; Look for "FOR" block + JP NZ,NFERR ; No "FOR" - ?NF Error + LD SP,HL ; Clear nested loops + PUSH DE ; Save index address + LD A,(HL) ; Get sign of STEP + INC HL + PUSH AF ; Save sign of STEP + PUSH DE ; Save index address + CALL PHLTFP ; Move index value to FPREG + EX (SP),HL ; Save address of TO value + PUSH HL ; Save address of index + CALL ADDPHL ; Add STEP to index value + POP HL ; Restore address of index + CALL FPTHL ; Move value to index variable + POP HL ; Restore address of TO value + CALL LOADFP ; Move TO value to BCDE + PUSH HL ; Save address of line of FOR + CALL CMPNUM ; Compare index with TO value + POP HL ; Restore address of line num + POP BC ; Address of sign of STEP + SUB B ; Compare with expected sign + CALL LOADFP ; BC = Loop stmt,DE = Line num + JP Z,KILFOR ; Loop finished - Terminate it + EX DE,HL ; Loop statement line number + LD (LINEAT),HL ; Set loop line number + LD L,C ; Set code string to loop + LD H,B + JP PUTFID ; Put back "FOR" and continue + +KILFOR: LD SP,HL ; Remove "FOR" block + LD HL,(BRKLIN) ; Code string after "NEXT" + LD A,(HL) ; Get next byte in code string + CP ',' ; More NEXTs ? + JP NZ,RUNCNT ; No - Do next statement + CALL GETCHR ; Position to index name + CALL NEXT1 ; Re-enter NEXT routine +; < will not RETurn to here , Exit to RUNCNT or Loop > + +GETNUM: CALL EVAL ; Get a numeric expression +TSTNUM: .BYTE 0F6H ; Clear carry (numeric) +TSTSTR: SCF ; Set carry (string) +CHKTYP: LD A,(TYPE) ; Check types match + ADC A,A ; Expected + actual + OR A ; Clear carry , set parity + RET PE ; Even parity - Types match + JP TMERR ; Different types - Error + +OPNPAR: CALL CHKSYN ; Make sure "(" follows + .BYTE "(" +EVAL: DEC HL ; Evaluate expression & save + LD D,0 ; Precedence value +EVAL1: PUSH DE ; Save precedence + LD C,1 + CALL CHKSTK ; Check for 1 level of stack + CALL OPRND ; Get next expression value +EVAL2: LD (NXTOPR),HL ; Save address of next operator +EVAL3: LD HL,(NXTOPR) ; Restore address of next opr + POP BC ; Precedence value and operator + LD A,B ; Get precedence value + CP 78H ; "AND" or "OR" ? + CALL NC,TSTNUM ; No - Make sure it's a number + LD A,(HL) ; Get next operator / function + LD D,0 ; Clear Last relation +RLTLP: SUB ZGTR ; ">" Token + JP C,FOPRND ; + - * / ^ AND OR - Test it + CP ZLTH+1-ZGTR ; < = > + JP NC,FOPRND ; Function - Call it + CP ZEQUAL-ZGTR ; "=" + RLA ; <- Test for legal + XOR D ; <- combinations of < = > + CP D ; <- by combining last token + LD D,A ; <- with current one + JP C,SNERR ; Error if "<<' '==" or ">>" + LD (CUROPR),HL ; Save address of current token + CALL GETCHR ; Get next character + JP RLTLP ; Treat the two as one + +FOPRND: LD A,D ; < = > found ? + OR A + JP NZ,TSTRED ; Yes - Test for reduction + LD A,(HL) ; Get operator token + LD (CUROPR),HL ; Save operator address + SUB ZPLUS ; Operator or function? + RET C ; Neither - Exit + CP ZOR+1-ZPLUS ; Is it + - * / ^ AND OR ? + RET NC ; No - Exit + LD E,A ; Coded operator + LD A,(TYPE) ; Get data type + DEC A ; FF = numeric , 00 = string + OR E ; Combine with coded operator + LD A,E ; Get coded operator + JP Z,CONCAT ; String concatenation + RLCA ; Times 2 + ADD A,E ; Times 3 + LD E,A ; To DE (D is 0) + LD HL,PRITAB ; Precedence table + ADD HL,DE ; To the operator concerned + LD A,B ; Last operator precedence + LD D,(HL) ; Get evaluation precedence + CP D ; Compare with eval precedence + RET NC ; Exit if higher precedence + INC HL ; Point to routine address + CALL TSTNUM ; Make sure it's a number + +STKTHS: PUSH BC ; Save last precedence & token + LD BC,EVAL3 ; Where to go on prec' break + PUSH BC ; Save on stack for return + LD B,E ; Save operator + LD C,D ; Save precedence + CALL STAKFP ; Move value to stack + LD E,B ; Restore operator + LD D,C ; Restore precedence + LD C,(HL) ; Get LSB of routine address + INC HL + LD B,(HL) ; Get MSB of routine address + INC HL + PUSH BC ; Save routine address + LD HL,(CUROPR) ; Address of current operator + JP EVAL1 ; Loop until prec' break + +OPRND: XOR A ; Get operand routine + LD (TYPE),A ; Set numeric expected + CALL GETCHR ; Get next character + LD E,MO ; ?MO Error + JP Z,ERROR ; No operand - Error + JP C,ASCTFP ; Number - Get value + CALL CHKLTR ; See if a letter + JP NC,CONVAR ; Letter - Find variable + CP '&' ; &H = HEX, &B = BINARY + JR NZ, NOTAMP + CALL GETCHR ; Get next character + CP 'H' ; Hex number indicated? [function added] + JP Z,HEXTFP ; Convert Hex to FPREG + CP 'B' ; Binary number indicated? [function added] + JP Z,BINTFP ; Convert Bin to FPREG + LD E,SN ; If neither then a ?SN Error + JP Z,ERROR ; +NOTAMP: CP ZPLUS ; '+' Token ? + JP Z,OPRND ; Yes - Look for operand + CP '.' ; '.' ? + JP Z,ASCTFP ; Yes - Create FP number + CP ZMINUS ; '-' Token ? + JP Z,MINUS ; Yes - Do minus + CP '"' ; Literal string ? + JP Z,QTSTR ; Get string terminated by '"' + CP ZNOT ; "NOT" Token ? + JP Z,EVNOT ; Yes - Eval NOT expression + CP ZFN ; "FN" Token ? + JP Z,DOFN ; Yes - Do FN routine + SUB ZSGN ; Is it a function? + JP NC,FNOFST ; Yes - Evaluate function +EVLPAR: CALL OPNPAR ; Evaluate expression in "()" + CALL CHKSYN ; Make sure ")" follows + .BYTE ")" + RET + +MINUS: LD D,7DH ; '-' precedence + CALL EVAL1 ; Evaluate until prec' break + LD HL,(NXTOPR) ; Get next operator address + PUSH HL ; Save next operator address + CALL INVSGN ; Negate value +RETNUM: CALL TSTNUM ; Make sure it's a number + POP HL ; Restore next operator address + RET + +CONVAR: CALL GETVAR ; Get variable address to DE +FRMEVL: PUSH HL ; Save code string address + EX DE,HL ; Variable address to HL + LD (FPREG),HL ; Save address of variable + LD A,(TYPE) ; Get type + OR A ; Numeric? + CALL Z,PHLTFP ; Yes - Move contents to FPREG + POP HL ; Restore code string address + RET + +FNOFST: LD B,0 ; Get address of function + RLCA ; Double function offset + LD C,A ; BC = Offset in function table + PUSH BC ; Save adjusted token value + CALL GETCHR ; Get next character + LD A,C ; Get adjusted token value + CP 2*(ZLEFT-ZSGN)-1; Adj' LEFT$,RIGHT$ or MID$ ? + JP C,FNVAL ; No - Do function + CALL OPNPAR ; Evaluate expression (X,... + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + CALL TSTSTR ; Make sure it's a string + EX DE,HL ; Save code string address + LD HL,(FPREG) ; Get address of string + EX (SP),HL ; Save address of string + PUSH HL ; Save adjusted token value + EX DE,HL ; Restore code string address + CALL GETINT ; Get integer 0-255 + EX DE,HL ; Save code string address + EX (SP),HL ; Save integer,HL = adj' token + JP GOFUNC ; Jump to string function + +FNVAL: CALL EVLPAR ; Evaluate expression + EX (SP),HL ; HL = Adjusted token value + LD DE,RETNUM ; Return number from function + PUSH DE ; Save on stack +GOFUNC: LD BC,FNCTAB ; Function routine addresses + ADD HL,BC ; Point to right address + LD C,(HL) ; Get LSB of address + INC HL ; + LD H,(HL) ; Get MSB of address + LD L,C ; Address to HL + JP (HL) ; Jump to function + +SGNEXP: DEC D ; Dee to flag negative exponent + CP ZMINUS ; '-' token ? + RET Z ; Yes - Return + CP '-' ; '-' ASCII ? + RET Z ; Yes - Return + INC D ; Inc to flag positive exponent + CP '+' ; '+' ASCII ? + RET Z ; Yes - Return + CP ZPLUS ; '+' token ? + RET Z ; Yes - Return + DEC HL ; DEC 'cos GETCHR INCs + RET ; Return "NZ" + +POR: .BYTE 0F6H ; Flag "OR" +PAND: XOR A ; Flag "AND" + PUSH AF ; Save "AND" / "OR" flag + CALL TSTNUM ; Make sure it's a number + CALL DEINT ; Get integer -32768 to 32767 + POP AF ; Restore "AND" / "OR" flag + EX DE,HL ; <- Get last + POP BC ; <- value + EX (SP),HL ; <- from + EX DE,HL ; <- stack + CALL FPBCDE ; Move last value to FPREG + PUSH AF ; Save "AND" / "OR" flag + CALL DEINT ; Get integer -32768 to 32767 + POP AF ; Restore "AND" / "OR" flag + POP BC ; Get value + LD A,C ; Get LSB + LD HL,ACPASS ; Address of save AC as current + JP NZ,POR1 ; Jump if OR + AND E ; "AND" LSBs + LD C,A ; Save LSB + LD A,B ; Get MBS + AND D ; "AND" MSBs + JP (HL) ; Save AC as current (ACPASS) + +POR1: OR E ; "OR" LSBs + LD C,A ; Save LSB + LD A,B ; Get MSB + OR D ; "OR" MSBs + JP (HL) ; Save AC as current (ACPASS) + +TSTRED: LD HL,CMPLOG ; Logical compare routine + LD A,(TYPE) ; Get data type + RRA ; Carry set = string + LD A,D ; Get last precedence value + RLA ; Times 2 plus carry + LD E,A ; To E + LD D,64H ; Relational precedence + LD A,B ; Get current precedence + CP D ; Compare with last + RET NC ; Eval if last was rel' or log' + JP STKTHS ; Stack this one and get next + +CMPLOG: .WORD CMPLG1 ; Compare two values / strings +CMPLG1: LD A,C ; Get data type + OR A + RRA + POP BC ; Get last expression to BCDE + POP DE + PUSH AF ; Save status + CALL CHKTYP ; Check that types match + LD HL,CMPRES ; Result to comparison + PUSH HL ; Save for RETurn + JP Z,CMPNUM ; Compare values if numeric + XOR A ; Compare two strings + LD (TYPE),A ; Set type to numeric + PUSH DE ; Save string name + CALL GSTRCU ; Get current string + LD A,(HL) ; Get length of string + INC HL + INC HL + LD C,(HL) ; Get LSB of address + INC HL + LD B,(HL) ; Get MSB of address + POP DE ; Restore string name + PUSH BC ; Save address of string + PUSH AF ; Save length of string + CALL GSTRDE ; Get second string + CALL LOADFP ; Get address of second string + POP AF ; Restore length of string 1 + LD D,A ; Length to D + POP HL ; Restore address of string 1 +CMPSTR: LD A,E ; Bytes of string 2 to do + OR D ; Bytes of string 1 to do + RET Z ; Exit if all bytes compared + LD A,D ; Get bytes of string 1 to do + SUB 1 + RET C ; Exit if end of string 1 + XOR A + CP E ; Bytes of string 2 to do + INC A + RET NC ; Exit if end of string 2 + DEC D ; Count bytes in string 1 + DEC E ; Count bytes in string 2 + LD A,(BC) ; Byte in string 2 + CP (HL) ; Compare to byte in string 1 + INC HL ; Move up string 1 + INC BC ; Move up string 2 + JP Z,CMPSTR ; Same - Try next bytes + CCF ; Flag difference (">" or "<") + JP FLGDIF ; "<" gives -1 , ">" gives +1 + +CMPRES: INC A ; Increment current value + ADC A,A ; Double plus carry + POP BC ; Get other value + AND B ; Combine them + ADD A,-1 ; Carry set if different + SBC A,A ; 00 - Equal , FF - Different + JP FLGREL ; Set current value & continue + +EVNOT: LD D,5AH ; Precedence value for "NOT" + CALL EVAL1 ; Eval until precedence break + CALL TSTNUM ; Make sure it's a number + CALL DEINT ; Get integer -32768 - 32767 + LD A,E ; Get LSB + CPL ; Invert LSB + LD C,A ; Save "NOT" of LSB + LD A,D ; Get MSB + CPL ; Invert MSB + CALL ACPASS ; Save AC as current + POP BC ; Clean up stack + JP EVAL3 ; Continue evaluation + +DIMRET: DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character + RET Z ; End of DIM statement + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' +DIM: LD BC,DIMRET ; Return to "DIMRET" + PUSH BC ; Save on stack + .BYTE 0F6H ; Flag "Create" variable +GETVAR: XOR A ; Find variable address,to DE + LD (LCRFLG),A ; Set locate / create flag + LD B,(HL) ; Get First byte of name +GTFNAM: CALL CHKLTR ; See if a letter + JP C,SNERR ; ?SN Error if not a letter + XOR A + LD C,A ; Clear second byte of name + LD (TYPE),A ; Set type to numeric + CALL GETCHR ; Get next character + JP C,SVNAM2 ; Numeric - Save in name + CALL CHKLTR ; See if a letter + JP C,CHARTY ; Not a letter - Check type +SVNAM2: LD C,A ; Save second byte of name +ENDNAM: CALL GETCHR ; Get next character + JP C,ENDNAM ; Numeric - Get another + CALL CHKLTR ; See if a letter + JP NC,ENDNAM ; Letter - Get another +CHARTY: SUB '$' ; String variable? + JP NZ,NOTSTR ; No - Numeric variable + INC A ; A = 1 (string type) + LD (TYPE),A ; Set type to string + RRCA ; A = 80H , Flag for string + ADD A,C ; 2nd byte of name has bit 7 on + LD C,A ; Resave second byte on name + CALL GETCHR ; Get next character +NOTSTR: LD A,(FORFLG) ; Array name needed ? + DEC A + JP Z,ARLDSV ; Yes - Get array name + JP P,NSCFOR ; No array with "FOR" or "FN" + LD A,(HL) ; Get byte again + SUB '(' ; Subscripted variable? + JP Z,SBSCPT ; Yes - Sort out subscript + +NSCFOR: XOR A ; Simple variable + LD (FORFLG),A ; Clear "FOR" flag + PUSH HL ; Save code string address + LD D,B ; DE = Variable name to find + LD E,C + LD HL,(FNRGNM) ; FN argument name + CALL CPDEHL ; Is it the FN argument? + LD DE,FNARG ; Point to argument value + JP Z,POPHRT ; Yes - Return FN argument value + LD HL,(VAREND) ; End of variables + EX DE,HL ; Address of end of search + LD HL,(PROGND) ; Start of variables address +FNDVAR: CALL CPDEHL ; End of variable list table? + JP Z,CFEVAL ; Yes - Called from EVAL? + LD A,C ; Get second byte of name + SUB (HL) ; Compare with name in list + INC HL ; Move on to first byte + JP NZ,FNTHR ; Different - Find another + LD A,B ; Get first byte of name + SUB (HL) ; Compare with name in list +FNTHR: INC HL ; Move on to LSB of value + JP Z,RETADR ; Found - Return address + INC HL ; <- Skip + INC HL ; <- over + INC HL ; <- F.P. + INC HL ; <- value + JP FNDVAR ; Keep looking + +CFEVAL: POP HL ; Restore code string address + EX (SP),HL ; Get return address + PUSH DE ; Save address of variable + LD DE,FRMEVL ; Return address in EVAL + CALL CPDEHL ; Called from EVAL ? + POP DE ; Restore address of variable + JP Z,RETNUL ; Yes - Return null variable + EX (SP),HL ; Put back return + PUSH HL ; Save code string address + PUSH BC ; Save variable name + LD BC,6 ; 2 byte name plus 4 byte data + LD HL,(ARREND) ; End of arrays + PUSH HL ; Save end of arrays + ADD HL,BC ; Move up 6 bytes + POP BC ; Source address in BC + PUSH HL ; Save new end address + CALL MOVUP ; Move arrays up + POP HL ; Restore new end address + LD (ARREND),HL ; Set new end address + LD H,B ; End of variables to HL + LD L,C + LD (VAREND),HL ; Set new end address + +ZEROLP: DEC HL ; Back through to zero variable + LD (HL),0 ; Zero byte in variable + CALL CPDEHL ; Done them all? + JP NZ,ZEROLP ; No - Keep on going + POP DE ; Get variable name + LD (HL),E ; Store second character + INC HL + LD (HL),D ; Store first character + INC HL +RETADR: EX DE,HL ; Address of variable in DE + POP HL ; Restore code string address + RET + +RETNUL: LD (FPEXP),A ; Set result to zero + LD HL,ZERBYT ; Also set a null string + LD (FPREG),HL ; Save for EVAL + POP HL ; Restore code string address + RET + +SBSCPT: PUSH HL ; Save code string address + LD HL,(LCRFLG) ; Locate/Create and Type + EX (SP),HL ; Save and get code string + LD D,A ; Zero number of dimensions +SCPTLP: PUSH DE ; Save number of dimensions + PUSH BC ; Save array name + CALL FPSINT ; Get subscript (0-32767) + POP BC ; Restore array name + POP AF ; Get number of dimensions + EX DE,HL + EX (SP),HL ; Save subscript value + PUSH HL ; Save LCRFLG and TYPE + EX DE,HL + INC A ; Count dimensions + LD D,A ; Save in D + LD A,(HL) ; Get next byte in code string + CP ',' ; Comma (more to come)? + JP Z,SCPTLP ; Yes - More subscripts + CALL CHKSYN ; Make sure ")" follows + .BYTE ")" + LD (NXTOPR),HL ; Save code string address + POP HL ; Get LCRFLG and TYPE + LD (LCRFLG),HL ; Restore Locate/create & type + LD E,0 ; Flag not CSAVE* or CLOAD* + PUSH DE ; Save number of dimensions (D) + .BYTE 11H ; Skip "PUSH HL" and "PUSH AF' + +ARLDSV: PUSH HL ; Save code string address + PUSH AF ; A = 00 , Flags set = Z,N + LD HL,(VAREND) ; Start of arrays + .BYTE 3EH ; Skip "ADD HL,DE" +FNDARY: ADD HL,DE ; Move to next array start + EX DE,HL + LD HL,(ARREND) ; End of arrays + EX DE,HL ; Current array pointer + CALL CPDEHL ; End of arrays found? + JP Z,CREARY ; Yes - Create array + LD A,(HL) ; Get second byte of name + CP C ; Compare with name given + INC HL ; Move on + JP NZ,NXTARY ; Different - Find next array + LD A,(HL) ; Get first byte of name + CP B ; Compare with name given +NXTARY: INC HL ; Move on + LD E,(HL) ; Get LSB of next array address + INC HL + LD D,(HL) ; Get MSB of next array address + INC HL + JP NZ,FNDARY ; Not found - Keep looking + LD A,(LCRFLG) ; Found Locate or Create it? + OR A + JP NZ,DDERR ; Create - ?DD Error + POP AF ; Locate - Get number of dim'ns + LD B,H ; BC Points to array dim'ns + LD C,L + JP Z,POPHRT ; Jump if array load/save + SUB (HL) ; Same number of dimensions? + JP Z,FINDEL ; Yes - Find element +BSERR: LD E,BS ; ?BS Error + JP ERROR ; Output error + +CREARY: LD DE,4 ; 4 Bytes per entry + POP AF ; Array to save or 0 dim'ns? + JP Z,FCERR ; Yes - ?FC Error + LD (HL),C ; Save second byte of name + INC HL + LD (HL),B ; Save first byte of name + INC HL + LD C,A ; Number of dimensions to C + CALL CHKSTK ; Check if enough memory + INC HL ; Point to number of dimensions + INC HL + LD (CUROPR),HL ; Save address of pointer + LD (HL),C ; Set number of dimensions + INC HL + LD A,(LCRFLG) ; Locate of Create? + RLA ; Carry set = Create + LD A,C ; Get number of dimensions +CRARLP: LD BC,10+1 ; Default dimension size 10 + JP NC,DEFSIZ ; Locate - Set default size + POP BC ; Get specified dimension size + INC BC ; Include zero element +DEFSIZ: LD (HL),C ; Save LSB of dimension size + INC HL + LD (HL),B ; Save MSB of dimension size + INC HL + PUSH AF ; Save num' of dim'ns an status + PUSH HL ; Save address of dim'n size + CALL MLDEBC ; Multiply DE by BC to find + EX DE,HL ; amount of mem needed (to DE) + POP HL ; Restore address of dimension + POP AF ; Restore number of dimensions + DEC A ; Count them + JP NZ,CRARLP ; Do next dimension if more + PUSH AF ; Save locate/create flag + LD B,D ; MSB of memory needed + LD C,E ; LSB of memory needed + EX DE,HL + ADD HL,DE ; Add bytes to array start + JP C,OMERR ; Too big - Error + CALL ENFMEM ; See if enough memory + LD (ARREND),HL ; Save new end of array + +ZERARY: DEC HL ; Back through array data + LD (HL),0 ; Set array element to zero + CALL CPDEHL ; All elements zeroed? + JP NZ,ZERARY ; No - Keep on going + INC BC ; Number of bytes + 1 + LD D,A ; A=0 + LD HL,(CUROPR) ; Get address of array + LD E,(HL) ; Number of dimensions + EX DE,HL ; To HL + ADD HL,HL ; Two bytes per dimension size + ADD HL,BC ; Add number of bytes + EX DE,HL ; Bytes needed to DE + DEC HL + DEC HL + LD (HL),E ; Save LSB of bytes needed + INC HL + LD (HL),D ; Save MSB of bytes needed + INC HL + POP AF ; Locate / Create? + JP C,ENDDIM ; A is 0 , End if create +FINDEL: LD B,A ; Find array element + LD C,A + LD A,(HL) ; Number of dimensions + INC HL + .BYTE 16H ; Skip "POP HL" +FNDELP: POP HL ; Address of next dim' size + LD E,(HL) ; Get LSB of dim'n size + INC HL + LD D,(HL) ; Get MSB of dim'n size + INC HL + EX (SP),HL ; Save address - Get index + PUSH AF ; Save number of dim'ns + CALL CPDEHL ; Dimension too large? + JP NC,BSERR ; Yes - ?BS Error + PUSH HL ; Save index + CALL MLDEBC ; Multiply previous by size + POP DE ; Index supplied to DE + ADD HL,DE ; Add index to pointer + POP AF ; Number of dimensions + DEC A ; Count them + LD B,H ; MSB of pointer + LD C,L ; LSB of pointer + JP NZ,FNDELP ; More - Keep going + ADD HL,HL ; 4 Bytes per element + ADD HL,HL + POP BC ; Start of array + ADD HL,BC ; Point to element + EX DE,HL ; Address of element to DE +ENDDIM: LD HL,(NXTOPR) ; Got code string address + RET + +FRE: LD HL,(ARREND) ; Start of free memory + EX DE,HL ; To DE + LD HL,0 ; End of free memory + ADD HL,SP ; Current stack value + LD A,(TYPE) ; Dummy argument type + OR A + JP Z,FRENUM ; Numeric - Free variable space + CALL GSTRCU ; Current string to pool + CALL GARBGE ; Garbage collection + LD HL,(STRSPC) ; Bottom of string space in use + EX DE,HL ; To DE + LD HL,(STRBOT) ; Bottom of string space +FRENUM: LD A,L ; Get LSB of end + SUB E ; Subtract LSB of beginning + LD C,A ; Save difference if C + LD A,H ; Get MSB of end + SBC A,D ; Subtract MSB of beginning +ACPASS: LD B,C ; Return integer AC +ABPASS: LD D,B ; Return integer AB + LD E,0 + LD HL,TYPE ; Point to type + LD (HL),E ; Set type to numeric + LD B,80H+16 ; 16 bit integer + JP RETINT ; Return the integr + +POS: LD A,(CURPOS) ; Get cursor position +PASSA: LD B,A ; Put A into AB + XOR A ; Zero A + JP ABPASS ; Return integer AB + +DEF: CALL CHEKFN ; Get "FN" and name + CALL IDTEST ; Test for illegal direct + LD BC,DATA ; To get next statement + PUSH BC ; Save address for RETurn + PUSH DE ; Save address of function ptr + CALL CHKSYN ; Make sure "(" follows + .BYTE "(" + CALL GETVAR ; Get argument variable name + PUSH HL ; Save code string address + EX DE,HL ; Argument address to HL + DEC HL + LD D,(HL) ; Get first byte of arg name + DEC HL + LD E,(HL) ; Get second byte of arg name + POP HL ; Restore code string address + CALL TSTNUM ; Make sure numeric argument + CALL CHKSYN ; Make sure ")" follows + .BYTE ")" + CALL CHKSYN ; Make sure "=" follows + .BYTE ZEQUAL ; "=" token + LD B,H ; Code string address to BC + LD C,L + EX (SP),HL ; Save code str , Get FN ptr + LD (HL),C ; Save LSB of FN code string + INC HL + LD (HL),B ; Save MSB of FN code string + JP SVSTAD ; Save address and do function + +DOFN: CALL CHEKFN ; Make sure FN follows + PUSH DE ; Save function pointer address + CALL EVLPAR ; Evaluate expression in "()" + CALL TSTNUM ; Make sure numeric result + EX (SP),HL ; Save code str , Get FN ptr + LD E,(HL) ; Get LSB of FN code string + INC HL + LD D,(HL) ; Get MSB of FN code string + INC HL + LD A,D ; And function DEFined? + OR E + JP Z,UFERR ; No - ?UF Error + LD A,(HL) ; Get LSB of argument address + INC HL + LD H,(HL) ; Get MSB of argument address + LD L,A ; HL = Arg variable address + PUSH HL ; Save it + LD HL,(FNRGNM) ; Get old argument name + EX (SP),HL ; ; Save old , Get new + LD (FNRGNM),HL ; Set new argument name + LD HL,(FNARG+2) ; Get LSB,NLSB of old arg value + PUSH HL ; Save it + LD HL,(FNARG) ; Get MSB,EXP of old arg value + PUSH HL ; Save it + LD HL,FNARG ; HL = Value of argument + PUSH DE ; Save FN code string address + CALL FPTHL ; Move FPREG to argument + POP HL ; Get FN code string address + CALL GETNUM ; Get value from function + DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character + JP NZ,SNERR ; Bad character in FN - Error + POP HL ; Get MSB,EXP of old arg + LD (FNARG),HL ; Restore it + POP HL ; Get LSB,NLSB of old arg + LD (FNARG+2),HL ; Restore it + POP HL ; Get name of old arg + LD (FNRGNM),HL ; Restore it + POP HL ; Restore code string address + RET + +IDTEST: PUSH HL ; Save code string address + LD HL,(LINEAT) ; Get current line number + INC HL ; -1 means direct statement + LD A,H + OR L + POP HL ; Restore code string address + RET NZ ; Return if in program + LD E,ID ; ?ID Error + JP ERROR + +CHEKFN: CALL CHKSYN ; Make sure FN follows + .BYTE ZFN ; "FN" token + LD A,80H + LD (FORFLG),A ; Flag FN name to find + OR (HL) ; FN name has bit 7 set + LD B,A ; in first byte of name + CALL GTFNAM ; Get FN name + JP TSTNUM ; Make sure numeric function + +STR: CALL TSTNUM ; Make sure it's a number + CALL NUMASC ; Turn number into text +STR1: CALL CRTST ; Create string entry for it + CALL GSTRCU ; Current string to pool + LD BC,TOPOOL ; Save in string pool + PUSH BC ; Save address on stack + +SAVSTR: LD A,(HL) ; Get string length + INC HL + INC HL + PUSH HL ; Save pointer to string + CALL TESTR ; See if enough string space + POP HL ; Restore pointer to string + LD C,(HL) ; Get LSB of address + INC HL + LD B,(HL) ; Get MSB of address + CALL CRTMST ; Create string entry + PUSH HL ; Save pointer to MSB of addr + LD L,A ; Length of string + CALL TOSTRA ; Move to string area + POP DE ; Restore pointer to MSB + RET + +MKTMST: CALL TESTR ; See if enough string space +CRTMST: LD HL,TMPSTR ; Temporary string + PUSH HL ; Save it + LD (HL),A ; Save length of string + INC HL +SVSTAD: INC HL + LD (HL),E ; Save LSB of address + INC HL + LD (HL),D ; Save MSB of address + POP HL ; Restore pointer + RET + +CRTST: DEC HL ; DEC - INCed after +QTSTR: LD B,'"' ; Terminating quote + LD D,B ; Quote to D +DTSTR: PUSH HL ; Save start + LD C,-1 ; Set counter to -1 +QTSTLP: INC HL ; Move on + LD A,(HL) ; Get byte + INC C ; Count bytes + OR A ; End of line? + JP Z,CRTSTE ; Yes - Create string entry + CP D ; Terminator D found? + JP Z,CRTSTE ; Yes - Create string entry + CP B ; Terminator B found? + JP NZ,QTSTLP ; No - Keep looking +CRTSTE: CP '"' ; End with '"'? + CALL Z,GETCHR ; Yes - Get next character + EX (SP),HL ; Starting quote + INC HL ; First byte of string + EX DE,HL ; To DE + LD A,C ; Get length + CALL CRTMST ; Create string entry +TSTOPL: LD DE,TMPSTR ; Temporary string + LD HL,(TMSTPT) ; Temporary string pool pointer + LD (FPREG),HL ; Save address of string ptr + LD A,1 + LD (TYPE),A ; Set type to string + CALL DETHL4 ; Move string to pool + CALL CPDEHL ; Out of string pool? + LD (TMSTPT),HL ; Save new pointer + POP HL ; Restore code string address + LD A,(HL) ; Get next code byte + RET NZ ; Return if pool OK + LD E,ST ; ?ST Error + JP ERROR ; String pool overflow + +PRNUMS: INC HL ; Skip leading space +PRS: CALL CRTST ; Create string entry for it +PRS1: CALL GSTRCU ; Current string to pool + CALL LOADFP ; Move string block to BCDE + INC E ; Length + 1 +PRSLP: DEC E ; Count characters + RET Z ; End of string + LD A,(BC) ; Get byte to output + CALL OUTC ; Output character in A + CP CR ; Return? + CALL Z,DONULL ; Yes - Do nulls + INC BC ; Next byte in string + JP PRSLP ; More characters to output + +TESTR: OR A ; Test if enough room + .BYTE 0EH ; No garbage collection done +GRBDON: POP AF ; Garbage collection done + PUSH AF ; Save status + LD HL,(STRSPC) ; Bottom of string space in use + EX DE,HL ; To DE + LD HL,(STRBOT) ; Bottom of string area + CPL ; Negate length (Top down) + LD C,A ; -Length to BC + LD B,-1 ; BC = -ve length of string + ADD HL,BC ; Add to bottom of space in use + INC HL ; Plus one for 2's complement + CALL CPDEHL ; Below string RAM area? + JP C,TESTOS ; Tidy up if not done else err + LD (STRBOT),HL ; Save new bottom of area + INC HL ; Point to first byte of string + EX DE,HL ; Address to DE +POPAF: POP AF ; Throw away status push + RET + +TESTOS: POP AF ; Garbage collect been done? + LD E,OS ; ?OS Error + JP Z,ERROR ; Yes - Not enough string apace + CP A ; Flag garbage collect done + PUSH AF ; Save status + LD BC,GRBDON ; Garbage collection done + PUSH BC ; Save for RETurn +GARBGE: LD HL,(LSTRAM) ; Get end of RAM pointer +GARBLP: LD (STRBOT),HL ; Reset string pointer + LD HL,0 + PUSH HL ; Flag no string found + LD HL,(STRSPC) ; Get bottom of string space + PUSH HL ; Save bottom of string space + LD HL,TMSTPL ; Temporary string pool +GRBLP: EX DE,HL + LD HL,(TMSTPT) ; Temporary string pool pointer + EX DE,HL + CALL CPDEHL ; Temporary string pool done? + LD BC,GRBLP ; Loop until string pool done + JP NZ,STPOOL ; No - See if in string area + LD HL,(PROGND) ; Start of simple variables +SMPVAR: EX DE,HL + LD HL,(VAREND) ; End of simple variables + EX DE,HL + CALL CPDEHL ; All simple strings done? + JP Z,ARRLP ; Yes - Do string arrays + LD A,(HL) ; Get type of variable + INC HL + INC HL + OR A ; "S" flag set if string + CALL STRADD ; See if string in string area + JP SMPVAR ; Loop until simple ones done + +GNXARY: POP BC ; Scrap address of this array +ARRLP: EX DE,HL + LD HL,(ARREND) ; End of string arrays + EX DE,HL + CALL CPDEHL ; All string arrays done? + JP Z,SCNEND ; Yes - Move string if found + CALL LOADFP ; Get array name to BCDE + LD A,E ; Get type of array + PUSH HL ; Save address of num of dim'ns + ADD HL,BC ; Start of next array + OR A ; Test type of array + JP P,GNXARY ; Numeric array - Ignore it + LD (CUROPR),HL ; Save address of next array + POP HL ; Get address of num of dim'ns + LD C,(HL) ; BC = Number of dimensions + LD B,0 + ADD HL,BC ; Two bytes per dimension size + ADD HL,BC + INC HL ; Plus one for number of dim'ns +GRBARY: EX DE,HL + LD HL,(CUROPR) ; Get address of next array + EX DE,HL + CALL CPDEHL ; Is this array finished? + JP Z,ARRLP ; Yes - Get next one + LD BC,GRBARY ; Loop until array all done +STPOOL: PUSH BC ; Save return address + OR 80H ; Flag string type +STRADD: LD A,(HL) ; Get string length + INC HL + INC HL + LD E,(HL) ; Get LSB of string address + INC HL + LD D,(HL) ; Get MSB of string address + INC HL + RET P ; Not a string - Return + OR A ; Set flags on string length + RET Z ; Null string - Return + LD B,H ; Save variable pointer + LD C,L + LD HL,(STRBOT) ; Bottom of new area + CALL CPDEHL ; String been done? + LD H,B ; Restore variable pointer + LD L,C + RET C ; String done - Ignore + POP HL ; Return address + EX (SP),HL ; Lowest available string area + CALL CPDEHL ; String within string area? + EX (SP),HL ; Lowest available string area + PUSH HL ; Re-save return address + LD H,B ; Restore variable pointer + LD L,C + RET NC ; Outside string area - Ignore + POP BC ; Get return , Throw 2 away + POP AF ; + POP AF ; + PUSH HL ; Save variable pointer + PUSH DE ; Save address of current + PUSH BC ; Put back return address + RET ; Go to it + +SCNEND: POP DE ; Addresses of strings + POP HL ; + LD A,L ; HL = 0 if no more to do + OR H + RET Z ; No more to do - Return + DEC HL + LD B,(HL) ; MSB of address of string + DEC HL + LD C,(HL) ; LSB of address of string + PUSH HL ; Save variable address + DEC HL + DEC HL + LD L,(HL) ; HL = Length of string + LD H,0 + ADD HL,BC ; Address of end of string+1 + LD D,B ; String address to DE + LD E,C + DEC HL ; Last byte in string + LD B,H ; Address to BC + LD C,L + LD HL,(STRBOT) ; Current bottom of string area + CALL MOVSTR ; Move string to new address + POP HL ; Restore variable address + LD (HL),C ; Save new LSB of address + INC HL + LD (HL),B ; Save new MSB of address + LD L,C ; Next string area+1 to HL + LD H,B + DEC HL ; Next string area address + JP GARBLP ; Look for more strings + +CONCAT: PUSH BC ; Save prec' opr & code string + PUSH HL ; + LD HL,(FPREG) ; Get first string + EX (SP),HL ; Save first string + CALL OPRND ; Get second string + EX (SP),HL ; Restore first string + CALL TSTSTR ; Make sure it's a string + LD A,(HL) ; Get length of second string + PUSH HL ; Save first string + LD HL,(FPREG) ; Get second string + PUSH HL ; Save second string + ADD A,(HL) ; Add length of second string + LD E,LS ; ?LS Error + JP C,ERROR ; String too long - Error + CALL MKTMST ; Make temporary string + POP DE ; Get second string to DE + CALL GSTRDE ; Move to string pool if needed + EX (SP),HL ; Get first string + CALL GSTRHL ; Move to string pool if needed + PUSH HL ; Save first string + LD HL,(TMPSTR+2) ; Temporary string address + EX DE,HL ; To DE + CALL SSTSA ; First string to string area + CALL SSTSA ; Second string to string area + LD HL,EVAL2 ; Return to evaluation loop + EX (SP),HL ; Save return,get code string + PUSH HL ; Save code string address + JP TSTOPL ; To temporary string to pool + +SSTSA: POP HL ; Return address + EX (SP),HL ; Get string block,save return + LD A,(HL) ; Get length of string + INC HL + INC HL + LD C,(HL) ; Get LSB of string address + INC HL + LD B,(HL) ; Get MSB of string address + LD L,A ; Length to L +TOSTRA: INC L ; INC - DECed after +TSALP: DEC L ; Count bytes moved + RET Z ; End of string - Return + LD A,(BC) ; Get source + LD (DE),A ; Save destination + INC BC ; Next source + INC DE ; Next destination + JP TSALP ; Loop until string moved + +GETSTR: CALL TSTSTR ; Make sure it's a string +GSTRCU: LD HL,(FPREG) ; Get current string +GSTRHL: EX DE,HL ; Save DE +GSTRDE: CALL BAKTMP ; Was it last tmp-str? + EX DE,HL ; Restore DE + RET NZ ; No - Return + PUSH DE ; Save string + LD D,B ; String block address to DE + LD E,C + DEC DE ; Point to length + LD C,(HL) ; Get string length + LD HL,(STRBOT) ; Current bottom of string area + CALL CPDEHL ; Last one in string area? + JP NZ,POPHL ; No - Return + LD B,A ; Clear B (A=0) + ADD HL,BC ; Remove string from str' area + LD (STRBOT),HL ; Save new bottom of str' area +POPHL: POP HL ; Restore string + RET + +BAKTMP: LD HL,(TMSTPT) ; Get temporary string pool top + DEC HL ; Back + LD B,(HL) ; Get MSB of address + DEC HL ; Back + LD C,(HL) ; Get LSB of address + DEC HL ; Back + DEC HL ; Back + CALL CPDEHL ; String last in string pool? + RET NZ ; Yes - Leave it + LD (TMSTPT),HL ; Save new string pool top + RET + +LEN: LD BC,PASSA ; To return integer A + PUSH BC ; Save address +GETLEN: CALL GETSTR ; Get string and its length + XOR A + LD D,A ; Clear D + LD (TYPE),A ; Set type to numeric + LD A,(HL) ; Get length of string + OR A ; Set status flags + RET + +ASC: LD BC,PASSA ; To return integer A + PUSH BC ; Save address +GTFLNM: CALL GETLEN ; Get length of string + JP Z,FCERR ; Null string - Error + INC HL + INC HL + LD E,(HL) ; Get LSB of address + INC HL + LD D,(HL) ; Get MSB of address + LD A,(DE) ; Get first byte of string + RET + +CHR: LD A,1 ; One character string + CALL MKTMST ; Make a temporary string + CALL MAKINT ; Make it integer A + LD HL,(TMPSTR+2) ; Get address of string + LD (HL),E ; Save character +TOPOOL: POP BC ; Clean up stack + JP TSTOPL ; Temporary string to pool + +LEFT: CALL LFRGNM ; Get number and ending ")" + XOR A ; Start at first byte in string +RIGHT1: EX (SP),HL ; Save code string,Get string + LD C,A ; Starting position in string +MID1: PUSH HL ; Save string block address + LD A,(HL) ; Get length of string + CP B ; Compare with number given + JP C,ALLFOL ; All following bytes required + LD A,B ; Get new length + .BYTE 11H ; Skip "LD C,0" +ALLFOL: LD C,0 ; First byte of string + PUSH BC ; Save position in string + CALL TESTR ; See if enough string space + POP BC ; Get position in string + POP HL ; Restore string block address + PUSH HL ; And re-save it + INC HL + INC HL + LD B,(HL) ; Get LSB of address + INC HL + LD H,(HL) ; Get MSB of address + LD L,B ; HL = address of string + LD B,0 ; BC = starting address + ADD HL,BC ; Point to that byte + LD B,H ; BC = source string + LD C,L + CALL CRTMST ; Create a string entry + LD L,A ; Length of new string + CALL TOSTRA ; Move string to string area + POP DE ; Clear stack + CALL GSTRDE ; Move to string pool if needed + JP TSTOPL ; Temporary string to pool + +RIGHT: CALL LFRGNM ; Get number and ending ")" + POP DE ; Get string length + PUSH DE ; And re-save + LD A,(DE) ; Get length + SUB B ; Move back N bytes + JP RIGHT1 ; Go and get sub-string + +MID: EX DE,HL ; Get code string address + LD A,(HL) ; Get next byte ',' or ")" + CALL MIDNUM ; Get number supplied + INC B ; Is it character zero? + DEC B + JP Z,FCERR ; Yes - Error + PUSH BC ; Save starting position + LD E,255 ; All of string + CP ')' ; Any length given? + JP Z,RSTSTR ; No - Rest of string + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + CALL GETINT ; Get integer 0-255 +RSTSTR: CALL CHKSYN ; Make sure ")" follows + .BYTE ")" + POP AF ; Restore starting position + EX (SP),HL ; Get string,8ave code string + LD BC,MID1 ; Continuation of MID$ routine + PUSH BC ; Save for return + DEC A ; Starting position-1 + CP (HL) ; Compare with length + LD B,0 ; Zero bytes length + RET NC ; Null string if start past end + LD C,A ; Save starting position-1 + LD A,(HL) ; Get length of string + SUB C ; Subtract start + CP E ; Enough string for it? + LD B,A ; Save maximum length available + RET C ; Truncate string if needed + LD B,E ; Set specified length + RET ; Go and create string + +VAL: CALL GETLEN ; Get length of string + JP Z,RESZER ; Result zero + LD E,A ; Save length + INC HL + INC HL + LD A,(HL) ; Get LSB of address + INC HL + LD H,(HL) ; Get MSB of address + LD L,A ; HL = String address + PUSH HL ; Save string address + ADD HL,DE + LD B,(HL) ; Get end of string+1 byte + LD (HL),D ; Zero it to terminate + EX (SP),HL ; Save string end,get start + PUSH BC ; Save end+1 byte + LD A,(HL) ; Get starting byte + CP '$' ; Hex number indicated? [function added] + JP NZ,VAL1 + CALL HEXTFP ; Convert Hex to FPREG + JR VAL3 +VAL1: CP '%' ; Binary number indicated? [function added] + JP NZ,VAL2 + CALL BINTFP ; Convert Bin to FPREG + JR VAL3 +VAL2: CALL ASCTFP ; Convert ASCII string to FP +VAL3: POP BC ; Restore end+1 byte + POP HL ; Restore end+1 address + LD (HL),B ; Put back original byte + RET + +LFRGNM: EX DE,HL ; Code string address to HL + CALL CHKSYN ; Make sure ")" follows + .BYTE ")" +MIDNUM: POP BC ; Get return address + POP DE ; Get number supplied + PUSH BC ; Re-save return address + LD B,E ; Number to B + RET + +INP: CALL MAKINT ; Make it integer A + LD (INPORT),A ; Set input port + CALL INPSUB ; Get input from port + JP PASSA ; Return integer A + +POUT: CALL SETIO ; Set up port number + JP OUTSUB ; Output data and return + +WAIT: CALL SETIO ; Set up port number + PUSH AF ; Save AND mask + LD E,0 ; Assume zero if none given + DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character + JP Z,NOXOR ; No XOR byte given + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + CALL GETINT ; Get integer 0-255 to XOR with +NOXOR: POP BC ; Restore AND mask +WAITLP: CALL INPSUB ; Get input + XOR E ; Flip selected bits + AND B ; Result non-zero? + JP Z,WAITLP ; No = keep waiting + RET + +SETIO: CALL GETINT ; Get integer 0-255 + LD (INPORT),A ; Set input port + LD (OTPORT),A ; Set output port + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + JP GETINT ; Get integer 0-255 and return + +FNDNUM: CALL GETCHR ; Get next character +GETINT: CALL GETNUM ; Get a number from 0 to 255 +MAKINT: CALL DEPINT ; Make sure value 0 - 255 + LD A,D ; Get MSB of number + OR A ; Zero? + JP NZ,FCERR ; No - Error + DEC HL ; DEC 'cos GETCHR INCs + CALL GETCHR ; Get next character + LD A,E ; Get number to A + RET + +PEEK: CALL DEINT ; Get memory address + LD A,(DE) ; Get byte in memory + JP PASSA ; Return integer A + +POKE: CALL GETNUM ; Get memory address + CALL DEINT ; Get integer -32768 to 3276 + PUSH DE ; Save memory address + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + CALL GETINT ; Get integer 0-255 + POP DE ; Restore memory address + LD (DE),A ; Load it into memory + RET + +ROUND: LD HL,HALF ; Add 0.5 to FPREG +ADDPHL: CALL LOADFP ; Load FP at (HL) to BCDE + JP FPADD ; Add BCDE to FPREG + +SUBPHL: CALL LOADFP ; FPREG = -FPREG + number at HL + .BYTE 21H ; Skip "POP BC" and "POP DE" +PSUB: POP BC ; Get FP number from stack + POP DE +SUBCDE: CALL INVSGN ; Negate FPREG +FPADD: LD A,B ; Get FP exponent + OR A ; Is number zero? + RET Z ; Yes - Nothing to add + LD A,(FPEXP) ; Get FPREG exponent + OR A ; Is this number zero? + JP Z,FPBCDE ; Yes - Move BCDE to FPREG + SUB B ; BCDE number larger? + JP NC,NOSWAP ; No - Don't swap them + CPL ; Two's complement + INC A ; FP exponent + EX DE,HL + CALL STAKFP ; Put FPREG on stack + EX DE,HL + CALL FPBCDE ; Move BCDE to FPREG + POP BC ; Restore number from stack + POP DE +NOSWAP: CP 24+1 ; Second number insignificant? + RET NC ; Yes - First number is result + PUSH AF ; Save number of bits to scale + CALL SIGNS ; Set MSBs & sign of result + LD H,A ; Save sign of result + POP AF ; Restore scaling factor + CALL SCALE ; Scale BCDE to same exponent + OR H ; Result to be positive? + LD HL,FPREG ; Point to FPREG + JP P,MINCDE ; No - Subtract FPREG from CDE + CALL PLUCDE ; Add FPREG to CDE + JP NC,RONDUP ; No overflow - Round it up + INC HL ; Point to exponent + INC (HL) ; Increment it + JP Z,OVERR ; Number overflowed - Error + LD L,1 ; 1 bit to shift right + CALL SHRT1 ; Shift result right + JP RONDUP ; Round it up + +MINCDE: XOR A ; Clear A and carry + SUB B ; Negate exponent + LD B,A ; Re-save exponent + LD A,(HL) ; Get LSB of FPREG + SBC A, E ; Subtract LSB of BCDE + LD E,A ; Save LSB of BCDE + INC HL + LD A,(HL) ; Get NMSB of FPREG + SBC A,D ; Subtract NMSB of BCDE + LD D,A ; Save NMSB of BCDE + INC HL + LD A,(HL) ; Get MSB of FPREG + SBC A,C ; Subtract MSB of BCDE + LD C,A ; Save MSB of BCDE +CONPOS: CALL C,COMPL ; Overflow - Make it positive + +BNORM: LD L,B ; L = Exponent + LD H,E ; H = LSB + XOR A +BNRMLP: LD B,A ; Save bit count + LD A,C ; Get MSB + OR A ; Is it zero? + JP NZ,PNORM ; No - Do it bit at a time + LD C,D ; MSB = NMSB + LD D,H ; NMSB= LSB + LD H,L ; LSB = VLSB + LD L,A ; VLSB= 0 + LD A,B ; Get exponent + SUB 8 ; Count 8 bits + CP -24-8 ; Was number zero? + JP NZ,BNRMLP ; No - Keep normalising +RESZER: XOR A ; Result is zero +SAVEXP: LD (FPEXP),A ; Save result as zero + RET + +NORMAL: DEC B ; Count bits + ADD HL,HL ; Shift HL left + LD A,D ; Get NMSB + RLA ; Shift left with last bit + LD D,A ; Save NMSB + LD A,C ; Get MSB + ADC A,A ; Shift left with last bit + LD C,A ; Save MSB +PNORM: JP P,NORMAL ; Not done - Keep going + LD A,B ; Number of bits shifted + LD E,H ; Save HL in EB + LD B,L + OR A ; Any shifting done? + JP Z,RONDUP ; No - Round it up + LD HL,FPEXP ; Point to exponent + ADD A,(HL) ; Add shifted bits + LD (HL),A ; Re-save exponent + JP NC,RESZER ; Underflow - Result is zero + RET Z ; Result is zero +RONDUP: LD A,B ; Get VLSB of number +RONDB: LD HL,FPEXP ; Point to exponent + OR A ; Any rounding? + CALL M,FPROND ; Yes - Round number up + LD B,(HL) ; B = Exponent + INC HL + LD A,(HL) ; Get sign of result + AND 10000000B ; Only bit 7 needed + XOR C ; Set correct sign + LD C,A ; Save correct sign in number + JP FPBCDE ; Move BCDE to FPREG + +FPROND: INC E ; Round LSB + RET NZ ; Return if ok + INC D ; Round NMSB + RET NZ ; Return if ok + INC C ; Round MSB + RET NZ ; Return if ok + LD C,80H ; Set normal value + INC (HL) ; Increment exponent + RET NZ ; Return if ok + JP OVERR ; Overflow error + +PLUCDE: LD A,(HL) ; Get LSB of FPREG + ADD A,E ; Add LSB of BCDE + LD E,A ; Save LSB of BCDE + INC HL + LD A,(HL) ; Get NMSB of FPREG + ADC A,D ; Add NMSB of BCDE + LD D,A ; Save NMSB of BCDE + INC HL + LD A,(HL) ; Get MSB of FPREG + ADC A,C ; Add MSB of BCDE + LD C,A ; Save MSB of BCDE + RET + +COMPL: LD HL,SGNRES ; Sign of result + LD A,(HL) ; Get sign of result + CPL ; Negate it + LD (HL),A ; Put it back + XOR A + LD L,A ; Set L to zero + SUB B ; Negate exponent,set carry + LD B,A ; Re-save exponent + LD A,L ; Load zero + SBC A,E ; Negate LSB + LD E,A ; Re-save LSB + LD A,L ; Load zero + SBC A,D ; Negate NMSB + LD D,A ; Re-save NMSB + LD A,L ; Load zero + SBC A,C ; Negate MSB + LD C,A ; Re-save MSB + RET + +SCALE: LD B,0 ; Clear underflow +SCALLP: SUB 8 ; 8 bits (a whole byte)? + JP C,SHRITE ; No - Shift right A bits + LD B,E ; <- Shift + LD E,D ; <- right + LD D,C ; <- eight + LD C,0 ; <- bits + JP SCALLP ; More bits to shift + +SHRITE: ADD A,8+1 ; Adjust count + LD L,A ; Save bits to shift +SHRLP: XOR A ; Flag for all done + DEC L ; All shifting done? + RET Z ; Yes - Return + LD A,C ; Get MSB +SHRT1: RRA ; Shift it right + LD C,A ; Re-save + LD A,D ; Get NMSB + RRA ; Shift right with last bit + LD D,A ; Re-save it + LD A,E ; Get LSB + RRA ; Shift right with last bit + LD E,A ; Re-save it + LD A,B ; Get underflow + RRA ; Shift right with last bit + LD B,A ; Re-save underflow + JP SHRLP ; More bits to do + +UNITY: .BYTE 000H,000H,000H,081H ; 1.00000 + +LOGTAB: .BYTE 3 ; Table used by LOG + .BYTE 0AAH,056H,019H,080H ; 0.59898 + .BYTE 0F1H,022H,076H,080H ; 0.96147 + .BYTE 045H,0AAH,038H,082H ; 2.88539 + +LOG: CALL TSTSGN ; Test sign of value + OR A + JP PE,FCERR ; ?FC Error if <= zero + LD HL,FPEXP ; Point to exponent + LD A,(HL) ; Get exponent + LD BC,8035H ; BCDE = SQR(1/2) + LD DE,04F3H + SUB B ; Scale value to be < 1 + PUSH AF ; Save scale factor + LD (HL),B ; Save new exponent + PUSH DE ; Save SQR(1/2) + PUSH BC + CALL FPADD ; Add SQR(1/2) to value + POP BC ; Restore SQR(1/2) + POP DE + INC B ; Make it SQR(2) + CALL DVBCDE ; Divide by SQR(2) + LD HL,UNITY ; Point to 1. + CALL SUBPHL ; Subtract FPREG from 1 + LD HL,LOGTAB ; Coefficient table + CALL SUMSER ; Evaluate sum of series + LD BC,8080H ; BCDE = -0.5 + LD DE,0000H + CALL FPADD ; Subtract 0.5 from FPREG + POP AF ; Restore scale factor + CALL RSCALE ; Re-scale number +MULLN2: LD BC,8031H ; BCDE = Ln(2) + LD DE,7218H + .BYTE 21H ; Skip "POP BC" and "POP DE" + +MULT: POP BC ; Get number from stack + POP DE +FPMULT: CALL TSTSGN ; Test sign of FPREG + RET Z ; Return zero if zero + LD L,0 ; Flag add exponents + CALL ADDEXP ; Add exponents + LD A,C ; Get MSB of multiplier + LD (MULVAL),A ; Save MSB of multiplier + EX DE,HL + LD (MULVAL+1),HL ; Save rest of multiplier + LD BC,0 ; Partial product (BCDE) = zero + LD D,B + LD E,B + LD HL,BNORM ; Address of normalise + PUSH HL ; Save for return + LD HL,MULT8 ; Address of 8 bit multiply + PUSH HL ; Save for NMSB,MSB + PUSH HL ; + LD HL,FPREG ; Point to number +MULT8: LD A,(HL) ; Get LSB of number + INC HL ; Point to NMSB + OR A ; Test LSB + JP Z,BYTSFT ; Zero - shift to next byte + PUSH HL ; Save address of number + LD L,8 ; 8 bits to multiply by +MUL8LP: RRA ; Shift LSB right + LD H,A ; Save LSB + LD A,C ; Get MSB + JP NC,NOMADD ; Bit was zero - Don't add + PUSH HL ; Save LSB and count + LD HL,(MULVAL+1) ; Get LSB and NMSB + ADD HL,DE ; Add NMSB and LSB + EX DE,HL ; Leave sum in DE + POP HL ; Restore MSB and count + LD A,(MULVAL) ; Get MSB of multiplier + ADC A,C ; Add MSB +NOMADD: RRA ; Shift MSB right + LD C,A ; Re-save MSB + LD A,D ; Get NMSB + RRA ; Shift NMSB right + LD D,A ; Re-save NMSB + LD A,E ; Get LSB + RRA ; Shift LSB right + LD E,A ; Re-save LSB + LD A,B ; Get VLSB + RRA ; Shift VLSB right + LD B,A ; Re-save VLSB + DEC L ; Count bits multiplied + LD A,H ; Get LSB of multiplier + JP NZ,MUL8LP ; More - Do it +POPHRT: POP HL ; Restore address of number + RET + +BYTSFT: LD B,E ; Shift partial product left + LD E,D + LD D,C + LD C,A + RET + +DIV10: CALL STAKFP ; Save FPREG on stack + LD BC,8420H ; BCDE = 10. + LD DE,0000H + CALL FPBCDE ; Move 10 to FPREG + +DIV: POP BC ; Get number from stack + POP DE +DVBCDE: CALL TSTSGN ; Test sign of FPREG + JP Z,DZERR ; Error if division by zero + LD L,-1 ; Flag subtract exponents + CALL ADDEXP ; Subtract exponents + INC (HL) ; Add 2 to exponent to adjust + INC (HL) + DEC HL ; Point to MSB + LD A,(HL) ; Get MSB of dividend + LD (DIV3),A ; Save for subtraction + DEC HL + LD A,(HL) ; Get NMSB of dividend + LD (DIV2),A ; Save for subtraction + DEC HL + LD A,(HL) ; Get MSB of dividend + LD (DIV1),A ; Save for subtraction + LD B,C ; Get MSB + EX DE,HL ; NMSB,LSB to HL + XOR A + LD C,A ; Clear MSB of quotient + LD D,A ; Clear NMSB of quotient + LD E,A ; Clear LSB of quotient + LD (DIV4),A ; Clear overflow count +DIVLP: PUSH HL ; Save divisor + PUSH BC + LD A,L ; Get LSB of number + CALL DIVSUP ; Subt' divisor from dividend + SBC A,0 ; Count for overflows + CCF + JP NC,RESDIV ; Restore divisor if borrow + LD (DIV4),A ; Re-save overflow count + POP AF ; Scrap divisor + POP AF + SCF ; Set carry to + .BYTE 0D2H ; Skip "POP BC" and "POP HL" + +RESDIV: POP BC ; Restore divisor + POP HL + LD A,C ; Get MSB of quotient + INC A + DEC A + RRA ; Bit 0 to bit 7 + JP M,RONDB ; Done - Normalise result + RLA ; Restore carry + LD A,E ; Get LSB of quotient + RLA ; Double it + LD E,A ; Put it back + LD A,D ; Get NMSB of quotient + RLA ; Double it + LD D,A ; Put it back + LD A,C ; Get MSB of quotient + RLA ; Double it + LD C,A ; Put it back + ADD HL,HL ; Double NMSB,LSB of divisor + LD A,B ; Get MSB of divisor + RLA ; Double it + LD B,A ; Put it back + LD A,(DIV4) ; Get VLSB of quotient + RLA ; Double it + LD (DIV4),A ; Put it back + LD A,C ; Get MSB of quotient + OR D ; Merge NMSB + OR E ; Merge LSB + JP NZ,DIVLP ; Not done - Keep dividing + PUSH HL ; Save divisor + LD HL,FPEXP ; Point to exponent + DEC (HL) ; Divide by 2 + POP HL ; Restore divisor + JP NZ,DIVLP ; Ok - Keep going + JP OVERR ; Overflow error + +ADDEXP: LD A,B ; Get exponent of dividend + OR A ; Test it + JP Z,OVTST3 ; Zero - Result zero + LD A,L ; Get add/subtract flag + LD HL,FPEXP ; Point to exponent + XOR (HL) ; Add or subtract it + ADD A,B ; Add the other exponent + LD B,A ; Save new exponent + RRA ; Test exponent for overflow + XOR B + LD A,B ; Get exponent + JP P,OVTST2 ; Positive - Test for overflow + ADD A,80H ; Add excess 128 + LD (HL),A ; Save new exponent + JP Z,POPHRT ; Zero - Result zero + CALL SIGNS ; Set MSBs and sign of result + LD (HL),A ; Save new exponent + DEC HL ; Point to MSB + RET + +OVTST1: CALL TSTSGN ; Test sign of FPREG + CPL ; Invert sign + POP HL ; Clean up stack +OVTST2: OR A ; Test if new exponent zero +OVTST3: POP HL ; Clear off return address + JP P,RESZER ; Result zero + JP OVERR ; Overflow error + +MLSP10: CALL BCDEFP ; Move FPREG to BCDE + LD A,B ; Get exponent + OR A ; Is it zero? + RET Z ; Yes - Result is zero + ADD A,2 ; Multiply by 4 + JP C,OVERR ; Overflow - ?OV Error + LD B,A ; Re-save exponent + CALL FPADD ; Add BCDE to FPREG (Times 5) + LD HL,FPEXP ; Point to exponent + INC (HL) ; Double number (Times 10) + RET NZ ; Ok - Return + JP OVERR ; Overflow error + +TSTSGN: LD A,(FPEXP) ; Get sign of FPREG + OR A + RET Z ; RETurn if number is zero + LD A,(FPREG+2) ; Get MSB of FPREG + .BYTE 0FEH ; Test sign +RETREL: CPL ; Invert sign + RLA ; Sign bit to carry +FLGDIF: SBC A,A ; Carry to all bits of A + RET NZ ; Return -1 if negative + INC A ; Bump to +1 + RET ; Positive - Return +1 + +SGN: CALL TSTSGN ; Test sign of FPREG +FLGREL: LD B,80H+8 ; 8 bit integer in exponent + LD DE,0 ; Zero NMSB and LSB +RETINT: LD HL,FPEXP ; Point to exponent + LD C,A ; CDE = MSB,NMSB and LSB + LD (HL),B ; Save exponent + LD B,0 ; CDE = integer to normalise + INC HL ; Point to sign of result + LD (HL),80H ; Set sign of result + RLA ; Carry = sign of integer + JP CONPOS ; Set sign of result + +ABS: CALL TSTSGN ; Test sign of FPREG + RET P ; Return if positive +INVSGN: LD HL,FPREG+2 ; Point to MSB + LD A,(HL) ; Get sign of mantissa + XOR 80H ; Invert sign of mantissa + LD (HL),A ; Re-save sign of mantissa + RET + +STAKFP: EX DE,HL ; Save code string address + LD HL,(FPREG) ; LSB,NLSB of FPREG + EX (SP),HL ; Stack them,get return + PUSH HL ; Re-save return + LD HL,(FPREG+2) ; MSB and exponent of FPREG + EX (SP),HL ; Stack them,get return + PUSH HL ; Re-save return + EX DE,HL ; Restore code string address + RET + +PHLTFP: CALL LOADFP ; Number at HL to BCDE +FPBCDE: EX DE,HL ; Save code string address + LD (FPREG),HL ; Save LSB,NLSB of number + LD H,B ; Exponent of number + LD L,C ; MSB of number + LD (FPREG+2),HL ; Save MSB and exponent + EX DE,HL ; Restore code string address + RET + +BCDEFP: LD HL,FPREG ; Point to FPREG +LOADFP: LD E,(HL) ; Get LSB of number + INC HL + LD D,(HL) ; Get NMSB of number + INC HL + LD C,(HL) ; Get MSB of number + INC HL + LD B,(HL) ; Get exponent of number +INCHL: INC HL ; Used for conditional "INC HL" + RET + +FPTHL: LD DE,FPREG ; Point to FPREG +DETHL4: LD B,4 ; 4 bytes to move +DETHLB: LD A,(DE) ; Get source + LD (HL),A ; Save destination + INC DE ; Next source + INC HL ; Next destination + DEC B ; Count bytes + JP NZ,DETHLB ; Loop if more + RET + +SIGNS: LD HL,FPREG+2 ; Point to MSB of FPREG + LD A,(HL) ; Get MSB + RLCA ; Old sign to carry + SCF ; Set MSBit + RRA ; Set MSBit of MSB + LD (HL),A ; Save new MSB + CCF ; Complement sign + RRA ; Old sign to carry + INC HL + INC HL + LD (HL),A ; Set sign of result + LD A,C ; Get MSB + RLCA ; Old sign to carry + SCF ; Set MSBit + RRA ; Set MSBit of MSB + LD C,A ; Save MSB + RRA + XOR (HL) ; New sign of result + RET + +CMPNUM: LD A,B ; Get exponent of number + OR A + JP Z,TSTSGN ; Zero - Test sign of FPREG + LD HL,RETREL ; Return relation routine + PUSH HL ; Save for return + CALL TSTSGN ; Test sign of FPREG + LD A,C ; Get MSB of number + RET Z ; FPREG zero - Number's MSB + LD HL,FPREG+2 ; MSB of FPREG + XOR (HL) ; Combine signs + LD A,C ; Get MSB of number + RET M ; Exit if signs different + CALL CMPFP ; Compare FP numbers + RRA ; Get carry to sign + XOR C ; Combine with MSB of number + RET + +CMPFP: INC HL ; Point to exponent + LD A,B ; Get exponent + CP (HL) ; Compare exponents + RET NZ ; Different + DEC HL ; Point to MBS + LD A,C ; Get MSB + CP (HL) ; Compare MSBs + RET NZ ; Different + DEC HL ; Point to NMSB + LD A,D ; Get NMSB + CP (HL) ; Compare NMSBs + RET NZ ; Different + DEC HL ; Point to LSB + LD A,E ; Get LSB + SUB (HL) ; Compare LSBs + RET NZ ; Different + POP HL ; Drop RETurn + POP HL ; Drop another RETurn + RET + +FPINT: LD B,A ; <- Move + LD C,A ; <- exponent + LD D,A ; <- to all + LD E,A ; <- bits + OR A ; Test exponent + RET Z ; Zero - Return zero + PUSH HL ; Save pointer to number + CALL BCDEFP ; Move FPREG to BCDE + CALL SIGNS ; Set MSBs & sign of result + XOR (HL) ; Combine with sign of FPREG + LD H,A ; Save combined signs + CALL M,DCBCDE ; Negative - Decrement BCDE + LD A,80H+24 ; 24 bits + SUB B ; Bits to shift + CALL SCALE ; Shift BCDE + LD A,H ; Get combined sign + RLA ; Sign to carry + CALL C,FPROND ; Negative - Round number up + LD B,0 ; Zero exponent + CALL C,COMPL ; If negative make positive + POP HL ; Restore pointer to number + RET + +DCBCDE: DEC DE ; Decrement BCDE + LD A,D ; Test LSBs + AND E + INC A + RET NZ ; Exit if LSBs not FFFF + DEC BC ; Decrement MSBs + RET + +INT: LD HL,FPEXP ; Point to exponent + LD A,(HL) ; Get exponent + CP 80H+24 ; Integer accuracy only? + LD A,(FPREG) ; Get LSB + RET NC ; Yes - Already integer + LD A,(HL) ; Get exponent + CALL FPINT ; F.P to integer + LD (HL),80H+24 ; Save 24 bit integer + LD A,E ; Get LSB of number + PUSH AF ; Save LSB + LD A,C ; Get MSB of number + RLA ; Sign to carry + CALL CONPOS ; Set sign of result + POP AF ; Restore LSB of number + RET + +MLDEBC: LD HL,0 ; Clear partial product + LD A,B ; Test multiplier + OR C + RET Z ; Return zero if zero + LD A,16 ; 16 bits +MLDBLP: ADD HL,HL ; Shift P.P left + JP C,BSERR ; ?BS Error if overflow + EX DE,HL + ADD HL,HL ; Shift multiplier left + EX DE,HL + JP NC,NOMLAD ; Bit was zero - No add + ADD HL,BC ; Add multiplicand + JP C,BSERR ; ?BS Error if overflow +NOMLAD: DEC A ; Count bits + JP NZ,MLDBLP ; More + RET + +ASCTFP: CP '-' ; Negative? + PUSH AF ; Save it and flags + JP Z,CNVNUM ; Yes - Convert number + CP '+' ; Positive? + JP Z,CNVNUM ; Yes - Convert number + DEC HL ; DEC 'cos GETCHR INCs +CNVNUM: CALL RESZER ; Set result to zero + LD B,A ; Digits after point counter + LD D,A ; Sign of exponent + LD E,A ; Exponent of ten + CPL + LD C,A ; Before or after point flag +MANLP: CALL GETCHR ; Get next character + JP C,ADDIG ; Digit - Add to number + CP '.' + JP Z,DPOINT ; '.' - Flag point + CP 'E' + JP NZ,CONEXP ; Not 'E' - Scale number + CALL GETCHR ; Get next character + CALL SGNEXP ; Get sign of exponent +EXPLP: CALL GETCHR ; Get next character + JP C,EDIGIT ; Digit - Add to exponent + INC D ; Is sign negative? + JP NZ,CONEXP ; No - Scale number + XOR A + SUB E ; Negate exponent + LD E,A ; And re-save it + INC C ; Flag end of number +DPOINT: INC C ; Flag point passed + JP Z,MANLP ; Zero - Get another digit +CONEXP: PUSH HL ; Save code string address + LD A,E ; Get exponent + SUB B ; Subtract digits after point +SCALMI: CALL P,SCALPL ; Positive - Multiply number + JP P,ENDCON ; Positive - All done + PUSH AF ; Save number of times to /10 + CALL DIV10 ; Divide by 10 + POP AF ; Restore count + INC A ; Count divides + +ENDCON: JP NZ,SCALMI ; More to do + POP DE ; Restore code string address + POP AF ; Restore sign of number + CALL Z,INVSGN ; Negative - Negate number + EX DE,HL ; Code string address to HL + RET + +SCALPL: RET Z ; Exit if no scaling needed +MULTEN: PUSH AF ; Save count + CALL MLSP10 ; Multiply number by 10 + POP AF ; Restore count + DEC A ; Count multiplies + RET + +ADDIG: PUSH DE ; Save sign of exponent + LD D,A ; Save digit + LD A,B ; Get digits after point + ADC A,C ; Add one if after point + LD B,A ; Re-save counter + PUSH BC ; Save point flags + PUSH HL ; Save code string address + PUSH DE ; Save digit + CALL MLSP10 ; Multiply number by 10 + POP AF ; Restore digit + SUB '0' ; Make it absolute + CALL RSCALE ; Re-scale number + POP HL ; Restore code string address + POP BC ; Restore point flags + POP DE ; Restore sign of exponent + JP MANLP ; Get another digit + +RSCALE: CALL STAKFP ; Put number on stack + CALL FLGREL ; Digit to add to FPREG +PADD: POP BC ; Restore number + POP DE + JP FPADD ; Add BCDE to FPREG and return + +EDIGIT: LD A,E ; Get digit + RLCA ; Times 2 + RLCA ; Times 4 + ADD A,E ; Times 5 + RLCA ; Times 10 + ADD A,(HL) ; Add next digit + SUB '0' ; Make it absolute + LD E,A ; Save new digit + JP EXPLP ; Look for another digit + +LINEIN: PUSH HL ; Save code string address + LD HL,INMSG ; Output " in " + CALL PRS ; Output string at HL + POP HL ; Restore code string address +PRNTHL: EX DE,HL ; Code string address to DE + XOR A + LD B,80H+24 ; 24 bits + CALL RETINT ; Return the integer + LD HL,PRNUMS ; Print number string + PUSH HL ; Save for return +NUMASC: LD HL,PBUFF ; Convert number to ASCII + PUSH HL ; Save for return + CALL TSTSGN ; Test sign of FPREG + LD (HL),' ' ; Space at start + JP P,SPCFST ; Positive - Space to start + LD (HL),'-' ; '-' sign at start +SPCFST: INC HL ; First byte of number + LD (HL),'0' ; '0' if zero + JP Z,JSTZER ; Return '0' if zero + PUSH HL ; Save buffer address + CALL M,INVSGN ; Negate FPREG if negative + XOR A ; Zero A + PUSH AF ; Save it + CALL RNGTST ; Test number is in range +SIXDIG: LD BC,9143H ; BCDE - 99999.9 + LD DE,4FF8H + CALL CMPNUM ; Compare numbers + OR A + JP PO,INRNG ; > 99999.9 - Sort it out + POP AF ; Restore count + CALL MULTEN ; Multiply by ten + PUSH AF ; Re-save count + JP SIXDIG ; Test it again + +GTSIXD: CALL DIV10 ; Divide by 10 + POP AF ; Get count + INC A ; Count divides + PUSH AF ; Re-save count + CALL RNGTST ; Test number is in range +INRNG: CALL ROUND ; Add 0.5 to FPREG + INC A + CALL FPINT ; F.P to integer + CALL FPBCDE ; Move BCDE to FPREG + LD BC,0306H ; 1E+06 to 1E-03 range + POP AF ; Restore count + ADD A,C ; 6 digits before point + INC A ; Add one + JP M,MAKNUM ; Do it in 'E' form if < 1E-02 + CP 6+1+1 ; More than 999999 ? + JP NC,MAKNUM ; Yes - Do it in 'E' form + INC A ; Adjust for exponent + LD B,A ; Exponent of number + LD A,2 ; Make it zero after + +MAKNUM: DEC A ; Adjust for digits to do + DEC A + POP HL ; Restore buffer address + PUSH AF ; Save count + LD DE,POWERS ; Powers of ten + DEC B ; Count digits before point + JP NZ,DIGTXT ; Not zero - Do number + LD (HL),'.' ; Save point + INC HL ; Move on + LD (HL),'0' ; Save zero + INC HL ; Move on +DIGTXT: DEC B ; Count digits before point + LD (HL),'.' ; Save point in case + CALL Z,INCHL ; Last digit - move on + PUSH BC ; Save digits before point + PUSH HL ; Save buffer address + PUSH DE ; Save powers of ten + CALL BCDEFP ; Move FPREG to BCDE + POP HL ; Powers of ten table + LD B, '0'-1 ; ASCII '0' - 1 +TRYAGN: INC B ; Count subtractions + LD A,E ; Get LSB + SUB (HL) ; Subtract LSB + LD E,A ; Save LSB + INC HL + LD A,D ; Get NMSB + SBC A,(HL) ; Subtract NMSB + LD D,A ; Save NMSB + INC HL + LD A,C ; Get MSB + SBC A,(HL) ; Subtract MSB + LD C,A ; Save MSB + DEC HL ; Point back to start + DEC HL + JP NC,TRYAGN ; No overflow - Try again + CALL PLUCDE ; Restore number + INC HL ; Start of next number + CALL FPBCDE ; Move BCDE to FPREG + EX DE,HL ; Save point in table + POP HL ; Restore buffer address + LD (HL),B ; Save digit in buffer + INC HL ; And move on + POP BC ; Restore digit count + DEC C ; Count digits + JP NZ,DIGTXT ; More - Do them + DEC B ; Any decimal part? + JP Z,DOEBIT ; No - Do 'E' bit +SUPTLZ: DEC HL ; Move back through buffer + LD A,(HL) ; Get character + CP '0' ; '0' character? + JP Z,SUPTLZ ; Yes - Look back for more + CP '.' ; A decimal point? + CALL NZ,INCHL ; Move back over digit + +DOEBIT: POP AF ; Get 'E' flag + JP Z,NOENED ; No 'E' needed - End buffer + LD (HL),'E' ; Put 'E' in buffer + INC HL ; And move on + LD (HL),'+' ; Put '+' in buffer + JP P,OUTEXP ; Positive - Output exponent + LD (HL),'-' ; Put '-' in buffer + CPL ; Negate exponent + INC A +OUTEXP: LD B,'0'-1 ; ASCII '0' - 1 +EXPTEN: INC B ; Count subtractions + SUB 10 ; Tens digit + JP NC,EXPTEN ; More to do + ADD A,'0'+10 ; Restore and make ASCII + INC HL ; Move on + LD (HL),B ; Save MSB of exponent +JSTZER: INC HL ; + LD (HL),A ; Save LSB of exponent + INC HL +NOENED: LD (HL),C ; Mark end of buffer + POP HL ; Restore code string address + RET + +RNGTST: LD BC,9474H ; BCDE = 999999. + LD DE,23F7H + CALL CMPNUM ; Compare numbers + OR A + POP HL ; Return address to HL + JP PO,GTSIXD ; Too big - Divide by ten + JP (HL) ; Otherwise return to caller + +HALF: .BYTE 00H,00H,00H,80H ; 0.5 + +POWERS: .BYTE 0A0H,086H,001H ; 100000 + .BYTE 010H,027H,000H ; 10000 + .BYTE 0E8H,003H,000H ; 1000 + .BYTE 064H,000H,000H ; 100 + .BYTE 00AH,000H,000H ; 10 + .BYTE 001H,000H,000H ; 1 + +NEGAFT: LD HL,INVSGN ; Negate result + EX (SP),HL ; To be done after caller + JP (HL) ; Return to caller + +SQR: CALL STAKFP ; Put value on stack + LD HL,HALF ; Set power to 1/2 + CALL PHLTFP ; Move 1/2 to FPREG + +POWER: POP BC ; Get base + POP DE + CALL TSTSGN ; Test sign of power + LD A,B ; Get exponent of base + JP Z,EXP ; Make result 1 if zero + JP P,POWER1 ; Positive base - Ok + OR A ; Zero to negative power? + JP Z,DZERR ; Yes - ?/0 Error +POWER1: OR A ; Base zero? + JP Z,SAVEXP ; Yes - Return zero + PUSH DE ; Save base + PUSH BC + LD A,C ; Get MSB of base + OR 01111111B ; Get sign status + CALL BCDEFP ; Move power to BCDE + JP P,POWER2 ; Positive base - Ok + PUSH DE ; Save power + PUSH BC + CALL INT ; Get integer of power + POP BC ; Restore power + POP DE + PUSH AF ; MSB of base + CALL CMPNUM ; Power an integer? + POP HL ; Restore MSB of base + LD A,H ; but don't affect flags + RRA ; Exponent odd or even? +POWER2: POP HL ; Restore MSB and exponent + LD (FPREG+2),HL ; Save base in FPREG + POP HL ; LSBs of base + LD (FPREG),HL ; Save in FPREG + CALL C,NEGAFT ; Odd power - Negate result + CALL Z,INVSGN ; Negative base - Negate it + PUSH DE ; Save power + PUSH BC + CALL LOG ; Get LOG of base + POP BC ; Restore power + POP DE + CALL FPMULT ; Multiply LOG by power + +EXP: CALL STAKFP ; Put value on stack + LD BC,08138H ; BCDE = 1/Ln(2) + LD DE,0AA3BH + CALL FPMULT ; Multiply value by 1/LN(2) + LD A,(FPEXP) ; Get exponent + CP 80H+8 ; Is it in range? + JP NC,OVTST1 ; No - Test for overflow + CALL INT ; Get INT of FPREG + ADD A,80H ; For excess 128 + ADD A,2 ; Exponent > 126? + JP C,OVTST1 ; Yes - Test for overflow + PUSH AF ; Save scaling factor + LD HL,UNITY ; Point to 1. + CALL ADDPHL ; Add 1 to FPREG + CALL MULLN2 ; Multiply by LN(2) + POP AF ; Restore scaling factor + POP BC ; Restore exponent + POP DE + PUSH AF ; Save scaling factor + CALL SUBCDE ; Subtract exponent from FPREG + CALL INVSGN ; Negate result + LD HL,EXPTAB ; Coefficient table + CALL SMSER1 ; Sum the series + LD DE,0 ; Zero LSBs + POP BC ; Scaling factor + LD C,D ; Zero MSB + JP FPMULT ; Scale result to correct value + +EXPTAB: .BYTE 8 ; Table used by EXP + .BYTE 040H,02EH,094H,074H ; -1/7! (-1/5040) + .BYTE 070H,04FH,02EH,077H ; 1/6! ( 1/720) + .BYTE 06EH,002H,088H,07AH ; -1/5! (-1/120) + .BYTE 0E6H,0A0H,02AH,07CH ; 1/4! ( 1/24) + .BYTE 050H,0AAH,0AAH,07EH ; -1/3! (-1/6) + .BYTE 0FFH,0FFH,07FH,07FH ; 1/2! ( 1/2) + .BYTE 000H,000H,080H,081H ; -1/1! (-1/1) + .BYTE 000H,000H,000H,081H ; 1/0! ( 1/1) + +SUMSER: CALL STAKFP ; Put FPREG on stack + LD DE,MULT ; Multiply by "X" + PUSH DE ; To be done after + PUSH HL ; Save address of table + CALL BCDEFP ; Move FPREG to BCDE + CALL FPMULT ; Square the value + POP HL ; Restore address of table +SMSER1: CALL STAKFP ; Put value on stack + LD A,(HL) ; Get number of coefficients + INC HL ; Point to start of table + CALL PHLTFP ; Move coefficient to FPREG + .BYTE 06H ; Skip "POP AF" +SUMLP: POP AF ; Restore count + POP BC ; Restore number + POP DE + DEC A ; Cont coefficients + RET Z ; All done + PUSH DE ; Save number + PUSH BC + PUSH AF ; Save count + PUSH HL ; Save address in table + CALL FPMULT ; Multiply FPREG by BCDE + POP HL ; Restore address in table + CALL LOADFP ; Number at HL to BCDE + PUSH HL ; Save address in table + CALL FPADD ; Add coefficient to FPREG + POP HL ; Restore address in table + JP SUMLP ; More coefficients + +RND: CALL TSTSGN ; Test sign of FPREG + LD HL,SEED+2 ; Random number seed + JP M,RESEED ; Negative - Re-seed + LD HL,LSTRND ; Last random number + CALL PHLTFP ; Move last RND to FPREG + LD HL,SEED+2 ; Random number seed + RET Z ; Return if RND(0) + ADD A,(HL) ; Add (SEED)+2) + AND 00000111B ; 0 to 7 + LD B,0 + LD (HL),A ; Re-save seed + INC HL ; Move to coefficient table + ADD A,A ; 4 bytes + ADD A,A ; per entry + LD C,A ; BC = Offset into table + ADD HL,BC ; Point to coefficient + CALL LOADFP ; Coefficient to BCDE + CALL FPMULT ; ; Multiply FPREG by coefficient + LD A,(SEED+1) ; Get (SEED+1) + INC A ; Add 1 + AND 00000011B ; 0 to 3 + LD B,0 + CP 1 ; Is it zero? + ADC A,B ; Yes - Make it 1 + LD (SEED+1),A ; Re-save seed + LD HL,RNDTAB-4 ; Addition table + ADD A,A ; 4 bytes + ADD A,A ; per entry + LD C,A ; BC = Offset into table + ADD HL,BC ; Point to value + CALL ADDPHL ; Add value to FPREG +RND1: CALL BCDEFP ; Move FPREG to BCDE + LD A,E ; Get LSB + LD E,C ; LSB = MSB + XOR 01001111B ; Fiddle around + LD C,A ; New MSB + LD (HL),80H ; Set exponent + DEC HL ; Point to MSB + LD B,(HL) ; Get MSB + LD (HL),80H ; Make value -0.5 + LD HL,SEED ; Random number seed + INC (HL) ; Count seed + LD A,(HL) ; Get seed + SUB 171 ; Do it modulo 171 + JP NZ,RND2 ; Non-zero - Ok + LD (HL),A ; Zero seed + INC C ; Fillde about + DEC D ; with the + INC E ; number +RND2: CALL BNORM ; Normalise number + LD HL,LSTRND ; Save random number + JP FPTHL ; Move FPREG to last and return + +RESEED: LD (HL),A ; Re-seed random numbers + DEC HL + LD (HL),A + DEC HL + LD (HL),A + JP RND1 ; Return RND seed + +RNDTAB: .BYTE 068H,0B1H,046H,068H ; Table used by RND + .BYTE 099H,0E9H,092H,069H + .BYTE 010H,0D1H,075H,068H + +COS: LD HL,HALFPI ; Point to PI/2 + CALL ADDPHL ; Add it to PPREG +SIN: CALL STAKFP ; Put angle on stack + LD BC,8349H ; BCDE = 2 PI + LD DE,0FDBH + CALL FPBCDE ; Move 2 PI to FPREG + POP BC ; Restore angle + POP DE + CALL DVBCDE ; Divide angle by 2 PI + CALL STAKFP ; Put it on stack + CALL INT ; Get INT of result + POP BC ; Restore number + POP DE + CALL SUBCDE ; Make it 0 <= value < 1 + LD HL,QUARTR ; Point to 0.25 + CALL SUBPHL ; Subtract value from 0.25 + CALL TSTSGN ; Test sign of value + SCF ; Flag positive + JP P,SIN1 ; Positive - Ok + CALL ROUND ; Add 0.5 to value + CALL TSTSGN ; Test sign of value + OR A ; Flag negative +SIN1: PUSH AF ; Save sign + CALL P,INVSGN ; Negate value if positive + LD HL,QUARTR ; Point to 0.25 + CALL ADDPHL ; Add 0.25 to value + POP AF ; Restore sign + CALL NC,INVSGN ; Negative - Make positive + LD HL,SINTAB ; Coefficient table + JP SUMSER ; Evaluate sum of series + +HALFPI: .BYTE 0DBH,00FH,049H,081H ; 1.5708 (PI/2) + +QUARTR: .BYTE 000H,000H,000H,07FH ; 0.25 + +SINTAB: .BYTE 5 ; Table used by SIN + .BYTE 0BAH,0D7H,01EH,086H ; 39.711 + .BYTE 064H,026H,099H,087H ;-76.575 + .BYTE 058H,034H,023H,087H ; 81.602 + .BYTE 0E0H,05DH,0A5H,086H ;-41.342 + .BYTE 0DAH,00FH,049H,083H ; 6.2832 + +TAN: CALL STAKFP ; Put angle on stack + CALL SIN ; Get SIN of angle + POP BC ; Restore angle + POP HL + CALL STAKFP ; Save SIN of angle + EX DE,HL ; BCDE = Angle + CALL FPBCDE ; Angle to FPREG + CALL COS ; Get COS of angle + JP DIV ; TAN = SIN / COS + +ATN: CALL TSTSGN ; Test sign of value + CALL M,NEGAFT ; Negate result after if -ve + CALL M,INVSGN ; Negate value if -ve + LD A,(FPEXP) ; Get exponent + CP 81H ; Number less than 1? + JP C,ATN1 ; Yes - Get arc tangnt + LD BC,8100H ; BCDE = 1 + LD D,C + LD E,C + CALL DVBCDE ; Get reciprocal of number + LD HL,SUBPHL ; Sub angle from PI/2 + PUSH HL ; Save for angle > 1 +ATN1: LD HL,ATNTAB ; Coefficient table + CALL SUMSER ; Evaluate sum of series + LD HL,HALFPI ; PI/2 - angle in case > 1 + RET ; Number > 1 - Sub from PI/2 + +ATNTAB: .BYTE 9 ; Table used by ATN + .BYTE 04AH,0D7H,03BH,078H ; 1/17 + .BYTE 002H,06EH,084H,07BH ;-1/15 + .BYTE 0FEH,0C1H,02FH,07CH ; 1/13 + .BYTE 074H,031H,09AH,07DH ;-1/11 + .BYTE 084H,03DH,05AH,07DH ; 1/9 + .BYTE 0C8H,07FH,091H,07EH ;-1/7 + .BYTE 0E4H,0BBH,04CH,07EH ; 1/5 + .BYTE 06CH,0AAH,0AAH,07FH ;-1/3 + .BYTE 000H,000H,000H,081H ; 1/1 + +ARET: RET ; A RETurn instruction + +GETINP: + PUSH BC + PUSH DE + PUSH HL + ; INPUT CHARACTER FROM CONSOLE VIA HBIOS + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +CLS: + LD A,CS ; ASCII Clear screen + JP MONOUT ; Output character + +WIDTH: CALL GETINT ; Get integer 0-255 + LD A,E ; Width to A + LD (LWIDTH),A ; Set width + RET + +LINES: CALL GETNUM ; Get a number + CALL DEINT ; Get integer -32768 to 32767 + LD (LINESC),DE ; Set lines counter + LD (LINESN),DE ; Set lines number + RET + +DEEK: CALL DEINT ; Get integer -32768 to 32767 + PUSH DE ; Save number + POP HL ; Number to HL + LD B,(HL) ; Get LSB of contents + INC HL + LD A,(HL) ; Get MSB of contents + JP ABPASS ; Return integer AB + +DOKE: CALL GETNUM ; Get a number + CALL DEINT ; Get integer -32768 to 32767 + PUSH DE ; Save address + CALL CHKSYN ; Make sure ',' follows + .BYTE ',' + CALL GETNUM ; Get a number + CALL DEINT ; Get integer -32768 to 32767 + EX (SP),HL ; Save value,get address + LD (HL),E ; Save LSB of value + INC HL + LD (HL),D ; Save MSB of value + POP HL ; Restore code string address + RET + +; HEX$(nn) Convert 16 bit number to Hexadecimal string + +HEX: CALL TSTNUM ; Verify it's a number + CALL DEINT ; Get integer -32768 to 32767 + PUSH BC ; Save contents of BC + LD HL,PBUFF + LD A,D ; Get high order into A + CP $0 + JR Z,HEX2 ; Skip output if both high digits are zero + CALL BYT2ASC ; Convert D to ASCII + LD A,B + CP '0' + JR Z,HEX1 ; Don't store high digit if zero + LD (HL),B ; Store it to PBUFF + INC HL ; Next location +HEX1: LD (HL),C ; Store C to PBUFF+1 + INC HL ; Next location +HEX2: LD A,E ; Get lower byte + CALL BYT2ASC ; Convert E to ASCII + LD A,D + CP $0 + JR NZ,HEX3 ; If upper byte was not zero then always print lower byte + LD A,B + CP '0' ; If high digit of lower byte is zero then don't print + JR Z,HEX4 +HEX3: LD (HL),B ; to PBUFF+2 + INC HL ; Next location +HEX4: LD (HL),C ; to PBUFF+3 + INC HL ; PBUFF+4 to zero + XOR A ; Terminating character + LD (HL),A ; Store zero to terminate + INC HL ; Make sure PBUFF is terminated + LD (HL),A ; Store the double zero there + POP BC ; Get BC back + LD HL,PBUFF ; Reset to start of PBUFF + JP STR1 ; Convert the PBUFF to a string and return it + +BYT2ASC LD B,A ; Save original value + AND $0F ; Strip off upper nybble + CP $0A ; 0-9? + JR C,ADD30 ; If A-F, add 7 more + ADD A,$07 ; Bring value up to ASCII A-F +ADD30 ADD A,$30 ; And make ASCII + LD C,A ; Save converted char to C + LD A,B ; Retrieve original value + RRCA ; and Rotate it right + RRCA + RRCA + RRCA + AND $0F ; Mask off upper nybble + CP $0A ; 0-9? < A hex? + JR C,ADD301 ; Skip Add 7 + ADD A,$07 ; Bring it up to ASCII A-F +ADD301 ADD A,$30 ; And make it full ASCII + LD B,A ; Store high order byte + RET + +; Convert "&Hnnnn" to FPREG +; Gets a character from (HL) checks for Hexadecimal ASCII numbers "&Hnnnn" +; Char is in A, NC if char is ;<=>?@ A-z, CY is set if 0-9 +HEXTFP EX DE,HL ; Move code string pointer to DE + LD HL,$0000 ; Zero out the value + CALL GETHEX ; Check the number for valid hex + JP C,HXERR ; First value wasn't hex, HX error + JR HEXLP1 ; Convert first character +HEXLP CALL GETHEX ; Get second and addtional characters + JR C,HEXIT ; Exit if not a hex character +HEXLP1 ADD HL,HL ; Rotate 4 bits to the left + ADD HL,HL + ADD HL,HL + ADD HL,HL + OR L ; Add in D0-D3 into L + LD L,A ; Save new value + JR HEXLP ; And continue until all hex characters are in + +GETHEX INC DE ; Next location + LD A,(DE) ; Load character at pointer + CP ' ' + JP Z,GETHEX ; Skip spaces + SUB $30 ; Get absolute value + RET C ; < "0", error + CP $0A + JR C,NOSUB7 ; Is already in the range 0-9 + SUB $07 ; Reduce to A-F + CP $0A ; Value should be $0A-$0F at this point + RET C ; CY set if was : ; < = > ? @ +NOSUB7 CP $10 ; > Greater than "F"? + CCF + RET ; CY set if it wasn't valid hex + +HEXIT EX DE,HL ; Value into DE, Code string into HL + LD A,D ; Load DE into AC + LD C,E ; For prep to + PUSH HL + CALL ACPASS ; ACPASS to set AC as integer into FPREG + POP HL + RET + +HXERR: LD E,HX ; ?HEX Error + JP ERROR + +; BIN$(NN) Convert integer to a 1-16 char binary string +BIN: CALL TSTNUM ; Verify it's a number + CALL DEINT ; Get integer -32768 to 32767 +BIN2: PUSH BC ; Save contents of BC + LD HL,PBUFF + LD B,17 ; One higher than max char count +ZEROSUP: ; Suppress leading zeros + DEC B ; Max 16 chars + LD A,B + CP $01 + JR Z,BITOUT ; Always output at least one character + RL E + RL D + JR NC,ZEROSUP + JR BITOUT2 +BITOUT: + RL E + RL D ; Top bit now in carry +BITOUT2: + LD A,'0' ; Char for '0' + ADC A,0 ; If carry set then '0' --> '1' + LD (HL),A + INC HL + DEC B + JR NZ,BITOUT + XOR A ; Terminating character + LD (HL),A ; Store zero to terminate + INC HL ; Make sure PBUFF is terminated + LD (HL),A ; Store the double zero there + POP BC + LD HL,PBUFF + JP STR1 + +; Convert "&Bnnnn" to FPREG +; Gets a character from (HL) checks for Binary ASCII numbers "&Bnnnn" +BINTFP: EX DE,HL ; Move code string pointer to DE + LD HL,$0000 ; Zero out the value + CALL CHKBIN ; Check the number for valid bin + JP C,BINERR ; First value wasn't bin, HX error +BINIT: SUB '0' + ADD HL,HL ; Rotate HL left + OR L + LD L,A + CALL CHKBIN ; Get second and addtional characters + JR NC,BINIT ; Process if a bin character + EX DE,HL ; Value into DE, Code string into HL + LD A,D ; Load DE into AC + LD C,E ; For prep to + PUSH HL + CALL ACPASS ; ACPASS to set AC as integer into FPREG + POP HL + RET + +; Char is in A, NC if char is 0 or 1 +CHKBIN: INC DE + LD A,(DE) + CP ' ' + JP Z,CHKBIN ; Skip spaces + CP '0' ; Set C if < '0' + RET C + CP '2' + CCF ; Set C if > '1' + RET + +BINERR: LD E,BN ; ?BIN Error + JP ERROR + + +JJUMP1: + LD IX,-1 ; Flag cold start + JP CSTART ; Go and initialise + +MONOUT: + ; SAVE ALL INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL + ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS + LD E,A ; OUTPUT CHAR TO E + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + RST 08 ; HBIOS OUTPUTS CHARACTDR + ; RESTORE ALL REGISTERS + POP HL + POP DE + POP BC + POP AF + RET + +MONITR: LD A,BID_BOOT ; BOOT BANK + LD HL,0 ; ADDRESS ZERO + CALL HB_BNKCALL ; DOES NOT RETURN + +INITST: LD A,0 ; Clear break flag + LD (BRKFLG),A + JP INIT + +ARETN: RETN ; Return from NMI + + +TSTBIT: PUSH AF ; Save bit mask + AND B ; Get common bits + POP BC ; Restore bit mask + CP B ; Same bit set? + LD A,0 ; Return 0 in A + RET + +OUTNCR: CALL OUTC ; Output character in A + JP PRNTCRLF ; Output CRLF + +TXT_READY: + .DB CR,LF + .TEXT "BASIC READY " + .DB CR,LF,0FFH + +SLACK .EQU (BAS_END - $) + .FILL SLACK,00H +; +BAS_STACK .EQU $ +; + .ECHO "BASIC space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" + +.end + diff --git a/Source/HBIOS/romldr.asm b/Source/HBIOS/romldr.asm index c2a0fdc5..fcbf8748 100644 --- a/Source/HBIOS/romldr.asm +++ b/Source/HBIOS/romldr.asm @@ -7,12 +7,37 @@ ; #INCLUDE "std.asm" ; -MONIMG .EQU $1000 -CPMIMG .EQU $2000 -ZSYSIMG .EQU $5000 +; osimg.bin +; +;LDRIMG .EQU $0000 ;SIZE 0A00 > 0000-0A00 +MONIMG .EQU $0A00 ;SIZE 1000 > 0A00-1A00 +CPMIMG .EQU $1A00 ;SIZE 3000 > 1A00-4A00 +ZSYSIMG .EQU $4A00 ;SIZE 3000 > 4A00-7A00 +; +; osimg1.bin +; +BASIMG .EQU $0000 ;SIZE 2000 > 0000-2000 +TBCIMG .EQU $2000 ;SIZE 0900 > 2000-2900 ; INT_IM1 .EQU $FF00 ; +;---------------------------------------------------------- +; NAME NAME OF ROM 8 CHAR +; BANK WHICH ROM BANK THE IMAGE IS IN. +; IMAGE LOCATION OF IMAGE IN 32K ROM BANK. +; LOCATION WHERE IMAGE NEEDS TO BE COPIED TO IN RAM. +; EXECUTE ADDRESS TO START EXECUTING. +; + +;ROMTBL .DB "B","BASIC $", 0, BASIMG, BAS_LOC, BAS_SIZ, BASE_LOC +; .DB "C","CP/M $", 0, +; .DB "F","FORTH $", 1, +; .DB "Z","ZSYSTEM$", 1, +; +; +; .DB "MONITOR$", 0, +; + .ORG 0 ; ;================================================================================================== @@ -62,6 +87,7 @@ INT_IM1 .EQU $FF00 ; BANNER LD DE,STR_BANNER CALL WRITESTR + ; #IF (PLATFORM != PLT_UNA) CALL DELAY_INIT ; INIT DELAY FUNCTIONS @@ -122,9 +148,11 @@ INT_IM1 .EQU $FF00 ;________________________________________________________________________________________________________________________________ ; DOBOOTMENU: - CALL NEWLINE - LD DE,STR_BOOTMENU +; CALL NEWLINE + LD DE,STR_BOOTMENU CALL WRITESTR + CALL PRTALL + CALL PC_COLON #IF (DSKYENABLE) LD HL,BOOT ; POINT TO BOOT MESSAGE @@ -144,14 +172,18 @@ DB_BOOTLOOP: OR A JP Z,DB_CONEND CALL CINUC - CP 'M' ; MONITOR - JP Z,GOMONSER + CP 'B' ; NASCOM BASIC + JP Z,GOBASIC CP 'C' ; CP/M BOOT FROM ROM JP Z,GOCPM + CP 'M' ; MONITOR + JP Z,GOMONSER +; CP 'L' ; LIST DRIVES +; JP Z,GOLIST + CP 'T' ; TASTY BASIC + JP Z,GOTBAS CP 'Z' ; ZSYSTEM BOOT FROM ROM JP Z,GOZSYS - CP 'L' ; LIST DRIVES - JP Z,GOLIST CP '0' ; 0-9, DISK DEVICE JP C,DB_INVALID CP '9' + 1 @@ -202,14 +234,18 @@ DB_DSKYEND: ; TIMEOUT EXPIRED, PERFORM DEFAULT BOOT ACTION LD A,BOOT_DEFAULT - CP 'M' ; MONITOR - JP Z,GOMON + CP 'B' ; NASCOM BASIC + JP Z,GOBASIC CP 'C' ; CP/M BOOT FROM ROM JP Z,GOCPM + CP 'M' ; MONITOR + JP Z,GOMONSER +; CP 'L' ; LIST DRIVES +; JP Z,GOLIST + CP 'T' ; TASTY BASIC + JP Z,GOTBAS CP 'Z' ; ZSYSTEM BOOT FROM ROM JP Z,GOZSYS - CP 'L' ; LIST DRIVES - JP Z,GOLIST CP '0' ; 0-9, DISK DEVICE JP C,DB_INVALID CP '9' + 1 @@ -227,6 +263,70 @@ DB_INVALID: CALL WRITESTR JP DOBOOTMENU ; +GOBASIC: + LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + ; COPY BASIC FROM BASIC FROM OSIMG0 IN ROM BANK TO THIS RAM BANKS + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_OSIMG ; E = SRC BANK = BIOS BANK + LD HL,BAS_SIZ ; HL = COPY LEN = 1 PAGE = 256 BYTES + RST 08 ; DO IT + LD DE,STR_LOADING + CALL WRITESTR ; WRITE IT TO CONSOLE + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,BASIMG ; COPY FROM + LD DE,BAS_LOC ; COPY TO + RST 08 ; DO IT + LD DE,STR_LAUNCH + CALL WRITESTR + LD HL,BAS_LOC + JP CHAIN + +; LD HL,BAS_LOC +; PUSH HL +; LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE +; CALL WRITESTR ; WRITE IT TO CONSOLE +; ; COPY IMAGE TO EXEC ADDRESS +; LD HL,BASIMG ; HL := BASIC IMAGE ADDRESS +; LD DE,BAS_LOC ; DE := BASIC EXEC ADDRESS +; LD BC,BAS_SIZ ; BC := BASIC SIZE +; LDIR ; COPY BASIC CODE TO EXEC ADDRESS +; POP HL ; RECOVER ENTRY ADDRESS +; JR CHAIN ; AND CHAIN TO IT + +GOTBAS: + LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + ; COPY BASIC FROM BASIC FROM OSIMG0 IN ROM BANK TO THIS RAM BANKS + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_OSIMG ; E = SRC BANK = BIOS BANK + LD HL,TBC_SIZ ; HL = COPY LEN = 1 PAGE = 256 BYTES + RST 08 ; DO IT + LD DE,STR_LOADING + CALL WRITESTR ; WRITE IT TO CONSOLE + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,TBCIMG ; COPY FROM + LD DE,TBC_LOC ; COPY TO + RST 08 ; DO IT + LD DE,STR_LAUNCH + CALL WRITESTR + LD HL,TBC_LOC + JP CHAIN + +; LD HL,TBC_LOC +; PUSH HL +; LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE +; CALL WRITESTR ; WRITE IT TO CONSOLE +; ; COPY IMAGE TO EXEC ADDRESS +; LD HL,TBCIMG ; HL := BASIC IMAGE ADDRESS +; LD DE,TBC_LOC ; DE := BASIC EXEC ADDRESS +; LD BC,TBC_SIZ ; BC := BASIC SIZE +; LDIR ; COPY BASIC CODE TO EXEC ADDRESS +; POP HL ; RECOVER ENTRY ADDRESS +; JR CHAIN ; AND CHAIN TO IT + GOMONSER: LD HL,MON_SERIAL ; MONITOR SERIAL INTERFACE ENTRY ADDRESS TO HL JR GOMON ; LOAD AND RUN MONITOR @@ -295,8 +395,8 @@ CHAIN: RST 08 ; LD A,BID_USR ; ACTIVATE USER BANK - POP HL ; RECOVER ENTRY ADDRESS - DI ; ENTER WITH INTS DISABLED + POP HL ; RECOVER ENTRY ADDRESS + DI ; ENTER WITH INTS DISABLED CALL HB_BNKCALL ; AND GO HALT ; WE SHOULD NEVER RETURN!!! #ENDIF @@ -601,7 +701,7 @@ PRTDRV: CALL COUT ; PRINT IT LD A,')' ; DRIVE LETTER COLON CALL COUT ; PRINT IT - CALL PC_SPACE +; CALL PC_SPACE POP DE ; RECOVER DISK TYPE LD A,D ; DISK TYPE TO A CP $40 ; RAM/ROM? @@ -637,7 +737,7 @@ PRTDRV2: ; PRINT DEVICE LD A,B ; UNIT TO A ADD A,'0' ; MAKE IT PRINTABLE NUMERIC CALL COUT ; PRINT IT - LD A,':' ; DEVICE NAME COLON + LD A,',' ; DEVICE NAME SEPARATOR CALL COUT ; PRINT IT RET ; DONE ; @@ -672,7 +772,7 @@ PRTALL1: CALL COUT ; PRINT IT LD A,')' ; FORMATTING CALL COUT ; PRINT IT - CALL PC_SPACE ; SPACING +; CALL PC_SPACE ; SPACING PUSH BC ; SAVE LOOP CONTROL LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO RST 08 ; CALL HBIOS @@ -708,7 +808,7 @@ PRTDRV: LD A,E ; LOAD DRIVER MODE/UNIT AND $0F ; ISOLATE UNIT CALL PRTDECB ; PRINT IT - CALL PC_COLON ; FORMATTING + CALL PC_SPACE ; FORMATTING ;LD A,E ; LOAD LU ;CALL PRTDECB ; PRINT IT RET @@ -746,7 +846,9 @@ DEV15 .EQU DEVUNK ; STR_BOOTDISK .DB "BOOT FROM DISK\r\n$" STR_BOOTDISK1 .DB "\r\nReading disk information...$" -STR_BOOTMON .DB "START MONITOR\r\n$" +STR_BOOTMON .DB "START MONITOR FROM ROM\r\n$" +STR_BOOTBAS .DB "START BASIC FROM ROM\r\n$" +STR_BOOTTBC .DB "START TASTYBASIC FROM ROM\r\n$" STR_BOOTCPM .DB "BOOT CPM FROM ROM\r\n$" STR_BOOTZSYS .DB "BOOT ZSYSTEM FROM ROM\r\n$" STR_LIST .DB "LIST DEVICES\r\n$" @@ -758,16 +860,19 @@ STR_CPMEND .DB "END=$" STR_CPMENT .DB "ENT=$" STR_LABEL .DB "LABEL=$" STR_DRVLIST .DB "\r\nDisk Devices:\r\n$" -STR_PREFIX .DB "\r\n $" +STR_PREFIX .DB "($" +;STR_PREFIX .DB "\r\n $" STR_LOADING .DB "\r\nLoading...$" STR_NODISK .DB "\r\nNo disk!$" STR_NOBOOT .DB "\r\nDisk not bootable!$" STR_BOOTERR .DB "\r\nBoot failure!$" +STR_ITSRAM .DB "\r\n\RAM$" +STR_LAUNCH .DB "\r\nLaunching ...$" ; STR_BANNER .DB "\r\n", PLATFORM_NAME, " Boot Loader$" STR_BOOTMENU .DB "\r\n" - .DB "Boot: (C)PM, (Z)System, (M)onitor,\r\n" - .DB " (L)ist disks, or Disk Unit # ===> $" + .DB "\r\nROM Boot: (B)ASIC, (C)PM, (M)onitor, (T)ASTYBASIC, (Z)System.\r\n" + .DB "Disk Boot: $" ; .IF DSKYENABLE BOOT: @@ -931,7 +1036,7 @@ CINUC: ; FILL REMAINDER OF BANK ;================================================================================================== ; -SLACK: .EQU ($1000 - $) +SLACK: .EQU ($LDR_SIZ - $) .FILL SLACK ; .ECHO "LOADER space remaining: " diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index 8e483c04..f37325b8 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -325,7 +325,7 @@ BID_ROMN .EQU (BID_ROM0 + ((ROMSIZE / 32) - 1)) BID_RAMN .EQU (BID_RAM0 + ((RAMSIZE / 32) - 1)) BID_BOOT .EQU BID_ROM0 ; BOOT BANK -;BID_BIOSIMG .EQU BID_ROM0 + 1 ; BIOS IMAGE BANK +BID_BIOSIMG .EQU BID_ROM0 + 1 ; BIOS IMAGE BANK BID_OSIMG .EQU BID_ROM0 + 2 ; ROM LOADER AND IMAGES BANK BID_FSFAT .EQU BID_ROM0 + 3 ; FAT FILESYSTEM DRIVER BANK BID_ROMD0 .EQU BID_ROM0 + 4 ; FIRST ROM DRIVE BANK @@ -364,10 +364,20 @@ CBIOS_LOC .EQU CBIOS_END - CBIOS_SIZ ; START OF CBIOS CPM_ENT .EQU CBIOS_LOC ; CPM ENTRY POINT (IN CBIOS) +LDR_SIZ .EQU $0A00 + MON_LOC .EQU $C000 ; LOCATION OF MONITOR FOR RUNNING SYSTEM MON_SIZ .EQU $1000 ; SIZE OF MONITOR BINARY IMAGE MON_END .EQU MON_LOC + MON_SIZ ; END OF MONITOR +BAS_LOC .EQU $0A00 ; NASCOM BASIC +BAS_SIZ .EQU $2000 +BAS_END .EQU BAS_LOC + BAS_SIZ + +TBC_LOC .EQU $0A00 ; TASTYBASIC +TBC_SIZ .EQU $0900 +TBC_END .EQU TBC_LOC + TBC_SIZ + MON_DSKY .EQU MON_LOC + (0 * 3) ; MONITOR ENTRY (DSKY) MON_SERIAL .EQU MON_LOC + (1 * 3) ; MONITOR ENTRY (SERIAL PORT) ; diff --git a/Source/HBIOS/tastybasic.asm b/Source/HBIOS/tastybasic.asm new file mode 100644 index 00000000..5a35782a --- /dev/null +++ b/Source/HBIOS/tastybasic.asm @@ -0,0 +1,1813 @@ + +; ----------------------------------------------------------------------------- +; Copyright 2018 Dimitri Theulings +; +; This file is part of Tasty Basic. +; +; Tasty Basic 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. +; +; Tasty Basic 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 Tasty Basic. If not, see . +; ----------------------------------------------------------------------------- +; Tasty Basic is derived from earlier works by Li-Chen Wang, Peter Rauskolb, +; and Doug Gabbard. Refer to the enclosed README.md file for details. +; ----------------------------------------------------------------------------- + +#INCLUDE "std.asm" + +zemu .equ 0 + +#if zemu +tty_data .equ 7ch ; Z80 Emulator +tty_status .equ 7dh +rx_full .equ 1 +tx_empty .equ 0 +#else +tty_data .equ 67h ; SBC V2 +tty_status .equ 68h +rx_full .equ 1 +tx_empty .equ 0 +#endif + +ctrlc .equ 03h +bs .equ 08h +lf .equ 0ah +cr .equ 0dh +ctrlo .equ 0fh +ctrlu .equ 15h + +#define dwa(addr) .db (addr >> 8) + 080h\ .db addr & 0ffh + + .org TBC_LOC +start: + ld sp,stack ; ** Cold Start ** + ld a,0ffh + jp init +testc: + ex (sp),hl ; ** TestC ** + call skipspace ; ignore spaces + cp (hl) ; test character + inc hl ; compare the byte that follows the + jr z,tc1 ; call instruction with the text pointer + push bc + ld c,(hl) ; if not equal, ad the seond byte + ld b, 0h ; that follows the call to the old pc + add hl,bc + pop bc + dec de +tc1: + inc de ; if equal, skip those bytes + inc hl ; and continue + ex (sp),hl + ret + +skipspace: + ld a,(de) ; ** SkipSpace ** + cp ' ' ; ignore spaces + ret nz ; in text (where de points) + inc de ; and return the first non-blank + jp skipspace ; character in A + +expr: + call expr2 ; ** Expr ** + push hl ; evaluate expression + jp expr1 + +comp: + ld a,h ; ** Compare ** + cp d ; compare hl with de + ret nz ; return c and z flags + ld a,l ; old a is lost + cp e + ret + +finish: + pop af ; ** Finish ** + call fin ; check end of command + jp qwhat + +;************************************************************* +; +; *** REM *** IF *** INPUT *** & LET (& DEFLT) *** +; +; 'REM' CAN BE FOLLOWED BY ANYTHING AND IS IGNORED BY TBI. +; TBI TREATS IT LIKE AN 'IF' WITH A FALSE CONDITION. +; +; 'IF' IS FOLLOWED BY AN EXPR. AS A CONDITION AND ONE OR MORE +; COMMANDS (INCLUDING OTHER 'IF'S) SEPERATED BY SEMI-COLONS. +; NOTE THAT THE WORD 'THEN' IS NOT USED. TBI EVALUATES THE +; EXPR. IF IT IS NON-ZERO, EXECUTION CONTINUES. IF THE +; EXPR. IS ZERO, THE COMMANDS THAT FOLLOWS ARE IGNORED AND +; EXECUTION CONTINUES AT THE NEXT LINE. +; +; 'INPUT' COMMAND IS LIKE THE 'PRINT' COMMAND, AND IS FOLLOWED +; BY A LIST OF ITEMS. IF THE ITEM IS A STRING IN SINGLE OR +; DOUBLE QUOTES, OR IS A BACK-ARROW, IT HAS THE SAME EFFECT AS +; IN 'PRINT'. IF AN ITEM IS A VARIABLE, THIS VARIABLE NAME IS +; PRINTED OUT FOLLOWED BY A COLON. THEN TBI WAITS FOR AN +; EXPR. TO BE TYPED IN. THE VARIABLE IS THEN SET TO THE +; VALUE OF THIS EXPR. IF THE VARIABLE IS PROCEDED BY A STRING +; (AGAIN IN SINGLE OR DOUBLE QUOTES), THE STRING WILL BE +; PRINTED FOLLOWED BY A COLON. TBI THEN WAITS FOR INPUT EXPR. +; AND SET THE VARIABLE TO THE VALUE OF THE EXPR. +; +; IF THE INPUT EXPR. IS INVALID, TBI WILL PRINT "WHAT?", +; "HOW?" OR "SORRY" AND REPRINT THE PROMPT AND REDO THE INPUT. +; THE EXECUTION WILL NOT TERMINATE UNLESS YOU TYPE CONTROL-C. +; THIS IS HANDLED IN 'INPERR'. +; +; 'LET' IS FOLLOWED BY A LIST OF ITEMS SEPERATED BY COMMAS. +; EACH ITEM CONSISTS OF A VARIABLE, AN EQUAL SIGN, AND AN EXPR. +; TBI EVALUATES THE EXPR. AND SET THE VARIABLE TO THAT VALUE. +; TBI WILL ALSO HANDLE 'LET' COMMAND WITHOUT THE WORD 'LET'. +; THIS IS DONE BY 'DEFLT'. +;************************************************************* +rem: + ld hl,0000h ; ** Rem ** + jr if1 ; this is like 'IF 0' +iff: + call expr ; ** If ** +if1: + ld a,h ; is the expr = 0? + or l + jp nz,runsml ; no, continue + call findskip ; yes, skip rest of line + jp nc,runtsl ; and run the next line + jp rstart ; if no, restart +inputerror: + ld hl,(stkinp) ; ** InputError ** + ld sp,hl ; restore old sp and old current + pop hl + ld (current),hl + pop de ; and old text pointer + pop de ; redo curret +input: + push de ; ** Input ** + call qtstg ; is next item a string? + jp ip2 ; no + call testvar ; yes and followed by a variable? + jp c,ip4 ; no + jp ip3 ; yes, input variable +ip2: + push de ; save for printstr + call testvar ; must be variable + jp c,qwhat ; no, what? + ld a,(de) ; prepare for printstr + ld c,a + sub a + ld (de),a + pop de + call printstr ; print string as prompt + ld a,c ; restore text + dec de + ld (de),a +ip3: + push de ; save text pointer + ex de,hl + ld hl,(current) ; also save current + push hl + ld hl,input + ld (current),hl + ld hl,0000h + add hl,sp + ld (stkinp),hl + push de + ld a,':' + call getline + ld de,buffer + call expr + nop ; ** TODO: check? ** + nop + nop + pop de + ex de,hl + ld (hl),e + inc hl + ld (hl),d + pop hl + ld (current),hl + pop de +ip4: + pop af ; purge stack + call testc ; is next character ','? + .db ',' + .db ip5-$-1 + jr input ; yes, more items +ip5: + call finish +deflt: + ld a,(de) ; ** DEFLT ** + cp cr ; empty line is fine + jr z,lt1 ; else it's 'LET' +let: + call setval ; ** Let ** + call testc ; set value to var + .db ',' + .db lt1-$-1 + jr let ; item by item +lt1: + call finish + +;************************************************************* +; +; *** PEEK *** POKE *** IN *** & OUT *** +; +; 'PEEK()' RETURNS THE VALUE OF THE BYTE AT THE GIVEN +; ADDRESS. +; 'POKE ,' SETS BYTE AT ADDRESS TO +; VALUE +; +;************************************************************* +peek: + call parn ; ** Peek(expr) ** + ld a,h ; expression must be positive + or a + jp m,qhow + ld a,(hl) + ld h,0 + ld l,a + ret +poke: + call expr ; ** Poke ** + ld a,h ; address must be positive + or a + jp m,qhow + push hl + call testc ; is next char a comma? + .db ',' + .db pk1-$-1 ; what, no? + call expr ; get value to store + ld a,0 ; is it > 255? + cp h + jp z,pk2 ; no, all good + pop hl + jp m,qhow +pk2: + ld a,l ; save value + pop hl + ld (hl),a + call finish +pk1: + pop hl + jp qwhat +usrexec: + call parn ; ** Usr(expr) ** + push de + ex de,hl + ld hl,ue1 + push hl + ld ix,(usrvector) + jp (ix) +ue1: + ex de,hl + pop de + ret +;************************************************************* +; +; *** EXPR *** +; +; 'EXPR' EVALUATES ARITHMETICAL OR LOGICAL EXPRESSIONS. +; :: +; +; WHERE IS ONE OF THE OPERATORS IN TAB8 AND THE +; RESULT OF THESE OPERATIONS IS 1 IF TRUE AND 0 IF FALSE. +; ::=(+ OR -)(+ OR -)(....) +; WHERE () ARE OPTIONAL AND (....) ARE OPTIONAL REPEATS. +; ::=(* OR />)(....) +; ::= +; +; () +; IS RECURSIVE SO THAT VARIABLE '@' CAN HAVE AN +; AS INDEX, FUNCTIONS CAN HAVE AN AS ARGUMENTS, AND +; CAN BE AN IN PARANTHESE. +;************************************************************* + +expr1: + ld hl,tab8-1 ; look up rel.op + jp exec ; go do it +xp11: + call xp18 ; rel.op.'>=' + ret c ; no, return hl=0 + ld l,a ; yes, return hl=1 + ret +xp12: + call xp18 ; rel.op.'#' + ret z ; no, return hl=0 + ld l,a ; yes, return hl=1 + ret +xp13: + call xp18 ; rel.op.'>' + ret z ; no + ret c ; also, no + ld l,a ; yes, return hl=1 + ret +xp14: + call xp18 ; rel.op.'<=' + ld l,a ; set hl=1 + ret z ; yes, return hl=1 + ret c + ld l,h ; else set hl=0 + ret +xp15: + call xp18 ; rel.op.'=' + ret nz ; no, return hl=0 + ld l,a ; else hl=1 + ret +xp16: + call xp18 ; rel.op.'<' + ret nc ; no, return hl=0 + ld l,a ; else hl=1 + ret +xp17: + pop hl ; not rel.op + ret ; return hl= +xp18: + ld a,c ; routine for all rel.ops + pop hl + pop bc + push hl + push bc ; reverse top of stack + ld c,a + call expr2 ; get second + ex de,hl ; value now in de + ex (sp),hl ; first in hl + call ckhlde ; compare them + pop de ; restore text pointer + ld hl,0000h ; set hl=0, a=1 + ld a,1 + ret +expr2: + call testc ; is it minus sign? + .db '-' + .db xp21-$-1 + ld hl,0000h ; yes, fake 0 - + jr xp26 ; treat like subtract +xp21: + call testc ; is it plus sign? + .db '+' + .db xp22-$-1 +xp22: + call expr3 ; first +xp23: + call testc ; addition? + .db '+' + .db xp25-$-1 + push hl ; yes, save value + call expr3 ; get second +xp24: + ex de,hl ; 2nd in de + ex (sp),hl ; 1st in hl + ld a,h ; compare sign + xor d + ld a,d + add hl,de + pop de ; restore text pointer + jp m,xp23 ; first and second sign differ + xor h ; first and second sign are equal + jp p,xp23 ; so is the result + jp qhow ; else we have overflow +xp25: + call testc ; subtract? + .db '-' + .db xp42-$-1 +xp26: + push hl ; yes, save first + call expr3 ; get second + call changesign ; negate + jr xp24 ; and add them +expr3: + call expr4 ; get first expr4 +xp31: + call testc ; multiply? + .db '*' + .db xp34-$-1 + push hl ; yes, save first and get second + call expr4 ; + ld b,0 ; clear b for sign + call checksign + ex (sp),hl ; first in hl + call checksign ; check sign of first + ex de,hl + ex (sp),hl + ld a,h ; is hl > 255? + or a + jr z,xp32 ; no + ld a,d ; yes, what about de + or d + ex de,hl + jp nz,ahow +xp32: + ld a,l + ld hl,0000h + or a + jr z,xp35 +xp33: + add hl,de + jp c,ahow + dec a + jr nz,xp33 + jr xp35 +xp34: + call testc ; divide + .db '/' + .db xp42-$-1 + push hl ; yes, save first + call expr4 ; and get the second one + ld b,0h ; clear b for sign + call checksign ; check sign of the second + ex (sp),hl ; get the first in hl + call checksign ; check sign of first + ex de,hl + ex (sp),hl + ex de,hl + ld a,d ; divide by 0? + or e + jp z,ahow ; err...how? + push bc ; else save sign + call divide + ld h,b + ld l,c + pop bc ; retrieve sign +xp35: + pop de ; and text pointer + ld a,h ; hl must be positive + or a + jp m,qhow ; else it's overflow + ld a,b + or a + call m,changesign ; change sign if needed + jp xp31 ; look for more terms +expr4: + ld hl,tab4-1 ; find function in tab4 + jp exec ; and execute it +xp40: + call testvar + jr c,xp41 ; nor a variable + ld a,(hl) + inc hl + ld h,(hl) ; value in hl + ld l,a + ret +xp41: + call testnum ; or is it a number + ld a,b ; number of digits + or a + ret nz ; ok + +parn: + call testc + .db '(' + .db xp43-$-1 + call expr ; "(expr)" + call testc + .db ')' + .db xp43-$-1 +xp42: + ret +xp43: + jp qwhat ; what? +rnd: + call parn ; ** Rnd(expr) ** + ld a,h ; expression must be positive + or a + jp m,qhow + or l ; and non-zero + jp z,qhow + push de ; save de and hl + push hl + ld hl,(rndptr) ; get memory as random number + ld de,lstrom + call comp + jr c,ra1 ; wrap around if last + ld hl,start +ra1: + ld e,(hl) + inc hl + ld d,(hl) + ld (rndptr),hl + pop hl + ex de,hl + push bc + call divide ; rnd(n)=mod(m,n)+1 + pop bc + pop de + inc hl + ret +abs: + call parn ; ** Abs (expr) ** + dec de + call checksign + inc de + ret +size: + ld hl,(textunfilled) ; ** Size ** + push de ; get the number of free bytes between + ex de,hl ; and varbegin + ld hl,varbegin + call subde + pop de + ret + +;************************************************************* +; +; *** DIVIDE *** SUBDE *** CHKSGN *** CHGSGN *** & CKHLDE *** +; +; 'DIVIDE' DIVIDES HL BY DE, RESULT IN BC, REMAINDER IN HL +; +; 'SUBDE' SUBSTRACTS DE FROM HL +; +; 'CHKSGN' CHECKS SIGN OF HL. IF +, NO CHANGE. IF -, CHANGE +; SIGN AND FLIP SIGN OF B. +; +; 'CHGSGN' CHECKS SIGN N OF HL AND B UNCONDITIONALLY. +; +; 'CKHLDE' CHECKS SIGN OF HL AND DE. IF DIFFERENT, HL AND DE +; ARE INTERCHANGED. IF SAME SIGN, NOT INTERCHANGED. EITHER +; CASE, HL DE ARE THEN COMPARED TO SET THE FLAGS. +;************************************************************* +divide: + push hl ; ** Divide ** + ld l,h ; divide h by de + ld h,0h + call dv1 + ld b,c ; save result in b + ld a,l ; (remainder + l) / de + pop hl + ld h,a +dv1: + ld c,0ffh ; result in c +dv2: + inc c ; dumb routine + call subde ; divide using subtract and count + jr nc,dv2 + add hl,de + ret +subde: + ld a,l ; ** subde ** + sub e ; subtract de from hl + ld l,a + ld a,h + sbc a,d + ld h,a + ret + +checksign: + ld a,h ; ** CheckSign ** + or a ; check sign of hl + ret p +changesign: + ld a,h ; ** ChangeSign ** + push af + cpl ; change sign of hl + ld h,a + ld a,l + cpl + ld l,a + inc hl + pop af + xor h + jp p,qhow + ld a,b ; and also flip b + xor 80h + ld b,a + ret +ckhlde: + ld a,h ; same sign? + xor d ; yes, compare + jp p,ck1 ; no, exchange and compare + ex de,hl +ck1: + call comp + ret + +;************************************************************* +; +; *** SETVAL *** FIN *** ENDCHK *** & ERROR (& FRIENDS) *** +; +; "SETVAL" EXPECTS A VARIABLE, FOLLOWED BY AN EQUAL SIGN AND +; THEN AN EXPR. IT EVALUATES THE EXPR. AND SET THE VARIABLE +; TO THAT VALUE. +; +; "FIN" CHECKS THE END OF A COMMAND. IF IT ENDED WITH ";", +; EXECUTION CONTINUES. IF IT ENDED WITH A CR, IT FINDS THE +; NEXT LINE AND CONTINUE FROM THERE. +; +; "ENDCHK" CHECKS IF A COMMAND IS ENDED WITH CR. THIS IS +; REQUIRED IN CERTAIN COMMANDS. (GOTO, RETURN, AND STOP ETC.) +; +; "ERROR" PRINTS THE STRING POINTED BY DE (AND ENDS WITH CR). +; IT THEN PRINTS THE LINE POINTED BY 'CURRNT' WITH A "?" +; INSERTED AT WHERE THE OLD TEXT POINTER (SHOULD BE ON TOP +; OF THE STACK) POINTS TO. EXECUTION OF TB IS STOPPED +; AND TBI IS RESTARTED. HOWEVER, IF 'CURRNT' -> ZERO +; (INDICATING A DIRECT COMMAND), THE DIRECT COMMAND IS NOT +; PRINTED. AND IF 'CURRNT' -> NEGATIVE # (INDICATING 'INPUT' +; COMMAND), THE INPUT LINE IS NOT PRINTED AND EXECUTION IS +; NOT TERMINATED BUT CONTINUED AT 'INPERR'. +; +; RELATED TO 'ERROR' ARE THE FOLLOWING: +; 'QWHAT' SAVES TEXT POINTER IN STACK AND GET MESSAGE "WHAT?" +; 'AWHAT' JUST GET MESSAGE "WHAT?" AND JUMP TO 'ERROR'. +; 'QSORRY' AND 'ASORRY' DO SAME KIND OF THING. +; 'AHOW' AND 'AHOW' IN THE ZERO PAGE SECTION ALSO DO THIS. +;************************************************************* +setval: + call testvar ; ** SetVal ** + jp c,qwhat ; no variable + push hl ; save address of var + call testc ; do we have =? + .db '=' + .db sv1-$-1 + call expr ; evaluate expression + ld b,h ; value is in bc now + ld c,l + pop hl ; get address + ld (hl),c ; save value + inc hl + ld (hl),b + ret +sv1: + jp qwhat +fin: + call testc ; test for ';' + .db ';' + .db fi1 - $ - 1 + pop af ; yes, purge return address + jp runsml ; continue on same line +fi1: + call testc ; not ';', is it cr + .db cr + .db fi2 - $ - 1 + pop af ; yes, purge return address + jp runnxl ; run next line +fi2: + ret ; else return to caller +endchk: + call skipspace ; ** EndChk ** + cp cr ; ends with cr? + ret z ; ok, otherwise say 'what?' +qwhat: + push de ; ** QWhat ** +awhat: + ld de,what ; ** AWhat ** +handleerror: + sub a ; ** Error ** + call printstr ; print error message + pop de + ld a,(de) ; save the character + push af ; at where old de points + sub a ; and put a 0 (zero) there + ld (de),a + ld hl,(current) ; get the current line number + push hl + ld a,(hl) ; check the value + inc hl + or (hl) + pop de + jp z,rstart ; if zero, just rerstart + ld a,(hl) ; if negative + or a + jp m,inputerror ; then redo input + call printline ; else print the line + dec de ; up to where the 0 is + pop af ; restore the character + ld (de),a + ld a,'?' ; print a ? + call outc + sub a ; and the rest of the line + call printstr + jp rstart +qsorry: + push de ; ** Sorry ** +asorry: + ld de,sorry + jr handleerror + +;************************************************************* +; +; *** GETLN *** FNDLN (& FRIENDS) *** +; +; 'GETLN' READS A INPUT LINE INTO 'BUFFER'. IT FIRST PROMPT +; THE CHARACTER IN A (GIVEN BY THE CALLER), THEN IT FILLS +; THE BUFFER AND ECHOS. IT IGNORES LF'S AND NULLS, BUT STILL +; ECHOS THEM BACK. RUB-OUT IS USED TO CAUSE IT TO DELETE +; THE LAST CHARACTER (IF THERE IS ONE), AND ALT-MOD IS USED TO +; CAUSE IT TO DELETE THE WHOLE LINE AND START IT ALL OVER. +; CR SIGNALS THE END OF A LINE, AND CAUSE 'GETLN' TO RETURN. +; +; 'FNDLN' FINDS A LINE WITH A GIVEN LINE # (IN HL) IN THE +; TEXT SAVE AREA. DE IS USED AS THE TEXT POINTER. IF THE +; LINE IS FOUND, DE WILL POINT TO THE BEGINNING OF THAT LINE +; (I.E., THE LOW BYTE OF THE LINE #), AND FLAGS ARE NC & Z. +; IF THAT LINE IS NOT THERE AND A LINE WITH A HIGHER LINE # +; IS FOUND, DE POINTS TO THERE AND FLAGS ARE NC & NZ. IF +; WE REACHED THE END OF TEXT SAVE AREA AND CANNOT FIND THE +; LINE, FLAGS ARE C & NZ. +; 'FNDLN' WILL INITIALIZE DE TO THE BEGINNING OF THE TEXT SAVE +; AREA TO START THE SEARCH. SOME OTHER ENTRIES OF THIS +; ROUTINE WILL NOT INITIALIZE DE AND DO THE SEARCH. +; 'FNDLNP' WILL START WITH DE AND SEARCH FOR THE LINE #. +; 'FNDNXT' WILL BUMP DE BY 2, FIND A CR AND THEN START SEARCH. +; 'FNDSKP' USE DE TO FIND A CR, AND THEN START SEARCH. +;************************************************************* +getline: + call outc ; ** GetLine ** + ld de,buffer ; prompt and initalise pointer +gl1: + call chkio ; check keyboard + jr z,gl1 ; no input, so wait + cp bs ; erase last character? + jr z,gl3 ; yes + call outc ; echo character + cp lf ; ignore lf + jr z,gl1 + or a ; ignore null + jr z,gl1 + cp ctrlu ; erase the whole line? + jr z,gl4 ; yes + ld (de),a ; save the input + inc de ; and increment pointer + cp cr ; was it cr? + ret z ; yes, end of line + ld a,e ; any free space left? + cp bufend & 0ffh + jr nz,gl1 ; yes, get next char +gl3: + ld a,e ; delete last character + cp buffer & 0ffh ; if there are any? + jr z,gl4 ; no, redo whole line + dec de ; yes, back pointer + ld a,5ch ; and echo a backslash + call outc + jr gl1 ; and get next character +gl4: + call crlf ; redo entire line + ld a,5eh + jr getline +findline: + ld a,h ; ** FindLine ** + or a ; check the sign of hl + jp m,qhow ; it cannot be negative + ld de,textbegin ; initialise the text pointer +findlineptr: +fl1: + push hl ; save line number + ld hl,(textunfilled) ; check if we passed end + dec hl + call comp + pop hl ; retrieve line number + ret c ; c,nz passed end + ld a,(de) ; we didn't; get first byte + sub l ; is this the line? + ld b,a ; compare low order + inc de + ld a,(de) ; get second byte + sbc a,h ; compare high order + jr c,fl2 ; no, not there yet + dec de ; else we either found it + or b ; or it's not there + ret ; nc,z:found; nc,nz:no +findnext: + inc de ; find next line +fl2: + inc de ; just passed first and second byte +findskip: + ld a,(de) ; ** FindSkip ** + cp cr ; try to find cr + jr nz,fl2 ; keep looking + inc de ; found cr, skip over + jr fl1 ; check if end of text + +;************************************************************* +; +; *** PRTSTG *** QTSTG *** PRTNUM *** & PRTLN *** +; +; 'PRTSTG' PRINTS A STRING POINTED BY DE. IT STOPS PRINTING +; AND RETURNS TO CALLER WHEN EITHER A CR IS PRINTED OR WHEN +; THE NEXT BYTE IS THE SAME AS WHAT WAS IN A (GIVEN BY THE +; CALLER). OLD A IS STORED IN B, OLD B IS LOST. +; +; 'QTSTG' LOOKS FOR A BACK-ARROW, SINGLE QUOTE, OR DOUBLE +; QUOTE. IF NONE OF THESE, RETURN TO CALLER. IF BACK-ARROW, +; OUTPUT A CR WITHOUT A LF. IF SINGLE OR DOUBLE QUOTE, PRINT +; THE STRING IN THE QUOTE AND DEMANDS A MATCHING UNQUOTE. +; AFTER THE PRINTING THE NEXT 3 BYTES OF THE CALLER IS SKIPPED +; OVER (USUALLY A JUMP INSTRUCTION. +; +; 'PRTNUM' PRINTS THE NUMBER IN HL. LEADING BLANKS ARE ADDED +; IF NEEDED TO PAD THE NUMBER OF SPACES TO THE NUMBER IN C. +; HOWEVER, IF THE NUMBER OF DIGITS IS LARGER THAN THE # IN +; C, ALL DIGITS ARE PRINTED ANYWAY. NEGATIVE SIGN IS ALSO +; PRINTED AND COUNTED IN, POSITIVE SIGN IS NOT. +; +; 'PRTLN' PRINTS A SAVED TEXT LINE WITH LINE # AND ALL. +;************************************************************* +printstr: + ld b,a +ps1: + ld a,(de) ; get a character + inc de ; bump pointer + cp b ; same as old A? + ret z ; yes, return + call outc ; no, show character + cp cr ; was it a cr? + jr nz,ps1 ; no, next character + ret ; yes, returns +qtstg: + call testc ; ** Qtstg ** + .db 22h ; is it a double quote + .db qt3-$-1 + ld a,22h +qt1: + call printstr ; print until another + cp cr + pop hl + jp z,runnxl +qt2: + inc hl ; skip 3 bytes on return + inc hl + inc hl + jp (hl) ; return +qt3: + call testc ; is it a single quote + .db 27h + .db qt4-$-1 + ld a,27h + jr qt1 +qt4: + call testc ; is it back-arrow + .db '_' + .db qt5-$-1 + ld a,8dh ; yes, cr without lf + call outc + call outc + pop hl ; return address + jr qt2 +qt5: + ret ; none of the above + +printnum: + ld b,0h ; ** PrintNum ** + call checksign ; check sign + jp p,pn1 ; no sign + ld b,'-' + dec c +pn1: + push de ; save + ld de, 000ah ; decimal + push de ; save as flag + dec c ; c=spaces + push bc ; save sign & space +pn2: + call divide ; divide hl by 10 + ld a,b ; result 0? + or c + jr z,pn3 ; yes, we got all + ex (sp),hl ; no, save remainder + dec l ; and count space + push hl ; hl is old bc + ld h,b ; mobed result to bc + ld l,c + jr pn2 ; and divide by 10 +pn3: + pop bc ; we got all digits +pn4: + dec c + ld a,c ; look at space count + or a + jp m,pn5 ; no leading spaces + ld a,' ' ; print a leading space + call outc + jr pn4 ; any more? +pn5: + ld a,b ; print sign + or a + call nz,outc + ld e,l ; last remainder in e +pn6: + ld a,e ; check digit in e + cp lf ; lf is flag for no more + pop de + ret z ; if yes, return + add a,30h ; else convert to ascii + call outc ; and print the digit + jr pn6 ; next digit + +printline: + ld a,(de) ; ** PrintLine ** + ld l,a ; low order line number + inc de + ld a,(de) ; high order + ld h,a + inc de + ld c,04h ; print 4 digit line number + call printnum + ld a,' ' ; followed by a space + call outc + sub a ; and the the rest + call printstr + ret + +;************************************************************* +; +; *** MVUP *** MVDOWN *** POPA *** & PUSHA *** +; +; 'MVUP' MOVES A BLOCK UP FROM WHERE DE-> TO WHERE BC-> UNTIL +; DE = HL +; +; 'MVDOWN' MOVES A BLOCK DOWN FROM WHERE DE-> TO WHERE HL-> +; UNTIL DE = BC +; +; 'POPA' RESTORES THE 'FOR' LOOP VARIABLE SAVE AREA FROM THE +; STACK +; +; 'PUSHA' STACKS THE 'FOR' LOOP VARIABLE SAVE AREA INTO THE +; STACK +;************************************************************* +mvup: + call comp ; ** mvup ** + ret z ; de = hl, return + ld a,(de) ; get one byte + ld (bc),a ; then copy it + inc de ; increase both pointers + inc bc + jr mvup ; until done +mvdown: + ld a,b ; ** mvdown ** + sub d ; check if de = bc + jp nz,md1 ; no, go move + ld a,c ; maybe, other byte + sub e + ret z ; yes, return +md1: + dec de ; else move a byte + dec hl ; but first decrease both pointers + ld a,(de) ; and then do it + ld (hl),a + jr mvdown ; loop back +popa: + pop bc ; bc = return address + pop hl ; restore loopvar + ld (loopvar),hl + ld a,h + or l + jr z,pp1 ; all done, so return + pop hl + ld (loopinc),hl + pop hl + ld (looplmt),hl + pop hl + ld (loopln),hl + pop hl + ld (loopptr),hl +pp1: + push bc ; bc = return address + ret +pusha: + ld hl,stacklimit ; ** PushA ** + call changesign + pop bc ; bc = return address + add hl,sp ; is stack near the top? + jp nc,qsorry ; yes, sorry + ld hl,(loopvar) ; else save loop variables + ld a,h + or l + jr z,pu1 ; only when loopvar not 0 + ld hl,(loopptr) + push hl + ld hl,(loopln) + push hl + ld hl,(looplmt) + push hl + ld hl,(loopinc) + push hl + ld hl,(loopvar) +pu1: + push hl + push bc ; bc = return address + ret + +testvar: + call skipspace ; ** testvar ** + sub '@' ; test variables + ret c ; not a variable + jr nz,tv1 ; not @ array + inc de ; is is the @ array + call parn ; @ should be followed by (expr) + add hl,hl ; as its index + jr c,qhow ; is index too big? + push de ; will it override text? + ex de,hl + call size ; find the size of free + call comp + jp c,asorry ; yes, sorry + ld hl,varbegin ; no, get address of @(expr) and + call subde ; put it in hl + pop de + ret +tv1: + cp 1bh ; not @, is it A to Z + ccf + ret c + inc de ; if A trhough Z + ld hl,varbegin ; calculate address of that variable + rlca ; and return it in hl + add a,l ; with the c flag cleared + ld l,a + ld a,0 + adc a,h + ld h,a + ret + +testnum: + ld hl,0000h ; ** TestNum ** + ld b,h ; test if the text is a number + call skipspace +tn1: + cp '0' ; if not,return 0 in b and hl + ret c + cp ':' ; if a digit, convert to binary in + ret nc ; b and hl + ld a,0f0h ; set b to number of digits + and h ; if h>255, there is no room for + jr nz,qhow ; next digit + inc b ; b counts number of digits + push bc + ld b,h ; hl=10*hl+(new digit) + ld c,l + add hl,hl ; where 10* is done by shift and add + add hl,hl + add hl,bc + add hl,hl + ld a,(de) ; and (digit) is by stripping the + inc de ; ascii code + and 0fh + add a,l + ld l,a + ld a,0 + adc a,h + ld h,a + pop bc + ld a,(de) + jp p,tn1 +qhow: + push de ; ** Error How? ** +ahow: + ld de,how + jp handleerror + +msg1 .db "TASTY BASIC",cr +how .db "HOW?",cr +ok .db "OK",cr +what .db "WHAT?",cr +sorry .db "SORRY",cr + +;************************************************************* +; +; *** MAIN *** +; +; THIS IS THE MAIN LOOP THAT COLLECTS THE TINY BASIC PROGRAM +; AND STORES IT IN THE MEMORY. +; +; AT START, IT PRINTS OUT "(CR)OK(CR)", AND INITIALIZES THE +; STACK AND SOME OTHER INTERNAL VARIABLES. THEN IT PROMPTS +; ">" AND READS A LINE. IF THE LINE STARTS WITH A NON-ZERO +; NUMBER, THIS NUMBER IS THE LINE NUMBER. THE LINE NUMBER +; (IN 16 BIT BINARY) AND THE REST OF THE LINE (INCLUDING CR) +; IS STORED IN THE MEMORY. IF A LINE WITH THE SAME LINE +; NUMBER IS ALREADY THERE, IT IS REPLACED BY THE NEW ONE. IF +; THE REST OF THE LINE CONSISTS OF A CR ONLY, IT IS NOT STORED +; AND ANY EXISTING LINE WITH THE SAME LINE NUMBER IS DELETED. +; +; AFTER A LINE IS INSERTED, REPLACED, OR DELETED, THE PROGRAM +; LOOPS BACK AND ASKS FOR ANOTHER LINE. THIS LOOP WILL BE +; TERMINATED WHEN IT READS A LINE WITH ZERO OR NO LINE +; NUMBER; AND CONTROL IS TRANSFERED TO "DIRECT". +; +; TINY BASIC PROGRAM SAVE AREA STARTS AT THE MEMORY LOCATION +; LABELED "TXTBGN" AND ENDS AT "TXTEND". WE ALWAYS FILL THIS +; AREA STARTING AT "TXTBGN", THE UNFILLED PORTION IS POINTED +; BY THE CONTENT OF A MEMORY LOCATION LABELED "TXTUNF". +; +; THE MEMORY LOCATION "CURRNT" POINTS TO THE LINE NUMBER +; THAT IS CURRENTLY BEING INTERPRETED. WHILE WE ARE IN +; THIS LOOP OR WHILE WE ARE INTERPRETING A DIRECT COMMAND +; (SEE NEXT SECTION). "CURRNT" SHOULD POINT TO A 0. +;************************************************************* +rstart: + ld sp,stack +st1: + call crlf + sub a ; a=0 + ld de,ok ; print ok + call printstr + ld hl,st2 + 1 ; literal zero + ld (current),hl ; reset current line pointer +st2: + ld hl,0000h + ld (loopvar),hl + ld (stkgos),hl +st3: + ld a,'>' ; initialise prompt + call getline + push de ; de points to end of line + ld de,buffer ; point de to beginning of line + call testnum ; check if it is a number + call skipspace + ld a,h ; hl = value of the number, or + or l ; 0 if no number was found + pop bc ; bc points to end of line + jp z,direct + dec de ; back up de and save the value of + ld a,h ; the value of the line number there + ld (de),a + dec de + ld a,l + ld (de),a + push bc ; bc,de point to begin,end + push de + ld a,c + sub e + + push af ; a = number of bytes in line + call findline ; find this line in save area + push de ; de points to save area + jr nz,st4 ; nz: line not found + push de ; z: found, delete it + call findnext ; find next line + ; de -> next line + pop bc ; bc -> line to be deleted + ld hl,(textunfilled) ; hl -> unfilled text area + call mvup ; move up to delete + ld h,b ; txtunf -> unfilled area + ld l,c + ld (textunfilled),hl +st4: + pop bc ; get ready to insert + ld hl,(textunfilled) ; but first check if the length + pop af ; of new line is 3 (line# and cr) + push hl + cp 3h ; if so, do not insert + jr z,rstart ; must clear the stack + add a,l ; calculate new txtunf + ld l,a + ld a,0 + adc a,h + ld h,a ; hl -> new unfilled area + ld de,textend ; check to see if there is space + call comp + jp nc,qsorry ; no, sorry + ld (textunfilled),hl ; ok, update textunfilled + pop de ; de -> old unfilled area + call mvdown + pop de ; de,hl -> begin,end + pop hl + call mvup ; copy new line to save area + jr st3 + +;************************************************************* +; +; WHAT FOLLOWS IS THE CODE TO EXECUTE DIRECT AND STATEMENT +; COMMANDS. CONTROL IS TRANSFERED TO THESE POINTS VIA THE +; COMMAND TABLE LOOKUP CODE OF 'DIRECT' AND 'EXEC' IN LAST +; SECTION. AFTER THE COMMAND IS EXECUTED, CONTROL IS +; TRANSFERED TO OTHERS SECTIONS AS FOLLOWS: +; +; FOR 'LIST', 'NEW', AND 'STOP': GO BACK TO 'RSTART' +; FOR 'RUN': GO EXECUTE THE FIRST STORED LINE IF ANY, ELSE +; GO BACK TO 'RSTART'. +; FOR 'GOTO' AND 'GOSUB': GO EXECUTE THE TARGET LINE. +; FOR 'RETURN' AND 'NEXT': GO BACK TO SAVED RETURN LINE. +; FOR ALL OTHERS: IF 'CURRENT' -> 0, GO TO 'RSTART', ELSE +; GO EXECUTE NEXT COMMAND. (THIS IS DONE IN 'FINISH'.) +;************************************************************* +; +; *** NEW *** STOP *** RUN (& FRIENDS) *** & GOTO *** +; +; 'NEW(CR)' SETS 'TXTUNF' TO POINT TO 'TXTBGN' +; +; 'END(CR)' GOES BACK TO 'RSTART' +; +; 'RUN(CR)' FINDS THE FIRST STORED LINE, STORE ITS ADDRESS (IN +; 'CURRENT'), AND START EXECUTE IT. NOTE THAT ONLY THOSE +; COMMANDS IN TAB2 ARE LEGAL FOR STORED PROGRAM. +; +; THERE ARE 3 MORE ENTRIES IN 'RUN': +; 'RUNNXL' FINDS NEXT LINE, STORES ITS ADDR. AND EXECUTES IT. +; 'RUNTSL' STORES THE ADDRESS OF THIS LINE AND EXECUTES IT. +; 'RUNSML' CONTINUES THE EXECUTION ON SAME LINE. +; +; 'GOTO EXPR(CR)' EVALUATES THE EXPRESSION, FIND THE TARGET +; LINE, AND JUMP TO 'RUNTSL' TO DO IT. +;************************************************************* + +new: + call endchk ; ** New ** + ld hl,textbegin + ld (textunfilled),hl +endd: + call endchk ; ** End ** + jp rstart +run: + call endchk ; ** Run ** + ld de,textbegin +runnxl: + ld hl,0h ; ** Run Next Line ** + call findlineptr + jp c,rstart +runtsl: + ex de,hl ; ** Run Tsl + ld (current),hl ; set current -> line # + ex de,hl + inc de + inc de +runsml: + call chkio ; ** Run Same Line ** + ld hl, tab2-1 ; find the command in table 2 + jp exec ; and execute it +goto: + call expr + push de ; save for error routine + call endchk ; must find a cr + call findline ; find the target line + jp nz, ahow ; no such line # + pop af ; clear the pushed de + jr runtsl ; go do it + +;************************************************************* +; +; *** LIST *** & PRINT *** +; +; LIST HAS TWO FORMS: +; 'LIST(CR)' LISTS ALL SAVED LINES +; 'LIST #(CR)' START LIST AT THIS LINE # +; YOU CAN STOP THE LISTING BY CONTROL C KEY +; +; PRINT COMMAND IS 'PRINT ....;' OR 'PRINT ....(CR)' +; WHERE '....' IS A LIST OF EXPRESIONS, FORMATS, BACK- +; ARROWS, AND STRINGS. THESE ITEMS ARE SEPERATED BY COMMAS. +; +; A FORMAT IS A POUND SIGN FOLLOWED BY A NUMBER. IT CONTROLS +; THE NUMBER OF SPACES THE VALUE OF A EXPRESION IS GOING TO +; BE PRINTED. IT STAYS EFFECTIVE FOR THE REST OF THE PRINT +; COMMAND UNLESS CHANGED BY ANOTHER FORMAT. IF NO FORMAT IS +; SPECIFIED, 6 POSITIONS WILL BE USED. +; +; A STRING IS QUOTED IN A PAIR OF SINGLE QUOTES OR A PAIR OF +; DOUBLE QUOTES. +; +; A BACK-ARROW MEANS GENERATE A (CR) WITHOUT (LF) +; +; A (CRLF) IS GENERATED AFTER THE ENTIRE LIST HAS BEEN +; PRINTED OR IF THE LIST IS A NULL LIST. HOWEVER IF THE LIST +; ENDED WITH A COMMA, NO (CRLF) IS GENERATED. +;************************************************************* +list: + call testnum ; check if there is a number + call endchk ; if no number we get a 0 + call findline ; find this or next line +ls1: + jp c,rstart + call printline ; print the line + call chkio ; stop on ctrl-c + call findlineptr ; find the next line + jr ls1 ; and loop back + +print: + ld c,6 ; c = number of spaces + call testc ; is it a semicolon? + .db ';' + .db pr2-$-1 + call crlf + jr runsml +pr2: + call testc ; is it a cr? + .db cr + .db pr0-$-1 + call crlf + jr runnxl +pr0: + call testc ; is it format? + .db '#' + .db pr1-$-1 + call expr + ld c,l + jr pr3 +pr1: + call qtstg ; is it a string? + jr pr8 +pr3: + call testc ; is it a comma? + .db ',' + .db pr6-$-1 + call fin + jr pr0 +pr6: + call crlf ; list ends + call finish +pr8: + call expr ; evaluate the expression + push bc + call printnum + pop bc + jr pr3 + +;************************************************************* +; +; *** GOSUB *** & RETURN *** +; +; 'GOSUB EXPR;' OR 'GOSUB EXPR (CR)' IS LIKE THE 'GOTO' +; COMMAND, EXCEPT THAT THE CURRENT TEXT POINTER, STACK POINTER +; ETC. ARE SAVE SO THAT EXECUTION CAN BE CONTINUED AFTER THE +; SUBROUTINE 'RETURN'. IN ORDER THAT 'GOSUB' CAN BE NESTED +; (AND EVEN RECURSIVE), THE SAVE AREA MUST BE STACKED. +; THE STACK POINTER IS SAVED IN 'STKGOS', THE OLD 'STKGOS' IS +; SAVED IN THE STACK. IF WE ARE IN THE MAIN ROUTINE, 'STKGOS' +; IS ZERO (THIS WAS DONE BY THE "MAIN" SECTION OF THE CODE), +; BUT WE STILL SAVE IT AS A FLAG FOR NO FURTHER 'RETURN'S. +; +; 'RETURN(CR)' UNDOS EVERYTHING THAT 'GOSUB' DID, AND THUS +; RETURN THE EXECUTION TO THE COMMAND AFTER THE MOST RECENT +; 'GOSUB'. IF 'STKGOS' IS ZERO, IT INDICATES THAT WE +; NEVER HAD A 'GOSUB' AND IS THUS AN ERROR. +;************************************************************* +gosub: + call pusha ; ** Gosub ** + call expr ; save the current "FOR" params + push de ; and text pointer + call findline ; find the target line + jp nz,ahow ; how? because it doesn't exist + ld hl,(current) ; found it, save old 'current' + push hl + ld hl,(stkgos) ; and 'stkgos' + push hl + ld hl,0000h ; and load new ones + ld (loopvar),hl + add hl,sp + ld (stkgos),hl + jp runtsl ; and run the line +return: + call endchk ; there must be a cr + ld hl,(stkgos) ; check old stack pointer + ld a,h ; + or l + jp z,what ; what? not found + ld sp,hl ; otherwise restore it + pop hl + ld (stkgos),hl + pop hl + ld (current),hl ; and old 'current' + pop de ; and old text pointer + call popa ; and old 'FOR' params + call finish ; and we're back + +;************************************************************* +; +; *** FOR *** & NEXT *** +; +; 'FOR' HAS TWO FORMS: +; 'FOR VAR=EXP1 TO EXP2 STEP EXP3' AND 'FOR VAR=EXP1 TO EXP2' +; THE SECOND FORM MEANS THE SAME THING AS THE FIRST FORM WITH +; EXP3=1. (I.E., WITH A STEP OF +1.) +; TBI WILL FIND THE VARIABLE VAR, AND SET ITS VALUE TO THE +; CURRENT VALUE OF EXP1. IT ALSO EVALUATES EXP2 AND EXP3 +; AND SAVE ALL THESE TOGETHER WITH THE TEXT POINTER ETC. IN +; THE 'FOR' SAVE AREA, WHICH CONSISTS OF 'LOPVAR', 'LOPINC', +; 'LOPLMT', 'LOPLN', AND 'LOPPT'. IF THERE IS ALREADY SOME- +; THING IN THE SAVE AREA (THIS IS INDICATED BY A NON-ZERO +; 'LOPVAR'), THEN THE OLD SAVE AREA IS SAVED IN THE STACK +; BEFORE THE NEW ONE OVERWRITES IT. +; TBI WILL THEN DIG IN THE STACK AND FIND OUT IF THIS SAME +; VARIABLE WAS USED IN ANOTHER CURRENTLY ACTIVE 'FOR' LOOP. +; IF THAT IS THE CASE, THEN THE OLD 'FOR' LOOP IS DEACTIVATED. +; (PURGED FROM THE STACK..) +; +; 'NEXT VAR' SERVES AS THE LOGICAL (NOT NECESSARILLY PHYSICAL) +; END OF THE 'FOR' LOOP. THE CONTROL VARIABLE VAR. IS CHECKED +; WITH THE 'LOPVAR'. IF THEY ARE NOT THE SAME, TBI DIGS IN +; THE STACK TO FIND THE RIGHT ONE AND PURGES ALL THOSE THAT +; DID NOT MATCH. EITHER WAY, TBI THEN ADDS THE 'STEP' TO +; THAT VARIABLE AND CHECK THE RESULT WITH THE LIMIT. IF IT +; IS WITHIN THE LIMIT, CONTROL LOOPS BACK TO THE COMMAND +; FOLLOWING THE 'FOR'. IF OUTSIDE THE LIMIT, THE SAVE AREA +; IS PURGED AND EXECUTION CONTINUES. +;************************************************************* + +for: + call pusha ; save old save area + call setval ; set the control variable + dec hl ; its address is hl + ld (loopvar),hl ; save that + ld hl,tab5-1 ; use 'exec' to find 'TO' + jp exec +fr1: + call expr ; evaluate the limit + ld (looplmt),hl ; and save it + ld hl,tab6-1 ; use 'exec' to find 'STEP' + jp exec +fr2: + call expr ; found 'STEP' + jr fr4 +fr3: + ld hl,0001h ; no 'STEP' so set to 1 +fr4: + ld (loopinc),hl ; and save that too +fr5: + ld hl,(current) ; save current line number + ld (loopln),hl + ex de,hl ; and text pointer + ld (loopptr),hl + ld bc,0ah ; dig into stack to find loopvar + ld hl,(loopvar) + ex de,hl + ld h,b + ld l,b + add hl,sp + .db 3eh +fr7: + add hl,bc + ld a,(hl) + inc hl + or (hl) + jr z,fr8 + ld a,(hl) + dec hl + cp d + jr nz,fr7 + ld a,(hl) + cp e + jr nz,fr7 + ex de,hl + ld hl,0000h + add hl,sp + ld b,h + ld c,l + ld hl,000ah + add hl,de + call mvdown + ld sp,hl +fr8: + ld hl,(loopptr) ; all done + ex de,hl + call finish +next: + call testvar ; get address of variable + jp c,qwhat ; what, no variable + ld (varnext),hl ; yes, save it +nx0: + push de ; save the text pointer + ex de,hl + ld hl,(loopvar) ; get the variable in 'FOR' + ld a,h + or l ; if 0, there never was one + jp z,awhat + call comp ; else check them + jr z,nx3 ; yes, they agree + pop de ; no, complete current loop + call popa + ld hl,(varnext) ; and pop one level + jr nx0 ; go check again +nx3: + ld e,(hl) + inc hl + ld d,(hl) ; de = value of variable + ld hl,(loopinc) + push hl + ld a,h + xor d + ld a,d + add hl,de + jp m,nx4 + xor h + jp m,nx5 +nx4: + ex de,hl + ld hl,(loopvar) + ld (hl),e + inc hl + ld (hl),d + ld hl,(looplmt) + pop af + or a + jp p,nx1 ; step > 0 + ex de,hl ; step < 0 +nx1: + call ckhlde ; compare with limit + pop de ; restore the text pointer + jr c,nx2 ; over the limit + ld hl,(loopln) ; within the limit + ld (current),hl + ld hl,(loopptr) + ex de,hl + call finish +nx5: + pop hl + pop de +nx2: + call popa ; purge this loop + call finish ; + + +init: + ld (ocsw),a ; enable output control switch + ld d,19h ; clear the screen +patloop: + call crlf ; by outputting 25 clear lines + dec d + jr nz,patloop + ld de,msg1 ; then output welcome message + call printstr + ld hl,start ; initialise random pointer + ld (rndptr),hl + ld hl,textbegin ; initialise text area pointers + ld (textunfilled),hl + jp rstart + +chkio: + ; in a,(tty_status) ; check if character available + ; bit rx_full,a + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL + ; GET CONSOLE INPUT STATUS VIA HBIOS + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + RST 08 ; HBIOS RETURNS STATUS IN A + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + ret z ; no, return +; in a,(tty_data) ; get the character + PUSH BC + PUSH DE + PUSH HL + ; INPUT CHARACTER FROM CONSOLE VIA HBIOS + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + + push bc ; is it a lf? + ld b,a + sub lf + jr z,io1 ; yes, ignore an return + ld a,b ; no, restore a and bc + pop bc + cp ctrlo ; is it ctrl-o? + jr nz,io2 ; no, done + ld a,(ocsw) ; toggle output control switch + cpl + ld (ocsw),a + jr chkio ; get next character +io1: + ld a,0h ; clear + or a ; set the z-flag + pop bc ; restore bc + ret ; return with z set +io2: + cp 60h ; is it lower case? + jp c,io3 ; no + and 0dfh ; yes, make upper case +io3: + cp ctrlc ; is it ctrl-c? + ret nz ; no + jp rstart ; yes, restart tasty basic +crlf: + ld a,cr +outc: +#if zemu + push af + ld a,(ocsw) ; check output control switch + or a + jr nz,uart_tx ; output is enabled + pop af ; output is disabled + ret ; so return +uart_tx: + call uart_tx_ready ; see if transmit is available + pop af ; restore the character + out (tty_data),a ; and send it + cp cr ; was it a cr? + ret nz ; no, return + ld a,lf ; send a lf + call outc + ld a,cr ; restore register + ret ; and return +uart_tx_ready: + push af +uart_tx_ready_loop: + in a,(tty_status) + bit tx_empty,a + jp z,uart_tx_ready_loop + pop af + ret +#else ; USE HBIOS + ; SAVE ALL INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL + ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS + LD E,A ; OUTPUT CHAR TO E + LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + RST 08 ; HBIOS OUTPUTS CHARACTDR + ; RESTORE ALL REGISTERS + POP HL + POP DE + POP BC + POP AF + RET +#endif + +;************************************************************* +; +; *** TABLES *** DIRECT *** & EXEC *** +; +; THIS SECTION OF THE CODE TESTS A STRING AGAINST A TABLE. +; WHEN A MATCH IS FOUND, CONTROL IS TRANSFERED TO THE SECTION +; OF CODE ACCORDING TO THE TABLE. +; +; AT 'EXEC', DE SHOULD POINT TO THE STRING AND HL SHOULD POINT +; TO THE TABLE-1. AT 'DIRECT', DE SHOULD POINT TO THE STRING. +; HL WILL BE SET UP TO POINT TO TAB1-1, WHICH IS THE TABLE OF +; ALL DIRECT AND STATEMENT COMMANDS. +; +; A '.' IN THE STRING WILL TERMINATE THE TEST AND THE PARTIAL +; MATCH WILL BE CONSIDERED AS A MATCH. E.G., 'P.', 'PR.', +; 'PRI.', 'PRIN.', OR 'PRINT' WILL ALL MATCH 'PRINT'. +; +; THE TABLE CONSISTS OF ANY NUMBER OF ITEMS. EACH ITEM +; IS A STRING OF CHARACTERS WITH BIT 7 SET TO 0 AND +; A JUMP ADDRESS STORED HI-LOW WITH BIT 7 OF THE HIGH +; BYTE SET TO 1. +; +; END OF TABLE IS AN ITEM WITH A JUMP ADDRESS ONLY. IF THE +; STRING DOES NOT MATCH ANY OF THE OTHER ITEMS, IT WILL +; MATCH THIS NULL ITEM AS DEFAULT. +;************************************************************* +tab1: ; direct commands + .db "LIST" + dwa(list) + .db "RUN" + dwa(run) + .db "NEW" + dwa(new) +tab2: ; direct/statement + .db "NEXT" + dwa(next) + .db "LET" + dwa(let) + .db "IF" + dwa(iff) + .db "GOTO" + dwa(goto) + .db "GOSUB" + dwa(gosub) + .db "RETURN" + dwa(return) + .db "REM" + dwa(rem) + .db "FOR" + dwa(for) + .db "INPUT" + dwa(input) + .db "PRINT" + dwa(print) + .db "POKE" + dwa(poke) + .db "END" + dwa(endd) + dwa(deflt) +tab4: ; functions + .db "PEEK" + dwa(peek) + .db "RND" + dwa(rnd) + .db "ABS" + dwa(abs) + .db "USR" + dwa(usrexec) + .db "SIZE" + dwa(size) + dwa(xp40) +tab5: ; 'TO' in 'FOR' + .db "TO" + dwa(fr1) +tab6: ; 'STEP' in 'FOR' + .db "STEP" + dwa(fr2) + dwa(fr3) +tab8: ; relational operators + .db ">=" + dwa(xp11) + .db "#" + dwa(xp12) + .db ">" + dwa(xp13) + .db "=" + dwa(xp15) + .db "<=" + dwa(xp14) + .db "<" + dwa(xp16) + dwa(xp17) + +direct: + ld hl,tab1-1 ; ** Direct ** +exec: + call skipspace ; ** Exec ** + push de +ex1: + ld a,(de) + inc de + cp 23h + jr z,ex3 + inc hl + cp (hl) + jr z,ex1 + ld a,7fh + dec de + cp (hl) + jr c,ex5 +ex2: + inc hl + cp (hl) + jr nc,ex2 + inc hl + pop de + jr exec +ex3: + ld a,7fh +ex4: + inc hl + cp (hl) + jr nc,ex4 +ex5: + ld a,(hl) + inc hl + ld l,(hl) + and 7fh + ld h,a + pop af + jp (hl) + +;------------------------------------------------------------------------------- + +lstrom: ; all above can be rom +; .org TBC_SIZ+09feh +usrvector: .db usrfunc & 0ffh ; location of user defined + .db (usrfunc >> 8) & 0ffh ; function + +; .org TBC_SIZ+0a00h ; following must be in ram +usrfunc jp qhow ; default user defined function + +codend .equ $ + +; .org TBC_SIZ+01000h ; start of state +ocsw .DS 1 ; output control switch +current .DS 2 ; points to current line +stkgos .DS 2 ; saves sp in 'GOSUB' +varnext .ds 2 ; temp storage +stkinp .ds 2 ; save sp in 'INPUT' +loopvar .ds 2 ; 'FOR' loop save area +loopinc .ds 2 ; loop increment +looplmt .ds 2 ; loop limit +loopln .ds 2 ; loop line number +loopptr .ds 2 ; loop text pointer +rndptr .ds 2 ; random number pointer +textunfilled .ds 2 ; -> unfilled text area +textbegin .ds 2 ; start of text save area +; .org 07fffh +textend .ds 0 ; end of text area +varbegin .ds 55 ; variable @(0) +buffer .ds 72 ; input buffer +bufend .ds 1 +stacklimit .ds 1 +stack .equ 0fe00h + +;TBC_STACK .EQU $ + +SLACK .EQU (TBC_END - codend) + .FILL SLACK,'t' +; + +; + .ECHO "TASTYBASIC space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" + + .end \ No newline at end of file From eb107c9b54237097143b2caf827e62e99797ce2d Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 28 Oct 2018 15:33:44 +0800 Subject: [PATCH 09/18] Update build process to build additonal ROM image --- Source/HBIOS/Build.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/HBIOS/Build.ps1 b/Source/HBIOS/Build.ps1 index 3a2290ad..e158b601 100644 --- a/Source/HBIOS/Build.ps1 +++ b/Source/HBIOS/Build.ps1 @@ -163,6 +163,10 @@ Copy-Item '..\zsdos\zsdos.bin' 'zsdos.bin' Asm 'dbgmon' Asm 'prefix' Asm 'romldr' +Asm 'nascom' +Asm 'tastybasic' +Asm 'imgpad' +Asm 'imgpad0' if ($Platform -ne "UNA") { Asm 'hbios' '-dROMBOOT' -Output 'hbios_rom.bin' -List 'hbios_rom.lst' @@ -185,7 +189,8 @@ Concat 'prefix.bin','cpm.bin' 'cpm.sys' Concat 'prefix.bin','zsys.bin' 'zsys.sys' # Build 32K OS chunk containing the loader, debug monitor, and OS images -Concat 'romldr.bin', 'dbgmon.bin','cpm.bin','zsys.bin' osimg.bin +Concat 'romldr.bin', 'dbgmon.bin','cpm.bin','zsys.bin', 'imgpad.bin' osimg.bin +Concat 'nascom.bin', 'tastybasic.bin', 'imgpad0.bin' osimg1.bin # # Now the ROM disk image is created. This is done by starting with a From aaf957af4e3ffc92150d52024fdfb33251b58a83 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 28 Oct 2018 18:02:06 +0800 Subject: [PATCH 10/18] Update build process to build additonal ROM image --- Source/HBIOS/Build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/HBIOS/Build.ps1 b/Source/HBIOS/Build.ps1 index e158b601..84e0b717 100644 --- a/Source/HBIOS/Build.ps1 +++ b/Source/HBIOS/Build.ps1 @@ -234,7 +234,7 @@ if ($Platform -eq "UNA") } else { - Concat 'hbios_rom.bin','osimg.bin','osimg.bin','osimg.bin',$RomDiskFile $RomFile + Concat 'hbios_rom.bin','osimg.bin','osimg1.bin','osimg.bin',$RomDiskFile $RomFile Concat 'hbios_app.bin','osimg.bin' $ComFile Concat 'hbios_img.bin','osimg.bin' $ImgFile } From d29ce909a0cb0620968a605c8518afb237f06d68 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Sun, 28 Oct 2018 22:57:28 +0800 Subject: [PATCH 11/18] Fix I/O, buffers and stack --- Source/HBIOS/tastybasic.asm | 150 ++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 84 deletions(-) diff --git a/Source/HBIOS/tastybasic.asm b/Source/HBIOS/tastybasic.asm index 5a35782a..65a7982c 100644 --- a/Source/HBIOS/tastybasic.asm +++ b/Source/HBIOS/tastybasic.asm @@ -23,20 +23,6 @@ #INCLUDE "std.asm" -zemu .equ 0 - -#if zemu -tty_data .equ 7ch ; Z80 Emulator -tty_status .equ 7dh -rx_full .equ 1 -tx_empty .equ 0 -#else -tty_data .equ 67h ; SBC V2 -tty_status .equ 68h -rx_full .equ 1 -tx_empty .equ 0 -#endif - ctrlc .equ 03h bs .equ 08h lf .equ 0ah @@ -46,7 +32,7 @@ ctrlu .equ 15h #define dwa(addr) .db (addr >> 8) + 080h\ .db addr & 0ffh - .org TBC_LOC + .org TBC_LOC start: ld sp,stack ; ** Cold Start ** ld a,0ffh @@ -745,12 +731,12 @@ gl3: cp buffer & 0ffh ; if there are any? jr z,gl4 ; no, redo whole line dec de ; yes, back pointer - ld a,5ch ; and echo a backslash + ld a,bs ; and echo a backslash 5ch ** call outc jr gl1 ; and get next character gl4: call crlf ; redo entire line - ld a,5eh + ld a,'>' ; 5eh ** jr getline findline: ld a,h ; ** FindLine ** @@ -1216,6 +1202,12 @@ new: endd: call endchk ; ** End ** jp rstart + +bye: call endchk ; ** Reboot ** + LD A,BID_BOOT ; BOOT BANK + LD HL,0 ; ADDRESS ZERO + CALL HB_BNKCALL ; DOES NOT RETURN + HALT run: call endchk ; ** Run ** ld de,textbegin @@ -1525,38 +1517,38 @@ patloop: jr nz,patloop ld de,msg1 ; then output welcome message call printstr - ld hl,start ; initialise random pointer + ld hl,start ; initialise random pointer ld (rndptr),hl ld hl,textbegin ; initialise text area pointers ld (textunfilled),hl jp rstart chkio: - ; in a,(tty_status) ; check if character available - ; bit rx_full,a ; SAVE INCOMING REGISTERS (AF IS OUTPUT) PUSH BC PUSH DE PUSH HL - ; GET CONSOLE INPUT STATUS VIA HBIOS - LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C - LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS - RST 08 ; HBIOS RETURNS STATUS IN A - ; RESTORE REGISTERS (AF IS OUTPUT) + ; GET CONSOLE INPUT STATUS VIA HBIOS + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + RST 08 ; HBIOS RETURNS STATUS IN A + + ; RESTORE REGISTERS (AF IS OUTPUT) + + POP HL POP DE POP BC ret z ; no, return -; in a,(tty_data) ; get the character PUSH BC PUSH DE PUSH HL - ; INPUT CHARACTER FROM CONSOLE VIA HBIOS - LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - RST 08 ; HBIOS READS CHARACTDR - LD A,E ; MOVE CHARACTER TO A FOR RETURN - ; RESTORE REGISTERS (AF IS OUTPUT) + ; INPUT CHARACTER FROM CONSOLE VIA HBIOS + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN + ; RESTORE REGISTERS (AF IS OUTPUT) POP HL POP DE POP BC @@ -1587,51 +1579,49 @@ io3: ret nz ; no jp rstart ; yes, restart tasty basic crlf: - ld a,cr -outc: -#if zemu + ld a,cr ; outc will alway output a lf after a cr +outc: ; using a recursice call push af ld a,(ocsw) ; check output control switch or a - jr nz,uart_tx ; output is enabled + jr nz,outen ; output is enabled pop af ; output is disabled - ret ; so return -uart_tx: - call uart_tx_ready ; see if transmit is available - pop af ; restore the character - out (tty_data),a ; and send it - cp cr ; was it a cr? - ret nz ; no, return - ld a,lf ; send a lf - call outc - ld a,cr ; restore register - ret ; and return -uart_tx_ready: - push af -uart_tx_ready_loop: - in a,(tty_status) - bit tx_empty,a - jp z,uart_tx_ready_loop - pop af ret -#else ; USE HBIOS - ; SAVE ALL INCOMING REGISTERS - PUSH AF + +outen: ;call canoutc ; + pop af ; recover character to output + push af PUSH BC PUSH DE PUSH HL - ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS - LD E,A ; OUTPUT CHAR TO E - LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C - LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR - RST 08 ; HBIOS OUTPUTS CHARACTDR - ; RESTORE ALL REGISTERS + ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS + LD E,A ; OUTPUT CHAR TO E + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + RST 08 ; HBIOS OUTPUTS CHARACTER POP HL POP DE POP BC POP AF + cp cr ; was it a cr? + ret nz ; no, return + ld a,lf ; send a lf + call outc + ld a,cr ; restore register RET -#endif + +;canoutc: +; push af +;uart_tx_ready_loop: +; LD C,CIODEV_CONSOLE; CONSOLE UNIT TO C +; LD B,BF_CIOOST ; HBIOS FUNC: CHAR OUTPUT STATUS +; RST 08 ; HBIOS CHECK STATUS +; OR A +; bit tx_empty,a +; jp z,uart_tx_ready_loop +; pop af +; ret + ;************************************************************* ; @@ -1691,6 +1681,8 @@ tab2: ; direct/statement dwa(poke) .db "END" dwa(endd) + .db "BYE" + dwa(bye) dwa(deflt) tab4: ; functions .db "PEEK" @@ -1766,19 +1758,10 @@ ex5: jp (hl) ;------------------------------------------------------------------------------- - -lstrom: ; all above can be rom -; .org TBC_SIZ+09feh +usrfunc jp qhow ; default user defined function usrvector: .db usrfunc & 0ffh ; location of user defined .db (usrfunc >> 8) & 0ffh ; function - -; .org TBC_SIZ+0a00h ; following must be in ram -usrfunc jp qhow ; default user defined function - -codend .equ $ - -; .org TBC_SIZ+01000h ; start of state -ocsw .DS 1 ; output control switch +ocsw .db 0ffh ; output control switch current .DS 2 ; points to current line stkgos .DS 2 ; saves sp in 'GOSUB' varnext .ds 2 ; temp storage @@ -1790,21 +1773,20 @@ loopln .ds 2 ; loop line number loopptr .ds 2 ; loop text pointer rndptr .ds 2 ; random number pointer textunfilled .ds 2 ; -> unfilled text area -textbegin .ds 2 ; start of text save area +;textbegin .ds 2 ; start of text save area ; .org 07fffh -textend .ds 0 ; end of text area +;textend .ds 0 ; end of text area varbegin .ds 55 ; variable @(0) buffer .ds 72 ; input buffer bufend .ds 1 stacklimit .ds 1 -stack .equ 0fe00h - -;TBC_STACK .EQU $ - -SLACK .EQU (TBC_END - codend) +textbegin .equ $ +lstrom: .equ $ +stack .equ 0fd00h +textend .equ stack-0100h + +SLACK .EQU (TBC_END - lstrom) .FILL SLACK,'t' -; - ; .ECHO "TASTYBASIC space remaining: " .ECHO SLACK From c33adf6cf7e6fca8342b12aef388b9ff783ce4f8 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Mon, 29 Oct 2018 23:21:22 +0800 Subject: [PATCH 12/18] Move and align buffers and stack to end of RAM --- Source/HBIOS/tastybasic.asm | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Source/HBIOS/tastybasic.asm b/Source/HBIOS/tastybasic.asm index 65a7982c..07e3516a 100644 --- a/Source/HBIOS/tastybasic.asm +++ b/Source/HBIOS/tastybasic.asm @@ -1726,7 +1726,7 @@ exec: ex1: ld a,(de) inc de - cp 23h + cp '.' jr z,ex3 inc hl cp (hl) @@ -1756,13 +1756,13 @@ ex5: ld h,a pop af jp (hl) - +usrfunc: jp qhow ; default user defined function ;------------------------------------------------------------------------------- -usrfunc jp qhow ; default user defined function -usrvector: .db usrfunc & 0ffh ; location of user defined - .db (usrfunc >> 8) & 0ffh ; function -ocsw .db 0ffh ; output control switch -current .DS 2 ; points to current line +usrvector: .db usrfunc & 0ffh ; location of user defined + .db (usrfunc >> 8) & 0ffh ; function +ocsw .db 0ffh ; output control switch +lstrom: .equ $ +current .DS 2 ; points to current line stkgos .DS 2 ; saves sp in 'GOSUB' varnext .ds 2 ; temp storage stkinp .ds 2 ; save sp in 'INPUT' @@ -1773,18 +1773,18 @@ loopln .ds 2 ; loop line number loopptr .ds 2 ; loop text pointer rndptr .ds 2 ; random number pointer textunfilled .ds 2 ; -> unfilled text area -;textbegin .ds 2 ; start of text save area -; .org 07fffh -;textend .ds 0 ; end of text area -varbegin .ds 55 ; variable @(0) -buffer .ds 72 ; input buffer +textbegin .ds 2 ; start of text save area + + .org 0fcffh +textend .ds 1 +varbegin .ds 55 ; variable @(0) +buffer .ds 72 ; input buffer bufend .ds 1 stacklimit .ds 1 -textbegin .equ $ -lstrom: .equ $ -stack .equ 0fd00h -textend .equ stack-0100h - + + .org 0fdffh +stack .equ $ + SLACK .EQU (TBC_END - lstrom) .FILL SLACK,'t' ; From 81eacdda2476e707964f9fdb5d5415219d69d9fc Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Tue, 30 Oct 2018 05:57:19 +0800 Subject: [PATCH 13/18] Cleanup, get ready for merge. No PIO support yet --- cfg_sbc.asm | 97 ++ hbios.asm | 3285 +++++++++++++++++++++++++++++++++++++++++++++++++++ romldr.asm | 1088 +++++++++++++++++ 3 files changed, 4470 insertions(+) create mode 100644 cfg_sbc.asm create mode 100644 hbios.asm create mode 100644 romldr.asm diff --git a/cfg_sbc.asm b/cfg_sbc.asm new file mode 100644 index 00000000..8e9813ea --- /dev/null +++ b/cfg_sbc.asm @@ -0,0 +1,97 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION DEFAULTS FOR SBC +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUOSC .EQU 8000000 ; CPU OSC FREQ +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SHOULD MATCH ABOVE) +INTMODE .EQU 0 ; 0=NONE, 1=INT MODE 1, 2=INT MODE 2 +; +CRTACT .EQU FALSE ; CRT ACTIVATION AT STARTUP +VDAEMU .EQU EMUTYP_ANSI ; DEFAULT VDA EMULATION (EMUTYP_TTY, EMUTYP_ANSI, ...) +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +HTIMENABLE .EQU FALSE ; TRUE FOR SIMH TIMER SUPPORT +SIMRTCENABLE .EQU FALSE ; SIMH CLOCK DRIVER +DSRTCENABLE .EQU TRUE ; DS-1302 CLOCK DRIVER +DSRTCMODE .EQU DSRTCMODE_STD ; DSRTCMODE_STD, DSRTCMODE_MFPIC +; +ASCIENABLE .EQU FALSE ; TRUE FOR Z180 ASCI SUPPORT +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTOSC .EQU 1843200 ; UART OSC FREQUENCY +ACIAENABLE .EQU FALSE ; TRUE FOR MOTOROLA 6850 ACIA SUPPORT +; +SIOENABLE .EQU FALSE ; TRUE FOR ZILOG SIO SUPPORT +SIOMODE .EQU SIOMODE_ZP ; SIOMODE_RC, SIOMODE_SMB, SIOMODE_ZP +DEFSIOACFG .EQU SER_9600_8N1 ; DEFAULT SERIAL LINE CONFIG +DEFSIOBCFG .EQU SER_9600_8N1 ; DEFAULT SERIAL LINE CONFIG +DEFSIODIV .EQU 8 ; 1=RC2014, SMB, 2/4/8/16/32/64/128/256 for ZP depending on jumper X5 +DEFSIOCLK .EQU 4915200 ; 2457600/4915200=ZP,7372800=RC/SMB - SIO FIXED OSC FREQUENCY +SIODEBUG .EQU FALSE ; +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU BOARD SUPPORT +CVDUENABLE .EQU FALSE ; TRUE FOR CVDU BOARD SUPPORT +NECENABLE .EQU FALSE ; TRUE FOR uPD7220 BOARD SUPPORT +TMSENABLE .EQU FALSE ; TRUE FOR N8 (TMS9918) VIDEO/KBD SUPPORT +VGAENABLE .EQU FALSE ; TRUE FOR VGA VIDEO/KBD SUPPORT +; +SPKENABLE .EQU FALSE ; TRUE FOR RTC LATCH IOBIT SOUND +AYENABLE .EQU FALSE ; TRUE FOR AY PSG SOUND +; +MDENABLE .EQU TRUE ; TRUE FOR ROM/RAM DISK SUPPORT (ALMOST ALWAYS WANT THIS ENABLED) +MDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF MDENABLE = TRUE) +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO3 ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +RFENABLE .EQU FALSE ; TRUE FOR RAM FLOPPY SUPPORT +RFCNT .EQU 1 ; NUMBER OF RAM FLOPPY UNITS (MAX IS 2) +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_SBC ; PPIDEMODE_SBC, PPPIDEMODE_DIO3, PPIDEMODE_MFP, PPIDEMODE_N8, PPIDEMODE_RC +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDMODE .EQU SDMODE_JUHA ; SDMODE_JUHA, SDMODE_CSIO, SDMODE_UART, SDMODE_PPI, SDMODE_DSD +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCSIOFAST .EQU FALSE ; TABLE-DRIVEN BIT INVERTER +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SUPPORT +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PARPORTPROP SD SUPPORT +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +; +PPKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPKENABLE = TRUE) +KBDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF KBDENABLE = TRUE) +; +TERMENABLE .EQU FALSE ; TERM PSEUDO DEVICE, WILL BE ENABLED IF A VDA IS ENABLED +ANSITRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF ANSIENABLE = TRUE) +; +BOOTTYPE .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'Z' ; SELECTION TO INVOKE AT TIMEOUT + +PIOENABLE .EQU FALSE ; TRUE FOR ZILOG PIO SUPPORT +PIOMODE .EQU PIOMODE_ZP ; PIOMODE_ZP=ECB-ZILOG PERIPHERALS BOARD PIOMODE_4P=ECB-4PIO diff --git a/hbios.asm b/hbios.asm new file mode 100644 index 00000000..56116b9c --- /dev/null +++ b/hbios.asm @@ -0,0 +1,3285 @@ +; +;================================================================================================== +; HBIOS +;================================================================================================== +; +; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS +; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512 +; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE +; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP +; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE +; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN +; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF +; THE BANK SWITCHING THAT OCCURS. +; +; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED +; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS: +; +; - ROMBOOT: BOOT FROM A ROM BANK +; +; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM +; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL +; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK +; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY. +; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY +; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL +; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS +; IS INSTALLED. +; +; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE +; +; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING +; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN +; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE +; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE USER RAM +; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. +; +; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK +; +; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED +; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES +; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT +; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE +; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED +; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED +; AFTER HBIOS IS INSTALLED. +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. +; +MODCNT .EQU 0 +#IFDEF ROMBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IFDEF APPBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IFDEF IMGBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IF (MODCNT != 1) + .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT, IMGBOOT!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +; +; +#IF ((PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) +#DEFINE DIAGP $00 +#ENDIF +; +#IFDEF DIAGP +#DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,N + #DEFCONT \ OUT (DIAGP),A + #DEFCONT \ POP AF +#ELSE +#DEFINE DIAG(N) \; +#ENDIF +; +; +; +#IF (INTMODE == 0) +; NO INTERRUPT HANDLING +#DEFINE HB_DI DI +#DEFINE HB_EI ; +#ELSE +; MODE 1 OR 2 INTERRUPT HANDLING +#DEFINE HB_DI DI +#DEFINE HB_EI EI +#ENDIF +; +; +; +#IFNDEF APPBOOT +; + .ORG 0 +; +;================================================================================================== +; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED +;================================================================================================== +; + .FILL (000H - $),0FFH ; RST 0 + JP HB_START + .DW ROM_SIG + .FILL (008H - $),0FFH ; RST 8 + JP HB_INVOKE ; INVOKE HBIOS FUNCTION + .FILL (010H - $),0FFH ; RST 10 + RET + .FILL (018H - $),0FFH ; RST 18 + RET + .FILL (020H - $),0FFH ; RST 20 + RET + .FILL (028H - $),0FFH ; RST 28 + RET + .FILL (030H - $),0FFH ; RST 30 + RET + .FILL (038H - $),0FFH ; RST 38 / IM1 INT +#IF (INTMODE == 1) + JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM +#ELSE + RETI ; RETURN W/ INTS DISABLED +#ENDIF + .FILL (066H - $),0FFH ; NMI + RETN +; + .FILL (070H - $),0FFH ; SIG STARTS AT $80 +; +ROM_SIG: + .DB $76, $B5 ; 2 SIGNATURE BYTES + .DB 1 ; STRUCTURE VERSION NUMBER + .DB 7 ; ROM SIZE (IN MULTIPLES OF 4KB, MINUS ONE) + .DW NAME ; POINTER TO HUMAN-READABLE ROM NAME + .DW AUTH ; POINTER TO AUTHOR INITIALS + .DW DESC ; POINTER TO LONGER DESCRIPTION OF ROM + .DB 0, 0, 0, 0, 0, 0 ; RESERVED FOR FUTURE USE; MUST BE ZERO +; +NAME .DB "ROMWBW v", BIOSVER, ", ", TIMESTAMP, 0 +AUTH .DB "WBW",0 +DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2015, Wayne Warthen, GNU GPL v3", 0 +; + .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO +; +#ENDIF +; +;================================================================================================== +; HBIOS CONFIGURATION BLOCK (HCB) +;================================================================================================== +; + .ORG HCB_LOC +HCB: + JP HB_START +; +CB_MARKER .DB 'W',~'W' ; MARKER +CB_VERSION .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO +; +CB_PLATFORM .DB PLATFORM +CB_CPUMHZ .DB CPUMHZ +CB_CPUKHZ .DW CPUKHZ +CB_RAMBANKS .DB RAMSIZE / 32 +CB_ROMBANKS .DB ROMSIZE / 32 +; +CB_BOOTVOL .DW 0 ; BOOT VOLUME IS UNIT/SLICE, SET BY LOADER +CB_BOOTBID .DB 0 ; BOOT BANK ID, SET BY LOADER +CB_SERDEV .DB 0 ; PRIMARY SERIAL UNIT IS UNIT #0 BY FIAT +CB_CRTDEV .DB $FF ; PRIMARY CRT UNIT, $FF UNTIL AFTER HBIOS INIT +CB_CONDEV .DB $FF ; CONSOLE UNIT, $FF UNTIL AFTER HBIOS INIT +; +; MEMORY MANAGEMENT VARIABLES START AT $20 +; + .FILL (HCB + $20 - $),0 +; +CB_HEAP .DW 0 +CB_HEAPTOP .DW 0 +; +; STANDARD BANK ID'S START AT $D8 +; + .FILL (HCB + $D8 - $),0 +; +CB_BIDCOM .DB BID_COM +CB_BIDUSR .DB BID_USR +CB_BIDBIOS .DB BID_BIOS +CB_BIDAUX .DB BID_AUX +CB_BIDRAMD0 .DB BID_RAMD0 +CB_BIDRAMDN .DB BID_RAMDN +CB_BIDROMD0 .DB BID_ROMD0 +CB_BIDROMDN .DB BID_ROMDN +; + .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB +; +;================================================================================================== +; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) +;================================================================================================== +; +; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING +; + .FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START + .ORG HBX_LOC ; ADJUST FOR RELOCATION +; +; MEMORY LAYOUT: +; +; HBIOS PROXY CODE $FE00 (256 BYTES) +; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) +; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) +; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) +; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) +; +; DEFINITIONS +; +HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BUFFER SIZE +; +; HBIOS IDENTIFICATION DATA BLOCK +; +HBX_IDENT: + .DB 'W',~'W' ; MARKER + .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO +; +;================================================================================================== +; HBIOS ENTRY FOR RST 08 PROCESSING +;================================================================================================== +; +HBX_INVOKE: + LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME + LD A,(HB_CURBNK) ; GET CURRENT BANK + LD (HB_INVBNK),A ; SAVE INVOCATION BANK + + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH + LD A,BID_BIOS ; HBIOS BANK + CALL HBX_BNKSEL ; SELECT IT + LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK + + CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER + + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH + PUSH AF ; SAVE AF (FUNCTION RETURN) + + LD A,(HB_INVBNK) ; LOAD ORIGINAL BANK + CALL HBX_BNKSEL ; SELECT IT + POP AF ; RESTORE AF + LD SP,0 ; RESTORE ORIGINAL STACK FRAME +HBX_INVSP .EQU $ - 2 + + RET ; RETURN TO CALLER +; +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +;; BNKSEL - Switch Memory Bank to Bank in A. +;; Preserve all Registers including Flags. +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKSEL: + ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, + ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT + ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE + ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT + ; OCCURS DURING PROCESSING. + LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK +; +HBX_BNKSEL_INT: +; +#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA)) + #IF (INTMODE == 1) + ; THIS BIT OF ABSURDITY HANDLES A RARE (BUT FATAL) SITUATION + ; WHERE AN IM1 INTERRUPT OCCURS BETWEEN SETTING THE RAM AND + ; ROM SELECTORS. BRACKETING THE INSTRUCTIONS WITH DI/EI + ; IS CONTRAINDICATED BECAUSE THIS ROUTINE IS CALLED BY + ; OTHER ROUTINES THAT MUST CONTROL INT ENABLE AT A HIGHER + ; LEVEL. THE FOLLOWING TECHNIQUE ENSURES THAT YOU ALWAYS + ; SWITCH DIRECTLY FROM THE PREVIOUS BANK TO THE TARGET BANK + ; WITHOUT AN "ERRANT" BANK BEING ACTIVE BETWEEN THE TWO + ; BANK SELECTION I/O INSTRUCTIONS. THE TECHNIQUE IS ONLY + ; NEEDED WHEN USING INT MODE 1 BECAUSE THAT MODE REQUIRES + ; PAGE ONE TO HAVE A VALID INT HANDLER WHENEVER INTS ARE + ; ENABLED. + ;BIT 7,A ; [8] TEST RAM BIT + ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM + OR A ; [4] SET FLAGS + JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM + #ENDIF + OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR +HBX_ROM: + OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR + RET ; DONE +#ENDIF +#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) + BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE + JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE + RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT + ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K +; +HBX_ROM: + RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K + OUT (MPGSEL_0),A ; BANK_0: 0K - 16K + INC A ; + OUT (MPGSEL_1),A ; BANK_1: 16K - 32K + RET ; DONE +#ENDIF +#IF (PLATFORM == PLT_N8) + BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM + JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE +; +HBX_RAM: + RES 7,A ; CLEAR BIT 7 FROM ABOVE + RLCA ; SCALE SELECTOR TO + RLCA ; ... GO FROM Z180 4K PAGE SIZE + RLCA ; ... TO DESIRED 32K PAGE SIZE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +; +HBX_ROM: + OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER + XOR A ; ZERO ACCUM + OUT0 (Z180_BBR),A ; ZERO BANK BASE + LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +; +#ENDIF +#IF (PLATFORM == PLT_MK4) + RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0 + JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD + XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 +HBX_BNKSEL1: + RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR + RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + RET ; DONE +#ENDIF +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Copy Data - Possibly between banks. This resembles CP/M 3, but +; usage of the HL and DE registers is reversed. +; Caller MUST ensure stack is already in high memory. +; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. +; Caller MUST disable ints if IM1 active +; Enter: +; HL = Source Address +; DE = Destination Address +; BC = Number of bytes to copy +; Exit : None +; Uses : AF,BC,DE,HL +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKCPY: + LD (HBX_BC_SP),SP ; PUT STACK + LD SP,HBX_TMPSTK ; ... IN HI MEM + + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; AND SAVE TO RESTORE LATER + PUSH BC ; CUR LEN -> (SP) +; +HBX_BC_LOOP: + EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC + LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE + OR A ; CLEAR CARRY FLAG + SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE + JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT + EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN + CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK + JR HBX_BC_LOOP ; AND REPEAT TILL DONE +; +HBX_BC_LAST: + ; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE + OR A ; CLEAR CARRY + ADC HL,BC ; HL := REM LEN (0 - 127) + EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN + POP BC ; BC := REM LEN + CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES + POP AF ; RECOVER ORIGINAL BANK + CALL HBX_BNKSEL ; SWITCH + + LD SP,$FFFF ; RESTORE STACK +HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE + RET +; +HBX_BC_ITER: + ; HL = SRC ADR, DE = DEST ADR, BC = LEN + PUSH BC ; SAVE COPY LEN + PUSH DE ; FINAL DEST ON STACK + LD DE,HBX_BUF ; SET DEST TO BUF + LD A,(HB_SRCBNK) ; GET SOURCE BANK + CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK + LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR + POP DE ; DE := FINAL DEST + POP BC ; GET LEN BACK IN BC + PUSH HL ; SAVE UPDATED SRC ADR + LD HL,HBX_BUF ; SET SRC ADR TO BUF + LD A,(HB_DSTBNK) ; GET DEST BANK + CALL HBX_BNKSEL ; SWITCH TO DEST BANK + LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR + POP HL ; RECOVER UPDATED SRC ADR + ; HL = UPD SRC, DE = UPD DEST, BC = 0 + RET +; +; CALL A ROUTINE IN ANOTHER BANK. +; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE. +; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO +; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGTET BANK IS PREPARED FOR THEM. +; ON INPUT A=TARGET BANK, HL=TARGET ADDRESS +; +HBX_BNKCALL: + LD (HBX_TGTBNK),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW + LD (HBX_TGTADR),HL ; STUFF ADDRESS TO CALL INTO CODE BELOW + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; SAVE FOR RETURN +HBX_TGTBNK .EQU $ + 1 + LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) + CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK + +HBX_TGTADR .EQU $ + 1 + CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE) + + EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL + PUSH AF ; SAVE AF + LD A,H ; BANK TO RESTORE TO A + CALL HBX_BNKSEL ; RESTORE IT + POP AF ; RECOVER AF + POP HL ; RECOVER HL + RET +; +; PEEK & POKE ROUTINES +; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED +; CALLER MUST DISABLE INTS IF IM1 AND ACCESSING PAGE W/O IM1 INT VECTOR +; +HBX_PEEK: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD E,(HL) + JR HBX_PPRET +; +HBX_POKE: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD (HL),E +; +HBX_PPRET: + POP AF + CALL HBX_BNKSEL + LD SP,0 ; RESTORE ORIGINAL STACK FRAME +HBX_PPSP .EQU $ - 2 + RET +; +; SMALL TEMPORARY STACK FOR USE BY INVOKE, PEEK, AND POKE +; + .FILL 20,$CC ; 10 LEVEL STACK +HBX_TMPSTK .EQU $ +; +; PRIVATE STACK AT END OF HBIOS CODE +; OCCUPIES SPACE BEFORE IVT +; +HBX_STKSIZ .EQU $FF00 - $ + .ECHO "HBIOS PROXY STACK space: " + .ECHO HBX_STKSIZ + .ECHO " bytes.\n" + .FILL HBX_STKSIZ,$FF +HBX_STACK .EQU $ +; +#IF (INTMODE == 2) +; +; HBIOS INTERRUPT VECTOR TABLE (16 ENTRIES) +; +HBX_IVT: + .DW INT_BAD ; IVT_INT1 + .DW INT_BAD ; IVT_INT2 + .DW INT_BAD ; IVT_TIM0 + .DW INT_BAD ; IVT_TIM1 + .DW INT_BAD ; IVT_DMA0 + .DW INT_BAD ; IVT_DMA1 + .DW INT_BAD ; IVT_CSIO + .DW INT_BAD ; IVT_SER0 + .DW INT_BAD ; IVT_SER1 + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; + .DW INT_BAD ; +; +HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 +; +HBX_ITBL: + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT + .DW HB_BADINT +#ENDIF +; +; INTERRUPT HANDLER STUBS +; +; THE FOLLOWING INTERRUPT STUBS RECEIVE CONTROL FROM THE +; INTERRUPT, SETUP A HANDLER VECTOR IN HBIOS AND THEN +; BRANCH TO THE COMMON INTERRUPT DISPATCHER +; +; +INT_IM1: +#IF (INTMODE == 1) + PUSH HL ; SAVE HL + LD HL,HB_IM1INT ; HL := IM1 INT HANDLER IN BIOS BANK + JR HBX_INT ; TO TO ROUTING CODE +#ELSE + RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED +#ENDIF +; +#IF (INTMODE == 2) +; +INT_BAD: ; BAD INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,HB_BADINT ; HL := INT HANDLER IN BIOS BANK + JR HBX_INT ; GO TO ROUTING CODE +; +INT_TIMER: ; TIMER INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,HB_TIMINT ; HL := INT ADR IN BIOS + JR HBX_INT ; GO TO ROUTING CODE +; + #IF (SIOENABLE) +INT_SIO: ; SIO INTERRUPT HANDLER + PUSH HL ; SAVE HL + LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK + JR HBX_INT ; GO TO ROUTING CODE + #ENDIF +; +#ENDIF +; +#IF (INTMODE > 0) +; +; COMMON INTERRUPT DISPATCHING CODE +; SETUP AND CALL HANDLER IN BIOS BANK +; +HBX_INT: ; COMMON INTERRUPT ROUTING CODE +; + LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_STACK ; USE STACK FRAME IN HI MEM + + ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) + PUSH AF ; SAVE AF + PUSH BC ; SAVE BC + PUSH DE ; SAVE DE + PUSH IY ; SAVE IY + + LD A,BID_BIOS ; HBIOS BANK + CALL HBX_BNKSEL_INT ; SELECT IT + + CALL JPHL ; CALL INTERRUPT ROUTINE + + LD A,(HB_CURBNK) ; GET PRE-INT BANK + CALL HBX_BNKSEL ; SELECT IT + + ; RESTORE STATE + POP IY ; RESTORE IY + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF + + LD SP,$FFFF ; RESTORE ORIGINAL STACK FRAME +HBX_INT_SP .EQU $ - 2 + + POP HL ; RESTORE HL + + EI ; ENABLE INTERRUPTS + RETI ; AND RETURN +; +#ENDIF +; +; FILL TO START OF BOUNCE BUFFER +; +HBX_INTFILL .EQU (HBX_XFC - HBX_BUFSIZ - $) + .ECHO "HBIOS INT space remaining: " + .ECHO HBX_INTFILL + .ECHO " bytes.\n" + .FILL HBX_INTFILL,$FF +; +; INTERBANK COPY BUFFER (64 BYTES) +; +HBX_BUF .FILL HBX_BUFSIZ,0 +; +; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) +; +#IFDEF ROMBOOT + .DB BID_BOOT ; CURRENTLY ACTIVE LOW MEMORY BANK ID +#ELSE + .DB BID_USR ; CURRENTLY ACTIVE LOW MEMORY BANK ID +#ENDIF + .DB 0 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION + .DW 0 ; BNKCPY SOURCE ADDRESS + .DB BID_USR ; BNKCPY SOURCE BANK ID + .DW 0 ; BNKCPY DESTINATION ADDRESS + .DB BID_USR ; BNKCPY DESTINATION BANK ID + .DW 0 ; BNKCPY LENGTH + .FILL 6,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE + JP HBX_INVOKE ; FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) + JP HBX_BNKSEL ; FIXED ADR ENTRY FOR HBX_BNKSEL + JP HBX_BNKCPY ; FIXED ADR ENTRY FOR HBX_BNKCPY + JP HBX_BNKCALL ; FIXED ADR ENTRY FOR HBX_BNKCALL + .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) + .DW HBX_IDENT ; ADDRESS OF HBIOS IDENT INFO DATA BLOCK +; + .FILL $MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) + .ORG HBX_IMG + HBX_SIZ ; RESET ORG +; +;================================================================================================== +; HBIOS CORE +;================================================================================================== +; +;================================================================================================== +; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK +;================================================================================================== +; +HB_ENTRYTBL .EQU $ +; + JP HB_START ; HBIOS INITIALIZATION + JP HB_DISPATCH ; VECTOR TO DISPATCHER +; +HB_STKSIZ .EQU HB_ENTRYTBL + 256 - $ +; + .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK +HB_STACK .EQU $ ; TOP OF HBIOS STACK + +; +;================================================================================================== +; SYSTEM INITIALIZATION +;================================================================================================== +; +HB_START: + DI ; NO INTERRUPTS + IM 1 ; INTERRUPT MODE 1 +; +#IFDEF DIAGP + LD A,%00000001 + OUT (DIAGP),A +#ENDIF +; + LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; SET BASE FOR CPU IO REGISTERS + LD A,Z180_BASE + OUT0 (Z180_ICR),A + + DIAG(%00000010) + + ; DISABLE REFRESH + XOR A + OUT0 (Z180_RCR),A + + ; MASK OFF TIMER INTERRUPTS + XOR A + OUT0 (Z180_TCR),A + + ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) + XOR A + OUT0 (Z180_CCR),A + OUT0 (Z180_CMR),A + + ; SET DEFAULT WAIT STATES + LD A,$F0 + OUT0 (Z180_DCNTL),A + +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4)) + ; MMU SETUP + LD A,$80 + OUT0 (Z180_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG +;#IFDEF ROMBOOT +; XOR A +; OUT0 (Z180_BBR),A ; BANK BASE = 0 +;#ENDIF + LD A,(RAMSIZE + RAMBIAS - 64) >> 2 + OUT0 (Z180_CBR),A ; COMMON BASE = LAST (TOP) BANK +#ENDIF + +#IF (Z180_CLKDIV >= 1) + ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED + LD A,$80 + OUT0 (Z180_CCR),A +#ENDIF + +#IF (Z180_CLKDIV >= 2) + ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED + LD A,$80 + OUT0 (Z180_CMR),A +#ENDIF + +#ENDIF +; +#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) + ; SET PAGING REGISTERS +#IFDEF ROMBOOT + XOR A + OUT (MPGSEL_0),A + INC A + OUT (MPGSEL_1),A +#ENDIF + LD A,62 + OUT (MPGSEL_2),A + INC A + OUT (MPGSEL_3),A + ; ENABLE PAGING + LD A,1 + OUT (MPGENA),A +#ENDIF +; + DIAG(%00000011) +; +; INSTALL PROXY IN UPPER MEMORY +; + +;X1 .EQU $8000 +;X2 .EQU X1 + 2 +;X3 .EQU X2 + 2 +;X4 .EQU X3 + 2 + +; LD HL,(HBX_IMG) +; LD (X1),HL + +; LD HL,(HBX_IMG) +; LD (X2),HL + + LD HL,HBX_IMG + LD DE,HBX_LOC + LD BC,HBX_SIZ + LDIR + +; LD HL,(HBX_IMG) +; LD (X3),HL + +; LD HL,(HBX_LOC) +; LD (X4),HL + +; +; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION +; + LD A,(HB_RAMFLAG) + OR A + JR NZ,HB_START1 +; +; INSTALL HBIOS IN RAM BANK +; + LD A,(HB_CURBNK) + LD (HB_SRCBNK),A + LD A,BID_BIOS + LD (HB_DSTBNK),A + LD HL,0 + LD DE,0 + LD BC,$8000 + CALL HBX_BNKCPY +; +; TRANSITION TO HBIOS IN RAM BANK +; + LD A,BID_BIOS ; BIOS BANK ID + LD HL,HB_START1 ; EXECUTION RESUMES HERE + CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN + HALT ; WE SHOULD NOT COME BACK HERE! +; +HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION +; +; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK +; +HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK +; + DIAG(%00000111) +; + LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN + LD A,TRUE ; ACCUM := TRUE + LD (HB_RAMFLAG),A ; SET RAMFLAG +; +; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO +; +#IFDEF APPBOOT + ; MAKE SURE RST 08 VECTOR IS RIGHT + LD A,$C3 + LD ($0008),A + LD HL,HB_INVOKE + LD ($0009),HL +; + ; MAKE SURE IM1 INT VECTOR IS RIGHT + #IF (INTMODE == 1) + ; JP INT_IM1 IF INTERRUPT MODE ACTIVE + LD A,$C3 + LD ($0038),A + LD HL,INT_IM1 + LD ($0039),HL + #ELSE + ; RETI ($ED, $4D) IF NON-INTERRUPT MODE + LD HL,($0038) + LD (HL),$ED + INC HL + LD (HL),$4D + #ENDIF +#ENDIF +; + DIAG(%00001111) +; +; PERFORM DYNAMIC CPU SPEED DERIVATION +; + CALL HB_CPUSPD ; CPU SPEED DETECTION +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) +; + ; SET DESIRED WAIT STATES + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (Z180_DCNTL),A +; +#ENDIF +; + CALL DELAY_INIT ; INITIALIZE SPEED COMPENSATED DELAY FUNCTIONS +; + DIAG(%00011111) +; +; INITIALIZE HEAP STORAGE +; + ; INITIALIZE POINTERS + LD HL,HB_END ; HEAP FOLLOWS HBIOS CODE + LD (CB_HEAP),HL ; INIT HEAP BASE ADDRESS + LD (CB_HEAPTOP),HL ; INIT HEAP TOP ADDRESS + ; CLEAR HEAP + LD BC,BNKTOP - HB_END ; MAX SIZE OF HEAP + LD A,$FF ; FILL WITH $FF + CALL FILL ; DO IT +; + DIAG(%00111111) +; +; PRE-CONSOLE INITIALIZATION +; +#IF (ASCIENABLE) + CALL ASCI_PREINIT +#ENDIF +#IF (UARTENABLE) + CALL UART_PREINIT +#ENDIF +#IF (SIOENABLE) + CALL SIO_PREINIT +#ENDIF +#IF (ACIAENABLE) + CALL ACIA_PREINIT +#ENDIF +; + DIAG(%01111111) +; +; PRIOR TO THIS POINT, CONSOLE I/O WAS DIRECTED TO HARDWARE (XIO.ASM). +; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O +; VIA HBIOS. +; + XOR A ; INITIALLY, FIRST SERIAL UNIT IS CONSOLE + LD (CB_CONDEV),A ; SAVE IT, ACTIVATES CONSOLE ON HBIOS +; +; ANNOUNCE HBIOS +; + CALL NEWLINE2 + PRTX(STR_BANNER) +; + DIAG(%11111111) +; +; IO PORT SCAN +; +#IF 0 +PSCN: + LD C,0 ; IO PORT NUMBER + LD B,0 ; LOOP COUNTER + CALL NEWLINE +PSCN1: + CALL NEWLINE + LD A,C + CALL PRTHEXBYTE + CALL PC_COLON + CALL PC_SPACE + CALL DELAY + LD A,C + LD (PSCNX),A +PSCNX .EQU $ + 1 + IN A,(0) + CALL PRTHEXBYTE + CALL PC_COMMA + PUSH BC + LD B,0 + IN A,(C) + POP BC + CALL PRTHEXBYTE + INC C + DJNZ PSCN1 +#ENDIF +; +; SETUP INTERRUPT VECTORS, AS APPROPRIATE +; +;#IF (INTMODE == 1) +; ; OVERLAY $0038 WITH JP INT_IM1 +; LD A,$C3 ; JP INSTRUCTION +; LD ($0038),A ; INSTALL IT +; LD HL,INT_IM1 ; DESTINATION ADDRESS +; LD ($0039),HL ; INSTALL IT +;#ENDIF +; +#IF (INTMODE == 2) + ; SETUP Z80 IVT AND INT MODE 2 + LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS + LD I,A ; ... AND PLACE IT IN I REGISTER + + #IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; SETUP Z180 IVT + XOR A ; SETUP LO BYTE OF IVT ADDRESS + OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER + #ENDIF + + IM 2 ; SWITCH TO INT MODE 2 +#ENDIF + +#IF (PLATFORM == PLT_SBC) +; + #IF (HTIMENABLE) ; SIMH TIMER +; + #IF (INTMODE == 1) + LD HL,HB_TIMINT + CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST + #ENDIF +; + #IF (INTMODE == 2) + ;LD HL,INT_TIMER + ;LD (HBX_IVT),HL + #ENDIF +; + #ENDIF +; +#ENDIF +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) +; + #IF (INTMODE == 2) +; + ; MASK ALL EXTERNAL INTERRUPTS FOR NOW + ;XOR A ; INT0-2 DISABLED + LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED + OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER +; + ; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT + LD HL,INT_TIMER + LD (HBX_IVT + IVT_TIM0),HL + + ; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0 + LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ + LD B,0 + LD C,Z180_RLDR0L ; INITIALIZE TIMER 0 RELOAD REGISTER + OUT (C),L + INC C + OUT (C),H + LD C,Z180_TMDR0L ; INITIALIZE TIMER 0 DATA REGISTER + OUT (C),L + INC C + OUT (C),H + LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING + OUT0 (Z180_TCR),A +; + #ENDIF +; +#ENDIF +; + HB_EI ; INTERRUPTS SHOULD BE OK NOW +; +; DISPLAY PLATFORM INFORMATION +; + CALL NEWLINE2 + PRTX(STR_PLATFORM) + PRTS(" @ $") + LD HL,(CB_CPUKHZ) + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA + PRTS("MHz$") +; +; DISPLAY CPU CONFIG +; + ;CALL PRTSTRD + ;.TEXT ", $" + CALL NEWLINE +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + LD A,Z180_MEMWAIT +#ELSE + LD A,0 +#ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " MEM W/S, $" +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + LD A,Z180_IOWAIT + 1 +#ELSE + LD A,1 +#ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " I/O W/S$" +#IF (INTMODE > 0) + CALL PRTSTRD + .TEXT ", INT MODE $" + LD A,INTMODE + CALL PRTDECB +#ENDIF +; +; DISPLAY MEMORY CONFIG +; + CALL NEWLINE + ;CALL PRTSTRD + ;.TEXT "MEMORY CONFIG: $" + LD HL,ROMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB ROM, $" + LD HL,RAMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB RAM$" +; +; PERFORM DEVICE INITIALIZATION +; + CALL NEWLINE + LD B,HB_INITTBLLEN + LD DE,HB_INITTBL +INITSYS1: + LD A,(DE) + LD L,A + INC DE + LD A,(DE) + LD H,A + INC DE + PUSH DE + PUSH BC + CALL JPHL + POP BC + POP DE + DJNZ INITSYS1 +; +; RECORD HEAP CURB AT THE CURRENT VALUE OF HEAP TOP. HEAP CURB +; MARKS THE POINT IN THE HEAP AFTER WHICH MEMORY IS RELEASED +; WHEN AN HBIOS RESET IS PEFORMED. +; + LD HL,(CB_HEAPTOP) + LD (HEAPCURB),HL +; +; NOW SWITCH TO CRT CONSOLE IF CONFIGURED +; +#IF CRTACT +; +; BIOS IS CONFIGURED TO AUTO ACTIVATE CRT DEVICE. FIRST, +; CHECK TO SEE IF WE HAVE A VALID CRT DEVICE TO USE. +; + LD A,(CB_CRTDEV) ; GET THE CRT DEVICE + INC A ; INCREMENT TO TEST FOR $FF + JR Z,INITSYS3 ; IF NO CRT DEVICE, BYPASS CONSOLE SWITCH +; +; IF PLATFORM HAS A CONFIG JUMPER, CHECK TO SEE IF IT IS JUMPERED. +; IF SO, BYPASS SWITCH TO CRT CONSOLE (FAILSAFE MODE) +; +#IF ((PLATFORM != PLT_N8) & (PLATFORM != PLT_MK4) & (PLATFORM != PLT_RC) & (PLATFORM != PLT_RC180)) + IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER + BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE + JR Z,INITSYS3 ; Z=SHORTED, BYPASS CONSOLE SWITCH +#ENDIF +; + ; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE + CALL NEWLINE2 + PRTX(STR_SWITCH) + CALL NEWLINE +; + ; SWITCH TO CRT CONSOLE + LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE + LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE +; + ; DISPLAY HBIOS BANNER ON NEW CONSOLE + PRTX(STR_BANNER) +#ENDIF +; +INITSYS3: +; + CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE +; +; CHAIN TO OS LOADER +; +#IFDEF ROMBOOT + ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM + LD A,BID_BIOSIMG ; CHAIN TO OS IMAGES BANK + LD HL,0 ; ENTER AT ADDRESS 0 + CALL HBX_BNKCALL ; GO THERE + HALT ; WE SHOULD NEVER COME BACK! +#ELSE + ; COPY OS IMAGE: BID_USR: --> BID_USR:0 + ;LD A,BID_USR + ;LD (HB_SRCBNK),A + ;LD (HB_DSTBNK),A + ;LD HL,HB_END + ;LD DE,0 + ;LD BC,$8000 + ;CALL HBX_BNKCPY + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_USR ; E = SRC BANK = USER BANK + LD HL,$8000 ; HL = COPY LEN = ENTIRE BANK + RST 08 ; DO IT + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,HB_END ; COPY FROM END OF OF HBIOS + LD DE,0 ; TO USER ADDRESS 0 + RST 08 ; DO IT +; + ; PERFORM BANK CALL TO USER BANK + LD A,BID_USR ; CHAIN TO OS IMAGES BANK + LD HL,0 ; ENTER AT ADDRESS 0 + CALL HBX_BNKCALL ; GO THERE + HALT ; WE SHOULD NEVER COME BACK! +; +#ENDIF +; + RET +; +;================================================================================================== +; TABLE OF INITIALIZATION ENTRY POINTS +;================================================================================================== +; +HB_INITTBL: +#IF (SPKENABLE) + .DW SPK_INIT ; AUDIBLE INDICATOR OF BOOT START +#ENDIF +#IF (AYENABLE) + .DW AY_INIT ; AUDIBLE INDICATOR OF BOOT START +#ENDIF +#IF (ASCIENABLE) + .DW ASCI_INIT +#ENDIF +#IF (UARTENABLE) + .DW UART_INIT +#ENDIF +#IF (SIOENABLE) + .DW SIO_INIT +#ENDIF +#IF (ACIAENABLE) + .DW ACIA_INIT +#ENDIF +#IF (SIMRTCENABLE) + .DW SIMRTC_INIT +#ENDIF +#IF (DSRTCENABLE) + .DW DSRTC_INIT +#ENDIF +#IF (VDUENABLE) + .DW VDU_INIT +#ENDIF +#IF (CVDUENABLE) + .DW CVDU_INIT +#ENDIF +#IF (VGAENABLE) + .DW VGA_INIT +#ENDIF +#IF (NECENABLE) + .DW NEC_INIT +#ENDIF +#IF (TMSENABLE) + .DW TMS_INIT +#ENDIF +#IF (DSKYENABLE) + .DW DSKY_INIT +#ENDIF +#IF (MDENABLE) + .DW MD_INIT +#ENDIF +#IF (FDENABLE) + .DW FD_INIT +#ENDIF +#IF (RFENABLE) + .DW RF_INIT +#ENDIF +#IF (IDEENABLE) + .DW IDE_INIT +#ENDIF +#IF (PPIDEENABLE) + .DW PPIDE_INIT +#ENDIF +#IF (SDENABLE) + .DW SD_INIT +#ENDIF +#IF (HDSKENABLE) + .DW HDSK_INIT +#ENDIF +#IF (PRPENABLE) + .DW PRP_INIT +#ENDIF +#IF (PPPENABLE) + .DW PPP_INIT +#ENDIF +; +HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) +; +;================================================================================================== +; IDLE +;================================================================================================== +; +;__________________________________________________________________________________________________ +; +IDLE: + PUSH AF + PUSH BC + PUSH DE + PUSH HL + PUSH IY +#IF (FDENABLE) + CALL FD_IDLE +#ENDIF + POP IY + POP HL + POP DE + POP BC + POP AF + RET +; +;================================================================================================== +; BIOS FUNCTION DISPATCHER +;================================================================================================== +; +; MAIN BIOS FUNCTION +; B: FUNCTION +;__________________________________________________________________________________________________ +; +HB_DISPATCH: +; +#IF 0 ; *DEBUG* START +; + CALL HB_DISPCALL ; DO THE WORK +; + ; CHECK STACK INTEGRITY + PUSH AF + LD A,(HB_STACK - HB_STKSIZ + $08) + CP $FF + CALL NZ,PANIC + LD A,$FF + LD (HB_STACK - HB_STKSIZ + $08),A + POP AF + RET +HB_DISPCALL: +; +#ENDIF ; *DEBUG* END +; + LD A,B ; REQUESTED FUNCTION IS IN B + CP BF_CIO + $10 ; $00-$0F: CHARACTER I/O + JP C,CIO_DISPATCH + CP BF_DIO + $10 ; $10-$1F: DISK I/O + JP C,DIO_DISPATCH + CP BF_RTC + $10 ; $20-$2F: REAL TIME CLOCK (RTC) + JP C,RTC_DISPATCH + CP BF_EMU + $10 ; $30-$3F: EMULATION + CALL C,PANIC ; OBSOLETE! + CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER + JP C,VDA_DISPATCH + CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 + CALL C,PANIC ; PANIC IF LESS THAN BF_SYS + JP SYS_DISPATCH ; OTHERWISE SYS CALL + CALL PANIC ; THIS SHOULD NEVER BE REACHED + RET +; +;================================================================================================== +; CHARACTER I/O DEVICE FUNCTION DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +CIO_DISPATCH: + BIT 7,C ; CHECK FOR SPECIAL UNIT CODE + CALL NZ,CIO_SPECIAL ; IF SO, HANDLE IT + + PUSH IY ; SAVE INCOMING IY + + LD IY,CIO_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; SPECIAL HANDLING FOR DEDICATED UNIT CODES +; +CIO_SPECIAL: + ; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST + ; SO JUST SWAP IN ACTIVE CONSOLE UNIT + LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE + LD C,A ; OVERLAY UNIT CODE IN C + RET ; AND REJOIN MAIN DISPATCH FLOW +; +; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS) +; +CIO_ADDENT: + LD HL,CIO_TBL ; POINT TO CIO TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS CHARACTER DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) +CIO_MAX .EQU 32 ; UP TO 32 UNITS +CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) + .DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX +CIO_CNT .DB 0 ; ENTRY COUNT PREFIX +CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES +; +;================================================================================================== +; DISK I/O DEVICE FUNCTION DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO SPECIFIED DISK I/O DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +DIO_DISPATCH: +; +#IF 0 ; *DEBUG* START +; + ; DUMP INCOMING CALL + CALL NEWLINE + PRTS("DIO>$") + CALL REGDMP ; DUMP REGS, NONE DESTROYED +; + ; DO THE ACTUAL DISPATCH PROCESSING + CALL DIO_DISPCALL +; + ; DUMP CALL RESULTS AND RETURN + CALL NEWLINE + PRTS("DIO<$") + CALL REGDMP ; DUMP REGS, NONE DESTROYED + RET +; +#ENDIF ; *DEBUG* END +; +DIO_DISPCALL: + PUSH IY ; SAVE INCOMING IY + + LD IY,DIO_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; ADD AN ENTRY TO THE DIO UNIT TABLE +; +DIO_ADDENT: + LD HL,DIO_TBL ; POINT TO DIO TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS DISK DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF DIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) +DIO_MAX .EQU 16 ; UP TO 16 UNITS +DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) + .DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX +DIO_CNT .DB 0 ; ENTRY COUNT PREFIX +DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES +; +;================================================================================================== +; REAL TIME CLOCK DEVICE DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO REAL TIME CLOCK DRIVER +; B: FUNCTION +; +RTC_DISPATCH: +#IF (SIMRTCENABLE) + JP SIMRTC_DISPATCH +#ENDIF +#IF (DSRTCENABLE) + JP DSRTC_DISPATCH +#ENDIF + CALL PANIC +; +;================================================================================================== +; VIDEO DISPLAY ADAPTER DEVICE DISPATCHER +;================================================================================================== +; +; ROUTE CALL TO SPECIFIED VDA DEVICE DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +VDA_DISPATCH: + PUSH IY ; SAVE INCOMING IY + + LD IY,VDA_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; ADD AN ENTRY TO THE VDA UNIT TABLE (SEE HB_ADDENT FOR DETAILS) +; +VDA_ADDENT: + LD HL,VDA_TBL ; POINT TO VDA TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS VIDEO DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +VDA_FNCNT .EQU 15 ; NUMBER OF VDA FUNCS (FOR RANGE CHECK) +VDA_MAX .EQU 16 ; UP TO 16 UNITS +VDA_SIZ .EQU VDA_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB VDA_FNCNT ; VDA FUNCTION COUNT (FOR RANGE CHECK) + .DB VDA_MAX ; MAX ENTRY COUNT TABLE PREFIX +VDA_CNT .DB 0 ; ENTRY COUNT PREFIX +VDA_TBL .FILL VDA_SIZ,0 ; SPACE FOR ENTRIES +; +;================================================================================================== +; SYSTEM FUNCTION DISPATCHER +;================================================================================================== +; +; B: FUNCTION +; +SYS_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JP Z,SYS_RESET ; $F0 + DEC A + JP Z,SYS_VER ; $F1 + DEC A + JP Z,SYS_SETBNK ; $F2 + DEC A + JP Z,SYS_GETBNK ; $F3 + DEC A + JP Z,SYS_SETCPY ; $F4 + DEC A + JP Z,SYS_BNKCPY ; $F5 + DEC A + JP Z,SYS_ALLOC ; $F6 + DEC A + JP Z,SYS_FREE ; $F7 + DEC A + JP Z,SYS_GET ; $F8 + DEC A + JP Z,SYS_SET ; $F9 + DEC A + JP Z,SYS_PEEK ; $FA + DEC A + JP Z,SYS_POKE ; $FB + DEC A + JP Z,SYS_INT ; $FC + CALL PANIC ; INVALID +; +; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS +; +SYS_RESET: + LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD + LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP + XOR A + RET +; +; GET THE CURRENT HBIOS VERSION +; ON INPUT, C=0 +; RETURNS VERSION IN DE AS BCD +; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS +; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS +; L: PLATFORM ID +; +SYS_VER: + LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP + LD L,PLATFORM + XOR A + RET +; +; SET ACTIVE MEMORY BANK AND RETURN PREVIOUSLY ACTIVE MEMORY BANK +; NOTE THAT IT GOES INTO EFFECT AS HBIOS FUNCTION IS EXITED +; HERE, WE JUST SET THE CURRENT BANK +; CALLER MUST EXTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! +; +SYS_SETBNK: + PUSH HL ; SAVE INCOMING HL + LD HL,HB_INVBNK ; POINT TO HBIOS INVOKE BANK ID ADDRESS + LD A,(HL) ; GET EXISTING BANK ID TO A + LD (HL),C ; UPDATE INVOKE BANK TO NEW BANK ID + LD C,A ; PUT PREVIOUS BANK ID IN C FOR RETURN + POP HL ; RESTORE ORIGINAL HL + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; GET ACTIVE MEMORY BANK +; +SYS_GETBNK: + LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK + LD C,A ; MOVE TO C + XOR A ; SIGNAL SUCCESS + RET +; +; SET BANKS AND LENGTH FOR INTERBANK MEMORY COPY (BNKCPY) +; ENTRY: E=SOURCE BANK ID +; D=DEST BANK ID +; HL=COPY LENGTH (IN BYTES) +; +SYS_SETCPY: + LD A,E + LD (HB_SRCBNK),A ; RECORD THE SOURCE BANK + LD A,D + LD (HB_DSTBNK),A ; RECORD THE DESTINATION BANK + LD (HB_CPYLEN),HL ; RECORD THE COPY LENGTH + XOR A + RET +; +; PERFORM MEMORY COPY POTENTIALLY ACROSS BANKS +; ENTRY: HL=SOURCE ADDRESS +; DE=DESTINATION ADDRESS +; NOTE: SRC/DEST BANK & COPY LENGTH MUST BE SET VIA SETCPY +; +SYS_BNKCPY: + PUSH HL ; SAVE INCOMING HL + LD HL,(HB_CPYLEN) ; HL := COPY LEN (SAVED IN SETCPY) + EX (SP),HL ; RESTORE HL & SET (SP) TO COPY LEN + POP BC ; BC := COPY LEN +#IF (INTMODE == 1) + DI +#ENDIF + CALL HB_BNKCPY +#IF (INTMODE == 1) + EI +#ENDIF + XOR A + RET +; +; ALLOCATE HL BYTES OF MEMORY FROM HBIOS HEAP +; RETURNS POINTER TO ALLOCATED MEMORY IN HL +; ON SUCCESS RETURN A == 0, AND Z SET +; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED +; ALL OTHER REGISTERS PRESERVED +; +SYS_ALLOC: + JP HB_ALLOC +; +; FREE HEAP MEMORY BY SIMPLY RELEASING ALL +; MEMORY BEYOND POINTER IN HL. +; ON SUCCESS RETURN A == 0, AND Z SET +; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED +; ALL OTHER REGISTERS PRESERVED +; +SYS_FREE: + CALL PANIC ; NOT YET IMPLEMENTED + OR $FF + RET +; +; GET SYSTEM INFORMATION +; ITEM TO RETURN INDICATED IN C +; +SYS_GET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSGET_CIOCNT + JR Z,SYS_GETCIOCNT + CP BF_SYSGET_DIOCNT + JR Z,SYS_GETDIOCNT + CP BF_SYSGET_VDACNT + JR Z,SYS_GETVDACNT + CP BF_SYSGET_TIMER + JR Z,SYS_GETTIMER + CP BF_SYSGET_BOOTINFO + JR Z,SYS_GETBOOTINFO + CP BF_SYSGET_CPUINFO + JR Z,SYS_GETCPUINFO + CP BF_SYSGET_MEMINFO + JR Z,SYS_GETMEMINFO + CP BF_SYSGET_BNKINFO + JR Z,SYS_GETBNKINFO + OR $FF ; SIGNAL ERROR + RET +; +; GET TIMER +; RETURNS: +; DE:HL: TIMER VALUE (32 BIT) +; +SYS_GETTIMER: + LD HL,HB_TICKS + HB_DI + CALL LD32 + HB_EI + XOR A + RET +; +; GET BOOT INFORMATION +; RETURNS: +; L: BOOT BANK ID +; DE: BOOT DISK VOLUME (UNIT/SLICE) +; +SYS_GETBOOTINFO: + LD A,(CB_BOOTBID) + LD L,A + LD DE,(CB_BOOTVOL) + XOR A + RET +; +; GET CPU INFORMATION +; RETURNS: +; H: Z80 CPU VARIANT +; L: CPU SPEED IN MHZ +; DE: CPU SPEED IN KHZ +; +SYS_GETCPUINFO: + LD H,0 ; NOT YET DEFINED + LD A,(CB_CPUMHZ) + LD L,A + LD DE,(CB_CPUKHZ) + XOR A + RET +; +; GET MEMORY INFORMATION +; RETURNS: +; D: COUNT OF ROM BANKS +; E: COUNT OF RAM BANKS +; +SYS_GETMEMINFO: + LD D,ROMSIZE / 32 + LD E,RAMSIZE / 32 + XOR A + RET +; +; GET BANK CONFIGURATION INFORMATION +; RETURNS: +; D: HBIOS BANK ID +; E: USER BANK ID +; +SYS_GETBNKINFO: + LD A,(CB_BIDBIOS) + LD D,A + LD A,(CB_BIDUSR) + LD E,A + XOR A + RET +; +; GET SERIAL UNIT COUNT +; +SYS_GETCIOCNT: + LD A,(CIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; GET DISK UNIT COUNT +; +SYS_GETDIOCNT: + LD A,(DIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; GET VIDEO UNIT COUNT +; +SYS_GETVDACNT: + LD A,(VDA_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; SET SYSTEM PARAMETERS +; PARAMETER(S) TO SET INDICATED IN C +; +SYS_SET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSSET_TIMER + JR Z,SYS_SETTIMER + CP BF_SYSSET_BOOTINFO + JR Z,SYS_SETBOOTINFO + OR $FF ; SIGNAL ERROR + RET +; +; SET BOOT INFORMATION +; ON ENTRY: +; L: BOOT BANK ID +; DE: BOOT DISK VOLUME (UNIT/SLICE) +; +SYS_SETBOOTINFO: + LD A,L + LD (CB_BOOTBID),A + LD (CB_BOOTVOL),DE + XOR A + RET +; +; SET TIMER +; ON ENTRY: +; DE:HL: TIMER VALUE (32 BIT) +; +SYS_SETTIMER: + LD BC,HB_TICKS + HB_DI + CALL ST32 + HB_EI + XOR A + RET +; +; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK +; ENTRY: D=BANK ID, HL=ADDRESS +; RETURN: E=BYTE VALUE +; +SYS_PEEK: +#IF (INTMODE == 1) + DI +#ENDIF + CALL HBX_PEEK ; IMPLEMENTED IN PROXY +#IF (INTMODE == 1) + EI +#ENDIF + XOR A + RET +; +; WRITE A BYTE OF MEMORY TO SPECIFIED BANK +; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE +; +SYS_POKE: +#IF (INTMODE == 1) + DI +#ENDIF + CALL HBX_POKE ; IMPLEMENTED IN PROXY +#IF (INTMODE == 1) + EI +#ENDIF + XOR A + RET +; +; INTERRUPT MANAGEMENT FUNCTIONS +; SUBFUNCTION IN C +; +SYS_INT: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSINT_INFO + JR Z,SYS_INTINFO + CP BF_SYSINT_GET + JR Z,SYS_INTGET + CP BF_SYSINT_SET + JR Z,SYS_INTSET + OR $FF ; SIGNAL ERROR + RET +; +; GET INTERRUPT SYSTEM INFORMATION +; RETURN D:=INTERRUPT MODE, E:=INT VEC TABLE SIZE +; +SYS_INTINFO: + LD D,INTMODE ; D := ACTIVE INTERRUPT MODE +#IF (INTMODE == 0) + LD E,0 ; 0 ENTRIES IF INTERRUPTS DISABLED +#ENDIF +#IF (INTMODE == 1) + LD A,(HB_IM1CNT) ; RETURN IM1 CALL LIST SIZE + LD E,A +#ENDIF +#IF (INTMODE == 2) + LD E,HBX_IVTCNT ; RETURN INT VEC TABLE SIZE +#ENDIF + XOR A ; INDICATE SUCCESS + RET ; AND DONE +; +; ROUTINE SHARED BY INT GET/SET. RETURNS ADDRESS OF VECTOR FOR SPECIFIED LIST / TABLE +; POSITION. ZF SET ON RETURN FOR SUCCESS, ELSE ERROR. +; +SYS_INTVECADR: +#IF (INTMODE == 0) + CALL PANIC ; INVALID FOR INT MODE 0 + OR $FF + RET +#ENDIF +#IF (INTMODE == 1) + LD A,(HB_IM1CNT) ; GET CURRENT ENTRY COUNT + INC A ; ALLOW FOR EXTRA ENTRY TO APPEND AT END + LD C,A ; SAVE IN C FOR COMPARE +#ENDIF +#IF (INTMODE == 2) + LD C,HBX_IVTCNT ; GET CURRENT ENTRY COUNT +#ENDIF + LD A,E ; INCOMING INDEX POSITION TO A + CP C ; COMPARE TO VECTOR COUNT + JR C,SYS_INTGET1 ; CONTINUE IF POSITION IN RANGE + CALL PANIC ; ELSE ERROR + OR $FF + RET +SYS_INTGET1: + OR A + RLA ; HL := (A * 2) FOR IM2 +#IF (INTMODE == 1) + RLA ; ... HL := (A * 4) + 1 FOR IM1 + INC A +#ENDIF + LD H,0 + LD L,A +#IF (INTMODE == 1) + LD DE,HB_IM1INT ; DE := START OF CALL LIST +#ENDIF +#IF (INTMODE == 2) + LD DE,HBX_IVT ; DE := START OF VECTOR TABLE +#ENDIF + ADD HL,DE ; HL := ADR OF VECTOR + XOR A ; INDICATE SUCCESS + RET +; +; RETURN THE INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE +; ENTRY: E=LIST/TABLE POSITION +; RETURN: HL=INTERRUPT VECTOR +; +SYS_INTGET: + CALL SYS_INTVECADR ; GET VECTOR ADDRESS + RET NZ ; BAIL OUT ON ERROR + LD A,(HL) ; DEREF HL TO GET VECTOR + INC HL + LD H,(HL) + LD L,A + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +; SET AN INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE +; ENTRY: E=LIST/TABLE POSITION, HL=NEW INTERRUPT VECTOR +; RETURN: HL=PREVIOUS INTERRUPT VECTOR, DE=ADR OF INT ROUTING ENGINE FOR IM2 +; +SYS_INTSET: + PUSH HL ; SAVE NEW VECTOR + CALL SYS_INTVECADR ; GET VECTOR ADDRESS + JR Z,SYS_INTSET1 ; CONTINUE IF OK + POP HL ; FIX STACK + RET NZ ; BAIL OUT ON ERROR +SYS_INTSET1: + PUSH HL ; SAVE VECTOR ADDRESS + LD A,(HL) ; DEREF HL TO GET PREV VECTOR + INC HL + LD H,(HL) + LD L,A + EX (SP),HL ; (SP) := PREV VEC, HL := VEC ADR + POP DE ; DE := PREV VEC + POP BC ; BC := NEW VEC + LD (HL),C ; SAVE LSB + INC HL + LD (HL),B ; SAVE MSB + EX DE,HL ; HL := PREV VEC +#IF (INTMODE == 2) + LD DE,HBX_INT ; DE := IM2 INT ROUTING ENGINE +#ENDIF + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +;================================================================================================== +; GLOBAL HBIOS FUNCTIONS +;================================================================================================== +; +; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN +; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT) +; +CIO_IDLE: + PUSH AF ; PRESERVE AF + LD A,(IDLECOUNT) ; GET CURRENT IDLE COUNT + DEC A ; DECREMENT + LD (IDLECOUNT),A ; SAVE UPDATED VALUE + CALL Z,IDLE ; IF ZERO, DO IDLE PROCESSING + POP AF ; RECOVER AF + RET +; +#IF (INTMODE == 1) +; +; IM1 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK +; LIST OF IM1 INT CALLS IS BUILT DYNAMICALLY BELOW +; SEE HB_ADDIM1 ROUTINE +; EACH ENTRY WILL LOOK LIKE: +; CALL XXXX ; CALL INT HANDLER +; RET NZ ; RETURN IF HANDLED +; +; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. +; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID +; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. +; +; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. +; +HB_IM1INT: ; IM1 DEVICE INTERRUPT HANDLER CALL LIST + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ + CALL HB_BADINT \ RET NZ +; +; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 +; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS +; +HB_ADDIM1: + EX DE,HL ; VECTOR ADDRESS TO DE + LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY + INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE + LD (HL),E ; ADD VECTOR ADDRESS + INC HL ; ... + LD (HL),D ; ... + INC HL ; BUMP PTR + INC HL ; BUMP PTR + LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER + LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT + INC (HL) ; INCREMENT + RET ; DONE +; +HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST +HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST +HB_IM1PTR .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY +; +#ENDIF +; +; TIMER INTERRUPT +; +HB_TIMINT: + ; INCREMENT TICK COUNTER (32 BIT) + LD HL,HB_TICKS ; POINT TO TICK COUNTER + INC (HL) + JR NZ,HB_TIMINT1 + INC HL + INC (HL) + JR NZ,HB_TIMINT1 + INC HL + INC (HL) + JR NZ,HB_TIMINT1 + INC HL + INC (HL) +; +HB_TIMINT1: +; +#IF 0 +; + LD HL,TEMPCNT + DEC (HL) + JR NZ,HB_TIMINT2 + LD (HL),250 +; + LD A,'*' + CALL COUT + JR HB_TIMINT2 +; +TEMPCNT .DB 250 +; +#ENDIF +; +HB_TIMINT2: +; +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; ACK/RESET Z180 TIMER INTERRUPT + IN0 A,(Z180_TCR) + IN0 A,(Z180_TMDR0L) +#ENDIF +; + OR $FF ; NZ SET TO INDICATE INT HANDLED + RET +; +; BAD INTERRUPT HANDLER +; +HB_BADINT: + CALL NEWLINE2 + PRTS("+++ BAD INT: $") + CALL _REGDMP + CALL CONTINUE + OR $FF ; SIGNAL INTERRUPT HANDLED + RET +; +; COMMON API FUNCTION DISPATCH CODE +; +; ON ENTRY C IS UNIT # (INDEX INTO XXX_TBL OF UNITS) +; AND IY POINTS TO START OF UNIT TABLE. +; USE UNIT # IN C TO LOOKUP XXX_TBL ENTRY. THE XXX_TBL +; ENTRY CONTAINS THE START OF THE DRIVER FUNCTION TABLE AND +; THE DEVICE SPECIFIC INSTANCE DATA (BLOB). SET IY TO BLOB ADDRESS +; AND CALL THE SPECIFIC FUNCTION REQUESTED IN THE DRIVER. +; +HB_DISPCALL: + ; CHECK INCOMING UNIT INDEX IN C FOR VAILIDITY + LD A,C ; A := INCOMING DISK UNIT INDEX + CP (IY-1) ; COMPARE TO COUNT + JR NC,HB_DISPERR ; HANDLE INVALID UNIT INDEX + + ; CHECK FUNCTION INDEX FOR VALIDITY + LD A,B ; A := INCOMING FUNCTION NUMBER + AND $0F ; LOW NIBBLE ONLY FOR FUNC INDEX + CP (IY-3) ; CHECK FN NUM AGAINST MAX + JR NC,HB_DISPERR ; HANDLE FN NUM OUT OF RANGE ERROR + + ; BUMP IY TO ACTUAL XXX_TBL ENTRY FOR INCOMING UNIT INDEX + LD B,0 ; MSB IS ALWAYS ZERO + RLC C ; MULTIPLY UNIT INDEX + RLC C ; ... BY 4 FOR TABLE ENTRY OFFSET + ADD IY,BC ; SET IY TO ENTRY ADDRESS + + ; DERIVE DRIVER FUNC ADR TO CALL + PUSH HL ; SAVE INCOMING HL + LD L,(IY+0) ; COPY DRIVER FUNC TABLE + LD H,(IY+1) ; ... START TO HL + RLCA ; CONV UNIT (STILL IN A) TO FN ADR OFFSET + CALL ADDHLA ; HL NOW HAS DRIVER FUNC TBL START ADR + LD A,(HL) ; DEREFERENCE HL + INC HL ; ... TO GET + LD H,(HL) ; ... ACTUAL + LD L,A ; ... TARGET FUNCTION ADDRESS + EX (SP),HL ; RESTORE HL, FUNC ADR ON STACK + + ; GET UNIT INSTANCE DATA BLOB ADDRESS TO IY + PUSH HL ; SAVE INCOMING HL + LD L,(IY+2) ; HL := DATA BLOB ADDRESS + LD H,(IY+3) ; ... + EX (SP),HL ; RESTORE HL, BLOB ADR ON TOS + POP IY ; IY := BLOB ADR + + RET ; JUMP TO DRIVER FUNC ADR ON TOS +; +HB_DISPERR: + CALL PANIC ; PANIC + OR $FF ; SIGNAL ERROR + RET ; AND RETURN VIA DISPEXIT +; +; ADD AN ENTRY TO THE UNIT TABLE AT ADDRESS IN HL +; BC: DRIVER FUNCTION TABLE +; DE: ADDRESS OF UNIT INSTANCE DATA +; RETURN +; A: UNIT NUMBER ASSIGNED +; +HB_ADDENT: + DEC HL ; POINT TO ENTRY COUNT + LD A,(HL) ; GET ENTRY COUNT + PUSH AF ; SAVE VALUE TO RETURN AS ENTRY NUM AT END + INC A ; INCREMENT TO ACCOUNT FOR NEW ENTRY + DEC HL ; POINT TO ENTRY MAX + CP (HL) ; COMPARE MAX TO CURRENT COUNT (COUNT - MAX) + CALL NC,PANIC ; OVERFLOW + INC HL ; POINT TO COUNT + LD (HL),A ; SAVE NEW COUNT + INC HL ; POINT TO START OF TABLE + DEC A ; CONVERT A FROM ENTRY COUNT TO ENTRY INDEX + RLCA ; MULTIPLY BY 4 + RLCA ; ... TO GET BYTE OFFSET OF ENTRY + CALL ADDHLA ; MAKE HL POINT TO ACTUAL ENTRY ADDRESS + PUSH BC ; GET TABLE ENTRY ADDRESS TO BC + EX (SP),HL ; ... AND DISPATCH ADDRESS TO HL + POP BC ; ... SO THAT DE:HL HAS 32 BIT ENTRY + CALL ST32 ; LD (BC),DE:HL STORES THE ENTRY + POP AF ; RETURN ENTRY INDEX (UNIT NUMBER ASSIGNED) + RET +; +; ALLOCATE HL BYTES OF MEMORY ON THE HEAP +; RETURNS POINTER TO ALLOCATED SPACE IN HL +; ON SUCCESS RETURN A == 0, AND Z SET +; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED +; ALL OTHER REGISTERS PRESERVED +; +; A 4 BYTE HEADER IS PLACED IN FRONT OF THE ALLOCATED MEMORY +; - DWORD: SIZE OF MEMROY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) +; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) +; +HB_ALLOC: + ; SAVE ALLOC SIZE AND REFERENCE ADR FOR SUBSEQUENT HEADER CONSTRUCTION + LD (HB_TMPSZ),HL ; SAVE INCOMING SIZE REQUESTED + ; USE EX (SP),HL INSTEAD???? + POP HL ; GET RETURN ADDRESS + LD (HB_TMPREF),HL ; SAVE AS REFERENCE + ; USE EX (SP),HL INSTEAD???? + PUSH HL ; PUT IT BACK ON STACK + LD HL,(HB_TMPSZ) ; RECOVER INCOMING MEM SIZE PARM +; + ; CALC NEW HEAP TOP AND HANDLE OUT-OF-SPACE ERROR + PUSH DE ; SAVE INCOMING DE + LD DE,4 ; SIZE OF HEADER + ADD HL,DE ; ADD IT IN + JR C,HB_ALLOC1 ; ERROR ON OVERFLOW + LD DE,(CB_HEAPTOP) ; CURRENT HEAP TOP + ADD HL,DE ; ADD IT IN, HL := NEW HEAP TOP + JR C,HB_ALLOC1 ; ERROR ON OVERFLOW + BIT 7,H ; TEST PAST END OF BANK (>= 32K) + JR NZ,HB_ALLOC1 ; ERROR IF PAST END +; + ; SAVE NEW HEAP TOP + LD DE,(CB_HEAPTOP) ; GET ORIGINAL HEAP TOP + LD (CB_HEAPTOP),HL ; SAVE NEW HEAP TOP +; + ; SET HEADER VALUES + EX DE,HL ; HEADER ADR TO HL + LD DE,(HB_TMPSZ) ; GET THE ORIG SIZE REQUESTED + LD (HL),E ; SAVE SIZE (LSB) + INC HL ; BUMP HEADER POINTER + LD (HL),D ; SAVE SIZE (MSB) + INC HL ; BUMP HEADER POINTER + LD DE,(HB_TMPREF) ; GET THE REFERENCE ADR + LD (HL),E ; SAVE REF ADR (LSB) + INC HL ; BUMP HEADER POINTER + LD (HL),D ; SAVE REF ADR (MSB) + INC HL ; BUMP HEADER POINTER +; + ; RETURN SUCCESS, HL POINTS TO START OF ALLOCATED MEMORY (PAST HEADER) + POP DE ; RESTORE INCOMING DE + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +HB_ALLOC1: + ; ERROR RETURN + POP DE ; RESTORE INCOMING DE + OR $FF ; SIGNAL ERROR + RET ; AND RETURN +; +HB_TMPSZ .DW 0 +HB_TMPREF .DW 0 +; +;================================================================================================== +; DEVICE DRIVERS +;================================================================================================== +; +#IF (SIMRTCENABLE) +ORG_SIMRTC .EQU $ + #INCLUDE "simrtc.asm" +SIZ_SIMRTC .EQU $ - ORG_SIMRTC + .ECHO "SIMRTC occupies " + .ECHO SIZ_SIMRTC + .ECHO " bytes.\n" +#ENDIF +; +#IF (DSRTCENABLE) +ORG_DSRTC .EQU $ + #INCLUDE "dsrtc.asm" +SIZ_DSRTC .EQU $ - ORG_DSRTC + .ECHO "DSRTC occupies " + .ECHO SIZ_DSRTC + .ECHO " bytes.\n" +#ENDIF +; +#IF (ASCIENABLE) +ORG_ASCI .EQU $ + #INCLUDE "asci.asm" +SIZ_ASCI .EQU $ - ORG_ASCI + .ECHO "ASCI occupies " + .ECHO SIZ_ASCI + .ECHO " bytes.\n" +#ENDIF +; +#IF (UARTENABLE) +ORG_UART .EQU $ + #INCLUDE "uart.asm" +SIZ_UART .EQU $ - ORG_UART + .ECHO "UART occupies " + .ECHO SIZ_UART + .ECHO " bytes.\n" +#ENDIF +; +#IF (SIOENABLE) +ORG_SIO .EQU $ + #INCLUDE "sio.asm" +SIZ_SIO .EQU $ - ORG_SIO + .ECHO "SIO occupies " + .ECHO SIZ_SIO + .ECHO " bytes.\n" +#ENDIF +; +#IF (ACIAENABLE) +ORG_ACIA .EQU $ + #INCLUDE "acia.asm" +SIZ_ACIA .EQU $ - ORG_ACIA + .ECHO "ACIA occupies " + .ECHO SIZ_ACIA + .ECHO " bytes.\n" +#ENDIF +; +#IF (VGAENABLE) +ORG_VGA .EQU $ + #INCLUDE "vga.asm" +SIZ_VGA .EQU $ - ORG_VGA + .ECHO "VGA occupies " + .ECHO SIZ_VGA + .ECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE) +ORG_CVDU .EQU $ + #INCLUDE "cvdu.asm" +SIZ_CVDU .EQU $ - ORG_CVDU + .ECHO "CVDU occupies " + .ECHO SIZ_CVDU + .ECHO " bytes.\n" +#ENDIF +; +#IF (VDUENABLE) +ORG_VDU .EQU $ + #INCLUDE "vdu.asm" +SIZ_VDU .EQU $ - ORG_VDU + .ECHO "VDU occupies " + .ECHO SIZ_VDU + .ECHO " bytes.\n" +#ENDIF +; +#IF (TMSENABLE) +ORG_TMS .EQU $ + #INCLUDE "tms.asm" +SIZ_TMS .EQU $ - ORG_TMS + .ECHO "TMS occupies " + .ECHO SIZ_TMS + .ECHO " bytes.\n" +#ENDIF +; +#IF (NECENABLE) +ORG_NEC .EQU $ + ;#INCLUDE "nec.asm" +SIZ_NEC .EQU $ - ORG_NEC + .ECHO "NEC occupies " + .ECHO SIZ_NEC + .ECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE | VGAENABLE) +ORG_FONTHI .EQU $ + #INCLUDE "font_hi.asm" +SIZ_FONTHI .EQU $ - ORG_FONTHI + .ECHO "FONTHI occupies " + .ECHO SIZ_FONTHI + .ECHO " bytes.\n" +#ENDIF +; +#IF (TMSENABLE) +ORG_FONTTMS .EQU $ + #INCLUDE "font_tms.asm" +SIZ_FONTTMS .EQU $ - ORG_FONTTMS + .ECHO "FONTTMS occupies " + .ECHO SIZ_FONTTMS + .ECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE | VGAENABLE) +ORG_KBD .EQU $ + #INCLUDE "kbd.asm" +SIZ_KBD .EQU $ - ORG_KBD + .ECHO "KBD occupies " + .ECHO SIZ_KBD + .ECHO " bytes.\n" +#ENDIF +; +#IF (VDUENABLE | (TMSENABLE & (PLATFORM == PLT_N8))) +ORG_PPK .EQU $ + #INCLUDE "ppk.asm" +SIZ_PPK .EQU $ - ORG_PPK + .ECHO "PPK occupies " + .ECHO SIZ_PPK + .ECHO " bytes.\n" +#ENDIF +; +#IF (PRPENABLE) +ORG_PRP .EQU $ + #INCLUDE "prp.asm" +SIZ_PRP .EQU $ - ORG_PRP + .ECHO "PRP occupies " + .ECHO SIZ_PRP + .ECHO " bytes.\n" +#ENDIF +; +#IF (PPPENABLE) +ORG_PPP .EQU $ + #INCLUDE "ppp.asm" +SIZ_PPP .EQU $ - ORG_PPP + .ECHO "PPP occupies " + .ECHO SIZ_PPP + .ECHO " bytes.\n" +#ENDIF +; +#IF (MDENABLE) +ORG_MD .EQU $ + #INCLUDE "md.asm" +SIZ_MD .EQU $ - ORG_MD + .ECHO "MD occupies " + .ECHO SIZ_MD + .ECHO " bytes.\n" +#ENDIF + +#IF (FDENABLE) +ORG_FD .EQU $ + #INCLUDE "fd.asm" +SIZ_FD .EQU $ - ORG_FD + .ECHO "FD occupies " + .ECHO SIZ_FD + .ECHO " bytes.\n" +#ENDIF + +#IF (RFENABLE) +ORG_RF .EQU $ + #INCLUDE "rf.asm" +SIZ_RF .EQU $ - ORG_RF + .ECHO "RF occupies " + .ECHO SIZ_RF + .ECHO " bytes.\n" +#ENDIF + +#IF (IDEENABLE) +ORG_IDE .EQU $ + #INCLUDE "ide.asm" +SIZ_IDE .EQU $ - ORG_IDE + .ECHO "IDE occupies " + .ECHO SIZ_IDE + .ECHO " bytes.\n" +#ENDIF + +#IF (PPIDEENABLE) +ORG_PPIDE .EQU $ + #INCLUDE "ppide.asm" +SIZ_PPIDE .EQU $ - ORG_PPIDE + .ECHO "PPIDE occupies " + .ECHO SIZ_PPIDE + .ECHO " bytes.\n" +#ENDIF + +#IF (SDENABLE) +ORG_SD .EQU $ + #INCLUDE "sd.asm" +SIZ_SD .EQU $ - ORG_SD + .ECHO "SD occupies " + .ECHO SIZ_SD + .ECHO " bytes.\n" +#ENDIF + +#IF (HDSKENABLE) +ORG_HDSK .EQU $ + #INCLUDE "hdsk.asm" +SIZ_HDSK .EQU $ - ORG_HDSK + .ECHO "HDSK occupies " + .ECHO SIZ_HDSK + .ECHO " bytes.\n" +#ENDIF + +#IF (TERMENABLE) +ORG_TERM .EQU $ + #INCLUDE "term.asm" +SIZ_TERM .EQU $ - ORG_TERM + .ECHO "TERM occupies " + .ECHO SIZ_TERM + .ECHO " bytes.\n" +#ENDIF +; +#IF (SPKENABLE) +ORG_SPK .EQU $ + #INCLUDE "spk.asm" +SIZ_SPK .EQU $ - ORG_SPK + .ECHO "SPK occupies " + .ECHO SIZ_SPK + .ECHO " bytes.\n" +#ENDIF +; +#IF (AYENABLE) +ORG_AY .EQU $ + #INCLUDE "ay.asm" +SIZ_AY .EQU $ - ORG_AY + .ECHO "AY occupies " + .ECHO SIZ_AY + .ECHO " bytes.\n" +#ENDIF +; +#DEFINE USEDELAY +#INCLUDE "util.asm" +#INCLUDE "time.asm" +#INCLUDE "bcd.asm" +#INCLUDE "decode.asm" +;#INCLUDE "xio.asm" +; +#IF (DSKYENABLE) +#DEFINE DSKY_KBD +#INCLUDE "dsky.asm" +#ENDIF +; +; DETECT CPU SPEED USING DS-1302 RTC +; +HB_CPUSPD: +; +#IF (DSRTCENABLE) +; + CALL DSRTC_TSTCLK ; IS CLOCK RUNNING? + JR Z,HB_CPUSPD1 ; YES, CONTINUE + ; MAKE SURE CLOCK IS RUNNING + LD HL,DSRTC_TIMDEF + CALL DSRTC_TIM2CLK + LD HL,DSRTC_BUF + CALL DSRTC_WRCLK + CALL DSRTC_TSTCLK ; NOW IS CLOCK RUNNING? + RET NZ +; +HB_CPUSPD1: +; LD B,8 +;HB_CPUSPDX: +; PUSH BC + + ; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT + ; FOR SECOND TICK AND TO GET A FULL ONE SECOND LOOP COUNT + + CALL HB_RDSEC ; GET SECONDS + LD (HB_CURSEC),A ; AND INIT CURSEC + CALL HB_WAITSEC ; WAIT FOR SECONDS TICK + LD (HB_CURSEC),A ; SAVE NEW VALUE + CALL HB_WAITSEC ; WAIT FOR SECONDS TICK + +; PUSH DE +; POP BC +; CALL NEWLINE +; CALL PRTHEXWORD + +; POP BC +; DJNZ HB_CPUSPDX +; + LD A,H + OR L + RET Z ; FAILURE, USE DEFAULT CPU SPEED + +; + ; MOVE LOOP COUNT TO HL + PUSH DE + POP HL +; + ; TIMES 4 FOR CPU SPEED IN KHZ + RES 0,L ; GRANULARITY +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + SLA L + RL H +#ENDIF + SLA L + RL H + SLA L + RL H +; + LD (CB_CPUKHZ),HL + LD DE,1000 + CALL DIV16 + LD A,C + LD (CB_CPUMHZ),A +; + RET +; +HB_WAITSEC: + ; WAIT FOR SECONDS TICK + ; RETURN SECS VALUE IN A, LOOP COUNT IN DE + LD DE,0 ; INIT LOOP COUNTER +HB_WAITSEC1: +#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2)| (PLATFORM == PLT_RC)) + ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 + CALL DLY32 + CALL DLY8 + CALL DLY2 + JP $ + 3 ; 10 TSTATES + JP $ + 3 ; 10 TSTATES + JP $ + 3 ; 10 TSTATES + JP $ + 3 ; 10 TSTATES + ;LD A,R ; 9 TSTATES + INC BC ; 6 TSTATES + ;LD A,(BC) ; 7 TSTATES + ;NOP ; 4 TSTATES + NOP ; 4 TSTATES +#ENDIF + +#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) + ; LOOP TARGET IS 8000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 8 + ;CALL DLY64 + CALL DLY32 + CALL DLY16 + CALL DLY8 + CALL DLY4 + CALL DLY2 + CALL DLY1 ; CALL (25TS) & RET (18TS) = 43TS + OR A ; 7 TSTATES + OR A ; 7 TSTATES + ;OR A ; 7 TSTATES + ;OR A ; 7 TSTATES + NOP ; 6 TSTATES + ;NOP ; 6 TSTATES + ;NOP ; 6 TSTATES + ;NOP ; 6 TSTATES + ;NOP ; 6 TSTATES +#ENDIF +; + PUSH DE + CALL HB_RDSEC ; GET SECONDS + POP DE + INC DE ; BUMP COUNTER + LD HL,HB_CURSEC ; POINT TO COMP VALUE + CP (HL) ; TEST FOR CHANGE + RET NZ ; DONE IF TICK OCCURRED + LD A,D ; CHECK HL + OR E ; ... FOR OVERFLOW + RET Z ; TIMEOUT, SOMETHING IS WRONG + JR HB_WAITSEC1 ; LOOP +; +HB_RDSEC: + ; READ SECONDS BYTE INTO A + LD C,$81 ; SECONDS REGISTER + CALL DSRTC_CMD ; SEND THE COMMAND + CALL DSRTC_GET ; READ THE REGISTER + CALL DSRTC_END ; FINISH IT + RET +; +#ELSE +; + RET ; NO RTC, ABORT +; +#ENDIF +; +; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 +; +PRTD3M: + PUSH BC + PUSH DE + PUSH HL + LD E,'0' + LD BC,-10000 + CALL PRTD3M1 + LD E,0 + LD BC,-1000 + CALL PRTD3M1 + CALL PC_PERIOD + LD BC,-100 + CALL PRTD3M1 + LD C,-10 + CALL PRTD3M1 + LD C,-1 + CALL PRTD3M1 + POP HL + POP DE + POP BC + RET +PRTD3M1: + LD A,'0' - 1 +PRTD3M2: + INC A + ADD HL,BC + JR C,PRTD3M2 + SBC HL,BC + CP E + JR Z,PRTD3M3 + LD E,0 + CALL COUT +PRTD3M3: + RET +; +;================================================================================================== +; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES +;================================================================================================== +; +PRTSUM: + CALL NEWLINE2 ; SKIP A LINE + LD DE,PS_STRHDR ; POINT TO HEADER + CALL WRITESTR ; PRINT IT +; + ; PRINT DISK DEVICES + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + LD C,BF_SYSGET_DIOCNT ; SUBFUNC: DISK UNIT COUNT + RST 08 ; E := DISK UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + JR Z,PRTSUM1A ; IF NONE, BYPASS + LD C,0 ; C WILL BE UNIT INDEX +PRTSUM1: + PUSH BC ; SAVE LOOP CONTROL + CALL PS_DISK ; PRINT DISK INFO + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP DISK UNIT INDEX + DJNZ PRTSUM1 ; LOOP THRU ALL DISK DEVICES +; +PRTSUM1A: + ; PRINT SERIAL DEVICES + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + LD C,BF_SYSGET_CIOCNT ; SUBFUNC: SERIAL UNIT COUNT + RST 08 ; E := SERIAL UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + JR Z,PRTSUM2A ; IF NONE, BYPASS + LD C,0 ; C WILL BE UNIT INDEX +PRTSUM2: + PUSH BC ; SAVE LOOP CONTROL + CALL PS_SERIAL ; PRINT SERIAL INFO + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP SERIAL UNIT INDEX + DJNZ PRTSUM2 ; LOOP THRU ALL SERIAL DEVICES +; +PRTSUM2A: + ; PRINT VIDEO DEVICES + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + LD C,BF_SYSGET_VDACNT ; SUBFUNC: VIDEO UNIT COUNT + RST 08 ; E := SERIAL UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + JR Z,PRTSUM3A ; IF NONE, BYPASS + LD C,0 ; C WILL BE UNIT INDEX +PRTSUM3: + PUSH BC ; SAVE LOOP CONTROL + CALL PS_VIDEO ; PRINT VIDEO INFO + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP VIDEO UNIT INDEX + DJNZ PRTSUM3 ; LOOP THRU ALL VIDEO DEVICES +; +PRTSUM3A: + RET ; DONE +; +; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C +; +PS_DISK: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("Disk $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_DDSTRREF ; POINT TO DISK DEVICE TYPE NAME TABLE + CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH + POP DE ; RECOVER ATTRIBUTES TO DE + PUSH DE ; SAVE ATTRIBUTES AGAIN + CALL PS_PRTDT ; PRINT DISK TYPE + POP DE ; RESTORE ATTRIBUTES + POP BC ; RESTORE UNIT NUM + CALL PS_PRTDC ; PRINT DISK CAPACITY +; + CALL NEWLINE + RET +; +; PRINT DISK TYPE (DISK ATTRIBUTE IN E) +; +PS_PRTDT: + LD A,E ; ATTRIBUTES TO A + BIT 7,A ; FLOPPY BIT SET? + LD HL,PS_DTFLOP ; ASSUME FLOPPY + JR NZ,PS_PRTDT1 ; IF FLOPPY, JUMP AHEAD + RRCA ; SHIFT TYPE BITS + RRCA + RRCA + AND $07 ; AND ISOLATE THEM + RLCA ; X2 FOR WORD OFFSET IN STRING TABLE + LD HL,PS_DTSTRREF + 2 ; POINT TO STR REF TABLE (SKIP FLOPPY STRING) + CALL ADDHLA + LD A,(HL) + INC HL + LD H,(HL) + LD L,A +; +PS_PRTDT1: + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,18 ; 18 CHAR FIELD + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E) +; +PS_PRTDC: +; + LD A,E ; ATTRIBUTE TO ACCUM + BIT 7,A ; TEST FOR FLOPPY + JR NZ,PS_PRTDC2 ; HANDLE FLOPPY + RRCA ; ISOLATE TYPE BITS + RRCA + RRCA + AND $07 + CP 4 ; ROM DISK? + JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB + CP 5 ; RAM DISK? + JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB +; + ; PRINT HARD DISK STORAGE SIZE IN MB + LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY + RST 08 ; DE:HL := BLOCKS + JP NZ,PS_PRTNUL ; MEDIA PROBLEM + RES 7,D ; CLEAR LBA BIT + LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB + CALL SRL32 ; RIGHT SHIFT + CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) + PRTS("MB$") ; PRINT SUFFIX + CALL PC_COMMA + PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA + RET ; DONE +; +PS_PRTDC1: + ; PRINT ROM/ROM DISK CAPACITY IN KB + LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY + RST 08 ; DE:HL := BLOCKS + JP NZ,PS_PRTNUL ; MEDIA PROBLEM + RES 7,D ; CLEAR LBA BIT + LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB + CALL SRL32 ; RIGHT SHIFT + CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) + PRTS("KB$") ; PRINT SUFFIX + CALL PC_COMMA + PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA + RET ; DONE +; +PS_PRTDC2: + LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING + ; PRINT FLOPPY TYPE + LD A,C ; ATTRIBUTE TO ACCUM + RLCA ; ISOLATE FORM FACTOR BITS + RLCA + RLCA + AND $03 + LD DE,PS_FLP8 ; ASSUME 8" + CP 0 + JR Z,PS_PRTDC2A + LD DE,PS_FLP5 ; ASSUME 5.25" + CP 1 + JR Z,PS_PRTDC2A + LD DE,PS_FLP3 ; ASSUME 3.5" + CP 2 + JR Z,PS_PRTDC2A + LD DE,PS_FLPN ; ASSUME OTHER" +PS_PRTDC2A: + CALL WRITESTR + ; PRINT FLOPPY SIDES + LD A,C ; ATTRIBUTE TO ACCUM + LD DE,PS_FLPSS ; ASSUME SINGLE SIDED + BIT 4,A ; DS? + JR Z,PS_PRTDC2B + LD DE,PS_FLPDS ; DOUBLE SIDED +PS_PRTDC2B: + CALL WRITESTR + ; PRINT FLOPPY DENSITY + LD A,C ; ATTRIBUTE TO ACCUM + RRCA ; ISOLATE DENSITY BITS + RRCA + AND $03 + LD DE,PS_FLPSD ; SINGLE DENSITY + CP 0 + JR Z,PS_PRTDC2C + LD DE,PS_FLPDD ; DOUBLE DENSITY + CP 1 + JR Z,PS_PRTDC2C + LD DE,PS_FLPHD ; HIGH DENSITY + CP 2 + JR Z,PS_PRTDC2C + LD DE,PS_FLPED ; EXTENDED DENSITY + CP 3 + JR Z,PS_PRTDC2C +PS_PRTDC2C: + CALL WRITESTR + CALL PC_COMMA + PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA +; + RET ; DONE +; +; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C +; +PS_SERIAL: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("Serial $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, C:=DEVICE ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_SDSTRREF ; POINT TO SERIAL DEVICE TYPE NAME TABLE + CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH + POP BC ; RECOVER ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES AGAIN + CALL PS_PRTST ; PRINT SERIAL TYPE + POP BC ; RESTORE ATTRIBUTES + POP DE ; RESTORE UNIT NUM TO E + CALL PS_PRTSC ; PRINT SERIAL CONFIG +; + CALL NEWLINE + RET +; +; PRINT SERIAL TYPE (SERIAL ATTRIBUTE IN E) +; +PS_PRTST: + LD HL,PS_STRS232 ; ASSUME RS-232 + BIT 7,C ; 0=RS-232, 1=TERMINAL + JR Z,PS_PRTST1 ; HANDLE TERMINAL TYPE + LD HL,PS_STTERM ; TYPE IS TERMINAL +; +PS_PRTST1: + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,18 ; 18 CHAR FIELD + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) +; +PS_PRTSC: + BIT 7,C ; 0=RS-232, 1=TERMINAL + JR NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG +; + ; PRINT RS-232 CONFIG + LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG + LD C,E ; SET SERIAL UNIT NUM + RST 08 ; DE:HL := BAUD RATE + LD A,D ; TEST FOR $FF + AND E + INC A ; SET Z IF DE == $FF + JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED +; +PS_PRTSC0: + ; PRINT BAUD RATE + PUSH DE ; PRESERVE DE + LD A,D + AND $1F ; ISOLATE ENCODED BAUD RATE + LD L,A ; PUT IN L + LD H,0 ; H IS ALWAYS ZERO + LD DE,75 ; BAUD RATE DECODE CONSTANT + CALL DECODE ; DE:HL := BAUD RATE + LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF + CALL BIN2BCD ; CONVERT TO BCD + CALL PRTBCD ; AND PRINT IN DECIMAL + POP DE ; RESTORE DE +; + ; PRINT DATA BITS + PUSH DE ; PRESERVE DE + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + AND $03 ; ISOLATE DATA BITS VALUE + ADD A,'5' ; CONVERT TO CHARACTER + CALL COUT ; AND PRINT + POP DE ; RESTORE DE +; + ; PRINT PARITY + PUSH DE ; PRESERVE DE + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + RRCA ; SHIFT RELEVANT BITS + RRCA ; ... + RRCA ; ... + AND $07 ; AND ISOLATE DATA BITS VALUE + LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE + CALL ADDHLA ; APPLY OFFSET + LD A,(HL) ; GET CHARACTER + CALL COUT ; AND PRINT + POP DE ; RESTORE DE +; + ; PRINT STOP BITS + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + RRCA ; SHIFT RELEVANT BITS + RRCA ; ... + AND $01 ; AND ISOLATE DATA BITS VALUE + ADD A,'1' ; MAKE IT A CHARACTER + CALL COUT ; AND PRINT +; + RET +; +PS_PRTSC1: + ; PRINT TERMINAL CONFIG + LD A,C ; GET ATTRIBUTE VALUE + CP $FF ; NO ATTACHED VDA + JR Z,PS_PRTSC2 + PRTS("Video $") ; FORMATTING + AND $0F ; ISOLATE VIDEO UNIT NUM + CALL PRTDECB ; PRINT IT + CALL PC_COMMA +#IF (VDAEMU == EMUTYP_TTY) + PRTS("TTY$") +#ENDIF +#IF (VDAEMU == EMUTYP_ANSI) + PRTS("ANSI$") +#ENDIF + RET +; +PS_PRTSC2: + PRTS("PropTerm$") ; ASSUME PROPELLER + CALL PC_COMMA + PRTS("ANSI$") + RET +; +; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C +; +PS_VIDEO: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("Video $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_VDSTRREF ; POINT TO VIDEO DEVICE TYPE NAME TABLE + CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH + POP DE ; RECOVER ATTRIBUTES + PUSH DE ; SAVE ATTRIBUTES AGAIN + CALL PS_PRTVT ; PRINT VIDEO TYPE + POP DE ; RESTORE ATTRIBUTES + POP BC ; RESTORE UNIT NUM + CALL PS_PRTVC ; PRINT VIDEO CONFIG +; + CALL NEWLINE + RET +; +; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E) +; +PS_PRTVT: + LD HL,PS_VTCRT ; ASSUME CRT + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,18 ; 18 CHAR FIELD + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E) +; +PS_PRTVC: + PRTS("Text$") + CALL PC_COMMA + LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG + RST 08 ; D:=ROWS, E:=COLS + LD A,E + CALL PRTDECB + LD A,'x' + CALL COUT + LD A,D + CALL PRTDECB + RET +; +; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE +; +PS_PRTDEV: + LD A,D + RRCA ; TYPE IS IN UPPER NIBBLE, MOVE TO LOWER NIBBLE + RRCA + RRCA + RRCA + RLCA ; X2 FOR WORD OFFSET IN STRING TABLE + CALL ADDHLA + LD A,(HL) + INC HL + LD H,(HL) + LD L,A + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED + LD A,E ; NUM + CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR + CALL PC_COLON ; PRINT COLON + LD A,12 - 2 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON + SUB C + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE +; +PS_PRTNUL: + LD HL,PS_STRNUL + ; FALL THRU TO PS_PRT +; +; +; +PS_PRT: + ; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C + LD C,0 ; INIT CHAR COUNT +PS_PRT1: + LD A,(HL) ; GET CHAR + INC HL ; BUMP INDEX + CP '$' ; TERM? + RET Z ; IF SO, DONE + CALL COUT ; PRINT IT + INC C ; BUMP COUNTER + JR PS_PRT1 ; AND LOOP +; +; +; +PS_PAD: + ; PAD N SPACES SPECIFIED IN A + LD B,A + LD A,' ' +PS_PAD1: + CALL COUT + DJNZ PS_PAD1 + RET +; +; +; +PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE +; +; DISK DEVICE STRINGS +; +PS_DDSTRREF: + .DW PS_DDMD, PS_DDFD, PS_DDRF, PS_DDIDE, PS_DDATAPI, PS_DDPPIDE + .DW PS_DDSD, PS_DDPRPSD, PS_DDPPPSD, PS_DDHDSK +; +PS_DDMD .TEXT "MD$" +PS_DDFD .TEXT "FD$" +PS_DDRF .TEXT "RF$" +PS_DDIDE .TEXT "IDE$" +PS_DDATAPI .TEXT "ATAPI$" +PS_DDPPIDE .TEXT "PPIDE$" +PS_DDSD .TEXT "SD$" +PS_DDPRPSD .TEXT "PRPSD$" +PS_DDPPPSD .TEXT "PPPSD$" +PS_DDHDSK .TEXT "HDSK$" +; +; DISK TYPE STRINGS +; +PS_DTSTRREF: + .DW PS_DTFLOP, PS_DTHARD, PS_DTCF, PS_DTSD + .DW PS_DTUSB, PS_DTROM, PS_DTRAM, PS_DTRF +; +PS_DTFLOP .TEXT "Floppy Disk$" +PS_DTHARD .TEXT "Hard Disk$" +PS_DTCF .TEXT "CompactFlash$" +PS_DTSD .TEXT "SD Card$" +PS_DTUSB .TEXT "USB Drive$" +PS_DTROM .TEXT "ROM Disk$" +PS_DTRAM .TEXT "RAM Disk$" +PS_DTRF .TEXT "RAM Floppy$" +PS_DTOTHER .TEXT "???$" +; +; FLOPPY ATTRIBUTE STRINGS +; +PS_FLP8 .TEXT "8\",$" +PS_FLP5 .TEXT "5.25\",$" +PS_FLP3 .TEXT "3.5\",$" +PS_FLPN .TEXT "???\",$" +; +PS_FLPSS .TEXT "SS/$" +PS_FLPDS .TEXT "DS/$" +; +PS_FLPSD .TEXT "SD$" +PS_FLPDD .TEXT "DD$" +PS_FLPHD .TEXT "HD$" +PS_FLPED .TEXT "ED$" +; +; SERIAL DEVICE STRINGS +; +PS_SDSTRREF: + .DW PS_SDUART, PS_SDASCI, PS_SDTERM, + .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA +; +PS_SDUART .TEXT "UART$" +PS_SDASCI .TEXT "ASCI$" +PS_SDTERM .TEXT "TERM$" +PS_SDPRPCON .TEXT "PRPCON$" +PS_SDPPPCON .TEXT "PPPCON$" +PS_SDSIO .TEXT "SIO$" +PS_SDACIA .TEXT "ACIA$" +; +; SERIAL TYPE STRINGS +; +PS_STRS232 .TEXT "RS-232$" +PS_STTERM .TEXT "Terminal$" +; +PS_STPARMAP .DB "NONENMNS" + +; +; SERIAL TYPE STRINGS +; +; +; VIDEO DEVICE STRINGS +; +PS_VDSTRREF: + .DW PS_VDVDU, PS_VDCVDU, PS_VDNEC, PS_VDTMS, PS_VDVGA +; +PS_VDVDU .TEXT "VDU$" +PS_VDCVDU .TEXT "CVDU$" +PS_VDNEC .TEXT "NEC$" +PS_VDTMS .TEXT "TMS$" +PS_VDVGA .TEXT "VGA$" +; +; VIDEO TYPE STRINGS +; +PS_VTCRT .TEXT "CRT$" +; +; VIDEO CONFIG STRINGS +; +; +; +; 0 1 2 3 4 5 6 7 +; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 +PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" + .TEXT "---------- ---------- ---------------- --------------------\r\n$" +; +;================================================================================================== +; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) +;================================================================================================== +; +; OUTPUT CHARACTER FROM A +; +COUT: + ; SAVE ALL INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL +; + ; GET CURRENT CONSOLE UNIT + LD E,A ; TEMPORARILY STASH OUTPUT CHAR IN E + LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE + CP $FF ; TEST FOR $FF (HBIOS NOT READY) + JR Z,COUT1 ; IF NOT READY, USE XIO +; + ; USE HBIOS + LD C,A ; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY + JR COUT2 ; CONTINUE +; +COUT1: + ;; USE XIO + ;LD A,E ; GET OUTPUT CHAR BACK TO ACCUM + ;CALL XIO_OUTC ; OUTPUT VIA XIO +; +COUT2: + ; RESTORE ALL REGISTERS + POP HL + POP DE + POP BC + POP AF + RET +; +; INPUT CHARACTER TO A +; +CIN: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE + CP $FF ; TEST FOR $FF (HBIOS NOT READY) + JR Z,CIN1 ; IF NOT READY, USE XIO +; + ; USE HBIOS + LD C,A ; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY + LD A,E ; RESULTANT CHAR TO A + JR CIN2 ; CONTINUE +; +CIN1: + ;; USE XIO + ;CALL XIO_INC ; GET CHAR +; +CIN2: +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) +; +CST: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE + CP $FF ; TEST FOR $FF (HBIOS NOT READY) + JR Z,CST1 ; IF NOT READY, USE XIO +; + ; USE HBIOS + LD C,A ; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY + JR CST2 ; CONTINUE +; +CST1: + ;; USE XIO + ;CALL XIO_IST ; GET STATUS +; +CST2: + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +;================================================================================================== +; MISCELLANEOUS UTILITY FUNCTIONS +;================================================================================================== +; +; SET HL TO IY+A, A IS TRASHED +; +LDHLIYA: + PUSH IY ; COPY INSTANCE DATA PTR + POP HL ; ... TO HL + ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN + ADD A,L ; ADD OFFSET TO LSB + LD L,A ; ... PUT BACK IN L + RET NC ; DONE IF CF NOT SET + INC H ; IF CF SET, BUMP MSB + RET ; ... AND RETURN +; +; CONVERT AN HBIOS STANDARD HARD DISK CHS ADDRESS TO +; AN LBA ADDRESS. A STANDARD HBIOS HARD DISK IS ASSUMED +; TO HAVE 16 SECTORS PER TRACK AND 16 HEADS PER CYLINDER. +; +; INPUT: HL=TRACK, D=HEAD, E=SECTOR +; OUTPUT: DE:HL=32 BIT LBA ADDRESS (D:7 IS NOT SET IN THE RESULT) +; +HB_CHS2LBA: +; + LD A,D ; HEAD TO A + RLCA ; LEFT SHIFT TO HIGH NIBBLE + RLCA ; ... DEPENDS ON HIGH + RLCA ; ... NIBBLE BEING 0 SINCE + RLCA ; ... IT ROTATES INTO LOW NIBBLE + OR E ; COMBINE WITH SECTOR (HIGH NIBBLE MUST BE ZERO) + LD D,0 + LD E,H + LD H,L + LD L,A + XOR A + RET +; +;================================================================================================== +; HBIOS GLOBAL DATA +;================================================================================================== +; +IDLECOUNT .DB 0 +; +HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION +; +HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER +; +STR_BANNER .DB "RetroBrew HBIOS v", BIOSVER, ", ", TIMESTAMP, "$" +STR_PLATFORM .DB PLATFORM_NAME, "$" +STR_SWITCH .DB "*** Activating CRT Console ***$" +STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" +; +HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) +; +HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) +; +HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER +; +HB_END .EQU $ +; +SLACK .EQU BNKTOP - $ + .ECHO "HBIOS space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +#IFDEF ROMBOOT + .FILL SLACK +#ENDIF +; + .END diff --git a/romldr.asm b/romldr.asm new file mode 100644 index 00000000..fcbf8748 --- /dev/null +++ b/romldr.asm @@ -0,0 +1,1088 @@ +; +;================================================================================================== +; LOADER +;================================================================================================== +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +; osimg.bin +; +;LDRIMG .EQU $0000 ;SIZE 0A00 > 0000-0A00 +MONIMG .EQU $0A00 ;SIZE 1000 > 0A00-1A00 +CPMIMG .EQU $1A00 ;SIZE 3000 > 1A00-4A00 +ZSYSIMG .EQU $4A00 ;SIZE 3000 > 4A00-7A00 +; +; osimg1.bin +; +BASIMG .EQU $0000 ;SIZE 2000 > 0000-2000 +TBCIMG .EQU $2000 ;SIZE 0900 > 2000-2900 +; +INT_IM1 .EQU $FF00 +; +;---------------------------------------------------------- +; NAME NAME OF ROM 8 CHAR +; BANK WHICH ROM BANK THE IMAGE IS IN. +; IMAGE LOCATION OF IMAGE IN 32K ROM BANK. +; LOCATION WHERE IMAGE NEEDS TO BE COPIED TO IN RAM. +; EXECUTE ADDRESS TO START EXECUTING. +; + +;ROMTBL .DB "B","BASIC $", 0, BASIMG, BAS_LOC, BAS_SIZ, BASE_LOC +; .DB "C","CP/M $", 0, +; .DB "F","FORTH $", 1, +; .DB "Z","ZSYSTEM$", 1, +; +; +; .DB "MONITOR$", 0, +; + + .ORG 0 +; +;================================================================================================== +; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE +;================================================================================================== +; + JP $100 ; RST 0: JUMP TO BOOT CODE + .FILL (008H - $),0FFH +#IF (PLATFORM == PLT_UNA) + JP $FFFD ; RST 8: INVOKE UBIOS FUNCTION +#ELSE + JP HB_INVOKE ; RST 8: INVOKE HBIOS FUNCTION +#ENDIF + .FILL (010H - $),0FFH + RET ; RST 10 + .FILL (018H - $),0FFH + RET ; RST 18 + .FILL (020H - $),0FFH + RET ; RST 20 + .FILL (028H - $),0FFH + RET ; RST 28 + .FILL (030H - $),0FFH + RET ; RST 30 + .FILL (038H - $),0FFH +#IF (PLATFORM == PLT_UNA) + RETI ; RETURN W/ INTS DISABLED +#ELSE + #IF (INTMODE == 1) + JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM + #ELSE + RETI ; RETURN W/ INTS DISABLED + #ENDIF +#ENDIF + .FILL (066H - $),0FFH + RETN ; NMI +; + .FILL (100H - $),0FFH ; PAD REMAINDER OF PAGE ZERO +; +; +;================================================================================================== +; LOADER +;================================================================================================== +; + DI ; NO INTERRUPTS + LD SP,BL_STACK ; SETUP STACK +; + ; BANNER + LD DE,STR_BANNER + CALL WRITESTR + +; +#IF (PLATFORM != PLT_UNA) + CALL DELAY_INIT ; INIT DELAY FUNCTIONS +#ENDIF +; +#IF (PLATFORM == PLT_UNA) +; ; COPY UNA BIOS PAGE ZERO TO USER BANK, LEAVE USER BANK ACTIVE +; LD BC,$01FB ; UNA FUNC = SET BANK +; LD DE,BID_BIOS ; UBIOS_PAGE (SEE PAGES.INC) +; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) +; PUSH DE ; SAVE PREVIOUS BANK +;; +; LD HL,0 ; FROM ADDRESS 0 (PAGE ZERO) +; LD DE,$9000 ; USE $9000 AS BOUNCE BUFFER +; LD BC,256 ; ONE PAGE IS 256 BYTES +; LDIR ; DO IT +;; +; LD BC,$01FB ; UNA FUNC = SET BANK +; ;POP DE ; RECOVER OPERATING BANK +; LD DE,BID_USR ; TO USER BANK +; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) +;; +; LD HL,$9000 ; USE $9000 AS BOUNCE BUFFER +; LD DE,0 ; TO PAGE ZERO OF OPERATING BANK +; LD BC,256 ; ONE PAGE IS 256 BYTES +; LDIR ; DO IT +;; +;; ; INSTALL UNA INVOCATION VECTOR FOR RST 08 +;; ; *** IS THIS REDUNDANT? *** +;; LD A,$C3 ; JP INSTRUCTION +;; LD (8),A ; STORE AT 0x0008 +;; LD HL,($FFFE) ; UNA ENTRY VECTOR +;; LD (9),HL ; STORE AT 0x0009 +;; +; LD BC,$01FB ; UNA FUNC = SET BANK +; POP DE ; RECOVER OPERATING BANK +; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) +#ELSE + ; PREP THE USER BANK (SETUP PAGE ZERO) + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_BIOS ; E = SRC BANK = BIOS BANK + LD HL,256 ; HL = COPY LEN = 1 PAGE = 256 BYTES + RST 08 ; DO IT + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,0 ; COPY FROM BIOS ADDRESS 0 + LD DE,0 ; TO USER ADDRESS 0 + RST 08 ; DO IT +#ENDIF + EI +; + ; RUN THE BOOT LOADER MENU + JP DOBOOTMENU +; +;__DOBOOT________________________________________________________________________________________________________________________ +; +; PERFORM BOOT FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; +DOBOOTMENU: +; CALL NEWLINE + LD DE,STR_BOOTMENU + CALL WRITESTR + CALL PRTALL + CALL PC_COLON + +#IF (DSKYENABLE) + LD HL,BOOT ; POINT TO BOOT MESSAGE + CALL SEGDISPLAY ; DISPLAY MESSAGE +#ENDIF + +#IF (BOOTTYPE == BT_AUTO) + LD BC,100 * BOOT_TIMEOUT + LD (BL_TIMEOUT),BC +#ENDIF + +DB_BOOTLOOP: +; +; CHECK FOR CONSOLE BOOT KEYPRESS +; + CALL CST + OR A + JP Z,DB_CONEND + CALL CINUC + CP 'B' ; NASCOM BASIC + JP Z,GOBASIC + CP 'C' ; CP/M BOOT FROM ROM + JP Z,GOCPM + CP 'M' ; MONITOR + JP Z,GOMONSER +; CP 'L' ; LIST DRIVES +; JP Z,GOLIST + CP 'T' ; TASTY BASIC + JP Z,GOTBAS + CP 'Z' ; ZSYSTEM BOOT FROM ROM + JP Z,GOZSYS + CP '0' ; 0-9, DISK DEVICE + JP C,DB_INVALID + CP '9' + 1 + JP NC,DB_INVALID + SUB '0' + JP GOBOOTDISK +DB_CONEND: +; +; CHECK FOR DSKY BOOT KEYPRESS +; +#IF (DSKYENABLE) + CALL KY_STAT ; GET KEY FROM KB INTO A + OR A + JP Z,DB_DSKYEND + CALL KY_GET + CP KY_GO ; GO = MONITOR + JP Z,GOMONDSKY + CP KY_BO ; BO = BOOT ROM + JP Z,GOCPM +; CP 0AH ; A-F, DISK BOOT +; JP C,DB_INVALID + CP 0FH + 1 ; 0-F, DISK BOOT +; JP NC,DB_INVALID +; SUB 0AH + JP GOBOOTDISK +; LD HL,BOOT ; POINT TO BOOT MESSAGE +; LD A,00H ; BLANK OUT SELECTION,IT WAS INVALID +; LD (HL),A ; STORE IT IN DISPLAY BUFFER +; CALL SEGDISPLAY ; DISPLAY THE BUFFER +DB_DSKYEND: +#ENDIF +; +; IF CONFIGURED, CHECK FOR AUTOBOOT TIMEOUT +; +#IF (BOOTTYPE == BT_AUTO) + + ; DELAY FOR 10MS TO MAKE TIMEOUT CALC EASY + LD DE,625 ; 16US * 625 = 10MS + CALL VDELAY + + ; CHECK/INCREMENT TIMEOUT + LD BC,(BL_TIMEOUT) + DEC BC + LD (BL_TIMEOUT),BC + LD A,B + OR C + JP NZ,DB_BOOTLOOP + + ; TIMEOUT EXPIRED, PERFORM DEFAULT BOOT ACTION + LD A,BOOT_DEFAULT + CP 'B' ; NASCOM BASIC + JP Z,GOBASIC + CP 'C' ; CP/M BOOT FROM ROM + JP Z,GOCPM + CP 'M' ; MONITOR + JP Z,GOMONSER +; CP 'L' ; LIST DRIVES +; JP Z,GOLIST + CP 'T' ; TASTY BASIC + JP Z,GOTBAS + CP 'Z' ; ZSYSTEM BOOT FROM ROM + JP Z,GOZSYS + CP '0' ; 0-9, DISK DEVICE + JP C,DB_INVALID + CP '9' + 1 + JP NC,DB_INVALID + SUB '0' + JP GOBOOTDISK +#ENDIF + + JP DB_BOOTLOOP +; +; BOOT OPTION PROCESSING +; +DB_INVALID: + LD DE,STR_INVALID + CALL WRITESTR + JP DOBOOTMENU +; +GOBASIC: + LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + ; COPY BASIC FROM BASIC FROM OSIMG0 IN ROM BANK TO THIS RAM BANKS + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_OSIMG ; E = SRC BANK = BIOS BANK + LD HL,BAS_SIZ ; HL = COPY LEN = 1 PAGE = 256 BYTES + RST 08 ; DO IT + LD DE,STR_LOADING + CALL WRITESTR ; WRITE IT TO CONSOLE + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,BASIMG ; COPY FROM + LD DE,BAS_LOC ; COPY TO + RST 08 ; DO IT + LD DE,STR_LAUNCH + CALL WRITESTR + LD HL,BAS_LOC + JP CHAIN + +; LD HL,BAS_LOC +; PUSH HL +; LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE +; CALL WRITESTR ; WRITE IT TO CONSOLE +; ; COPY IMAGE TO EXEC ADDRESS +; LD HL,BASIMG ; HL := BASIC IMAGE ADDRESS +; LD DE,BAS_LOC ; DE := BASIC EXEC ADDRESS +; LD BC,BAS_SIZ ; BC := BASIC SIZE +; LDIR ; COPY BASIC CODE TO EXEC ADDRESS +; POP HL ; RECOVER ENTRY ADDRESS +; JR CHAIN ; AND CHAIN TO IT + +GOTBAS: + LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + ; COPY BASIC FROM BASIC FROM OSIMG0 IN ROM BANK TO THIS RAM BANKS + LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY + LD D,BID_USR ; D = DEST BANK = USER BANK + LD E,BID_OSIMG ; E = SRC BANK = BIOS BANK + LD HL,TBC_SIZ ; HL = COPY LEN = 1 PAGE = 256 BYTES + RST 08 ; DO IT + LD DE,STR_LOADING + CALL WRITESTR ; WRITE IT TO CONSOLE + LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY + LD HL,TBCIMG ; COPY FROM + LD DE,TBC_LOC ; COPY TO + RST 08 ; DO IT + LD DE,STR_LAUNCH + CALL WRITESTR + LD HL,TBC_LOC + JP CHAIN + +; LD HL,TBC_LOC +; PUSH HL +; LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE +; CALL WRITESTR ; WRITE IT TO CONSOLE +; ; COPY IMAGE TO EXEC ADDRESS +; LD HL,TBCIMG ; HL := BASIC IMAGE ADDRESS +; LD DE,TBC_LOC ; DE := BASIC EXEC ADDRESS +; LD BC,TBC_SIZ ; BC := BASIC SIZE +; LDIR ; COPY BASIC CODE TO EXEC ADDRESS +; POP HL ; RECOVER ENTRY ADDRESS +; JR CHAIN ; AND CHAIN TO IT + +GOMONSER: + LD HL,MON_SERIAL ; MONITOR SERIAL INTERFACE ENTRY ADDRESS TO HL + JR GOMON ; LOAD AND RUN MONITOR +; +GOMONDSKY: + LD HL,MON_DSKY ; MONITOR DSKY INTERFACE ENTRY ADDRESS TO HL + JR GOMON ; LOAD AND RUN MONITOR +; +GOMON: + LD DE,STR_BOOTMON ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE +; + PUSH HL ; SAVE DESIRED MONITOR ENTRY ADDRESS +; + ; COPY MONITOR IMAGE TO EXEC ADDRESS + LD HL,MONIMG ; HL := MONITOR IMAGE ADDRESS + LD DE,MON_LOC ; DE := MONITOR EXEC ADDRESS + LD BC,MON_SIZ ; BC := MONITOR SIZE + LDIR ; COPY MONITOR CODE TO EXEC ADDRESS +; + POP HL ; RECOVER ENTRY ADDRESS + JR CHAIN ; AND CHAIN TO IT +; +GOCPM: + LD DE,STR_BOOTCPM ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + LD HL,CPMIMG ; SET HL TO CPM IMAGE ADDRESS + JR GOOS ; LOAD AND RUN OS +; +GOZSYS: + LD DE,STR_BOOTZSYS ; DE POINTS TO MESSAGE + CALL WRITESTR ; WRITE IT TO CONSOLE + LD HL,ZSYSIMG ; SET HL TO ZSYS IMAGE ADDRESS + JR GOOS ; LOAD AND RUN OS +; +GOOS: + ; COPY OS IMAGE TO EXEC ADDRESS + LD DE,CPM_LOC ; DE := MONITOR EXEC ADDRESS + LD BC,CPM_SIZ ; BC := MONITOR SIZE + LDIR ; COPY MONITOR CODE TO EXEC ADDRESS +; + LD HL,CPM_ENT + ;JR CHAIN ; CHAIN TO ENTRY ADDRESS IN USER BANK +; +CHAIN: + PUSH HL ; SAVE ENTRY ADDRESS +; +#IF (PLATFORM == PLT_UNA) + LD BC,$00FB ; GET LOWER PAGE ID + RST 08 ; DE := LOWER PAGE ID == BOOT ROM PAGE + LD L,1 ; BOOT DISK UNIT IS ROM (UNIT ID = 1) + LD BC,$01FC ; UNA FUNC: SET BOOTSTRAP HISTORY + RST 08 ; CALL UNA +; + ; HL IS ALREADY ON STACK AS REQUIRED BY UNA EXEC CHAIN CALL + LD DE,BID_USR ; TARGET BANK ID + PUSH DE ; ... ON STACK + DI ; ENTER WITH INTS DISABLED + JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN +#ELSE + LD B,BF_SYSSET ; HB FUNC: SET HBIOS PARAMETER + LD C,BF_SYSSET_BOOTINFO ; HB SUBFUNC: SET BOOT INFO + LD A,(HB_CURBNK) ; GET CURRENT BANK ID FROM PROXY DATA + LD L,A ; ... AND SAVE AS BOOT BANK + LD DE,$0100 ; BOOT VOLUME (UNIT, SLICE) + RST 08 +; + LD A,BID_USR ; ACTIVATE USER BANK + POP HL ; RECOVER ENTRY ADDRESS + DI ; ENTER WITH INTS DISABLED + CALL HB_BNKCALL ; AND GO + HALT ; WE SHOULD NEVER RETURN!!! +#ENDIF + +; +GOLIST: + LD DE,STR_LIST + CALL WRITESTR + LD DE,STR_DRVLIST + CALL WRITESTR + CALL PRTALL + JP DOBOOTMENU +; +GOBOOTDISK: + LD (BL_BOOTID),A + LD DE,STR_BOOTDISK + CALL WRITESTR + JP BOOTDISK +; +; BOOT FROM DISK DRIVE +; +BOOTDISK: + LD DE,STR_BOOTDISK1 ; DISK BOOT MESSAGE + CALL WRITESTR ; PRINT IT + +#IF (PLATFORM == PLT_UNA) +; +; BOOT FROM UNA DISK DRIVE +; + LD A,(BL_BOOTID) ; GET BOOT DEVICE ID + LD B,A ; MOVE TO B + + ; LOAD SECTOR 2 (BOOT INFO) + LD C,$41 ; UNA FUNC: SET LBA + LD DE,0 ; HI WORD OF LBA IS ALWAYS ZERO + LD HL,2 ; LOAD STARTING INFO SECTOR 2 + RST 08 ; SET LBA + JP NZ,DB_ERR ; HANDLE ERROR +; + LD C,$42 ; UNA FUNC: READ SECTORS + LD DE,BL_INFOSEC ; DEST OF CPM IMAGE + LD L,1 ; SECTORS TO READ + RST 08 ; DO READ + JP NZ,DB_ERR ; HANDLE ERROR +; +#ELSE + ; CHECK FOR VALID DRIVE LETTER + LD A,(BL_BOOTID) ; BOOT DEVICE TO A + PUSH AF ; SAVE BOOT DEVICE + LD B,BF_SYSGET + LD C,BF_SYSGET_DIOCNT + RST 08 ; E := DISK UNIT COUNT + POP AF ; RESTORE BOOT DEVICE + CP E ; CHECK MAX (INDEX - COUNT) + JP NC,DB_NODISK ; HANDLE INVALID SELECTION + + ; SET THE BOOT UNIT AND SLICE + LD A,(BL_BOOTID) ; GET BOOTID + LD (BL_DEVICE),A ; STORE IT + XOR A ; LU ALWAYS ZERO + LD (BL_LU),A ; STORE IT + + ; SENSE MEDIA + LD A,(BL_DEVICE) ; GET DEVICE/UNIT + LD C,A ; STORE IN C + LD B,BF_DIOMEDIA ; DRIVER FUNCTION = DISK MEDIA + LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY + RST 08 ; CALL HBIOS + JP NZ,DB_ERR ; HANDLE ERROR + + ; SEEK TO SECTOR 2 OF LU + LD A,(BL_LU) ; GET LU SPECIFIED + LD E,A ; LU INDEX + LD H,65 ; 65 TRACKS PER LU + CALL MULT8 ; HL := H * E + LD DE,$02 ; HEAD 0, SECTOR 2 + LD B,BF_DIOSEEK ; SETUP FOR NEW SEEK CALL + LD A,(BL_DEVICE) ; GET BOOT DISK UNIT + LD C,A ; PUT IN C + RST 08 ; DO IT + JP NZ,DB_ERR ; HANDLE ERROR + + ; READ + LD B,BF_DIOREAD ; FUNCTION IN B + LD A,(BL_DEVICE) ; GET BOOT DISK UNIT + LD C,A ; PUT IN C + LD HL,BL_INFOSEC ; READ INTO INFO SEC BUFFER + LD DE,1 ; TRANSFER ONE SECTOR + RST 08 ; DO IT + JP NZ,DB_ERR ; HANDLE ERROR +; +#ENDIF +; + ; CHECK SIGNATURE + CALL NEWLINE ; FORMATTING + LD DE,(BB_SIG) ; GET THE SIGNATURE + LD A,$A5 ; FIRST BYTE SHOULD BE $A5 + CP D ; COMPARE + JP NZ,DB_NOBOOT ; ERROR IF NOT EQUAL + LD A,$5A ; SECOND BYTE SHOULD BE $5A + CP E ; COMPARE + JP NZ,DB_NOBOOT ; ERROR IS NOT EQUAL + + ; PRINT CPMLOC VALUE + CALL NEWLINE + LD DE,STR_CPMLOC + CALL WRITESTR + LD BC,(BB_CPMLOC) + CALL PRTHEXWORD + + ; PRINT CPMEND VALUE + CALL PC_SPACE + LD DE,STR_CPMEND + CALL WRITESTR + LD BC,(BB_CPMEND) + CALL PRTHEXWORD + + ; PRINT CPMENT VALUE + CALL PC_SPACE + LD DE,STR_CPMENT + CALL WRITESTR + LD BC,(BB_CPMENT) + CALL PRTHEXWORD + CALL PC_SPACE + + ; PRINT DISK LABEL + LD DE,STR_LABEL + CALL WRITESTR + LD DE,BB_LABEL ; if it is there, then a printable + LD A,(BB_TERM) ; Display Disk Label if Present + CP '$' ; (dwg 2/7/2012) + CALL Z,WRITESTR ; label is there as well even if spaces. +; + LD DE,STR_LOADING ; LOADING MESSAGE + CALL WRITESTR ; PRINT IT +; + ; COMPUTE NUMBER OF SECTORS TO LOAD + LD HL,(BB_CPMEND) ; HL := END + LD DE,(BB_CPMLOC) ; DE := START + OR A ; CLEAR CARRY + SBC HL,DE ; HL := LENGTH TO LOAD + LD A,H ; DETERMINE 512 BYTE SECTOR COUNT + RRCA ; ... BY DIVIDING MSB BY TWO + LD (BL_COUNT),A ; ... AND SAVE IT +; +#IF (PLATFORM == PLT_UNA) +; + ; READ OS IMAGE INTO MEMORY + LD C,$42 ; UNA FUNC: READ SECTORS + LD A,(BL_BOOTID) ; GET BOOT DEVICE ID + LD B,A ; MOVE TO B + LD DE,(BB_CPMLOC) ; DEST OF CPM IMAGE + LD A,(BL_COUNT) ; GET SECTORS TO READ + LD L,A ; SECTORS TO READ + RST 08 ; DO READ + JP NZ,DB_ERR ; HANDLE ERROR +; + ; PASS BOOT DEVICE/UNIT/LU TO CBIOS COLD BOOT + LD DE,-1 ; BOOT ROM PAGE, -1 FOR N/A + LD A,(BL_BOOTID) ; GET BOOT DISK UNIT ID + LD L,A ; PUT IN L + LD BC,$01FC ; UNA FUNC: SET BOOTSTRAP HISTORY + RST 08 ; CALL UNA + JP NZ,DB_ERR ; HANDLE ERROR +; + ; JUMP TO COLD BOOT ENTRY + LD HL,(BB_CPMENT) ; GET THE ENTRY POINT + PUSH HL ; PUT ON STACK FOR UNA CHAIN FUNC + LD DE,BID_USR ; TARGET BANK ID IS USER BANK + PUSH DE ; PUT ON STACK FOR UNA CHAIN FUNC + DI ; ENTER WITH INTS DISABLED + JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN +; +#ELSE +; + ; READ OS IMAGE INTO MEMORY + LD B,BF_DIOREAD ; FUNCTION IN B + LD A,(BL_DEVICE) ; GET BOOT DISK UNIT + LD C,A ; PUT IN C + LD HL,(BB_CPMLOC) ; LOAD ADDRESS + LD D,0 + LD A,(BL_COUNT) ; GET SECTORS TO READ + LD E,A ; NUMBER OF SECTORS TO LOAD + RST 08 + JP NZ,DB_ERR ; HANDLE ERRORS + + ; PASS BOOT DEVICE/UNIT/LU TO CBIOS COLD BOOT + LD B,BF_SYSSET ; HB FUNC: SET HBIOS PARAMETER + LD C,BF_SYSSET_BOOTINFO ; HB SUBFUNC: SET BOOT INFO + LD A,(HB_CURBNK) ; GET CURRENT BANK ID FROM PROXY DATA + LD L,A ; ... AND SAVE AS BOOT BANK + LD A,(BL_DEVICE) ; LOAD BOOT DEVICE/UNIT + LD D,A ; SAVE IN D + LD A,(BL_LU) ; LOAD BOOT LU + LD E,A ; SAVE IN E + RST 08 + JP NZ,DB_ERR ; HANDLE ERRORS + + ; JUMP TO COLD BOOT ENTRY + LD A,BID_USR ; ACTIVATE USER BANK + LD HL,(BB_CPMENT) ; OS ENTRY ADDRESS + DI ; ENTER WITH INTS DISABLED + CALL HB_BNKCALL ; AND GO + HALT ; WE SHOULD NEVER RETURN!!! +; +#ENDIF +; +DB_NODISK: + ; SELDSK DID NOT LIKE DRIVE SELECTION + LD DE,STR_NODISK + CALL WRITESTR + JP DOBOOTMENU + +DB_NOBOOT: + ; DISK IS NOT BOOTABLE + LD DE,STR_NOBOOT + CALL WRITESTR + JP DOBOOTMENU + +DB_ERR: + ; I/O ERROR DURING BOOT ATTEMPT + LD DE,STR_BOOTERR + CALL WRITESTR + JP DOBOOTMENU +; +#IF (DSKYENABLE) +; +; +;__SEGDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +;____________________________________________________________________________________________________ +; +SEGDISPLAY: + PUSH AF ; STORE AF + PUSH BC ; STORE BC + PUSH HL ; STORE HL + LD BC,0007H + ADD HL,BC + LD B,08H ; SET DIGIT COUNT + LD A,40H | 30H ; SET CONTROL PORT 7218 TO OFF + OUT (PPIC),A ; OUTPUT + CALL DLY2 ; WAIT + LD A,0F0H ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + +SEGDISPLAY1: ; + OUT (PPIA),A ; OUTPUT TO PORT + LD A,80H | 30H ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PPIC),A ; OUTPUT TO PORT + CALL DLY2 ; WAIT + LD A,40H | 30H ; SET CONTROL PORT 7218 TO OFF + OUT (PPIC),A ; OUTPUT + +SEGDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + OUT (PPIA),A ; OUT TO PPIA + LD A,00H | 30H ; SET WRITE STROBE + OUT (PPIC),A ; OUT TO PPIC + CALL DLY2 ; DELAY + LD A,40H | 30H ; SET CONTROL PORT OFF + OUT (PPIC),A ; OUT TO PPIC + CALL DLY2 ; WAIT + DEC HL ; INC POINTER + DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + POP HL ; RESTORE HL + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET +#ENDIF + +#IF (PLATFORM == PLT_UNA) +; +; +; PRINT LIST OF ALL DRIVES UNDER UNA +; +PRTALL: + LD B,0 ; START WITH UNIT 0 +; +PRTALL1: ; LOOP THRU ALL UNITS AVAILABLE + LD C,$48 ; UNA FUNC: GET DISK TYPE + LD L,0 ; PRESET UNIT COUNT TO ZERO + RST 08 ; CALL UNA, B IS ASSUMED TO BE UNTOUCHED!!! + LD A,L ; UNIT COUNT TO A + OR A ; PAST END? + RET Z ; WE ARE DONE + PUSH BC ; SAVE UNIT + CALL PRTDRV ; PROCESS THE UNIT + POP BC ; RESTORE UNIT + INC B ; NEXT UNIT + JR PRTALL1 ; LOOP +; +; PRINT THE UNA UNIT INFO +; ON INPUT B HAS UNIT +; +PRTDRV: + PUSH BC ; SAVE UNIT + PUSH DE ; SAVE DISK TYPE + LD DE,STR_PREFIX ; NEWLINE AND SPACING + CALL WRITESTR ; PRINT IT + LD A,B ; DRIVE LETTER TO A + ADD A,'0' ; MAKE IT DISPLAY NUMERIC + CALL COUT ; PRINT IT + LD A,')' ; DRIVE LETTER COLON + CALL COUT ; PRINT IT +; CALL PC_SPACE + POP DE ; RECOVER DISK TYPE + LD A,D ; DISK TYPE TO A + CP $40 ; RAM/ROM? + JR Z,PRTDRV1 ; HANDLE RAM/ROM + LD DE,DEVIDE ; ASSUME IDE + CP $41 ; IDE? + JR Z,PRTDRV2 ; PRINT IT + LD DE,DEVPPIDE ; ASSUME PPIDE + CP $42 ; PPIDE? + JR Z,PRTDRV2 ; PRINT IT + LD DE,DEVSD ; ASSUME SD + CP $43 ; SD? + JR Z,PRTDRV2 ; PRINT IT + LD DE,DEVDSD ; ASSUME DSD + CP $44 ; DSD? + JR Z,PRTDRV2 ; PRINT IT + LD DE,DEVUNK ; OTHERWISE UNKNOWN + JR PRTDRV2 +; +PRTDRV1: ; HANDLE RAM/ROM + LD C,$45 ; UNA FUNC: GET DISK INFO + LD DE,BL_INFOSEC ; 512 BYTE BUFFER + RST 08 ; CALL UNA + BIT 7,B ; TEST RAM DRIVE BIT + LD DE,DEVROM ; ASSUME ROM + JR Z,PRTDRV2 ; IF SO, PRINT IT + LD DE,DEVRAM ; OTHERWISE RAM + JR PRTDRV2 ; PRINT IT +; +PRTDRV2: ; PRINT DEVICE + POP BC ; RECOVER UNIT + CALL WRITESTR ; PRINT DEVICE NAME + LD A,B ; UNIT TO A + ADD A,'0' ; MAKE IT PRINTABLE NUMERIC + CALL COUT ; PRINT IT + LD A,',' ; DEVICE NAME SEPARATOR + CALL COUT ; PRINT IT + RET ; DONE +; +DEVRAM .DB "RAM$" +DEVROM .DB "ROM$" +DEVIDE .DB "IDE$" +DEVPPIDE .DB "PPIDE$" +DEVSD .DB "SD$" +DEVDSD .DB "DSD$" +DEVUNK .DB "UNK$" +; +#ELSE +; +; PRINT LIST OF ALL DRIVES +; +PRTALL: +; + LD B,BF_SYSGET + LD C,BF_SYSGET_DIOCNT + RST 08 ; E := DISK UNIT COUNT + LD B,E ; COUNT TO B + LD A,B ; COUNT TO A + OR A ; SET FLAGS + RET Z ; BAIL OUT IF ZERO + LD C,0 ; INIT DEVICE INDEX +; +PRTALL1: + LD DE,STR_PREFIX ; FORMATTING + CALL WRITESTR ; PRINT IT + LD A,C ; INDEX TO A + ADD A,'0' ; MAKE NUMERIC CHAR + CALL COUT ; PRINT IT + LD A,')' ; FORMATTING + CALL COUT ; PRINT IT +; CALL PC_SPACE ; SPACING + PUSH BC ; SAVE LOOP CONTROL + LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO + RST 08 ; CALL HBIOS + CALL PRTDRV ; PRINT IT + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP INDEX + DJNZ PRTALL1 ; LOOP AS NEEDED + RET ; DONE +; +; PRINT THE DRIVER DEVICE/UNIT INFO +; ON INPUT D HAS DRIVER ID, E HAS DRIVER MODE/UNIT +; DESTROY NO REGISTERS OTHER THAN A +; +PRTDRV: + PUSH DE ; PRESERVE DE + PUSH HL ; PRESERVE HL + LD A,D ; LOAD DEVICE/UNIT + RRCA ; ROTATE DEVICE + RRCA ; ... BITS + RRCA ; ... INTO + RRCA ; ... LOWEST 4 BITS + AND $0F ; ISOLATE DEVICE BITS + ADD A,A ; MULTIPLE BY TWO FOR WORD TABLE + LD HL,DEVTBL ; POINT TO START OF DEVICE NAME TABLE + CALL ADDHLA ; ADD A TO HL TO POINT TO TABLE ENTRY + LD A,(HL) ; DEREFERENCE HL TO LOC OF DEVICE NAME STRING + INC HL ; ... + LD D,(HL) ; ... + LD E,A ; ... + CALL WRITESTR ; PRINT THE DEVICE NMEMONIC + POP HL ; RECOVER HL + POP DE ; RECOVER DE + LD A,E ; LOAD DRIVER MODE/UNIT + AND $0F ; ISOLATE UNIT + CALL PRTDECB ; PRINT IT + CALL PC_SPACE ; FORMATTING + ;LD A,E ; LOAD LU + ;CALL PRTDECB ; PRINT IT + RET +; +DEVTBL: ; DEVICE TABLE + .DW DEV00, DEV01, DEV02, DEV03 + .DW DEV04, DEV05, DEV06, DEV07 + .DW DEV08, DEV09, DEV10, DEV11 + .DW DEV12, DEV13, DEV14, DEV15 +; +DEVUNK .DB "???$" +DEV00 .DB "MD$" +DEV01 .DB "FD$" +DEV02 .DB "RAMF$" +DEV03 .DB "IDE$" +DEV04 .DB "ATAPI$" +DEV05 .DB "PPIDE$" +DEV06 .DB "SD$" +DEV07 .DB "PRPSD$" +DEV08 .DB "PPPSD$" +DEV09 .DB "HDSK$" +DEV10 .EQU DEVUNK +DEV11 .EQU DEVUNK +DEV12 .EQU DEVUNK +DEV13 .EQU DEVUNK +DEV14 .EQU DEVUNK +DEV15 .EQU DEVUNK +; +#ENDIF +; +;__TEXT_STRINGS_________________________________________________________________________________________________________________ +; +; STRINGS +;_____________________________________________________________________________________________________________________________ +; +STR_BOOTDISK .DB "BOOT FROM DISK\r\n$" +STR_BOOTDISK1 .DB "\r\nReading disk information...$" +STR_BOOTMON .DB "START MONITOR FROM ROM\r\n$" +STR_BOOTBAS .DB "START BASIC FROM ROM\r\n$" +STR_BOOTTBC .DB "START TASTYBASIC FROM ROM\r\n$" +STR_BOOTCPM .DB "BOOT CPM FROM ROM\r\n$" +STR_BOOTZSYS .DB "BOOT ZSYSTEM FROM ROM\r\n$" +STR_LIST .DB "LIST DEVICES\r\n$" +STR_INVALID .DB "INVALID SELECTION\r\n$" +STR_SETUP .DB "SYSTEM SETUP\r\n$" +STR_SIG .DB "SIGNATURE=$" +STR_CPMLOC .DB "LOC=$" +STR_CPMEND .DB "END=$" +STR_CPMENT .DB "ENT=$" +STR_LABEL .DB "LABEL=$" +STR_DRVLIST .DB "\r\nDisk Devices:\r\n$" +STR_PREFIX .DB "($" +;STR_PREFIX .DB "\r\n $" +STR_LOADING .DB "\r\nLoading...$" +STR_NODISK .DB "\r\nNo disk!$" +STR_NOBOOT .DB "\r\nDisk not bootable!$" +STR_BOOTERR .DB "\r\nBoot failure!$" +STR_ITSRAM .DB "\r\n\RAM$" +STR_LAUNCH .DB "\r\nLaunching ...$" +; +STR_BANNER .DB "\r\n", PLATFORM_NAME, " Boot Loader$" +STR_BOOTMENU .DB "\r\n" + .DB "\r\nROM Boot: (B)ASIC, (C)PM, (M)onitor, (T)ASTYBASIC, (Z)System.\r\n" + .DB "Disk Boot: $" +; + .IF DSKYENABLE +BOOT: +; . . t o o b + .DB 00H, 00H, 80H, 80H, 094H, 09DH, 09DH, 09FH + .ENDIF +; +#DEFINE USEDELAY +#INCLUDE "util.asm" +; +#IF (DSKYENABLE) +#DEFINE DSKY_KBD +#INCLUDE "dsky.asm" +#ENDIF +; +;================================================================================================== +; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) +;================================================================================================== +; +#IF (PLATFORM != PLT_UNA) +; +; OUTPUT CHARACTER FROM A +; +COUT: + ; SAVE ALL INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL +; + ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS + LD E,A ; OUTPUT CHAR TO E + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR + RST 08 ; HBIOS OUTPUTS CHARACTDR +; + ; RESTORE ALL REGISTERS + POP HL + POP DE + POP BC + POP AF + RET +; +; INPUT CHARACTER TO A +; +CIN: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + ; INPUT CHARACTER FROM CONSOLE VIA HBIOS + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR + RST 08 ; HBIOS READS CHARACTDR + LD A,E ; MOVE CHARACTER TO A FOR RETURN +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) +; +CST: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + ; GET CONSOLE INPUT STATUS VIA HBIOS + LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C + LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS + RST 08 ; HBIOS RETURNS STATUS IN A +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +#ENDIF +; +#IF (PLATFORM == PLT_UNA) +; +; OUTPUT CHARACTER FROM A +; +COUT: + ; SAVE ALL INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL +; + ; OUTPUT CHARACTER TO CONSOLE VIA UBIOS + LD E,A + LD BC,$12 + RST 08 +; + ; RESTORE ALL REGISTERS + POP HL + POP DE + POP BC + POP AF + RET +; +; INPUT CHARACTER TO A +; +CIN: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + ; INPUT CHARACTER FROM CONSOLE VIA UBIOS + LD BC,$11 + RST 08 + LD A,E +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) +; +CST: + ; SAVE INCOMING REGISTERS (AF IS OUTPUT) + PUSH BC + PUSH DE + PUSH HL +; + ; GET CONSOLE INPUT STATUS VIA UBIOS + LD BC,$13 + RST 08 + LD A,E +; + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +#ENDIF +; +; READ A CONSOLE CHARACTER AND CONVERT TO UPPER CASE +; +CINUC: + CALL CIN + AND 7FH ; STRIP HI BIT + CP 'A' ; KEEP NUMBERS, CONTROLS + RET C ; AND UPPER CASE + CP 7BH ; SEE IF NOT LOWER CASE + RET NC + AND 5FH ; MAKE UPPER CASE + RET +; +;================================================================================================== +; FILL REMAINDER OF BANK +;================================================================================================== +; +SLACK: .EQU ($LDR_SIZ - $) + .FILL SLACK +; + .ECHO "LOADER space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +;================================================================================================== +; WORKING DATA STORAGE +;================================================================================================== +; + .ORG $8000 +; + .DS 64 ; 32 LEVEL STACK +BL_STACK .EQU $ ; ... TOP IS HERE +; +BL_COUNT .DS 1 ; LOAD COUNTER +BL_TIMEOUT .DS 2 ; AUTOBOOT TIMEOUT COUNTDOWN COUNTER +BL_BOOTID .DS 1 ; BOOT DEVICE ID CHOSEN BY USER +BL_DEVICE .DS 1 ; DEVICE TO LOAD FROM +BL_LU .DS 1 ; LU TO LOAD FROM +; +; BOOT INFO SECTOR IS READ INTO AREA BELOW +; THE THIRD SECTOR OF A DISK DEVICE IS RESERVED FOR BOOT INFO +; +BL_INFOSEC .EQU $ + .DS (512 - 128) +BB_METABUF .EQU $ +BB_SIG .DS 2 ; SIGNATURE (WILL BE 0A55AH IF SET) +BB_PLATFORM .DS 1 ; FORMATTING PLATFORM +BB_DEVICE .DS 1 ; FORMATTING DEVICE +BB_FORMATTER .DS 8 ; FORMATTING PROGRAM +BB_DRIVE .DS 1 ; PHYSICAL DISK DRIVE # +BB_LU .DS 1 ; LOGICAL UNIT (LU) + .DS 1 ; MSB OF LU, NOW DEPRECATED + .DS (BB_METABUF + 128) - $ - 32 +BB_PROTECT .DS 1 ; WRITE PROTECT BOOLEAN +BB_UPDATES .DS 2 ; UPDATE COUNTER +BB_RMJ .DS 1 ; RMJ MAJOR VERSION NUMBER +BB_RMN .DS 1 ; RMN MINOR VERSION NUMBER +BB_RUP .DS 1 ; RUP UPDATE NUMBER +BB_RTP .DS 1 ; RTP PATCH LEVEL +BB_LABEL .DS 16 ; 16 CHARACTER DRIVE LABEL +BB_TERM .DS 1 ; LABEL TERMINATOR ('$') +BB_BILOC .DS 2 ; LOC TO PATCH BOOT DRIVE INFO TO (IF NOT ZERO) +BB_CPMLOC .DS 2 ; FINAL RAM DESTINATION FOR CPM/CBIOS +BB_CPMEND .DS 2 ; END ADDRESS FOR LOAD +BB_CPMENT .DS 2 ; CP/M ENTRY POINT (CBIOS COLD BOOT) +; + .END From 2f9cd64489468c2aa49aded424b96db7df6e2182 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Tue, 30 Oct 2018 05:58:59 +0800 Subject: [PATCH 14/18] Delete cfg_sbc.asm --- cfg_sbc.asm | 97 ----------------------------------------------------- 1 file changed, 97 deletions(-) delete mode 100644 cfg_sbc.asm diff --git a/cfg_sbc.asm b/cfg_sbc.asm deleted file mode 100644 index 8e9813ea..00000000 --- a/cfg_sbc.asm +++ /dev/null @@ -1,97 +0,0 @@ -; -;================================================================================================== -; ROMWBW 2.X CONFIGURATION DEFAULTS FOR SBC -;================================================================================================== -; -; BUILD CONFIGURATION OPTIONS -; -CPUOSC .EQU 8000000 ; CPU OSC FREQ -RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! -DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SHOULD MATCH ABOVE) -INTMODE .EQU 0 ; 0=NONE, 1=INT MODE 1, 2=INT MODE 2 -; -CRTACT .EQU FALSE ; CRT ACTIVATION AT STARTUP -VDAEMU .EQU EMUTYP_ANSI ; DEFAULT VDA EMULATION (EMUTYP_TTY, EMUTYP_ANSI, ...) -; -DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) -; -HTIMENABLE .EQU FALSE ; TRUE FOR SIMH TIMER SUPPORT -SIMRTCENABLE .EQU FALSE ; SIMH CLOCK DRIVER -DSRTCENABLE .EQU TRUE ; DS-1302 CLOCK DRIVER -DSRTCMODE .EQU DSRTCMODE_STD ; DSRTCMODE_STD, DSRTCMODE_MFPIC -; -ASCIENABLE .EQU FALSE ; TRUE FOR Z180 ASCI SUPPORT -UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) -UARTOSC .EQU 1843200 ; UART OSC FREQUENCY -ACIAENABLE .EQU FALSE ; TRUE FOR MOTOROLA 6850 ACIA SUPPORT -; -SIOENABLE .EQU FALSE ; TRUE FOR ZILOG SIO SUPPORT -SIOMODE .EQU SIOMODE_ZP ; SIOMODE_RC, SIOMODE_SMB, SIOMODE_ZP -DEFSIOACFG .EQU SER_9600_8N1 ; DEFAULT SERIAL LINE CONFIG -DEFSIOBCFG .EQU SER_9600_8N1 ; DEFAULT SERIAL LINE CONFIG -DEFSIODIV .EQU 8 ; 1=RC2014, SMB, 2/4/8/16/32/64/128/256 for ZP depending on jumper X5 -DEFSIOCLK .EQU 4915200 ; 2457600/4915200=ZP,7372800=RC/SMB - SIO FIXED OSC FREQUENCY -SIODEBUG .EQU FALSE ; -; -VDUENABLE .EQU FALSE ; TRUE FOR VDU BOARD SUPPORT -CVDUENABLE .EQU FALSE ; TRUE FOR CVDU BOARD SUPPORT -NECENABLE .EQU FALSE ; TRUE FOR uPD7220 BOARD SUPPORT -TMSENABLE .EQU FALSE ; TRUE FOR N8 (TMS9918) VIDEO/KBD SUPPORT -VGAENABLE .EQU FALSE ; TRUE FOR VGA VIDEO/KBD SUPPORT -; -SPKENABLE .EQU FALSE ; TRUE FOR RTC LATCH IOBIT SOUND -AYENABLE .EQU FALSE ; TRUE FOR AY PSG SOUND -; -MDENABLE .EQU TRUE ; TRUE FOR ROM/RAM DISK SUPPORT (ALMOST ALWAYS WANT THIS ENABLED) -MDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF MDENABLE = TRUE) -; -FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT -FDMODE .EQU FDMODE_DIO3 ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 -FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) -FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) -FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) -FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY -; -RFENABLE .EQU FALSE ; TRUE FOR RAM FLOPPY SUPPORT -RFCNT .EQU 1 ; NUMBER OF RAM FLOPPY UNITS (MAX IS 2) -; -IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT -IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE -IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) -IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) -; -PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) -PPIDEMODE .EQU PPIDEMODE_SBC ; PPIDEMODE_SBC, PPPIDEMODE_DIO3, PPIDEMODE_MFP, PPIDEMODE_N8, PPIDEMODE_RC -PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) -PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) -; -SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT -SDMODE .EQU SDMODE_JUHA ; SDMODE_JUHA, SDMODE_CSIO, SDMODE_UART, SDMODE_PPI, SDMODE_DSD -SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) -SDCSIOFAST .EQU FALSE ; TABLE-DRIVEN BIT INVERTER -; -PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SUPPORT -PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT -PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) -PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) -; -PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT -PPPSDENABLE .EQU TRUE ; TRUE FOR PARPORTPROP SD SUPPORT -PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) -PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) -; -HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT -HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) -; -PPKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPKENABLE = TRUE) -KBDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF KBDENABLE = TRUE) -; -TERMENABLE .EQU FALSE ; TERM PSEUDO DEVICE, WILL BE ENABLED IF A VDA IS ENABLED -ANSITRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF ANSIENABLE = TRUE) -; -BOOTTYPE .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) -BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE -BOOT_DEFAULT .EQU 'Z' ; SELECTION TO INVOKE AT TIMEOUT - -PIOENABLE .EQU FALSE ; TRUE FOR ZILOG PIO SUPPORT -PIOMODE .EQU PIOMODE_ZP ; PIOMODE_ZP=ECB-ZILOG PERIPHERALS BOARD PIOMODE_4P=ECB-4PIO From 5b1348d1233ccbb2d537e358d03076e763c403b6 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Tue, 30 Oct 2018 05:59:13 +0800 Subject: [PATCH 15/18] Delete hbios.asm --- hbios.asm | 3285 ----------------------------------------------------- 1 file changed, 3285 deletions(-) delete mode 100644 hbios.asm diff --git a/hbios.asm b/hbios.asm deleted file mode 100644 index 56116b9c..00000000 --- a/hbios.asm +++ /dev/null @@ -1,3285 +0,0 @@ -; -;================================================================================================== -; HBIOS -;================================================================================================== -; -; THIS FILE CONTAINS THE HBIOS IMAGE THAT IS INTENDED TO RUN IN A DEDICATED RAM BANK. THE CODE IS -; CONSTRUCTED SUCH THAT IT CAN BE LAUNCHED IN A VARIETY OF MODES AND INSTALL ITSELF. A SMALL 512 -; BYTE PROXY IS PLACED AT THE TOP OF CPU MEMORY (FE00H-FFFFH). THIS PROXY CODE ALLOWS CODE -; RUNNING FROM ANY BANK TO INVOKE HBIOS FUNCTIONS. NORMALLY, ANY BANK THAT RUNS CODE WOULD SETUP -; THE RST 8 VECTOR TO POINT TO THE PROXY INVOKE ENTRY POINT AT FFF0H. CALLS VIA THE PROXY INVOKE -; ENTRY POINT TRANSPARENTLY SWAP IN THE HBIOS BANK, PERFORM THE REQUESTED FUNCTION, AND RETURN -; WITH THE ORIGINAL BANK ACTIVE. THE CODE USING HBIOS FUNCTIONS DOES NOT NEED TO BE AWARE OF -; THE BANK SWITCHING THAT OCCURS. -; -; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 3 MODES (ROM, APPLICATION, OR IMAGE) AS DESCRIBED -; BELOW. WHEN COMPILED, YOU MUST DEFINE EXACTLY ONE OF THE FOLLOWING MACROS: -; -; - ROMBOOT: BOOT FROM A ROM BANK -; -; WHEN ROMBOOT IS DEFINED, THE FILE IS ASSEMBLED TO BE IMBEDDED AT THE START OF A ROM -; ASSUMING THAT THE CPU WILL START EXECUTION AT ADDRESS 0. AFTER PERFORMING MINIMAL -; SYSTEM INITIALIZATION, THE IMAGE OF THE RUNNING ROM BANK IS COPIED TO A RAM BANK -; CREATING A SHADOW COPY IN RAM. EXECUTION IS THAN TRANSFERRED TO THE RAM SHADOW COPY. -; THIS IS ESSENTIAL BECAUSE THE HBIOS CODE DOES NOT SUPPORT RUNNING IN READ ONLY MEMORY -; (EXCEPT FOR THE INITIAL LAUNCHING CODE). IN THIS MODE, THE HBIOS INITIALIZATION WILL -; ALSO COPY THE OS IMAGES BANK IN ROM TO THE USER RAM BANK AND LAUNCH IT AFTER HBIOS -; IS INSTALLED. -; -; - APPBOOT: BOOT FROM A CP/M STYLE APPLICATION FILE -; -; WHEN APPBOOT IS DEFINED, THE FILE IS ASSEMBLED AS A CP/M APPLICATION ASSUMING -; THAT IT WILL BE LOADED AT 100H BY THE CP/M (OR COMPATIBLE) OS. NOTE THAT IN -; THIS CASE IT IS ASSUMED THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE -; HBIOS APPLICATION BINARY. THE APPENDED OS IMAGES ARE COPIED TO THE USER RAM -; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. -; -; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK -; -; WHEN IMGBOOT IS DEFINED, THE FILE IS ASSEMBLED SUCH THAT IT CAN BE PRELOADED -; INTO THE RAM USER BANK BY AN EXTERNAL PROCESS THAT SUBSEQUENTLY LAUNCHES -; THE CODE AT ADDRESS 0. THE MOST COMMON EXAMPLE OF THIS IS THE UNA FSFAT -; TOOL WHICH CAN LOAD AN IMAGE FROM A DOS FAT FILESYSTEM PROVIDING A SIMPLE -; WAY TO LOAD A TEST COPY OF HBIOS. AS IS THE CASE WITH APPBOOT, IT IS ASSUMED -; THAT AN OS IMAGES FILE IS APPENDED TO THE END OF THE IMAGE AND IS LAUNCHED -; AFTER HBIOS IS INSTALLED. -; -; INCLUDE GENERIC STUFF -; -#INCLUDE "std.asm" -; -; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. -; -MODCNT .EQU 0 -#IFDEF ROMBOOT -MODCNT .SET MODCNT + 1 -#ENDIF -#IFDEF APPBOOT -MODCNT .SET MODCNT + 1 -#ENDIF -#IFDEF IMGBOOT -MODCNT .SET MODCNT + 1 -#ENDIF -#IF (MODCNT != 1) - .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT, IMGBOOT!!!\n" - !!! ; FORCE AN ASSEMBLY ERROR -#ENDIF -; -; -; -#IF ((PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) -#DEFINE DIAGP $00 -#ENDIF -; -#IFDEF DIAGP -#DEFINE DIAG(N) PUSH AF - #DEFCONT \ LD A,N - #DEFCONT \ OUT (DIAGP),A - #DEFCONT \ POP AF -#ELSE -#DEFINE DIAG(N) \; -#ENDIF -; -; -; -#IF (INTMODE == 0) -; NO INTERRUPT HANDLING -#DEFINE HB_DI DI -#DEFINE HB_EI ; -#ELSE -; MODE 1 OR 2 INTERRUPT HANDLING -#DEFINE HB_DI DI -#DEFINE HB_EI EI -#ENDIF -; -; -; -#IFNDEF APPBOOT -; - .ORG 0 -; -;================================================================================================== -; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED -;================================================================================================== -; - .FILL (000H - $),0FFH ; RST 0 - JP HB_START - .DW ROM_SIG - .FILL (008H - $),0FFH ; RST 8 - JP HB_INVOKE ; INVOKE HBIOS FUNCTION - .FILL (010H - $),0FFH ; RST 10 - RET - .FILL (018H - $),0FFH ; RST 18 - RET - .FILL (020H - $),0FFH ; RST 20 - RET - .FILL (028H - $),0FFH ; RST 28 - RET - .FILL (030H - $),0FFH ; RST 30 - RET - .FILL (038H - $),0FFH ; RST 38 / IM1 INT -#IF (INTMODE == 1) - JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM -#ELSE - RETI ; RETURN W/ INTS DISABLED -#ENDIF - .FILL (066H - $),0FFH ; NMI - RETN -; - .FILL (070H - $),0FFH ; SIG STARTS AT $80 -; -ROM_SIG: - .DB $76, $B5 ; 2 SIGNATURE BYTES - .DB 1 ; STRUCTURE VERSION NUMBER - .DB 7 ; ROM SIZE (IN MULTIPLES OF 4KB, MINUS ONE) - .DW NAME ; POINTER TO HUMAN-READABLE ROM NAME - .DW AUTH ; POINTER TO AUTHOR INITIALS - .DW DESC ; POINTER TO LONGER DESCRIPTION OF ROM - .DB 0, 0, 0, 0, 0, 0 ; RESERVED FOR FUTURE USE; MUST BE ZERO -; -NAME .DB "ROMWBW v", BIOSVER, ", ", TIMESTAMP, 0 -AUTH .DB "WBW",0 -DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2015, Wayne Warthen, GNU GPL v3", 0 -; - .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO -; -#ENDIF -; -;================================================================================================== -; HBIOS CONFIGURATION BLOCK (HCB) -;================================================================================================== -; - .ORG HCB_LOC -HCB: - JP HB_START -; -CB_MARKER .DB 'W',~'W' ; MARKER -CB_VERSION .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO - .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO -; -CB_PLATFORM .DB PLATFORM -CB_CPUMHZ .DB CPUMHZ -CB_CPUKHZ .DW CPUKHZ -CB_RAMBANKS .DB RAMSIZE / 32 -CB_ROMBANKS .DB ROMSIZE / 32 -; -CB_BOOTVOL .DW 0 ; BOOT VOLUME IS UNIT/SLICE, SET BY LOADER -CB_BOOTBID .DB 0 ; BOOT BANK ID, SET BY LOADER -CB_SERDEV .DB 0 ; PRIMARY SERIAL UNIT IS UNIT #0 BY FIAT -CB_CRTDEV .DB $FF ; PRIMARY CRT UNIT, $FF UNTIL AFTER HBIOS INIT -CB_CONDEV .DB $FF ; CONSOLE UNIT, $FF UNTIL AFTER HBIOS INIT -; -; MEMORY MANAGEMENT VARIABLES START AT $20 -; - .FILL (HCB + $20 - $),0 -; -CB_HEAP .DW 0 -CB_HEAPTOP .DW 0 -; -; STANDARD BANK ID'S START AT $D8 -; - .FILL (HCB + $D8 - $),0 -; -CB_BIDCOM .DB BID_COM -CB_BIDUSR .DB BID_USR -CB_BIDBIOS .DB BID_BIOS -CB_BIDAUX .DB BID_AUX -CB_BIDRAMD0 .DB BID_RAMD0 -CB_BIDRAMDN .DB BID_RAMDN -CB_BIDROMD0 .DB BID_ROMD0 -CB_BIDROMDN .DB BID_ROMDN -; - .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB -; -;================================================================================================== -; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) -;================================================================================================== -; -; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING -; - .FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START - .ORG HBX_LOC ; ADJUST FOR RELOCATION -; -; MEMORY LAYOUT: -; -; HBIOS PROXY CODE $FE00 (256 BYTES) -; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) -; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) -; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) -; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) -; -; DEFINITIONS -; -HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BUFFER SIZE -; -; HBIOS IDENTIFICATION DATA BLOCK -; -HBX_IDENT: - .DB 'W',~'W' ; MARKER - .DB RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO - .DB RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO -; -;================================================================================================== -; HBIOS ENTRY FOR RST 08 PROCESSING -;================================================================================================== -; -HBX_INVOKE: - LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME - LD A,(HB_CURBNK) ; GET CURRENT BANK - LD (HB_INVBNK),A ; SAVE INVOCATION BANK - - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH - LD A,BID_BIOS ; HBIOS BANK - CALL HBX_BNKSEL ; SELECT IT - LD SP,HB_STACK ; NOW USE FULL HBIOS STACK IN HBIOS BANK - - CALL HB_DISPATCH ; CALL HBIOS FUNCTION DISPATCHER - - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM FOR BANK SWITCH - PUSH AF ; SAVE AF (FUNCTION RETURN) - - LD A,(HB_INVBNK) ; LOAD ORIGINAL BANK - CALL HBX_BNKSEL ; SELECT IT - POP AF ; RESTORE AF - LD SP,0 ; RESTORE ORIGINAL STACK FRAME -HBX_INVSP .EQU $ - 2 - - RET ; RETURN TO CALLER -; -;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -;; BNKSEL - Switch Memory Bank to Bank in A. -;; Preserve all Registers including Flags. -;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -; -HBX_BNKSEL: - ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, - ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT - ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE - ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT - ; OCCURS DURING PROCESSING. - LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK -; -HBX_BNKSEL_INT: -; -#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA)) - #IF (INTMODE == 1) - ; THIS BIT OF ABSURDITY HANDLES A RARE (BUT FATAL) SITUATION - ; WHERE AN IM1 INTERRUPT OCCURS BETWEEN SETTING THE RAM AND - ; ROM SELECTORS. BRACKETING THE INSTRUCTIONS WITH DI/EI - ; IS CONTRAINDICATED BECAUSE THIS ROUTINE IS CALLED BY - ; OTHER ROUTINES THAT MUST CONTROL INT ENABLE AT A HIGHER - ; LEVEL. THE FOLLOWING TECHNIQUE ENSURES THAT YOU ALWAYS - ; SWITCH DIRECTLY FROM THE PREVIOUS BANK TO THE TARGET BANK - ; WITHOUT AN "ERRANT" BANK BEING ACTIVE BETWEEN THE TWO - ; BANK SELECTION I/O INSTRUCTIONS. THE TECHNIQUE IS ONLY - ; NEEDED WHEN USING INT MODE 1 BECAUSE THAT MODE REQUIRES - ; PAGE ONE TO HAVE A VALID INT HANDLER WHENEVER INTS ARE - ; ENABLED. - ;BIT 7,A ; [8] TEST RAM BIT - ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM - OR A ; [4] SET FLAGS - JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM - #ENDIF - OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR -HBX_ROM: - OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR - RET ; DONE -#ENDIF -#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) - BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE - JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE - RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT - ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K -; -HBX_ROM: - RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K - OUT (MPGSEL_0),A ; BANK_0: 0K - 16K - INC A ; - OUT (MPGSEL_1),A ; BANK_1: 16K - 32K - RET ; DONE -#ENDIF -#IF (PLATFORM == PLT_N8) - BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM - JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE -; -HBX_RAM: - RES 7,A ; CLEAR BIT 7 FROM ABOVE - RLCA ; SCALE SELECTOR TO - RLCA ; ... GO FROM Z180 4K PAGE SIZE - RLCA ; ... TO DESIRED 32K PAGE SIZE - OUT0 (Z180_BBR),A ; WRITE TO BANK BASE - LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 - OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER - RET ; DONE -; -HBX_ROM: - OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER - XOR A ; ZERO ACCUM - OUT0 (Z180_BBR),A ; ZERO BANK BASE - LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 - OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER - RET ; DONE -; -#ENDIF -#IF (PLATFORM == PLT_MK4) - RLCA ; RAM FLAG TO CARRY FLAG AND BIT 0 - JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD - XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 -HBX_BNKSEL1: - RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR - RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE - OUT0 (Z180_BBR),A ; WRITE TO BANK BASE - RET ; DONE -#ENDIF -; -;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -; Copy Data - Possibly between banks. This resembles CP/M 3, but -; usage of the HL and DE registers is reversed. -; Caller MUST ensure stack is already in high memory. -; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. -; Caller MUST disable ints if IM1 active -; Enter: -; HL = Source Address -; DE = Destination Address -; BC = Number of bytes to copy -; Exit : None -; Uses : AF,BC,DE,HL -; -;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -; -HBX_BNKCPY: - LD (HBX_BC_SP),SP ; PUT STACK - LD SP,HBX_TMPSTK ; ... IN HI MEM - - LD A,(HB_CURBNK) ; GET CURRENT BANK - PUSH AF ; AND SAVE TO RESTORE LATER - PUSH BC ; CUR LEN -> (SP) -; -HBX_BC_LOOP: - EX (SP),HL ; HL := CUR LEN, (SP) := CUR SRC - LD BC,HBX_BUFSIZ ; SET BC TO BOUNCE BUFFER SIZE - OR A ; CLEAR CARRY FLAG - SBC HL,BC ; CUR LEN := CUR LEN - BBUF SIZE - JR C,HBX_BC_LAST ; END GAME, LESS THAN BBUF BYTES LEFT - EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN - CALL HBX_BC_ITER ; DO A FULL BBUF SIZE CHUNK - JR HBX_BC_LOOP ; AND REPEAT TILL DONE -; -HBX_BC_LAST: - ; HL IS BETWEEN -(BBUF SIZE) AND -1, BC = BBUF SIZE - OR A ; CLEAR CARRY - ADC HL,BC ; HL := REM LEN (0 - 127) - EX (SP),HL ; HL := CUR SRC, (SP) := REM LEN - POP BC ; BC := REM LEN - CALL NZ,HBX_BC_ITER ; DO FINAL CHUNK, IFF > 0 BYTES - POP AF ; RECOVER ORIGINAL BANK - CALL HBX_BNKSEL ; SWITCH - - LD SP,$FFFF ; RESTORE STACK -HBX_BC_SP .EQU $ - 2 ; ... TO ORIGINAL VALUE - RET -; -HBX_BC_ITER: - ; HL = SRC ADR, DE = DEST ADR, BC = LEN - PUSH BC ; SAVE COPY LEN - PUSH DE ; FINAL DEST ON STACK - LD DE,HBX_BUF ; SET DEST TO BUF - LD A,(HB_SRCBNK) ; GET SOURCE BANK - CALL HBX_BNKSEL ; SWITCH TO SOURCE BANK - LDIR ; HL -> BUF (DE), BC BYTES, HL UPDATED SRC ADR - POP DE ; DE := FINAL DEST - POP BC ; GET LEN BACK IN BC - PUSH HL ; SAVE UPDATED SRC ADR - LD HL,HBX_BUF ; SET SRC ADR TO BUF - LD A,(HB_DSTBNK) ; GET DEST BANK - CALL HBX_BNKSEL ; SWITCH TO DEST BANK - LDIR ; BUF (HL) -> DE, BC BYTES, DE UPDATED DEST ADR - POP HL ; RECOVER UPDATED SRC ADR - ; HL = UPD SRC, DE = UPD DEST, BC = 0 - RET -; -; CALL A ROUTINE IN ANOTHER BANK. -; CALLER MUST ENSURE STACK IS ALREADY IN HIGH MEMORY AND HAS ADEQUATE SPACE. -; IF IM1 INTERRUPTS ARE POSSIBLE, CALLER MUST EITHER DISABLE THEM PRIOR TO -; BNKCALL OR MAKE SURE THAT PAGE ZERO IN TARGTET BANK IS PREPARED FOR THEM. -; ON INPUT A=TARGET BANK, HL=TARGET ADDRESS -; -HBX_BNKCALL: - LD (HBX_TGTBNK),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW - LD (HBX_TGTADR),HL ; STUFF ADDRESS TO CALL INTO CODE BELOW - LD A,(HB_CURBNK) ; GET CURRENT BANK - PUSH AF ; SAVE FOR RETURN -HBX_TGTBNK .EQU $ + 1 - LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) - CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK - -HBX_TGTADR .EQU $ + 1 - CALL $FFFF ; CALL ROUTINE ($FFFF IS OVERLAID ABOVE) - - EX (SP),HL ; SAVE HL AND GET BANK TO RESTORE IN HL - PUSH AF ; SAVE AF - LD A,H ; BANK TO RESTORE TO A - CALL HBX_BNKSEL ; RESTORE IT - POP AF ; RECOVER AF - POP HL ; RECOVER HL - RET -; -; PEEK & POKE ROUTINES -; ADDRESS IN HL, BANK IN D, VALUE IN/OUT IN E, A IS TRASHED -; CALLER MUST DISABLE INTS IF IM1 AND ACCESSING PAGE W/O IM1 INT VECTOR -; -HBX_PEEK: - LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM - LD A,(HB_CURBNK) - PUSH AF - LD A,D - CALL HBX_BNKSEL - LD E,(HL) - JR HBX_PPRET -; -HBX_POKE: - LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME - LD SP,HBX_TMPSTK ; USE SMALL TEMP STACK FRAME IN HI MEM - LD A,(HB_CURBNK) - PUSH AF - LD A,D - CALL HBX_BNKSEL - LD (HL),E -; -HBX_PPRET: - POP AF - CALL HBX_BNKSEL - LD SP,0 ; RESTORE ORIGINAL STACK FRAME -HBX_PPSP .EQU $ - 2 - RET -; -; SMALL TEMPORARY STACK FOR USE BY INVOKE, PEEK, AND POKE -; - .FILL 20,$CC ; 10 LEVEL STACK -HBX_TMPSTK .EQU $ -; -; PRIVATE STACK AT END OF HBIOS CODE -; OCCUPIES SPACE BEFORE IVT -; -HBX_STKSIZ .EQU $FF00 - $ - .ECHO "HBIOS PROXY STACK space: " - .ECHO HBX_STKSIZ - .ECHO " bytes.\n" - .FILL HBX_STKSIZ,$FF -HBX_STACK .EQU $ -; -#IF (INTMODE == 2) -; -; HBIOS INTERRUPT VECTOR TABLE (16 ENTRIES) -; -HBX_IVT: - .DW INT_BAD ; IVT_INT1 - .DW INT_BAD ; IVT_INT2 - .DW INT_BAD ; IVT_TIM0 - .DW INT_BAD ; IVT_TIM1 - .DW INT_BAD ; IVT_DMA0 - .DW INT_BAD ; IVT_DMA1 - .DW INT_BAD ; IVT_CSIO - .DW INT_BAD ; IVT_SER0 - .DW INT_BAD ; IVT_SER1 - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; - .DW INT_BAD ; -; -HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 -; -HBX_ITBL: - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT - .DW HB_BADINT -#ENDIF -; -; INTERRUPT HANDLER STUBS -; -; THE FOLLOWING INTERRUPT STUBS RECEIVE CONTROL FROM THE -; INTERRUPT, SETUP A HANDLER VECTOR IN HBIOS AND THEN -; BRANCH TO THE COMMON INTERRUPT DISPATCHER -; -; -INT_IM1: -#IF (INTMODE == 1) - PUSH HL ; SAVE HL - LD HL,HB_IM1INT ; HL := IM1 INT HANDLER IN BIOS BANK - JR HBX_INT ; TO TO ROUTING CODE -#ELSE - RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED -#ENDIF -; -#IF (INTMODE == 2) -; -INT_BAD: ; BAD INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,HB_BADINT ; HL := INT HANDLER IN BIOS BANK - JR HBX_INT ; GO TO ROUTING CODE -; -INT_TIMER: ; TIMER INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,HB_TIMINT ; HL := INT ADR IN BIOS - JR HBX_INT ; GO TO ROUTING CODE -; - #IF (SIOENABLE) -INT_SIO: ; SIO INTERRUPT HANDLER - PUSH HL ; SAVE HL - LD HL,SIO_INT ; HL := SIO INT HANDLER IN BIOS BANK - JR HBX_INT ; GO TO ROUTING CODE - #ENDIF -; -#ENDIF -; -#IF (INTMODE > 0) -; -; COMMON INTERRUPT DISPATCHING CODE -; SETUP AND CALL HANDLER IN BIOS BANK -; -HBX_INT: ; COMMON INTERRUPT ROUTING CODE -; - LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME - LD SP,HBX_STACK ; USE STACK FRAME IN HI MEM - - ; SAVE STATE (HL SAVED PREVIOUSLY ON ORIGINAL STACK FRAME) - PUSH AF ; SAVE AF - PUSH BC ; SAVE BC - PUSH DE ; SAVE DE - PUSH IY ; SAVE IY - - LD A,BID_BIOS ; HBIOS BANK - CALL HBX_BNKSEL_INT ; SELECT IT - - CALL JPHL ; CALL INTERRUPT ROUTINE - - LD A,(HB_CURBNK) ; GET PRE-INT BANK - CALL HBX_BNKSEL ; SELECT IT - - ; RESTORE STATE - POP IY ; RESTORE IY - POP DE ; RESTORE DE - POP BC ; RESTORE BC - POP AF ; RESTORE AF - - LD SP,$FFFF ; RESTORE ORIGINAL STACK FRAME -HBX_INT_SP .EQU $ - 2 - - POP HL ; RESTORE HL - - EI ; ENABLE INTERRUPTS - RETI ; AND RETURN -; -#ENDIF -; -; FILL TO START OF BOUNCE BUFFER -; -HBX_INTFILL .EQU (HBX_XFC - HBX_BUFSIZ - $) - .ECHO "HBIOS INT space remaining: " - .ECHO HBX_INTFILL - .ECHO " bytes.\n" - .FILL HBX_INTFILL,$FF -; -; INTERBANK COPY BUFFER (64 BYTES) -; -HBX_BUF .FILL HBX_BUFSIZ,0 -; -; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) -; -#IFDEF ROMBOOT - .DB BID_BOOT ; CURRENTLY ACTIVE LOW MEMORY BANK ID -#ELSE - .DB BID_USR ; CURRENTLY ACTIVE LOW MEMORY BANK ID -#ENDIF - .DB 0 ; BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION - .DW 0 ; BNKCPY SOURCE ADDRESS - .DB BID_USR ; BNKCPY SOURCE BANK ID - .DW 0 ; BNKCPY DESTINATION ADDRESS - .DB BID_USR ; BNKCPY DESTINATION BANK ID - .DW 0 ; BNKCPY LENGTH - .FILL 6,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE - JP HBX_INVOKE ; FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) - JP HBX_BNKSEL ; FIXED ADR ENTRY FOR HBX_BNKSEL - JP HBX_BNKCPY ; FIXED ADR ENTRY FOR HBX_BNKCPY - JP HBX_BNKCALL ; FIXED ADR ENTRY FOR HBX_BNKCALL - .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) - .DW HBX_IDENT ; ADDRESS OF HBIOS IDENT INFO DATA BLOCK -; - .FILL $MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) - .ORG HBX_IMG + HBX_SIZ ; RESET ORG -; -;================================================================================================== -; HBIOS CORE -;================================================================================================== -; -;================================================================================================== -; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK -;================================================================================================== -; -HB_ENTRYTBL .EQU $ -; - JP HB_START ; HBIOS INITIALIZATION - JP HB_DISPATCH ; VECTOR TO DISPATCHER -; -HB_STKSIZ .EQU HB_ENTRYTBL + 256 - $ -; - .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK -HB_STACK .EQU $ ; TOP OF HBIOS STACK - -; -;================================================================================================== -; SYSTEM INITIALIZATION -;================================================================================================== -; -HB_START: - DI ; NO INTERRUPTS - IM 1 ; INTERRUPT MODE 1 -; -#IFDEF DIAGP - LD A,%00000001 - OUT (DIAGP),A -#ENDIF -; - LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; SET BASE FOR CPU IO REGISTERS - LD A,Z180_BASE - OUT0 (Z180_ICR),A - - DIAG(%00000010) - - ; DISABLE REFRESH - XOR A - OUT0 (Z180_RCR),A - - ; MASK OFF TIMER INTERRUPTS - XOR A - OUT0 (Z180_TCR),A - - ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) - XOR A - OUT0 (Z180_CCR),A - OUT0 (Z180_CMR),A - - ; SET DEFAULT WAIT STATES - LD A,$F0 - OUT0 (Z180_DCNTL),A - -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4)) - ; MMU SETUP - LD A,$80 - OUT0 (Z180_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG -;#IFDEF ROMBOOT -; XOR A -; OUT0 (Z180_BBR),A ; BANK BASE = 0 -;#ENDIF - LD A,(RAMSIZE + RAMBIAS - 64) >> 2 - OUT0 (Z180_CBR),A ; COMMON BASE = LAST (TOP) BANK -#ENDIF - -#IF (Z180_CLKDIV >= 1) - ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED - LD A,$80 - OUT0 (Z180_CCR),A -#ENDIF - -#IF (Z180_CLKDIV >= 2) - ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED - LD A,$80 - OUT0 (Z180_CMR),A -#ENDIF - -#ENDIF -; -#IF ((PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_RC) | (PLATFORM == PLT_RC180)) - ; SET PAGING REGISTERS -#IFDEF ROMBOOT - XOR A - OUT (MPGSEL_0),A - INC A - OUT (MPGSEL_1),A -#ENDIF - LD A,62 - OUT (MPGSEL_2),A - INC A - OUT (MPGSEL_3),A - ; ENABLE PAGING - LD A,1 - OUT (MPGENA),A -#ENDIF -; - DIAG(%00000011) -; -; INSTALL PROXY IN UPPER MEMORY -; - -;X1 .EQU $8000 -;X2 .EQU X1 + 2 -;X3 .EQU X2 + 2 -;X4 .EQU X3 + 2 - -; LD HL,(HBX_IMG) -; LD (X1),HL - -; LD HL,(HBX_IMG) -; LD (X2),HL - - LD HL,HBX_IMG - LD DE,HBX_LOC - LD BC,HBX_SIZ - LDIR - -; LD HL,(HBX_IMG) -; LD (X3),HL - -; LD HL,(HBX_LOC) -; LD (X4),HL - -; -; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION -; - LD A,(HB_RAMFLAG) - OR A - JR NZ,HB_START1 -; -; INSTALL HBIOS IN RAM BANK -; - LD A,(HB_CURBNK) - LD (HB_SRCBNK),A - LD A,BID_BIOS - LD (HB_DSTBNK),A - LD HL,0 - LD DE,0 - LD BC,$8000 - CALL HBX_BNKCPY -; -; TRANSITION TO HBIOS IN RAM BANK -; - LD A,BID_BIOS ; BIOS BANK ID - LD HL,HB_START1 ; EXECUTION RESUMES HERE - CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN - HALT ; WE SHOULD NOT COME BACK HERE! -; -HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION -; -; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK -; -HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK -; - DIAG(%00000111) -; - LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN - LD A,TRUE ; ACCUM := TRUE - LD (HB_RAMFLAG),A ; SET RAMFLAG -; -; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO -; -#IFDEF APPBOOT - ; MAKE SURE RST 08 VECTOR IS RIGHT - LD A,$C3 - LD ($0008),A - LD HL,HB_INVOKE - LD ($0009),HL -; - ; MAKE SURE IM1 INT VECTOR IS RIGHT - #IF (INTMODE == 1) - ; JP INT_IM1 IF INTERRUPT MODE ACTIVE - LD A,$C3 - LD ($0038),A - LD HL,INT_IM1 - LD ($0039),HL - #ELSE - ; RETI ($ED, $4D) IF NON-INTERRUPT MODE - LD HL,($0038) - LD (HL),$ED - INC HL - LD (HL),$4D - #ENDIF -#ENDIF -; - DIAG(%00001111) -; -; PERFORM DYNAMIC CPU SPEED DERIVATION -; - CALL HB_CPUSPD ; CPU SPEED DETECTION -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) -; - ; SET DESIRED WAIT STATES - LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) - OUT0 (Z180_DCNTL),A -; -#ENDIF -; - CALL DELAY_INIT ; INITIALIZE SPEED COMPENSATED DELAY FUNCTIONS -; - DIAG(%00011111) -; -; INITIALIZE HEAP STORAGE -; - ; INITIALIZE POINTERS - LD HL,HB_END ; HEAP FOLLOWS HBIOS CODE - LD (CB_HEAP),HL ; INIT HEAP BASE ADDRESS - LD (CB_HEAPTOP),HL ; INIT HEAP TOP ADDRESS - ; CLEAR HEAP - LD BC,BNKTOP - HB_END ; MAX SIZE OF HEAP - LD A,$FF ; FILL WITH $FF - CALL FILL ; DO IT -; - DIAG(%00111111) -; -; PRE-CONSOLE INITIALIZATION -; -#IF (ASCIENABLE) - CALL ASCI_PREINIT -#ENDIF -#IF (UARTENABLE) - CALL UART_PREINIT -#ENDIF -#IF (SIOENABLE) - CALL SIO_PREINIT -#ENDIF -#IF (ACIAENABLE) - CALL ACIA_PREINIT -#ENDIF -; - DIAG(%01111111) -; -; PRIOR TO THIS POINT, CONSOLE I/O WAS DIRECTED TO HARDWARE (XIO.ASM). -; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O -; VIA HBIOS. -; - XOR A ; INITIALLY, FIRST SERIAL UNIT IS CONSOLE - LD (CB_CONDEV),A ; SAVE IT, ACTIVATES CONSOLE ON HBIOS -; -; ANNOUNCE HBIOS -; - CALL NEWLINE2 - PRTX(STR_BANNER) -; - DIAG(%11111111) -; -; IO PORT SCAN -; -#IF 0 -PSCN: - LD C,0 ; IO PORT NUMBER - LD B,0 ; LOOP COUNTER - CALL NEWLINE -PSCN1: - CALL NEWLINE - LD A,C - CALL PRTHEXBYTE - CALL PC_COLON - CALL PC_SPACE - CALL DELAY - LD A,C - LD (PSCNX),A -PSCNX .EQU $ + 1 - IN A,(0) - CALL PRTHEXBYTE - CALL PC_COMMA - PUSH BC - LD B,0 - IN A,(C) - POP BC - CALL PRTHEXBYTE - INC C - DJNZ PSCN1 -#ENDIF -; -; SETUP INTERRUPT VECTORS, AS APPROPRIATE -; -;#IF (INTMODE == 1) -; ; OVERLAY $0038 WITH JP INT_IM1 -; LD A,$C3 ; JP INSTRUCTION -; LD ($0038),A ; INSTALL IT -; LD HL,INT_IM1 ; DESTINATION ADDRESS -; LD ($0039),HL ; INSTALL IT -;#ENDIF -; -#IF (INTMODE == 2) - ; SETUP Z80 IVT AND INT MODE 2 - LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS - LD I,A ; ... AND PLACE IT IN I REGISTER - - #IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; SETUP Z180 IVT - XOR A ; SETUP LO BYTE OF IVT ADDRESS - OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER - #ENDIF - - IM 2 ; SWITCH TO INT MODE 2 -#ENDIF - -#IF (PLATFORM == PLT_SBC) -; - #IF (HTIMENABLE) ; SIMH TIMER -; - #IF (INTMODE == 1) - LD HL,HB_TIMINT - CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST - #ENDIF -; - #IF (INTMODE == 2) - ;LD HL,INT_TIMER - ;LD (HBX_IVT),HL - #ENDIF -; - #ENDIF -; -#ENDIF -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) -; - #IF (INTMODE == 2) -; - ; MASK ALL EXTERNAL INTERRUPTS FOR NOW - ;XOR A ; INT0-2 DISABLED - LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED - OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER -; - ; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT - LD HL,INT_TIMER - LD (HBX_IVT + IVT_TIM0),HL - - ; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0 - LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ - LD B,0 - LD C,Z180_RLDR0L ; INITIALIZE TIMER 0 RELOAD REGISTER - OUT (C),L - INC C - OUT (C),H - LD C,Z180_TMDR0L ; INITIALIZE TIMER 0 DATA REGISTER - OUT (C),L - INC C - OUT (C),H - LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING - OUT0 (Z180_TCR),A -; - #ENDIF -; -#ENDIF -; - HB_EI ; INTERRUPTS SHOULD BE OK NOW -; -; DISPLAY PLATFORM INFORMATION -; - CALL NEWLINE2 - PRTX(STR_PLATFORM) - PRTS(" @ $") - LD HL,(CB_CPUKHZ) - CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA - PRTS("MHz$") -; -; DISPLAY CPU CONFIG -; - ;CALL PRTSTRD - ;.TEXT ", $" - CALL NEWLINE -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - LD A,Z180_MEMWAIT -#ELSE - LD A,0 -#ENDIF - CALL PRTDECB - CALL PRTSTRD - .TEXT " MEM W/S, $" -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - LD A,Z180_IOWAIT + 1 -#ELSE - LD A,1 -#ENDIF - CALL PRTDECB - CALL PRTSTRD - .TEXT " I/O W/S$" -#IF (INTMODE > 0) - CALL PRTSTRD - .TEXT ", INT MODE $" - LD A,INTMODE - CALL PRTDECB -#ENDIF -; -; DISPLAY MEMORY CONFIG -; - CALL NEWLINE - ;CALL PRTSTRD - ;.TEXT "MEMORY CONFIG: $" - LD HL,ROMSIZE - CALL PRTDEC - CALL PRTSTRD - .TEXT "KB ROM, $" - LD HL,RAMSIZE - CALL PRTDEC - CALL PRTSTRD - .TEXT "KB RAM$" -; -; PERFORM DEVICE INITIALIZATION -; - CALL NEWLINE - LD B,HB_INITTBLLEN - LD DE,HB_INITTBL -INITSYS1: - LD A,(DE) - LD L,A - INC DE - LD A,(DE) - LD H,A - INC DE - PUSH DE - PUSH BC - CALL JPHL - POP BC - POP DE - DJNZ INITSYS1 -; -; RECORD HEAP CURB AT THE CURRENT VALUE OF HEAP TOP. HEAP CURB -; MARKS THE POINT IN THE HEAP AFTER WHICH MEMORY IS RELEASED -; WHEN AN HBIOS RESET IS PEFORMED. -; - LD HL,(CB_HEAPTOP) - LD (HEAPCURB),HL -; -; NOW SWITCH TO CRT CONSOLE IF CONFIGURED -; -#IF CRTACT -; -; BIOS IS CONFIGURED TO AUTO ACTIVATE CRT DEVICE. FIRST, -; CHECK TO SEE IF WE HAVE A VALID CRT DEVICE TO USE. -; - LD A,(CB_CRTDEV) ; GET THE CRT DEVICE - INC A ; INCREMENT TO TEST FOR $FF - JR Z,INITSYS3 ; IF NO CRT DEVICE, BYPASS CONSOLE SWITCH -; -; IF PLATFORM HAS A CONFIG JUMPER, CHECK TO SEE IF IT IS JUMPERED. -; IF SO, BYPASS SWITCH TO CRT CONSOLE (FAILSAFE MODE) -; -#IF ((PLATFORM != PLT_N8) & (PLATFORM != PLT_MK4) & (PLATFORM != PLT_RC) & (PLATFORM != PLT_RC180)) - IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER - BIT 6,A ; BIT 6 HAS CONFIG JUMPER STATE - JR Z,INITSYS3 ; Z=SHORTED, BYPASS CONSOLE SWITCH -#ENDIF -; - ; NOTIFY USER OF CONSOLE SWITCH ON BOOT CONSOLE - CALL NEWLINE2 - PRTX(STR_SWITCH) - CALL NEWLINE -; - ; SWITCH TO CRT CONSOLE - LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE - LD (CB_CONDEV),A ; SAVE IT AS ACTIVE CONSOLE DEVICE -; - ; DISPLAY HBIOS BANNER ON NEW CONSOLE - PRTX(STR_BANNER) -#ENDIF -; -INITSYS3: -; - CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE -; -; CHAIN TO OS LOADER -; -#IFDEF ROMBOOT - ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM - LD A,BID_BIOSIMG ; CHAIN TO OS IMAGES BANK - LD HL,0 ; ENTER AT ADDRESS 0 - CALL HBX_BNKCALL ; GO THERE - HALT ; WE SHOULD NEVER COME BACK! -#ELSE - ; COPY OS IMAGE: BID_USR: --> BID_USR:0 - ;LD A,BID_USR - ;LD (HB_SRCBNK),A - ;LD (HB_DSTBNK),A - ;LD HL,HB_END - ;LD DE,0 - ;LD BC,$8000 - ;CALL HBX_BNKCPY - LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY - LD D,BID_USR ; D = DEST BANK = USER BANK - LD E,BID_USR ; E = SRC BANK = USER BANK - LD HL,$8000 ; HL = COPY LEN = ENTIRE BANK - RST 08 ; DO IT - LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY - LD HL,HB_END ; COPY FROM END OF OF HBIOS - LD DE,0 ; TO USER ADDRESS 0 - RST 08 ; DO IT -; - ; PERFORM BANK CALL TO USER BANK - LD A,BID_USR ; CHAIN TO OS IMAGES BANK - LD HL,0 ; ENTER AT ADDRESS 0 - CALL HBX_BNKCALL ; GO THERE - HALT ; WE SHOULD NEVER COME BACK! -; -#ENDIF -; - RET -; -;================================================================================================== -; TABLE OF INITIALIZATION ENTRY POINTS -;================================================================================================== -; -HB_INITTBL: -#IF (SPKENABLE) - .DW SPK_INIT ; AUDIBLE INDICATOR OF BOOT START -#ENDIF -#IF (AYENABLE) - .DW AY_INIT ; AUDIBLE INDICATOR OF BOOT START -#ENDIF -#IF (ASCIENABLE) - .DW ASCI_INIT -#ENDIF -#IF (UARTENABLE) - .DW UART_INIT -#ENDIF -#IF (SIOENABLE) - .DW SIO_INIT -#ENDIF -#IF (ACIAENABLE) - .DW ACIA_INIT -#ENDIF -#IF (SIMRTCENABLE) - .DW SIMRTC_INIT -#ENDIF -#IF (DSRTCENABLE) - .DW DSRTC_INIT -#ENDIF -#IF (VDUENABLE) - .DW VDU_INIT -#ENDIF -#IF (CVDUENABLE) - .DW CVDU_INIT -#ENDIF -#IF (VGAENABLE) - .DW VGA_INIT -#ENDIF -#IF (NECENABLE) - .DW NEC_INIT -#ENDIF -#IF (TMSENABLE) - .DW TMS_INIT -#ENDIF -#IF (DSKYENABLE) - .DW DSKY_INIT -#ENDIF -#IF (MDENABLE) - .DW MD_INIT -#ENDIF -#IF (FDENABLE) - .DW FD_INIT -#ENDIF -#IF (RFENABLE) - .DW RF_INIT -#ENDIF -#IF (IDEENABLE) - .DW IDE_INIT -#ENDIF -#IF (PPIDEENABLE) - .DW PPIDE_INIT -#ENDIF -#IF (SDENABLE) - .DW SD_INIT -#ENDIF -#IF (HDSKENABLE) - .DW HDSK_INIT -#ENDIF -#IF (PRPENABLE) - .DW PRP_INIT -#ENDIF -#IF (PPPENABLE) - .DW PPP_INIT -#ENDIF -; -HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) -; -;================================================================================================== -; IDLE -;================================================================================================== -; -;__________________________________________________________________________________________________ -; -IDLE: - PUSH AF - PUSH BC - PUSH DE - PUSH HL - PUSH IY -#IF (FDENABLE) - CALL FD_IDLE -#ENDIF - POP IY - POP HL - POP DE - POP BC - POP AF - RET -; -;================================================================================================== -; BIOS FUNCTION DISPATCHER -;================================================================================================== -; -; MAIN BIOS FUNCTION -; B: FUNCTION -;__________________________________________________________________________________________________ -; -HB_DISPATCH: -; -#IF 0 ; *DEBUG* START -; - CALL HB_DISPCALL ; DO THE WORK -; - ; CHECK STACK INTEGRITY - PUSH AF - LD A,(HB_STACK - HB_STKSIZ + $08) - CP $FF - CALL NZ,PANIC - LD A,$FF - LD (HB_STACK - HB_STKSIZ + $08),A - POP AF - RET -HB_DISPCALL: -; -#ENDIF ; *DEBUG* END -; - LD A,B ; REQUESTED FUNCTION IS IN B - CP BF_CIO + $10 ; $00-$0F: CHARACTER I/O - JP C,CIO_DISPATCH - CP BF_DIO + $10 ; $10-$1F: DISK I/O - JP C,DIO_DISPATCH - CP BF_RTC + $10 ; $20-$2F: REAL TIME CLOCK (RTC) - JP C,RTC_DISPATCH - CP BF_EMU + $10 ; $30-$3F: EMULATION - CALL C,PANIC ; OBSOLETE! - CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER - JP C,VDA_DISPATCH - CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 - CALL C,PANIC ; PANIC IF LESS THAN BF_SYS - JP SYS_DISPATCH ; OTHERWISE SYS CALL - CALL PANIC ; THIS SHOULD NEVER BE REACHED - RET -; -;================================================================================================== -; CHARACTER I/O DEVICE FUNCTION DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO SPECIFIED CHARACTER I/O DRIVER -; B: FUNCTION -; C: UNIT NUMBER -; -CIO_DISPATCH: - BIT 7,C ; CHECK FOR SPECIAL UNIT CODE - CALL NZ,CIO_SPECIAL ; IF SO, HANDLE IT - - PUSH IY ; SAVE INCOMING IY - - LD IY,CIO_TBL ; POINT IY TO START OF DIO TABLE - CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE - - POP IY ; RESTORE IY - RET ; AND DONE -; -; SPECIAL HANDLING FOR DEDICATED UNIT CODES -; -CIO_SPECIAL: - ; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST - ; SO JUST SWAP IN ACTIVE CONSOLE UNIT - LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE - LD C,A ; OVERLAY UNIT CODE IN C - RET ; AND REJOIN MAIN DISPATCH FLOW -; -; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS) -; -CIO_ADDENT: - LD HL,CIO_TBL ; POINT TO CIO TABLE - JP HB_ADDENT ; ... AND GO TO COMMON CODE -; -; HBIOS CHARACTER DEVICE UNIT TABLE -; -; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. -; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT -; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. -; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS -; EACH ENTRY IS DEFINED AS: -; -; WORD DRIVER FUNCTION TABLE ADDRESS -; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) -; -CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) -CIO_MAX .EQU 32 ; UP TO 32 UNITS -CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES -; - .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) - .DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX -CIO_CNT .DB 0 ; ENTRY COUNT PREFIX -CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES -; -;================================================================================================== -; DISK I/O DEVICE FUNCTION DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO SPECIFIED DISK I/O DRIVER -; B: FUNCTION -; C: UNIT NUMBER -; -DIO_DISPATCH: -; -#IF 0 ; *DEBUG* START -; - ; DUMP INCOMING CALL - CALL NEWLINE - PRTS("DIO>$") - CALL REGDMP ; DUMP REGS, NONE DESTROYED -; - ; DO THE ACTUAL DISPATCH PROCESSING - CALL DIO_DISPCALL -; - ; DUMP CALL RESULTS AND RETURN - CALL NEWLINE - PRTS("DIO<$") - CALL REGDMP ; DUMP REGS, NONE DESTROYED - RET -; -#ENDIF ; *DEBUG* END -; -DIO_DISPCALL: - PUSH IY ; SAVE INCOMING IY - - LD IY,DIO_TBL ; POINT IY TO START OF DIO TABLE - CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE - - POP IY ; RESTORE IY - RET ; AND DONE -; -; ADD AN ENTRY TO THE DIO UNIT TABLE -; -DIO_ADDENT: - LD HL,DIO_TBL ; POINT TO DIO TABLE - JP HB_ADDENT ; ... AND GO TO COMMON CODE -; -; HBIOS DISK DEVICE UNIT TABLE -; -; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. -; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT -; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. -; TABLE - 3 CONTAINS THE NUMBER OF DIO FUNCTION IDS -; EACH ENTRY IS DEFINED AS: -; -; WORD DRIVER FUNCTION TABLE ADDRESS -; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) -; -DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) -DIO_MAX .EQU 16 ; UP TO 16 UNITS -DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES -; - .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) - .DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX -DIO_CNT .DB 0 ; ENTRY COUNT PREFIX -DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES -; -;================================================================================================== -; REAL TIME CLOCK DEVICE DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO REAL TIME CLOCK DRIVER -; B: FUNCTION -; -RTC_DISPATCH: -#IF (SIMRTCENABLE) - JP SIMRTC_DISPATCH -#ENDIF -#IF (DSRTCENABLE) - JP DSRTC_DISPATCH -#ENDIF - CALL PANIC -; -;================================================================================================== -; VIDEO DISPLAY ADAPTER DEVICE DISPATCHER -;================================================================================================== -; -; ROUTE CALL TO SPECIFIED VDA DEVICE DRIVER -; B: FUNCTION -; C: UNIT NUMBER -; -VDA_DISPATCH: - PUSH IY ; SAVE INCOMING IY - - LD IY,VDA_TBL ; POINT IY TO START OF DIO TABLE - CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE - - POP IY ; RESTORE IY - RET ; AND DONE -; -; ADD AN ENTRY TO THE VDA UNIT TABLE (SEE HB_ADDENT FOR DETAILS) -; -VDA_ADDENT: - LD HL,VDA_TBL ; POINT TO VDA TABLE - JP HB_ADDENT ; ... AND GO TO COMMON CODE -; -; HBIOS VIDEO DEVICE UNIT TABLE -; -; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. -; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT -; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. -; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS -; EACH ENTRY IS DEFINED AS: -; -; WORD DRIVER FUNCTION TABLE ADDRESS -; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) -; -VDA_FNCNT .EQU 15 ; NUMBER OF VDA FUNCS (FOR RANGE CHECK) -VDA_MAX .EQU 16 ; UP TO 16 UNITS -VDA_SIZ .EQU VDA_MAX * 4 ; EACH ENTRY IS 4 BYTES -; - .DB VDA_FNCNT ; VDA FUNCTION COUNT (FOR RANGE CHECK) - .DB VDA_MAX ; MAX ENTRY COUNT TABLE PREFIX -VDA_CNT .DB 0 ; ENTRY COUNT PREFIX -VDA_TBL .FILL VDA_SIZ,0 ; SPACE FOR ENTRIES -; -;================================================================================================== -; SYSTEM FUNCTION DISPATCHER -;================================================================================================== -; -; B: FUNCTION -; -SYS_DISPATCH: - LD A,B ; GET REQUESTED FUNCTION - AND $0F ; ISOLATE SUB-FUNCTION - JP Z,SYS_RESET ; $F0 - DEC A - JP Z,SYS_VER ; $F1 - DEC A - JP Z,SYS_SETBNK ; $F2 - DEC A - JP Z,SYS_GETBNK ; $F3 - DEC A - JP Z,SYS_SETCPY ; $F4 - DEC A - JP Z,SYS_BNKCPY ; $F5 - DEC A - JP Z,SYS_ALLOC ; $F6 - DEC A - JP Z,SYS_FREE ; $F7 - DEC A - JP Z,SYS_GET ; $F8 - DEC A - JP Z,SYS_SET ; $F9 - DEC A - JP Z,SYS_PEEK ; $FA - DEC A - JP Z,SYS_POKE ; $FB - DEC A - JP Z,SYS_INT ; $FC - CALL PANIC ; INVALID -; -; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS -; -SYS_RESET: - LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD - LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP - XOR A - RET -; -; GET THE CURRENT HBIOS VERSION -; ON INPUT, C=0 -; RETURNS VERSION IN DE AS BCD -; D: MAJOR VERION IN TOP 4 BITS, MINOR VERSION IN LOW 4 BITS -; E: UPDATE VERION IN TOP 4 BITS, PATCH VERSION IN LOW 4 BITS -; L: PLATFORM ID -; -SYS_VER: - LD DE,0 | (RMJ << 12) | (RMN << 8) | (RUP << 4) | RTP - LD L,PLATFORM - XOR A - RET -; -; SET ACTIVE MEMORY BANK AND RETURN PREVIOUSLY ACTIVE MEMORY BANK -; NOTE THAT IT GOES INTO EFFECT AS HBIOS FUNCTION IS EXITED -; HERE, WE JUST SET THE CURRENT BANK -; CALLER MUST EXTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! -; -SYS_SETBNK: - PUSH HL ; SAVE INCOMING HL - LD HL,HB_INVBNK ; POINT TO HBIOS INVOKE BANK ID ADDRESS - LD A,(HL) ; GET EXISTING BANK ID TO A - LD (HL),C ; UPDATE INVOKE BANK TO NEW BANK ID - LD C,A ; PUT PREVIOUS BANK ID IN C FOR RETURN - POP HL ; RESTORE ORIGINAL HL - XOR A ; SIGNAL SUCCESS - RET ; DONE -; -; GET ACTIVE MEMORY BANK -; -SYS_GETBNK: - LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK - LD C,A ; MOVE TO C - XOR A ; SIGNAL SUCCESS - RET -; -; SET BANKS AND LENGTH FOR INTERBANK MEMORY COPY (BNKCPY) -; ENTRY: E=SOURCE BANK ID -; D=DEST BANK ID -; HL=COPY LENGTH (IN BYTES) -; -SYS_SETCPY: - LD A,E - LD (HB_SRCBNK),A ; RECORD THE SOURCE BANK - LD A,D - LD (HB_DSTBNK),A ; RECORD THE DESTINATION BANK - LD (HB_CPYLEN),HL ; RECORD THE COPY LENGTH - XOR A - RET -; -; PERFORM MEMORY COPY POTENTIALLY ACROSS BANKS -; ENTRY: HL=SOURCE ADDRESS -; DE=DESTINATION ADDRESS -; NOTE: SRC/DEST BANK & COPY LENGTH MUST BE SET VIA SETCPY -; -SYS_BNKCPY: - PUSH HL ; SAVE INCOMING HL - LD HL,(HB_CPYLEN) ; HL := COPY LEN (SAVED IN SETCPY) - EX (SP),HL ; RESTORE HL & SET (SP) TO COPY LEN - POP BC ; BC := COPY LEN -#IF (INTMODE == 1) - DI -#ENDIF - CALL HB_BNKCPY -#IF (INTMODE == 1) - EI -#ENDIF - XOR A - RET -; -; ALLOCATE HL BYTES OF MEMORY FROM HBIOS HEAP -; RETURNS POINTER TO ALLOCATED MEMORY IN HL -; ON SUCCESS RETURN A == 0, AND Z SET -; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED -; ALL OTHER REGISTERS PRESERVED -; -SYS_ALLOC: - JP HB_ALLOC -; -; FREE HEAP MEMORY BY SIMPLY RELEASING ALL -; MEMORY BEYOND POINTER IN HL. -; ON SUCCESS RETURN A == 0, AND Z SET -; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED -; ALL OTHER REGISTERS PRESERVED -; -SYS_FREE: - CALL PANIC ; NOT YET IMPLEMENTED - OR $FF - RET -; -; GET SYSTEM INFORMATION -; ITEM TO RETURN INDICATED IN C -; -SYS_GET: - LD A,C ; GET REQUESTED SUB-FUNCTION - CP BF_SYSGET_CIOCNT - JR Z,SYS_GETCIOCNT - CP BF_SYSGET_DIOCNT - JR Z,SYS_GETDIOCNT - CP BF_SYSGET_VDACNT - JR Z,SYS_GETVDACNT - CP BF_SYSGET_TIMER - JR Z,SYS_GETTIMER - CP BF_SYSGET_BOOTINFO - JR Z,SYS_GETBOOTINFO - CP BF_SYSGET_CPUINFO - JR Z,SYS_GETCPUINFO - CP BF_SYSGET_MEMINFO - JR Z,SYS_GETMEMINFO - CP BF_SYSGET_BNKINFO - JR Z,SYS_GETBNKINFO - OR $FF ; SIGNAL ERROR - RET -; -; GET TIMER -; RETURNS: -; DE:HL: TIMER VALUE (32 BIT) -; -SYS_GETTIMER: - LD HL,HB_TICKS - HB_DI - CALL LD32 - HB_EI - XOR A - RET -; -; GET BOOT INFORMATION -; RETURNS: -; L: BOOT BANK ID -; DE: BOOT DISK VOLUME (UNIT/SLICE) -; -SYS_GETBOOTINFO: - LD A,(CB_BOOTBID) - LD L,A - LD DE,(CB_BOOTVOL) - XOR A - RET -; -; GET CPU INFORMATION -; RETURNS: -; H: Z80 CPU VARIANT -; L: CPU SPEED IN MHZ -; DE: CPU SPEED IN KHZ -; -SYS_GETCPUINFO: - LD H,0 ; NOT YET DEFINED - LD A,(CB_CPUMHZ) - LD L,A - LD DE,(CB_CPUKHZ) - XOR A - RET -; -; GET MEMORY INFORMATION -; RETURNS: -; D: COUNT OF ROM BANKS -; E: COUNT OF RAM BANKS -; -SYS_GETMEMINFO: - LD D,ROMSIZE / 32 - LD E,RAMSIZE / 32 - XOR A - RET -; -; GET BANK CONFIGURATION INFORMATION -; RETURNS: -; D: HBIOS BANK ID -; E: USER BANK ID -; -SYS_GETBNKINFO: - LD A,(CB_BIDBIOS) - LD D,A - LD A,(CB_BIDUSR) - LD E,A - XOR A - RET -; -; GET SERIAL UNIT COUNT -; -SYS_GETCIOCNT: - LD A,(CIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) - LD E,A ; PUT IT IN E - XOR A ; SIGNALS SUCCESS - RET -; -; GET DISK UNIT COUNT -; -SYS_GETDIOCNT: - LD A,(DIO_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) - LD E,A ; PUT IT IN E - XOR A ; SIGNALS SUCCESS - RET -; -; GET VIDEO UNIT COUNT -; -SYS_GETVDACNT: - LD A,(VDA_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) - LD E,A ; PUT IT IN E - XOR A ; SIGNALS SUCCESS - RET -; -; SET SYSTEM PARAMETERS -; PARAMETER(S) TO SET INDICATED IN C -; -SYS_SET: - LD A,C ; GET REQUESTED SUB-FUNCTION - CP BF_SYSSET_TIMER - JR Z,SYS_SETTIMER - CP BF_SYSSET_BOOTINFO - JR Z,SYS_SETBOOTINFO - OR $FF ; SIGNAL ERROR - RET -; -; SET BOOT INFORMATION -; ON ENTRY: -; L: BOOT BANK ID -; DE: BOOT DISK VOLUME (UNIT/SLICE) -; -SYS_SETBOOTINFO: - LD A,L - LD (CB_BOOTBID),A - LD (CB_BOOTVOL),DE - XOR A - RET -; -; SET TIMER -; ON ENTRY: -; DE:HL: TIMER VALUE (32 BIT) -; -SYS_SETTIMER: - LD BC,HB_TICKS - HB_DI - CALL ST32 - HB_EI - XOR A - RET -; -; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK -; ENTRY: D=BANK ID, HL=ADDRESS -; RETURN: E=BYTE VALUE -; -SYS_PEEK: -#IF (INTMODE == 1) - DI -#ENDIF - CALL HBX_PEEK ; IMPLEMENTED IN PROXY -#IF (INTMODE == 1) - EI -#ENDIF - XOR A - RET -; -; WRITE A BYTE OF MEMORY TO SPECIFIED BANK -; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE -; -SYS_POKE: -#IF (INTMODE == 1) - DI -#ENDIF - CALL HBX_POKE ; IMPLEMENTED IN PROXY -#IF (INTMODE == 1) - EI -#ENDIF - XOR A - RET -; -; INTERRUPT MANAGEMENT FUNCTIONS -; SUBFUNCTION IN C -; -SYS_INT: - LD A,C ; GET REQUESTED SUB-FUNCTION - CP BF_SYSINT_INFO - JR Z,SYS_INTINFO - CP BF_SYSINT_GET - JR Z,SYS_INTGET - CP BF_SYSINT_SET - JR Z,SYS_INTSET - OR $FF ; SIGNAL ERROR - RET -; -; GET INTERRUPT SYSTEM INFORMATION -; RETURN D:=INTERRUPT MODE, E:=INT VEC TABLE SIZE -; -SYS_INTINFO: - LD D,INTMODE ; D := ACTIVE INTERRUPT MODE -#IF (INTMODE == 0) - LD E,0 ; 0 ENTRIES IF INTERRUPTS DISABLED -#ENDIF -#IF (INTMODE == 1) - LD A,(HB_IM1CNT) ; RETURN IM1 CALL LIST SIZE - LD E,A -#ENDIF -#IF (INTMODE == 2) - LD E,HBX_IVTCNT ; RETURN INT VEC TABLE SIZE -#ENDIF - XOR A ; INDICATE SUCCESS - RET ; AND DONE -; -; ROUTINE SHARED BY INT GET/SET. RETURNS ADDRESS OF VECTOR FOR SPECIFIED LIST / TABLE -; POSITION. ZF SET ON RETURN FOR SUCCESS, ELSE ERROR. -; -SYS_INTVECADR: -#IF (INTMODE == 0) - CALL PANIC ; INVALID FOR INT MODE 0 - OR $FF - RET -#ENDIF -#IF (INTMODE == 1) - LD A,(HB_IM1CNT) ; GET CURRENT ENTRY COUNT - INC A ; ALLOW FOR EXTRA ENTRY TO APPEND AT END - LD C,A ; SAVE IN C FOR COMPARE -#ENDIF -#IF (INTMODE == 2) - LD C,HBX_IVTCNT ; GET CURRENT ENTRY COUNT -#ENDIF - LD A,E ; INCOMING INDEX POSITION TO A - CP C ; COMPARE TO VECTOR COUNT - JR C,SYS_INTGET1 ; CONTINUE IF POSITION IN RANGE - CALL PANIC ; ELSE ERROR - OR $FF - RET -SYS_INTGET1: - OR A - RLA ; HL := (A * 2) FOR IM2 -#IF (INTMODE == 1) - RLA ; ... HL := (A * 4) + 1 FOR IM1 - INC A -#ENDIF - LD H,0 - LD L,A -#IF (INTMODE == 1) - LD DE,HB_IM1INT ; DE := START OF CALL LIST -#ENDIF -#IF (INTMODE == 2) - LD DE,HBX_IVT ; DE := START OF VECTOR TABLE -#ENDIF - ADD HL,DE ; HL := ADR OF VECTOR - XOR A ; INDICATE SUCCESS - RET -; -; RETURN THE INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE -; ENTRY: E=LIST/TABLE POSITION -; RETURN: HL=INTERRUPT VECTOR -; -SYS_INTGET: - CALL SYS_INTVECADR ; GET VECTOR ADDRESS - RET NZ ; BAIL OUT ON ERROR - LD A,(HL) ; DEREF HL TO GET VECTOR - INC HL - LD H,(HL) - LD L,A - XOR A ; SIGNAL SUCCESS - RET ; DONE -; -; SET AN INTERRUPT VECTOR FOR A SPECIFIED POSITION IN THE INT VECTOR LIST / TABLE -; ENTRY: E=LIST/TABLE POSITION, HL=NEW INTERRUPT VECTOR -; RETURN: HL=PREVIOUS INTERRUPT VECTOR, DE=ADR OF INT ROUTING ENGINE FOR IM2 -; -SYS_INTSET: - PUSH HL ; SAVE NEW VECTOR - CALL SYS_INTVECADR ; GET VECTOR ADDRESS - JR Z,SYS_INTSET1 ; CONTINUE IF OK - POP HL ; FIX STACK - RET NZ ; BAIL OUT ON ERROR -SYS_INTSET1: - PUSH HL ; SAVE VECTOR ADDRESS - LD A,(HL) ; DEREF HL TO GET PREV VECTOR - INC HL - LD H,(HL) - LD L,A - EX (SP),HL ; (SP) := PREV VEC, HL := VEC ADR - POP DE ; DE := PREV VEC - POP BC ; BC := NEW VEC - LD (HL),C ; SAVE LSB - INC HL - LD (HL),B ; SAVE MSB - EX DE,HL ; HL := PREV VEC -#IF (INTMODE == 2) - LD DE,HBX_INT ; DE := IM2 INT ROUTING ENGINE -#ENDIF - XOR A ; SIGNAL SUCCESS - RET ; DONE -; -;================================================================================================== -; GLOBAL HBIOS FUNCTIONS -;================================================================================================== -; -; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN -; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT) -; -CIO_IDLE: - PUSH AF ; PRESERVE AF - LD A,(IDLECOUNT) ; GET CURRENT IDLE COUNT - DEC A ; DECREMENT - LD (IDLECOUNT),A ; SAVE UPDATED VALUE - CALL Z,IDLE ; IF ZERO, DO IDLE PROCESSING - POP AF ; RECOVER AF - RET -; -#IF (INTMODE == 1) -; -; IM1 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK -; LIST OF IM1 INT CALLS IS BUILT DYNAMICALLY BELOW -; SEE HB_ADDIM1 ROUTINE -; EACH ENTRY WILL LOOK LIKE: -; CALL XXXX ; CALL INT HANDLER -; RET NZ ; RETURN IF HANDLED -; -; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. -; AS THE TABLE IS POPULATED, THE ADDRESS OF HB_BADINT IS OVERLAID -; WITH THE ADDRESS OF A REAL INTERRUPT HANDLER. -; -; THERE IS ROOM FOR 8 ENTRIES PLUS A FINAL CALL TO HB_BADINT. -; -HB_IM1INT: ; IM1 DEVICE INTERRUPT HANDLER CALL LIST - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ - CALL HB_BADINT \ RET NZ -; -; ROUTINE BELOW IS USED TO ADD A NEW VECTOR TO THE IM1 -; CALL LIST ABOVE. ENTER WITH HL=VECTOR ADDRESS IN HBIOS -; -HB_ADDIM1: - EX DE,HL ; VECTOR ADDRESS TO DE - LD HL,(HB_IM1PTR) ; GET PTR FOR NEXT ENTRY - INC HL ; BUMP PTR TO ADDRESS FIELD OF CALL OPCODE - LD (HL),E ; ADD VECTOR ADDRESS - INC HL ; ... - LD (HL),D ; ... - INC HL ; BUMP PTR - INC HL ; BUMP PTR - LD (HB_IM1PTR),HL ; SAVE UPDATED POINTER - LD HL,HB_IM1CNT ; POINT TO ENTRY COUNT - INC (HL) ; INCREMENT - RET ; DONE -; -HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST -HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST -HB_IM1PTR .DW HB_IM1INT ; POINTER FOR NEXT IM1 ENTRY -; -#ENDIF -; -; TIMER INTERRUPT -; -HB_TIMINT: - ; INCREMENT TICK COUNTER (32 BIT) - LD HL,HB_TICKS ; POINT TO TICK COUNTER - INC (HL) - JR NZ,HB_TIMINT1 - INC HL - INC (HL) - JR NZ,HB_TIMINT1 - INC HL - INC (HL) - JR NZ,HB_TIMINT1 - INC HL - INC (HL) -; -HB_TIMINT1: -; -#IF 0 -; - LD HL,TEMPCNT - DEC (HL) - JR NZ,HB_TIMINT2 - LD (HL),250 -; - LD A,'*' - CALL COUT - JR HB_TIMINT2 -; -TEMPCNT .DB 250 -; -#ENDIF -; -HB_TIMINT2: -; -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; ACK/RESET Z180 TIMER INTERRUPT - IN0 A,(Z180_TCR) - IN0 A,(Z180_TMDR0L) -#ENDIF -; - OR $FF ; NZ SET TO INDICATE INT HANDLED - RET -; -; BAD INTERRUPT HANDLER -; -HB_BADINT: - CALL NEWLINE2 - PRTS("+++ BAD INT: $") - CALL _REGDMP - CALL CONTINUE - OR $FF ; SIGNAL INTERRUPT HANDLED - RET -; -; COMMON API FUNCTION DISPATCH CODE -; -; ON ENTRY C IS UNIT # (INDEX INTO XXX_TBL OF UNITS) -; AND IY POINTS TO START OF UNIT TABLE. -; USE UNIT # IN C TO LOOKUP XXX_TBL ENTRY. THE XXX_TBL -; ENTRY CONTAINS THE START OF THE DRIVER FUNCTION TABLE AND -; THE DEVICE SPECIFIC INSTANCE DATA (BLOB). SET IY TO BLOB ADDRESS -; AND CALL THE SPECIFIC FUNCTION REQUESTED IN THE DRIVER. -; -HB_DISPCALL: - ; CHECK INCOMING UNIT INDEX IN C FOR VAILIDITY - LD A,C ; A := INCOMING DISK UNIT INDEX - CP (IY-1) ; COMPARE TO COUNT - JR NC,HB_DISPERR ; HANDLE INVALID UNIT INDEX - - ; CHECK FUNCTION INDEX FOR VALIDITY - LD A,B ; A := INCOMING FUNCTION NUMBER - AND $0F ; LOW NIBBLE ONLY FOR FUNC INDEX - CP (IY-3) ; CHECK FN NUM AGAINST MAX - JR NC,HB_DISPERR ; HANDLE FN NUM OUT OF RANGE ERROR - - ; BUMP IY TO ACTUAL XXX_TBL ENTRY FOR INCOMING UNIT INDEX - LD B,0 ; MSB IS ALWAYS ZERO - RLC C ; MULTIPLY UNIT INDEX - RLC C ; ... BY 4 FOR TABLE ENTRY OFFSET - ADD IY,BC ; SET IY TO ENTRY ADDRESS - - ; DERIVE DRIVER FUNC ADR TO CALL - PUSH HL ; SAVE INCOMING HL - LD L,(IY+0) ; COPY DRIVER FUNC TABLE - LD H,(IY+1) ; ... START TO HL - RLCA ; CONV UNIT (STILL IN A) TO FN ADR OFFSET - CALL ADDHLA ; HL NOW HAS DRIVER FUNC TBL START ADR - LD A,(HL) ; DEREFERENCE HL - INC HL ; ... TO GET - LD H,(HL) ; ... ACTUAL - LD L,A ; ... TARGET FUNCTION ADDRESS - EX (SP),HL ; RESTORE HL, FUNC ADR ON STACK - - ; GET UNIT INSTANCE DATA BLOB ADDRESS TO IY - PUSH HL ; SAVE INCOMING HL - LD L,(IY+2) ; HL := DATA BLOB ADDRESS - LD H,(IY+3) ; ... - EX (SP),HL ; RESTORE HL, BLOB ADR ON TOS - POP IY ; IY := BLOB ADR - - RET ; JUMP TO DRIVER FUNC ADR ON TOS -; -HB_DISPERR: - CALL PANIC ; PANIC - OR $FF ; SIGNAL ERROR - RET ; AND RETURN VIA DISPEXIT -; -; ADD AN ENTRY TO THE UNIT TABLE AT ADDRESS IN HL -; BC: DRIVER FUNCTION TABLE -; DE: ADDRESS OF UNIT INSTANCE DATA -; RETURN -; A: UNIT NUMBER ASSIGNED -; -HB_ADDENT: - DEC HL ; POINT TO ENTRY COUNT - LD A,(HL) ; GET ENTRY COUNT - PUSH AF ; SAVE VALUE TO RETURN AS ENTRY NUM AT END - INC A ; INCREMENT TO ACCOUNT FOR NEW ENTRY - DEC HL ; POINT TO ENTRY MAX - CP (HL) ; COMPARE MAX TO CURRENT COUNT (COUNT - MAX) - CALL NC,PANIC ; OVERFLOW - INC HL ; POINT TO COUNT - LD (HL),A ; SAVE NEW COUNT - INC HL ; POINT TO START OF TABLE - DEC A ; CONVERT A FROM ENTRY COUNT TO ENTRY INDEX - RLCA ; MULTIPLY BY 4 - RLCA ; ... TO GET BYTE OFFSET OF ENTRY - CALL ADDHLA ; MAKE HL POINT TO ACTUAL ENTRY ADDRESS - PUSH BC ; GET TABLE ENTRY ADDRESS TO BC - EX (SP),HL ; ... AND DISPATCH ADDRESS TO HL - POP BC ; ... SO THAT DE:HL HAS 32 BIT ENTRY - CALL ST32 ; LD (BC),DE:HL STORES THE ENTRY - POP AF ; RETURN ENTRY INDEX (UNIT NUMBER ASSIGNED) - RET -; -; ALLOCATE HL BYTES OF MEMORY ON THE HEAP -; RETURNS POINTER TO ALLOCATED SPACE IN HL -; ON SUCCESS RETURN A == 0, AND Z SET -; ON FAILURE A <> 0 AND NZ SET AND HL TRASHED -; ALL OTHER REGISTERS PRESERVED -; -; A 4 BYTE HEADER IS PLACED IN FRONT OF THE ALLOCATED MEMORY -; - DWORD: SIZE OF MEMROY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) -; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) -; -HB_ALLOC: - ; SAVE ALLOC SIZE AND REFERENCE ADR FOR SUBSEQUENT HEADER CONSTRUCTION - LD (HB_TMPSZ),HL ; SAVE INCOMING SIZE REQUESTED - ; USE EX (SP),HL INSTEAD???? - POP HL ; GET RETURN ADDRESS - LD (HB_TMPREF),HL ; SAVE AS REFERENCE - ; USE EX (SP),HL INSTEAD???? - PUSH HL ; PUT IT BACK ON STACK - LD HL,(HB_TMPSZ) ; RECOVER INCOMING MEM SIZE PARM -; - ; CALC NEW HEAP TOP AND HANDLE OUT-OF-SPACE ERROR - PUSH DE ; SAVE INCOMING DE - LD DE,4 ; SIZE OF HEADER - ADD HL,DE ; ADD IT IN - JR C,HB_ALLOC1 ; ERROR ON OVERFLOW - LD DE,(CB_HEAPTOP) ; CURRENT HEAP TOP - ADD HL,DE ; ADD IT IN, HL := NEW HEAP TOP - JR C,HB_ALLOC1 ; ERROR ON OVERFLOW - BIT 7,H ; TEST PAST END OF BANK (>= 32K) - JR NZ,HB_ALLOC1 ; ERROR IF PAST END -; - ; SAVE NEW HEAP TOP - LD DE,(CB_HEAPTOP) ; GET ORIGINAL HEAP TOP - LD (CB_HEAPTOP),HL ; SAVE NEW HEAP TOP -; - ; SET HEADER VALUES - EX DE,HL ; HEADER ADR TO HL - LD DE,(HB_TMPSZ) ; GET THE ORIG SIZE REQUESTED - LD (HL),E ; SAVE SIZE (LSB) - INC HL ; BUMP HEADER POINTER - LD (HL),D ; SAVE SIZE (MSB) - INC HL ; BUMP HEADER POINTER - LD DE,(HB_TMPREF) ; GET THE REFERENCE ADR - LD (HL),E ; SAVE REF ADR (LSB) - INC HL ; BUMP HEADER POINTER - LD (HL),D ; SAVE REF ADR (MSB) - INC HL ; BUMP HEADER POINTER -; - ; RETURN SUCCESS, HL POINTS TO START OF ALLOCATED MEMORY (PAST HEADER) - POP DE ; RESTORE INCOMING DE - XOR A ; SIGNAL SUCCESS - RET ; AND RETURN -; -HB_ALLOC1: - ; ERROR RETURN - POP DE ; RESTORE INCOMING DE - OR $FF ; SIGNAL ERROR - RET ; AND RETURN -; -HB_TMPSZ .DW 0 -HB_TMPREF .DW 0 -; -;================================================================================================== -; DEVICE DRIVERS -;================================================================================================== -; -#IF (SIMRTCENABLE) -ORG_SIMRTC .EQU $ - #INCLUDE "simrtc.asm" -SIZ_SIMRTC .EQU $ - ORG_SIMRTC - .ECHO "SIMRTC occupies " - .ECHO SIZ_SIMRTC - .ECHO " bytes.\n" -#ENDIF -; -#IF (DSRTCENABLE) -ORG_DSRTC .EQU $ - #INCLUDE "dsrtc.asm" -SIZ_DSRTC .EQU $ - ORG_DSRTC - .ECHO "DSRTC occupies " - .ECHO SIZ_DSRTC - .ECHO " bytes.\n" -#ENDIF -; -#IF (ASCIENABLE) -ORG_ASCI .EQU $ - #INCLUDE "asci.asm" -SIZ_ASCI .EQU $ - ORG_ASCI - .ECHO "ASCI occupies " - .ECHO SIZ_ASCI - .ECHO " bytes.\n" -#ENDIF -; -#IF (UARTENABLE) -ORG_UART .EQU $ - #INCLUDE "uart.asm" -SIZ_UART .EQU $ - ORG_UART - .ECHO "UART occupies " - .ECHO SIZ_UART - .ECHO " bytes.\n" -#ENDIF -; -#IF (SIOENABLE) -ORG_SIO .EQU $ - #INCLUDE "sio.asm" -SIZ_SIO .EQU $ - ORG_SIO - .ECHO "SIO occupies " - .ECHO SIZ_SIO - .ECHO " bytes.\n" -#ENDIF -; -#IF (ACIAENABLE) -ORG_ACIA .EQU $ - #INCLUDE "acia.asm" -SIZ_ACIA .EQU $ - ORG_ACIA - .ECHO "ACIA occupies " - .ECHO SIZ_ACIA - .ECHO " bytes.\n" -#ENDIF -; -#IF (VGAENABLE) -ORG_VGA .EQU $ - #INCLUDE "vga.asm" -SIZ_VGA .EQU $ - ORG_VGA - .ECHO "VGA occupies " - .ECHO SIZ_VGA - .ECHO " bytes.\n" -#ENDIF -; -#IF (CVDUENABLE) -ORG_CVDU .EQU $ - #INCLUDE "cvdu.asm" -SIZ_CVDU .EQU $ - ORG_CVDU - .ECHO "CVDU occupies " - .ECHO SIZ_CVDU - .ECHO " bytes.\n" -#ENDIF -; -#IF (VDUENABLE) -ORG_VDU .EQU $ - #INCLUDE "vdu.asm" -SIZ_VDU .EQU $ - ORG_VDU - .ECHO "VDU occupies " - .ECHO SIZ_VDU - .ECHO " bytes.\n" -#ENDIF -; -#IF (TMSENABLE) -ORG_TMS .EQU $ - #INCLUDE "tms.asm" -SIZ_TMS .EQU $ - ORG_TMS - .ECHO "TMS occupies " - .ECHO SIZ_TMS - .ECHO " bytes.\n" -#ENDIF -; -#IF (NECENABLE) -ORG_NEC .EQU $ - ;#INCLUDE "nec.asm" -SIZ_NEC .EQU $ - ORG_NEC - .ECHO "NEC occupies " - .ECHO SIZ_NEC - .ECHO " bytes.\n" -#ENDIF -; -#IF (CVDUENABLE | VGAENABLE) -ORG_FONTHI .EQU $ - #INCLUDE "font_hi.asm" -SIZ_FONTHI .EQU $ - ORG_FONTHI - .ECHO "FONTHI occupies " - .ECHO SIZ_FONTHI - .ECHO " bytes.\n" -#ENDIF -; -#IF (TMSENABLE) -ORG_FONTTMS .EQU $ - #INCLUDE "font_tms.asm" -SIZ_FONTTMS .EQU $ - ORG_FONTTMS - .ECHO "FONTTMS occupies " - .ECHO SIZ_FONTTMS - .ECHO " bytes.\n" -#ENDIF -; -#IF (CVDUENABLE | VGAENABLE) -ORG_KBD .EQU $ - #INCLUDE "kbd.asm" -SIZ_KBD .EQU $ - ORG_KBD - .ECHO "KBD occupies " - .ECHO SIZ_KBD - .ECHO " bytes.\n" -#ENDIF -; -#IF (VDUENABLE | (TMSENABLE & (PLATFORM == PLT_N8))) -ORG_PPK .EQU $ - #INCLUDE "ppk.asm" -SIZ_PPK .EQU $ - ORG_PPK - .ECHO "PPK occupies " - .ECHO SIZ_PPK - .ECHO " bytes.\n" -#ENDIF -; -#IF (PRPENABLE) -ORG_PRP .EQU $ - #INCLUDE "prp.asm" -SIZ_PRP .EQU $ - ORG_PRP - .ECHO "PRP occupies " - .ECHO SIZ_PRP - .ECHO " bytes.\n" -#ENDIF -; -#IF (PPPENABLE) -ORG_PPP .EQU $ - #INCLUDE "ppp.asm" -SIZ_PPP .EQU $ - ORG_PPP - .ECHO "PPP occupies " - .ECHO SIZ_PPP - .ECHO " bytes.\n" -#ENDIF -; -#IF (MDENABLE) -ORG_MD .EQU $ - #INCLUDE "md.asm" -SIZ_MD .EQU $ - ORG_MD - .ECHO "MD occupies " - .ECHO SIZ_MD - .ECHO " bytes.\n" -#ENDIF - -#IF (FDENABLE) -ORG_FD .EQU $ - #INCLUDE "fd.asm" -SIZ_FD .EQU $ - ORG_FD - .ECHO "FD occupies " - .ECHO SIZ_FD - .ECHO " bytes.\n" -#ENDIF - -#IF (RFENABLE) -ORG_RF .EQU $ - #INCLUDE "rf.asm" -SIZ_RF .EQU $ - ORG_RF - .ECHO "RF occupies " - .ECHO SIZ_RF - .ECHO " bytes.\n" -#ENDIF - -#IF (IDEENABLE) -ORG_IDE .EQU $ - #INCLUDE "ide.asm" -SIZ_IDE .EQU $ - ORG_IDE - .ECHO "IDE occupies " - .ECHO SIZ_IDE - .ECHO " bytes.\n" -#ENDIF - -#IF (PPIDEENABLE) -ORG_PPIDE .EQU $ - #INCLUDE "ppide.asm" -SIZ_PPIDE .EQU $ - ORG_PPIDE - .ECHO "PPIDE occupies " - .ECHO SIZ_PPIDE - .ECHO " bytes.\n" -#ENDIF - -#IF (SDENABLE) -ORG_SD .EQU $ - #INCLUDE "sd.asm" -SIZ_SD .EQU $ - ORG_SD - .ECHO "SD occupies " - .ECHO SIZ_SD - .ECHO " bytes.\n" -#ENDIF - -#IF (HDSKENABLE) -ORG_HDSK .EQU $ - #INCLUDE "hdsk.asm" -SIZ_HDSK .EQU $ - ORG_HDSK - .ECHO "HDSK occupies " - .ECHO SIZ_HDSK - .ECHO " bytes.\n" -#ENDIF - -#IF (TERMENABLE) -ORG_TERM .EQU $ - #INCLUDE "term.asm" -SIZ_TERM .EQU $ - ORG_TERM - .ECHO "TERM occupies " - .ECHO SIZ_TERM - .ECHO " bytes.\n" -#ENDIF -; -#IF (SPKENABLE) -ORG_SPK .EQU $ - #INCLUDE "spk.asm" -SIZ_SPK .EQU $ - ORG_SPK - .ECHO "SPK occupies " - .ECHO SIZ_SPK - .ECHO " bytes.\n" -#ENDIF -; -#IF (AYENABLE) -ORG_AY .EQU $ - #INCLUDE "ay.asm" -SIZ_AY .EQU $ - ORG_AY - .ECHO "AY occupies " - .ECHO SIZ_AY - .ECHO " bytes.\n" -#ENDIF -; -#DEFINE USEDELAY -#INCLUDE "util.asm" -#INCLUDE "time.asm" -#INCLUDE "bcd.asm" -#INCLUDE "decode.asm" -;#INCLUDE "xio.asm" -; -#IF (DSKYENABLE) -#DEFINE DSKY_KBD -#INCLUDE "dsky.asm" -#ENDIF -; -; DETECT CPU SPEED USING DS-1302 RTC -; -HB_CPUSPD: -; -#IF (DSRTCENABLE) -; - CALL DSRTC_TSTCLK ; IS CLOCK RUNNING? - JR Z,HB_CPUSPD1 ; YES, CONTINUE - ; MAKE SURE CLOCK IS RUNNING - LD HL,DSRTC_TIMDEF - CALL DSRTC_TIM2CLK - LD HL,DSRTC_BUF - CALL DSRTC_WRCLK - CALL DSRTC_TSTCLK ; NOW IS CLOCK RUNNING? - RET NZ -; -HB_CPUSPD1: -; LD B,8 -;HB_CPUSPDX: -; PUSH BC - - ; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT - ; FOR SECOND TICK AND TO GET A FULL ONE SECOND LOOP COUNT - - CALL HB_RDSEC ; GET SECONDS - LD (HB_CURSEC),A ; AND INIT CURSEC - CALL HB_WAITSEC ; WAIT FOR SECONDS TICK - LD (HB_CURSEC),A ; SAVE NEW VALUE - CALL HB_WAITSEC ; WAIT FOR SECONDS TICK - -; PUSH DE -; POP BC -; CALL NEWLINE -; CALL PRTHEXWORD - -; POP BC -; DJNZ HB_CPUSPDX -; - LD A,H - OR L - RET Z ; FAILURE, USE DEFAULT CPU SPEED - -; - ; MOVE LOOP COUNT TO HL - PUSH DE - POP HL -; - ; TIMES 4 FOR CPU SPEED IN KHZ - RES 0,L ; GRANULARITY -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - SLA L - RL H -#ENDIF - SLA L - RL H - SLA L - RL H -; - LD (CB_CPUKHZ),HL - LD DE,1000 - CALL DIV16 - LD A,C - LD (CB_CPUMHZ),A -; - RET -; -HB_WAITSEC: - ; WAIT FOR SECONDS TICK - ; RETURN SECS VALUE IN A, LOOP COUNT IN DE - LD DE,0 ; INIT LOOP COUNTER -HB_WAITSEC1: -#IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2)| (PLATFORM == PLT_RC)) - ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 - CALL DLY32 - CALL DLY8 - CALL DLY2 - JP $ + 3 ; 10 TSTATES - JP $ + 3 ; 10 TSTATES - JP $ + 3 ; 10 TSTATES - JP $ + 3 ; 10 TSTATES - ;LD A,R ; 9 TSTATES - INC BC ; 6 TSTATES - ;LD A,(BC) ; 7 TSTATES - ;NOP ; 4 TSTATES - NOP ; 4 TSTATES -#ENDIF - -#IF ((PLATFORM == PLT_N8) | (PLATFORM == PLT_MK4) | (PLATFORM == PLT_RC180)) - ; LOOP TARGET IS 8000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 8 - ;CALL DLY64 - CALL DLY32 - CALL DLY16 - CALL DLY8 - CALL DLY4 - CALL DLY2 - CALL DLY1 ; CALL (25TS) & RET (18TS) = 43TS - OR A ; 7 TSTATES - OR A ; 7 TSTATES - ;OR A ; 7 TSTATES - ;OR A ; 7 TSTATES - NOP ; 6 TSTATES - ;NOP ; 6 TSTATES - ;NOP ; 6 TSTATES - ;NOP ; 6 TSTATES - ;NOP ; 6 TSTATES -#ENDIF -; - PUSH DE - CALL HB_RDSEC ; GET SECONDS - POP DE - INC DE ; BUMP COUNTER - LD HL,HB_CURSEC ; POINT TO COMP VALUE - CP (HL) ; TEST FOR CHANGE - RET NZ ; DONE IF TICK OCCURRED - LD A,D ; CHECK HL - OR E ; ... FOR OVERFLOW - RET Z ; TIMEOUT, SOMETHING IS WRONG - JR HB_WAITSEC1 ; LOOP -; -HB_RDSEC: - ; READ SECONDS BYTE INTO A - LD C,$81 ; SECONDS REGISTER - CALL DSRTC_CMD ; SEND THE COMMAND - CALL DSRTC_GET ; READ THE REGISTER - CALL DSRTC_END ; FINISH IT - RET -; -#ELSE -; - RET ; NO RTC, ABORT -; -#ENDIF -; -; PRINT VALUE OF HL AS THOUSANDTHS, IE. 0.000 -; -PRTD3M: - PUSH BC - PUSH DE - PUSH HL - LD E,'0' - LD BC,-10000 - CALL PRTD3M1 - LD E,0 - LD BC,-1000 - CALL PRTD3M1 - CALL PC_PERIOD - LD BC,-100 - CALL PRTD3M1 - LD C,-10 - CALL PRTD3M1 - LD C,-1 - CALL PRTD3M1 - POP HL - POP DE - POP BC - RET -PRTD3M1: - LD A,'0' - 1 -PRTD3M2: - INC A - ADD HL,BC - JR C,PRTD3M2 - SBC HL,BC - CP E - JR Z,PRTD3M3 - LD E,0 - CALL COUT -PRTD3M3: - RET -; -;================================================================================================== -; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES -;================================================================================================== -; -PRTSUM: - CALL NEWLINE2 ; SKIP A LINE - LD DE,PS_STRHDR ; POINT TO HEADER - CALL WRITESTR ; PRINT IT -; - ; PRINT DISK DEVICES - LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET - LD C,BF_SYSGET_DIOCNT ; SUBFUNC: DISK UNIT COUNT - RST 08 ; E := DISK UNIT COUNT - LD B,E ; MOVE TO B FOR LOOP COUNT - LD A,E ; MOVE TO ACCUM - OR A ; SET FLAGS - JR Z,PRTSUM1A ; IF NONE, BYPASS - LD C,0 ; C WILL BE UNIT INDEX -PRTSUM1: - PUSH BC ; SAVE LOOP CONTROL - CALL PS_DISK ; PRINT DISK INFO - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP DISK UNIT INDEX - DJNZ PRTSUM1 ; LOOP THRU ALL DISK DEVICES -; -PRTSUM1A: - ; PRINT SERIAL DEVICES - LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET - LD C,BF_SYSGET_CIOCNT ; SUBFUNC: SERIAL UNIT COUNT - RST 08 ; E := SERIAL UNIT COUNT - LD B,E ; MOVE TO B FOR LOOP COUNT - LD A,E ; MOVE TO ACCUM - OR A ; SET FLAGS - JR Z,PRTSUM2A ; IF NONE, BYPASS - LD C,0 ; C WILL BE UNIT INDEX -PRTSUM2: - PUSH BC ; SAVE LOOP CONTROL - CALL PS_SERIAL ; PRINT SERIAL INFO - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP SERIAL UNIT INDEX - DJNZ PRTSUM2 ; LOOP THRU ALL SERIAL DEVICES -; -PRTSUM2A: - ; PRINT VIDEO DEVICES - LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET - LD C,BF_SYSGET_VDACNT ; SUBFUNC: VIDEO UNIT COUNT - RST 08 ; E := SERIAL UNIT COUNT - LD B,E ; MOVE TO B FOR LOOP COUNT - LD A,E ; MOVE TO ACCUM - OR A ; SET FLAGS - JR Z,PRTSUM3A ; IF NONE, BYPASS - LD C,0 ; C WILL BE UNIT INDEX -PRTSUM3: - PUSH BC ; SAVE LOOP CONTROL - CALL PS_VIDEO ; PRINT VIDEO INFO - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP VIDEO UNIT INDEX - DJNZ PRTSUM3 ; LOOP THRU ALL VIDEO DEVICES -; -PRTSUM3A: - RET ; DONE -; -; PRINT ONE LINE DISK UNIT/DEVICE INFO, DISK UNIT INDEX IN C -; -PS_DISK: - PUSH BC ; SAVE UNIT INDEX FOR LATER -; - ; UNIT COLUMN - PRTS("Disk $") - LD A,C ; MOVE UNIT NUM TO A - CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT - PRTS(" $") ; PAD TO NEXT COLUMN -; - ; DEVICE COLUMN - LD B,BF_DIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C - RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES - LD HL,PS_DDSTRREF ; POINT TO DISK DEVICE TYPE NAME TABLE - CALL PS_PRTDEV ; PRINT DISK DEVICE NMEMONIC PADDED TO FIELD WIDTH - POP DE ; RECOVER ATTRIBUTES TO DE - PUSH DE ; SAVE ATTRIBUTES AGAIN - CALL PS_PRTDT ; PRINT DISK TYPE - POP DE ; RESTORE ATTRIBUTES - POP BC ; RESTORE UNIT NUM - CALL PS_PRTDC ; PRINT DISK CAPACITY -; - CALL NEWLINE - RET -; -; PRINT DISK TYPE (DISK ATTRIBUTE IN E) -; -PS_PRTDT: - LD A,E ; ATTRIBUTES TO A - BIT 7,A ; FLOPPY BIT SET? - LD HL,PS_DTFLOP ; ASSUME FLOPPY - JR NZ,PS_PRTDT1 ; IF FLOPPY, JUMP AHEAD - RRCA ; SHIFT TYPE BITS - RRCA - RRCA - AND $07 ; AND ISOLATE THEM - RLCA ; X2 FOR WORD OFFSET IN STRING TABLE - LD HL,PS_DTSTRREF + 2 ; POINT TO STR REF TABLE (SKIP FLOPPY STRING) - CALL ADDHLA - LD A,(HL) - INC HL - LD H,(HL) - LD L,A -; -PS_PRTDT1: - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,18 ; 18 CHAR FIELD - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT DISK CAPACITY (UNIT IN C, ATTRIBUTE IN E) -; -PS_PRTDC: -; - LD A,E ; ATTRIBUTE TO ACCUM - BIT 7,A ; TEST FOR FLOPPY - JR NZ,PS_PRTDC2 ; HANDLE FLOPPY - RRCA ; ISOLATE TYPE BITS - RRCA - RRCA - AND $07 - CP 4 ; ROM DISK? - JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB - CP 5 ; RAM DISK? - JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB -; - ; PRINT HARD DISK STORAGE SIZE IN MB - LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY - RST 08 ; DE:HL := BLOCKS - JP NZ,PS_PRTNUL ; MEDIA PROBLEM - RES 7,D ; CLEAR LBA BIT - LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB - CALL SRL32 ; RIGHT SHIFT - CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) - PRTS("MB$") ; PRINT SUFFIX - CALL PC_COMMA - PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA - RET ; DONE -; -PS_PRTDC1: - ; PRINT ROM/ROM DISK CAPACITY IN KB - LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY - RST 08 ; DE:HL := BLOCKS - JP NZ,PS_PRTNUL ; MEDIA PROBLEM - RES 7,D ; CLEAR LBA BIT - LD B,1 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB - CALL SRL32 ; RIGHT SHIFT - CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) - PRTS("KB$") ; PRINT SUFFIX - CALL PC_COMMA - PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA - RET ; DONE -; -PS_PRTDC2: - LD C,E ; ATTRIBUTE TO C FOR SAFE KEEPING - ; PRINT FLOPPY TYPE - LD A,C ; ATTRIBUTE TO ACCUM - RLCA ; ISOLATE FORM FACTOR BITS - RLCA - RLCA - AND $03 - LD DE,PS_FLP8 ; ASSUME 8" - CP 0 - JR Z,PS_PRTDC2A - LD DE,PS_FLP5 ; ASSUME 5.25" - CP 1 - JR Z,PS_PRTDC2A - LD DE,PS_FLP3 ; ASSUME 3.5" - CP 2 - JR Z,PS_PRTDC2A - LD DE,PS_FLPN ; ASSUME OTHER" -PS_PRTDC2A: - CALL WRITESTR - ; PRINT FLOPPY SIDES - LD A,C ; ATTRIBUTE TO ACCUM - LD DE,PS_FLPSS ; ASSUME SINGLE SIDED - BIT 4,A ; DS? - JR Z,PS_PRTDC2B - LD DE,PS_FLPDS ; DOUBLE SIDED -PS_PRTDC2B: - CALL WRITESTR - ; PRINT FLOPPY DENSITY - LD A,C ; ATTRIBUTE TO ACCUM - RRCA ; ISOLATE DENSITY BITS - RRCA - AND $03 - LD DE,PS_FLPSD ; SINGLE DENSITY - CP 0 - JR Z,PS_PRTDC2C - LD DE,PS_FLPDD ; DOUBLE DENSITY - CP 1 - JR Z,PS_PRTDC2C - LD DE,PS_FLPHD ; HIGH DENSITY - CP 2 - JR Z,PS_PRTDC2C - LD DE,PS_FLPED ; EXTENDED DENSITY - CP 3 - JR Z,PS_PRTDC2C -PS_PRTDC2C: - CALL WRITESTR - CALL PC_COMMA - PRTS("CHS$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA -; - RET ; DONE -; -; PRINT ONE LINE SERIAL UNIT/DEVICE INFO, SERIAL UNIT INDEX IN C -; -PS_SERIAL: - PUSH BC ; SAVE UNIT INDEX FOR LATER -; - ; UNIT COLUMN - PRTS("Serial $") - LD A,C ; MOVE UNIT NUM TO A - CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT - PRTS(" $") ; PAD TO NEXT COLUMN -; - ; DEVICE COLUMN - LD B,BF_CIODEVICE ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C - RST 08 ; DE:=DEVTYP/NUM, C:=DEVICE ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES - LD HL,PS_SDSTRREF ; POINT TO SERIAL DEVICE TYPE NAME TABLE - CALL PS_PRTDEV ; PRINT SERIAL DEVICE NMEMONIC PADDED TO FIELD WIDTH - POP BC ; RECOVER ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES AGAIN - CALL PS_PRTST ; PRINT SERIAL TYPE - POP BC ; RESTORE ATTRIBUTES - POP DE ; RESTORE UNIT NUM TO E - CALL PS_PRTSC ; PRINT SERIAL CONFIG -; - CALL NEWLINE - RET -; -; PRINT SERIAL TYPE (SERIAL ATTRIBUTE IN E) -; -PS_PRTST: - LD HL,PS_STRS232 ; ASSUME RS-232 - BIT 7,C ; 0=RS-232, 1=TERMINAL - JR Z,PS_PRTST1 ; HANDLE TERMINAL TYPE - LD HL,PS_STTERM ; TYPE IS TERMINAL -; -PS_PRTST1: - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,18 ; 18 CHAR FIELD - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) -; -PS_PRTSC: - BIT 7,C ; 0=RS-232, 1=TERMINAL - JR NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG -; - ; PRINT RS-232 CONFIG - LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG - LD C,E ; SET SERIAL UNIT NUM - RST 08 ; DE:HL := BAUD RATE - LD A,D ; TEST FOR $FF - AND E - INC A ; SET Z IF DE == $FF - JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED -; -PS_PRTSC0: - ; PRINT BAUD RATE - PUSH DE ; PRESERVE DE - LD A,D - AND $1F ; ISOLATE ENCODED BAUD RATE - LD L,A ; PUT IN L - LD H,0 ; H IS ALWAYS ZERO - LD DE,75 ; BAUD RATE DECODE CONSTANT - CALL DECODE ; DE:HL := BAUD RATE - LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF - CALL BIN2BCD ; CONVERT TO BCD - CALL PRTBCD ; AND PRINT IN DECIMAL - POP DE ; RESTORE DE -; - ; PRINT DATA BITS - PUSH DE ; PRESERVE DE - CALL PC_COMMA ; FORMATTING - LD A,E ; GET CONFIG BYTE - AND $03 ; ISOLATE DATA BITS VALUE - ADD A,'5' ; CONVERT TO CHARACTER - CALL COUT ; AND PRINT - POP DE ; RESTORE DE -; - ; PRINT PARITY - PUSH DE ; PRESERVE DE - CALL PC_COMMA ; FORMATTING - LD A,E ; GET CONFIG BYTE - RRCA ; SHIFT RELEVANT BITS - RRCA ; ... - RRCA ; ... - AND $07 ; AND ISOLATE DATA BITS VALUE - LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE - CALL ADDHLA ; APPLY OFFSET - LD A,(HL) ; GET CHARACTER - CALL COUT ; AND PRINT - POP DE ; RESTORE DE -; - ; PRINT STOP BITS - CALL PC_COMMA ; FORMATTING - LD A,E ; GET CONFIG BYTE - RRCA ; SHIFT RELEVANT BITS - RRCA ; ... - AND $01 ; AND ISOLATE DATA BITS VALUE - ADD A,'1' ; MAKE IT A CHARACTER - CALL COUT ; AND PRINT -; - RET -; -PS_PRTSC1: - ; PRINT TERMINAL CONFIG - LD A,C ; GET ATTRIBUTE VALUE - CP $FF ; NO ATTACHED VDA - JR Z,PS_PRTSC2 - PRTS("Video $") ; FORMATTING - AND $0F ; ISOLATE VIDEO UNIT NUM - CALL PRTDECB ; PRINT IT - CALL PC_COMMA -#IF (VDAEMU == EMUTYP_TTY) - PRTS("TTY$") -#ENDIF -#IF (VDAEMU == EMUTYP_ANSI) - PRTS("ANSI$") -#ENDIF - RET -; -PS_PRTSC2: - PRTS("PropTerm$") ; ASSUME PROPELLER - CALL PC_COMMA - PRTS("ANSI$") - RET -; -; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C -; -PS_VIDEO: - PUSH BC ; SAVE UNIT INDEX FOR LATER -; - ; UNIT COLUMN - PRTS("Video $") - LD A,C ; MOVE UNIT NUM TO A - CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT - PRTS(" $") ; PAD TO NEXT COLUMN -; - ; DEVICE COLUMN - LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C - RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES - PUSH BC ; SAVE ATTRIBUTES - LD HL,PS_VDSTRREF ; POINT TO VIDEO DEVICE TYPE NAME TABLE - CALL PS_PRTDEV ; PRINT VIDEO DEVICE NMEMONIC PADDED TO FIELD WIDTH - POP DE ; RECOVER ATTRIBUTES - PUSH DE ; SAVE ATTRIBUTES AGAIN - CALL PS_PRTVT ; PRINT VIDEO TYPE - POP DE ; RESTORE ATTRIBUTES - POP BC ; RESTORE UNIT NUM - CALL PS_PRTVC ; PRINT VIDEO CONFIG -; - CALL NEWLINE - RET -; -; PRINT VIDEO TYPE (VIDEO ATTRIBUTE IN E) -; -PS_PRTVT: - LD HL,PS_VTCRT ; ASSUME CRT - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,18 ; 18 CHAR FIELD - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT VIDEO CONFIG (UNIT IN C, ATTRIBUTE IN E) -; -PS_PRTVC: - PRTS("Text$") - CALL PC_COMMA - LD B,BF_VDAQRY ; FUNC: QUERY FOR VDA CONFIG - RST 08 ; D:=ROWS, E:=COLS - LD A,E - CALL PRTDECB - LD A,'x' - CALL COUT - LD A,D - CALL PRTDECB - RET -; -; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE -; -PS_PRTDEV: - LD A,D - RRCA ; TYPE IS IN UPPER NIBBLE, MOVE TO LOWER NIBBLE - RRCA - RRCA - RRCA - RLCA ; X2 FOR WORD OFFSET IN STRING TABLE - CALL ADDHLA - LD A,(HL) - INC HL - LD H,(HL) - LD L,A - CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED - LD A,E ; NUM - CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR - CALL PC_COLON ; PRINT COLON - LD A,12 - 2 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON - SUB C - CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) - RET -; -; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE -; -PS_PRTNUL: - LD HL,PS_STRNUL - ; FALL THRU TO PS_PRT -; -; -; -PS_PRT: - ; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C - LD C,0 ; INIT CHAR COUNT -PS_PRT1: - LD A,(HL) ; GET CHAR - INC HL ; BUMP INDEX - CP '$' ; TERM? - RET Z ; IF SO, DONE - CALL COUT ; PRINT IT - INC C ; BUMP COUNTER - JR PS_PRT1 ; AND LOOP -; -; -; -PS_PAD: - ; PAD N SPACES SPECIFIED IN A - LD B,A - LD A,' ' -PS_PAD1: - CALL COUT - DJNZ PS_PAD1 - RET -; -; -; -PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE -; -; DISK DEVICE STRINGS -; -PS_DDSTRREF: - .DW PS_DDMD, PS_DDFD, PS_DDRF, PS_DDIDE, PS_DDATAPI, PS_DDPPIDE - .DW PS_DDSD, PS_DDPRPSD, PS_DDPPPSD, PS_DDHDSK -; -PS_DDMD .TEXT "MD$" -PS_DDFD .TEXT "FD$" -PS_DDRF .TEXT "RF$" -PS_DDIDE .TEXT "IDE$" -PS_DDATAPI .TEXT "ATAPI$" -PS_DDPPIDE .TEXT "PPIDE$" -PS_DDSD .TEXT "SD$" -PS_DDPRPSD .TEXT "PRPSD$" -PS_DDPPPSD .TEXT "PPPSD$" -PS_DDHDSK .TEXT "HDSK$" -; -; DISK TYPE STRINGS -; -PS_DTSTRREF: - .DW PS_DTFLOP, PS_DTHARD, PS_DTCF, PS_DTSD - .DW PS_DTUSB, PS_DTROM, PS_DTRAM, PS_DTRF -; -PS_DTFLOP .TEXT "Floppy Disk$" -PS_DTHARD .TEXT "Hard Disk$" -PS_DTCF .TEXT "CompactFlash$" -PS_DTSD .TEXT "SD Card$" -PS_DTUSB .TEXT "USB Drive$" -PS_DTROM .TEXT "ROM Disk$" -PS_DTRAM .TEXT "RAM Disk$" -PS_DTRF .TEXT "RAM Floppy$" -PS_DTOTHER .TEXT "???$" -; -; FLOPPY ATTRIBUTE STRINGS -; -PS_FLP8 .TEXT "8\",$" -PS_FLP5 .TEXT "5.25\",$" -PS_FLP3 .TEXT "3.5\",$" -PS_FLPN .TEXT "???\",$" -; -PS_FLPSS .TEXT "SS/$" -PS_FLPDS .TEXT "DS/$" -; -PS_FLPSD .TEXT "SD$" -PS_FLPDD .TEXT "DD$" -PS_FLPHD .TEXT "HD$" -PS_FLPED .TEXT "ED$" -; -; SERIAL DEVICE STRINGS -; -PS_SDSTRREF: - .DW PS_SDUART, PS_SDASCI, PS_SDTERM, - .DW PS_SDPRPCON, PS_SDPPPCON, PS_SDSIO, PS_SDACIA -; -PS_SDUART .TEXT "UART$" -PS_SDASCI .TEXT "ASCI$" -PS_SDTERM .TEXT "TERM$" -PS_SDPRPCON .TEXT "PRPCON$" -PS_SDPPPCON .TEXT "PPPCON$" -PS_SDSIO .TEXT "SIO$" -PS_SDACIA .TEXT "ACIA$" -; -; SERIAL TYPE STRINGS -; -PS_STRS232 .TEXT "RS-232$" -PS_STTERM .TEXT "Terminal$" -; -PS_STPARMAP .DB "NONENMNS" - -; -; SERIAL TYPE STRINGS -; -; -; VIDEO DEVICE STRINGS -; -PS_VDSTRREF: - .DW PS_VDVDU, PS_VDCVDU, PS_VDNEC, PS_VDTMS, PS_VDVGA -; -PS_VDVDU .TEXT "VDU$" -PS_VDCVDU .TEXT "CVDU$" -PS_VDNEC .TEXT "NEC$" -PS_VDTMS .TEXT "TMS$" -PS_VDVGA .TEXT "VGA$" -; -; VIDEO TYPE STRINGS -; -PS_VTCRT .TEXT "CRT$" -; -; VIDEO CONFIG STRINGS -; -; -; -; 0 1 2 3 4 5 6 7 -; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 -PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" - .TEXT "---------- ---------- ---------------- --------------------\r\n$" -; -;================================================================================================== -; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) -;================================================================================================== -; -; OUTPUT CHARACTER FROM A -; -COUT: - ; SAVE ALL INCOMING REGISTERS - PUSH AF - PUSH BC - PUSH DE - PUSH HL -; - ; GET CURRENT CONSOLE UNIT - LD E,A ; TEMPORARILY STASH OUTPUT CHAR IN E - LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE - CP $FF ; TEST FOR $FF (HBIOS NOT READY) - JR Z,COUT1 ; IF NOT READY, USE XIO -; - ; USE HBIOS - LD C,A ; CONSOLE UNIT TO C - LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR - CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY - JR COUT2 ; CONTINUE -; -COUT1: - ;; USE XIO - ;LD A,E ; GET OUTPUT CHAR BACK TO ACCUM - ;CALL XIO_OUTC ; OUTPUT VIA XIO -; -COUT2: - ; RESTORE ALL REGISTERS - POP HL - POP DE - POP BC - POP AF - RET -; -; INPUT CHARACTER TO A -; -CIN: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE - CP $FF ; TEST FOR $FF (HBIOS NOT READY) - JR Z,CIN1 ; IF NOT READY, USE XIO -; - ; USE HBIOS - LD C,A ; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY - LD A,E ; RESULTANT CHAR TO A - JR CIN2 ; CONTINUE -; -CIN1: - ;; USE XIO - ;CALL XIO_INC ; GET CHAR -; -CIN2: -; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) -; -CST: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - LD A,(CB_CONDEV) ; GET CONSOLE UNIT BYTE - CP $FF ; TEST FOR $FF (HBIOS NOT READY) - JR Z,CST1 ; IF NOT READY, USE XIO -; - ; USE HBIOS - LD C,A ; CONSOLE UNIT TO C - LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS - CALL CIO_DISPATCH ; CALL CIO DISPATCHER DIRECTLY - JR CST2 ; CONTINUE -; -CST1: - ;; USE XIO - ;CALL XIO_IST ; GET STATUS -; -CST2: - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -;================================================================================================== -; MISCELLANEOUS UTILITY FUNCTIONS -;================================================================================================== -; -; SET HL TO IY+A, A IS TRASHED -; -LDHLIYA: - PUSH IY ; COPY INSTANCE DATA PTR - POP HL ; ... TO HL - ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN - ADD A,L ; ADD OFFSET TO LSB - LD L,A ; ... PUT BACK IN L - RET NC ; DONE IF CF NOT SET - INC H ; IF CF SET, BUMP MSB - RET ; ... AND RETURN -; -; CONVERT AN HBIOS STANDARD HARD DISK CHS ADDRESS TO -; AN LBA ADDRESS. A STANDARD HBIOS HARD DISK IS ASSUMED -; TO HAVE 16 SECTORS PER TRACK AND 16 HEADS PER CYLINDER. -; -; INPUT: HL=TRACK, D=HEAD, E=SECTOR -; OUTPUT: DE:HL=32 BIT LBA ADDRESS (D:7 IS NOT SET IN THE RESULT) -; -HB_CHS2LBA: -; - LD A,D ; HEAD TO A - RLCA ; LEFT SHIFT TO HIGH NIBBLE - RLCA ; ... DEPENDS ON HIGH - RLCA ; ... NIBBLE BEING 0 SINCE - RLCA ; ... IT ROTATES INTO LOW NIBBLE - OR E ; COMBINE WITH SECTOR (HIGH NIBBLE MUST BE ZERO) - LD D,0 - LD E,H - LD H,L - LD L,A - XOR A - RET -; -;================================================================================================== -; HBIOS GLOBAL DATA -;================================================================================================== -; -IDLECOUNT .DB 0 -; -HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION -; -HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER -; -STR_BANNER .DB "RetroBrew HBIOS v", BIOSVER, ", ", TIMESTAMP, "$" -STR_PLATFORM .DB PLATFORM_NAME, "$" -STR_SWITCH .DB "*** Activating CRT Console ***$" -STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" -; -HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) -; -HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) -; -HB_WRKBUF .FILL 512,0 ; INTERNAL DISK BUFFER -; -HB_END .EQU $ -; -SLACK .EQU BNKTOP - $ - .ECHO "HBIOS space remaining: " - .ECHO SLACK - .ECHO " bytes.\n" -; -#IFDEF ROMBOOT - .FILL SLACK -#ENDIF -; - .END From 127d5bc676101d58ddf962e285b40e5603627adc Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Tue, 30 Oct 2018 05:59:27 +0800 Subject: [PATCH 16/18] Delete romldr.asm --- romldr.asm | 1088 ---------------------------------------------------- 1 file changed, 1088 deletions(-) delete mode 100644 romldr.asm diff --git a/romldr.asm b/romldr.asm deleted file mode 100644 index fcbf8748..00000000 --- a/romldr.asm +++ /dev/null @@ -1,1088 +0,0 @@ -; -;================================================================================================== -; LOADER -;================================================================================================== -; -; INCLUDE GENERIC STUFF -; -#INCLUDE "std.asm" -; -; osimg.bin -; -;LDRIMG .EQU $0000 ;SIZE 0A00 > 0000-0A00 -MONIMG .EQU $0A00 ;SIZE 1000 > 0A00-1A00 -CPMIMG .EQU $1A00 ;SIZE 3000 > 1A00-4A00 -ZSYSIMG .EQU $4A00 ;SIZE 3000 > 4A00-7A00 -; -; osimg1.bin -; -BASIMG .EQU $0000 ;SIZE 2000 > 0000-2000 -TBCIMG .EQU $2000 ;SIZE 0900 > 2000-2900 -; -INT_IM1 .EQU $FF00 -; -;---------------------------------------------------------- -; NAME NAME OF ROM 8 CHAR -; BANK WHICH ROM BANK THE IMAGE IS IN. -; IMAGE LOCATION OF IMAGE IN 32K ROM BANK. -; LOCATION WHERE IMAGE NEEDS TO BE COPIED TO IN RAM. -; EXECUTE ADDRESS TO START EXECUTING. -; - -;ROMTBL .DB "B","BASIC $", 0, BASIMG, BAS_LOC, BAS_SIZ, BASE_LOC -; .DB "C","CP/M $", 0, -; .DB "F","FORTH $", 1, -; .DB "Z","ZSYSTEM$", 1, -; -; -; .DB "MONITOR$", 0, -; - - .ORG 0 -; -;================================================================================================== -; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE -;================================================================================================== -; - JP $100 ; RST 0: JUMP TO BOOT CODE - .FILL (008H - $),0FFH -#IF (PLATFORM == PLT_UNA) - JP $FFFD ; RST 8: INVOKE UBIOS FUNCTION -#ELSE - JP HB_INVOKE ; RST 8: INVOKE HBIOS FUNCTION -#ENDIF - .FILL (010H - $),0FFH - RET ; RST 10 - .FILL (018H - $),0FFH - RET ; RST 18 - .FILL (020H - $),0FFH - RET ; RST 20 - .FILL (028H - $),0FFH - RET ; RST 28 - .FILL (030H - $),0FFH - RET ; RST 30 - .FILL (038H - $),0FFH -#IF (PLATFORM == PLT_UNA) - RETI ; RETURN W/ INTS DISABLED -#ELSE - #IF (INTMODE == 1) - JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM - #ELSE - RETI ; RETURN W/ INTS DISABLED - #ENDIF -#ENDIF - .FILL (066H - $),0FFH - RETN ; NMI -; - .FILL (100H - $),0FFH ; PAD REMAINDER OF PAGE ZERO -; -; -;================================================================================================== -; LOADER -;================================================================================================== -; - DI ; NO INTERRUPTS - LD SP,BL_STACK ; SETUP STACK -; - ; BANNER - LD DE,STR_BANNER - CALL WRITESTR - -; -#IF (PLATFORM != PLT_UNA) - CALL DELAY_INIT ; INIT DELAY FUNCTIONS -#ENDIF -; -#IF (PLATFORM == PLT_UNA) -; ; COPY UNA BIOS PAGE ZERO TO USER BANK, LEAVE USER BANK ACTIVE -; LD BC,$01FB ; UNA FUNC = SET BANK -; LD DE,BID_BIOS ; UBIOS_PAGE (SEE PAGES.INC) -; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) -; PUSH DE ; SAVE PREVIOUS BANK -;; -; LD HL,0 ; FROM ADDRESS 0 (PAGE ZERO) -; LD DE,$9000 ; USE $9000 AS BOUNCE BUFFER -; LD BC,256 ; ONE PAGE IS 256 BYTES -; LDIR ; DO IT -;; -; LD BC,$01FB ; UNA FUNC = SET BANK -; ;POP DE ; RECOVER OPERATING BANK -; LD DE,BID_USR ; TO USER BANK -; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) -;; -; LD HL,$9000 ; USE $9000 AS BOUNCE BUFFER -; LD DE,0 ; TO PAGE ZERO OF OPERATING BANK -; LD BC,256 ; ONE PAGE IS 256 BYTES -; LDIR ; DO IT -;; -;; ; INSTALL UNA INVOCATION VECTOR FOR RST 08 -;; ; *** IS THIS REDUNDANT? *** -;; LD A,$C3 ; JP INSTRUCTION -;; LD (8),A ; STORE AT 0x0008 -;; LD HL,($FFFE) ; UNA ENTRY VECTOR -;; LD (9),HL ; STORE AT 0x0009 -;; -; LD BC,$01FB ; UNA FUNC = SET BANK -; POP DE ; RECOVER OPERATING BANK -; CALL $FFFD ; DO IT (RST 08 NOT YET INSTALLED) -#ELSE - ; PREP THE USER BANK (SETUP PAGE ZERO) - LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY - LD D,BID_USR ; D = DEST BANK = USER BANK - LD E,BID_BIOS ; E = SRC BANK = BIOS BANK - LD HL,256 ; HL = COPY LEN = 1 PAGE = 256 BYTES - RST 08 ; DO IT - LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY - LD HL,0 ; COPY FROM BIOS ADDRESS 0 - LD DE,0 ; TO USER ADDRESS 0 - RST 08 ; DO IT -#ENDIF - EI -; - ; RUN THE BOOT LOADER MENU - JP DOBOOTMENU -; -;__DOBOOT________________________________________________________________________________________________________________________ -; -; PERFORM BOOT FRONT PANEL ACTION -;________________________________________________________________________________________________________________________________ -; -DOBOOTMENU: -; CALL NEWLINE - LD DE,STR_BOOTMENU - CALL WRITESTR - CALL PRTALL - CALL PC_COLON - -#IF (DSKYENABLE) - LD HL,BOOT ; POINT TO BOOT MESSAGE - CALL SEGDISPLAY ; DISPLAY MESSAGE -#ENDIF - -#IF (BOOTTYPE == BT_AUTO) - LD BC,100 * BOOT_TIMEOUT - LD (BL_TIMEOUT),BC -#ENDIF - -DB_BOOTLOOP: -; -; CHECK FOR CONSOLE BOOT KEYPRESS -; - CALL CST - OR A - JP Z,DB_CONEND - CALL CINUC - CP 'B' ; NASCOM BASIC - JP Z,GOBASIC - CP 'C' ; CP/M BOOT FROM ROM - JP Z,GOCPM - CP 'M' ; MONITOR - JP Z,GOMONSER -; CP 'L' ; LIST DRIVES -; JP Z,GOLIST - CP 'T' ; TASTY BASIC - JP Z,GOTBAS - CP 'Z' ; ZSYSTEM BOOT FROM ROM - JP Z,GOZSYS - CP '0' ; 0-9, DISK DEVICE - JP C,DB_INVALID - CP '9' + 1 - JP NC,DB_INVALID - SUB '0' - JP GOBOOTDISK -DB_CONEND: -; -; CHECK FOR DSKY BOOT KEYPRESS -; -#IF (DSKYENABLE) - CALL KY_STAT ; GET KEY FROM KB INTO A - OR A - JP Z,DB_DSKYEND - CALL KY_GET - CP KY_GO ; GO = MONITOR - JP Z,GOMONDSKY - CP KY_BO ; BO = BOOT ROM - JP Z,GOCPM -; CP 0AH ; A-F, DISK BOOT -; JP C,DB_INVALID - CP 0FH + 1 ; 0-F, DISK BOOT -; JP NC,DB_INVALID -; SUB 0AH - JP GOBOOTDISK -; LD HL,BOOT ; POINT TO BOOT MESSAGE -; LD A,00H ; BLANK OUT SELECTION,IT WAS INVALID -; LD (HL),A ; STORE IT IN DISPLAY BUFFER -; CALL SEGDISPLAY ; DISPLAY THE BUFFER -DB_DSKYEND: -#ENDIF -; -; IF CONFIGURED, CHECK FOR AUTOBOOT TIMEOUT -; -#IF (BOOTTYPE == BT_AUTO) - - ; DELAY FOR 10MS TO MAKE TIMEOUT CALC EASY - LD DE,625 ; 16US * 625 = 10MS - CALL VDELAY - - ; CHECK/INCREMENT TIMEOUT - LD BC,(BL_TIMEOUT) - DEC BC - LD (BL_TIMEOUT),BC - LD A,B - OR C - JP NZ,DB_BOOTLOOP - - ; TIMEOUT EXPIRED, PERFORM DEFAULT BOOT ACTION - LD A,BOOT_DEFAULT - CP 'B' ; NASCOM BASIC - JP Z,GOBASIC - CP 'C' ; CP/M BOOT FROM ROM - JP Z,GOCPM - CP 'M' ; MONITOR - JP Z,GOMONSER -; CP 'L' ; LIST DRIVES -; JP Z,GOLIST - CP 'T' ; TASTY BASIC - JP Z,GOTBAS - CP 'Z' ; ZSYSTEM BOOT FROM ROM - JP Z,GOZSYS - CP '0' ; 0-9, DISK DEVICE - JP C,DB_INVALID - CP '9' + 1 - JP NC,DB_INVALID - SUB '0' - JP GOBOOTDISK -#ENDIF - - JP DB_BOOTLOOP -; -; BOOT OPTION PROCESSING -; -DB_INVALID: - LD DE,STR_INVALID - CALL WRITESTR - JP DOBOOTMENU -; -GOBASIC: - LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE - CALL WRITESTR ; WRITE IT TO CONSOLE - ; COPY BASIC FROM BASIC FROM OSIMG0 IN ROM BANK TO THIS RAM BANKS - LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY - LD D,BID_USR ; D = DEST BANK = USER BANK - LD E,BID_OSIMG ; E = SRC BANK = BIOS BANK - LD HL,BAS_SIZ ; HL = COPY LEN = 1 PAGE = 256 BYTES - RST 08 ; DO IT - LD DE,STR_LOADING - CALL WRITESTR ; WRITE IT TO CONSOLE - LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY - LD HL,BASIMG ; COPY FROM - LD DE,BAS_LOC ; COPY TO - RST 08 ; DO IT - LD DE,STR_LAUNCH - CALL WRITESTR - LD HL,BAS_LOC - JP CHAIN - -; LD HL,BAS_LOC -; PUSH HL -; LD DE,STR_BOOTBAS ; DE POINTS TO MESSAGE -; CALL WRITESTR ; WRITE IT TO CONSOLE -; ; COPY IMAGE TO EXEC ADDRESS -; LD HL,BASIMG ; HL := BASIC IMAGE ADDRESS -; LD DE,BAS_LOC ; DE := BASIC EXEC ADDRESS -; LD BC,BAS_SIZ ; BC := BASIC SIZE -; LDIR ; COPY BASIC CODE TO EXEC ADDRESS -; POP HL ; RECOVER ENTRY ADDRESS -; JR CHAIN ; AND CHAIN TO IT - -GOTBAS: - LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE - CALL WRITESTR ; WRITE IT TO CONSOLE - ; COPY BASIC FROM BASIC FROM OSIMG0 IN ROM BANK TO THIS RAM BANKS - LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY - LD D,BID_USR ; D = DEST BANK = USER BANK - LD E,BID_OSIMG ; E = SRC BANK = BIOS BANK - LD HL,TBC_SIZ ; HL = COPY LEN = 1 PAGE = 256 BYTES - RST 08 ; DO IT - LD DE,STR_LOADING - CALL WRITESTR ; WRITE IT TO CONSOLE - LD B,BF_SYSBNKCPY ; HBIOS FUNC: PERFORM BANK COPY - LD HL,TBCIMG ; COPY FROM - LD DE,TBC_LOC ; COPY TO - RST 08 ; DO IT - LD DE,STR_LAUNCH - CALL WRITESTR - LD HL,TBC_LOC - JP CHAIN - -; LD HL,TBC_LOC -; PUSH HL -; LD DE,STR_BOOTTBC ; DE POINTS TO MESSAGE -; CALL WRITESTR ; WRITE IT TO CONSOLE -; ; COPY IMAGE TO EXEC ADDRESS -; LD HL,TBCIMG ; HL := BASIC IMAGE ADDRESS -; LD DE,TBC_LOC ; DE := BASIC EXEC ADDRESS -; LD BC,TBC_SIZ ; BC := BASIC SIZE -; LDIR ; COPY BASIC CODE TO EXEC ADDRESS -; POP HL ; RECOVER ENTRY ADDRESS -; JR CHAIN ; AND CHAIN TO IT - -GOMONSER: - LD HL,MON_SERIAL ; MONITOR SERIAL INTERFACE ENTRY ADDRESS TO HL - JR GOMON ; LOAD AND RUN MONITOR -; -GOMONDSKY: - LD HL,MON_DSKY ; MONITOR DSKY INTERFACE ENTRY ADDRESS TO HL - JR GOMON ; LOAD AND RUN MONITOR -; -GOMON: - LD DE,STR_BOOTMON ; DE POINTS TO MESSAGE - CALL WRITESTR ; WRITE IT TO CONSOLE -; - PUSH HL ; SAVE DESIRED MONITOR ENTRY ADDRESS -; - ; COPY MONITOR IMAGE TO EXEC ADDRESS - LD HL,MONIMG ; HL := MONITOR IMAGE ADDRESS - LD DE,MON_LOC ; DE := MONITOR EXEC ADDRESS - LD BC,MON_SIZ ; BC := MONITOR SIZE - LDIR ; COPY MONITOR CODE TO EXEC ADDRESS -; - POP HL ; RECOVER ENTRY ADDRESS - JR CHAIN ; AND CHAIN TO IT -; -GOCPM: - LD DE,STR_BOOTCPM ; DE POINTS TO MESSAGE - CALL WRITESTR ; WRITE IT TO CONSOLE - LD HL,CPMIMG ; SET HL TO CPM IMAGE ADDRESS - JR GOOS ; LOAD AND RUN OS -; -GOZSYS: - LD DE,STR_BOOTZSYS ; DE POINTS TO MESSAGE - CALL WRITESTR ; WRITE IT TO CONSOLE - LD HL,ZSYSIMG ; SET HL TO ZSYS IMAGE ADDRESS - JR GOOS ; LOAD AND RUN OS -; -GOOS: - ; COPY OS IMAGE TO EXEC ADDRESS - LD DE,CPM_LOC ; DE := MONITOR EXEC ADDRESS - LD BC,CPM_SIZ ; BC := MONITOR SIZE - LDIR ; COPY MONITOR CODE TO EXEC ADDRESS -; - LD HL,CPM_ENT - ;JR CHAIN ; CHAIN TO ENTRY ADDRESS IN USER BANK -; -CHAIN: - PUSH HL ; SAVE ENTRY ADDRESS -; -#IF (PLATFORM == PLT_UNA) - LD BC,$00FB ; GET LOWER PAGE ID - RST 08 ; DE := LOWER PAGE ID == BOOT ROM PAGE - LD L,1 ; BOOT DISK UNIT IS ROM (UNIT ID = 1) - LD BC,$01FC ; UNA FUNC: SET BOOTSTRAP HISTORY - RST 08 ; CALL UNA -; - ; HL IS ALREADY ON STACK AS REQUIRED BY UNA EXEC CHAIN CALL - LD DE,BID_USR ; TARGET BANK ID - PUSH DE ; ... ON STACK - DI ; ENTER WITH INTS DISABLED - JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN -#ELSE - LD B,BF_SYSSET ; HB FUNC: SET HBIOS PARAMETER - LD C,BF_SYSSET_BOOTINFO ; HB SUBFUNC: SET BOOT INFO - LD A,(HB_CURBNK) ; GET CURRENT BANK ID FROM PROXY DATA - LD L,A ; ... AND SAVE AS BOOT BANK - LD DE,$0100 ; BOOT VOLUME (UNIT, SLICE) - RST 08 -; - LD A,BID_USR ; ACTIVATE USER BANK - POP HL ; RECOVER ENTRY ADDRESS - DI ; ENTER WITH INTS DISABLED - CALL HB_BNKCALL ; AND GO - HALT ; WE SHOULD NEVER RETURN!!! -#ENDIF - -; -GOLIST: - LD DE,STR_LIST - CALL WRITESTR - LD DE,STR_DRVLIST - CALL WRITESTR - CALL PRTALL - JP DOBOOTMENU -; -GOBOOTDISK: - LD (BL_BOOTID),A - LD DE,STR_BOOTDISK - CALL WRITESTR - JP BOOTDISK -; -; BOOT FROM DISK DRIVE -; -BOOTDISK: - LD DE,STR_BOOTDISK1 ; DISK BOOT MESSAGE - CALL WRITESTR ; PRINT IT - -#IF (PLATFORM == PLT_UNA) -; -; BOOT FROM UNA DISK DRIVE -; - LD A,(BL_BOOTID) ; GET BOOT DEVICE ID - LD B,A ; MOVE TO B - - ; LOAD SECTOR 2 (BOOT INFO) - LD C,$41 ; UNA FUNC: SET LBA - LD DE,0 ; HI WORD OF LBA IS ALWAYS ZERO - LD HL,2 ; LOAD STARTING INFO SECTOR 2 - RST 08 ; SET LBA - JP NZ,DB_ERR ; HANDLE ERROR -; - LD C,$42 ; UNA FUNC: READ SECTORS - LD DE,BL_INFOSEC ; DEST OF CPM IMAGE - LD L,1 ; SECTORS TO READ - RST 08 ; DO READ - JP NZ,DB_ERR ; HANDLE ERROR -; -#ELSE - ; CHECK FOR VALID DRIVE LETTER - LD A,(BL_BOOTID) ; BOOT DEVICE TO A - PUSH AF ; SAVE BOOT DEVICE - LD B,BF_SYSGET - LD C,BF_SYSGET_DIOCNT - RST 08 ; E := DISK UNIT COUNT - POP AF ; RESTORE BOOT DEVICE - CP E ; CHECK MAX (INDEX - COUNT) - JP NC,DB_NODISK ; HANDLE INVALID SELECTION - - ; SET THE BOOT UNIT AND SLICE - LD A,(BL_BOOTID) ; GET BOOTID - LD (BL_DEVICE),A ; STORE IT - XOR A ; LU ALWAYS ZERO - LD (BL_LU),A ; STORE IT - - ; SENSE MEDIA - LD A,(BL_DEVICE) ; GET DEVICE/UNIT - LD C,A ; STORE IN C - LD B,BF_DIOMEDIA ; DRIVER FUNCTION = DISK MEDIA - LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY - RST 08 ; CALL HBIOS - JP NZ,DB_ERR ; HANDLE ERROR - - ; SEEK TO SECTOR 2 OF LU - LD A,(BL_LU) ; GET LU SPECIFIED - LD E,A ; LU INDEX - LD H,65 ; 65 TRACKS PER LU - CALL MULT8 ; HL := H * E - LD DE,$02 ; HEAD 0, SECTOR 2 - LD B,BF_DIOSEEK ; SETUP FOR NEW SEEK CALL - LD A,(BL_DEVICE) ; GET BOOT DISK UNIT - LD C,A ; PUT IN C - RST 08 ; DO IT - JP NZ,DB_ERR ; HANDLE ERROR - - ; READ - LD B,BF_DIOREAD ; FUNCTION IN B - LD A,(BL_DEVICE) ; GET BOOT DISK UNIT - LD C,A ; PUT IN C - LD HL,BL_INFOSEC ; READ INTO INFO SEC BUFFER - LD DE,1 ; TRANSFER ONE SECTOR - RST 08 ; DO IT - JP NZ,DB_ERR ; HANDLE ERROR -; -#ENDIF -; - ; CHECK SIGNATURE - CALL NEWLINE ; FORMATTING - LD DE,(BB_SIG) ; GET THE SIGNATURE - LD A,$A5 ; FIRST BYTE SHOULD BE $A5 - CP D ; COMPARE - JP NZ,DB_NOBOOT ; ERROR IF NOT EQUAL - LD A,$5A ; SECOND BYTE SHOULD BE $5A - CP E ; COMPARE - JP NZ,DB_NOBOOT ; ERROR IS NOT EQUAL - - ; PRINT CPMLOC VALUE - CALL NEWLINE - LD DE,STR_CPMLOC - CALL WRITESTR - LD BC,(BB_CPMLOC) - CALL PRTHEXWORD - - ; PRINT CPMEND VALUE - CALL PC_SPACE - LD DE,STR_CPMEND - CALL WRITESTR - LD BC,(BB_CPMEND) - CALL PRTHEXWORD - - ; PRINT CPMENT VALUE - CALL PC_SPACE - LD DE,STR_CPMENT - CALL WRITESTR - LD BC,(BB_CPMENT) - CALL PRTHEXWORD - CALL PC_SPACE - - ; PRINT DISK LABEL - LD DE,STR_LABEL - CALL WRITESTR - LD DE,BB_LABEL ; if it is there, then a printable - LD A,(BB_TERM) ; Display Disk Label if Present - CP '$' ; (dwg 2/7/2012) - CALL Z,WRITESTR ; label is there as well even if spaces. -; - LD DE,STR_LOADING ; LOADING MESSAGE - CALL WRITESTR ; PRINT IT -; - ; COMPUTE NUMBER OF SECTORS TO LOAD - LD HL,(BB_CPMEND) ; HL := END - LD DE,(BB_CPMLOC) ; DE := START - OR A ; CLEAR CARRY - SBC HL,DE ; HL := LENGTH TO LOAD - LD A,H ; DETERMINE 512 BYTE SECTOR COUNT - RRCA ; ... BY DIVIDING MSB BY TWO - LD (BL_COUNT),A ; ... AND SAVE IT -; -#IF (PLATFORM == PLT_UNA) -; - ; READ OS IMAGE INTO MEMORY - LD C,$42 ; UNA FUNC: READ SECTORS - LD A,(BL_BOOTID) ; GET BOOT DEVICE ID - LD B,A ; MOVE TO B - LD DE,(BB_CPMLOC) ; DEST OF CPM IMAGE - LD A,(BL_COUNT) ; GET SECTORS TO READ - LD L,A ; SECTORS TO READ - RST 08 ; DO READ - JP NZ,DB_ERR ; HANDLE ERROR -; - ; PASS BOOT DEVICE/UNIT/LU TO CBIOS COLD BOOT - LD DE,-1 ; BOOT ROM PAGE, -1 FOR N/A - LD A,(BL_BOOTID) ; GET BOOT DISK UNIT ID - LD L,A ; PUT IN L - LD BC,$01FC ; UNA FUNC: SET BOOTSTRAP HISTORY - RST 08 ; CALL UNA - JP NZ,DB_ERR ; HANDLE ERROR -; - ; JUMP TO COLD BOOT ENTRY - LD HL,(BB_CPMENT) ; GET THE ENTRY POINT - PUSH HL ; PUT ON STACK FOR UNA CHAIN FUNC - LD DE,BID_USR ; TARGET BANK ID IS USER BANK - PUSH DE ; PUT ON STACK FOR UNA CHAIN FUNC - DI ; ENTER WITH INTS DISABLED - JP $FFF7 ; UNA INTER-PAGE EXEC CHAIN -; -#ELSE -; - ; READ OS IMAGE INTO MEMORY - LD B,BF_DIOREAD ; FUNCTION IN B - LD A,(BL_DEVICE) ; GET BOOT DISK UNIT - LD C,A ; PUT IN C - LD HL,(BB_CPMLOC) ; LOAD ADDRESS - LD D,0 - LD A,(BL_COUNT) ; GET SECTORS TO READ - LD E,A ; NUMBER OF SECTORS TO LOAD - RST 08 - JP NZ,DB_ERR ; HANDLE ERRORS - - ; PASS BOOT DEVICE/UNIT/LU TO CBIOS COLD BOOT - LD B,BF_SYSSET ; HB FUNC: SET HBIOS PARAMETER - LD C,BF_SYSSET_BOOTINFO ; HB SUBFUNC: SET BOOT INFO - LD A,(HB_CURBNK) ; GET CURRENT BANK ID FROM PROXY DATA - LD L,A ; ... AND SAVE AS BOOT BANK - LD A,(BL_DEVICE) ; LOAD BOOT DEVICE/UNIT - LD D,A ; SAVE IN D - LD A,(BL_LU) ; LOAD BOOT LU - LD E,A ; SAVE IN E - RST 08 - JP NZ,DB_ERR ; HANDLE ERRORS - - ; JUMP TO COLD BOOT ENTRY - LD A,BID_USR ; ACTIVATE USER BANK - LD HL,(BB_CPMENT) ; OS ENTRY ADDRESS - DI ; ENTER WITH INTS DISABLED - CALL HB_BNKCALL ; AND GO - HALT ; WE SHOULD NEVER RETURN!!! -; -#ENDIF -; -DB_NODISK: - ; SELDSK DID NOT LIKE DRIVE SELECTION - LD DE,STR_NODISK - CALL WRITESTR - JP DOBOOTMENU - -DB_NOBOOT: - ; DISK IS NOT BOOTABLE - LD DE,STR_NOBOOT - CALL WRITESTR - JP DOBOOTMENU - -DB_ERR: - ; I/O ERROR DURING BOOT ATTEMPT - LD DE,STR_BOOTERR - CALL WRITESTR - JP DOBOOTMENU -; -#IF (DSKYENABLE) -; -; -;__SEGDISPLAY________________________________________________________________________________________ -; -; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP -;____________________________________________________________________________________________________ -; -SEGDISPLAY: - PUSH AF ; STORE AF - PUSH BC ; STORE BC - PUSH HL ; STORE HL - LD BC,0007H - ADD HL,BC - LD B,08H ; SET DIGIT COUNT - LD A,40H | 30H ; SET CONTROL PORT 7218 TO OFF - OUT (PPIC),A ; OUTPUT - CALL DLY2 ; WAIT - LD A,0F0H ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) - -SEGDISPLAY1: ; - OUT (PPIA),A ; OUTPUT TO PORT - LD A,80H | 30H ; STROBE WRITE PULSE WITH CONTROL=1 - OUT (PPIC),A ; OUTPUT TO PORT - CALL DLY2 ; WAIT - LD A,40H | 30H ; SET CONTROL PORT 7218 TO OFF - OUT (PPIC),A ; OUTPUT - -SEGDISPLAY_LP: - LD A,(HL) ; GET DISPLAY DIGIT - OUT (PPIA),A ; OUT TO PPIA - LD A,00H | 30H ; SET WRITE STROBE - OUT (PPIC),A ; OUT TO PPIC - CALL DLY2 ; DELAY - LD A,40H | 30H ; SET CONTROL PORT OFF - OUT (PPIC),A ; OUT TO PPIC - CALL DLY2 ; WAIT - DEC HL ; INC POINTER - DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT - POP HL ; RESTORE HL - POP BC ; RESTORE BC - POP AF ; RESTORE AF - RET -#ENDIF - -#IF (PLATFORM == PLT_UNA) -; -; -; PRINT LIST OF ALL DRIVES UNDER UNA -; -PRTALL: - LD B,0 ; START WITH UNIT 0 -; -PRTALL1: ; LOOP THRU ALL UNITS AVAILABLE - LD C,$48 ; UNA FUNC: GET DISK TYPE - LD L,0 ; PRESET UNIT COUNT TO ZERO - RST 08 ; CALL UNA, B IS ASSUMED TO BE UNTOUCHED!!! - LD A,L ; UNIT COUNT TO A - OR A ; PAST END? - RET Z ; WE ARE DONE - PUSH BC ; SAVE UNIT - CALL PRTDRV ; PROCESS THE UNIT - POP BC ; RESTORE UNIT - INC B ; NEXT UNIT - JR PRTALL1 ; LOOP -; -; PRINT THE UNA UNIT INFO -; ON INPUT B HAS UNIT -; -PRTDRV: - PUSH BC ; SAVE UNIT - PUSH DE ; SAVE DISK TYPE - LD DE,STR_PREFIX ; NEWLINE AND SPACING - CALL WRITESTR ; PRINT IT - LD A,B ; DRIVE LETTER TO A - ADD A,'0' ; MAKE IT DISPLAY NUMERIC - CALL COUT ; PRINT IT - LD A,')' ; DRIVE LETTER COLON - CALL COUT ; PRINT IT -; CALL PC_SPACE - POP DE ; RECOVER DISK TYPE - LD A,D ; DISK TYPE TO A - CP $40 ; RAM/ROM? - JR Z,PRTDRV1 ; HANDLE RAM/ROM - LD DE,DEVIDE ; ASSUME IDE - CP $41 ; IDE? - JR Z,PRTDRV2 ; PRINT IT - LD DE,DEVPPIDE ; ASSUME PPIDE - CP $42 ; PPIDE? - JR Z,PRTDRV2 ; PRINT IT - LD DE,DEVSD ; ASSUME SD - CP $43 ; SD? - JR Z,PRTDRV2 ; PRINT IT - LD DE,DEVDSD ; ASSUME DSD - CP $44 ; DSD? - JR Z,PRTDRV2 ; PRINT IT - LD DE,DEVUNK ; OTHERWISE UNKNOWN - JR PRTDRV2 -; -PRTDRV1: ; HANDLE RAM/ROM - LD C,$45 ; UNA FUNC: GET DISK INFO - LD DE,BL_INFOSEC ; 512 BYTE BUFFER - RST 08 ; CALL UNA - BIT 7,B ; TEST RAM DRIVE BIT - LD DE,DEVROM ; ASSUME ROM - JR Z,PRTDRV2 ; IF SO, PRINT IT - LD DE,DEVRAM ; OTHERWISE RAM - JR PRTDRV2 ; PRINT IT -; -PRTDRV2: ; PRINT DEVICE - POP BC ; RECOVER UNIT - CALL WRITESTR ; PRINT DEVICE NAME - LD A,B ; UNIT TO A - ADD A,'0' ; MAKE IT PRINTABLE NUMERIC - CALL COUT ; PRINT IT - LD A,',' ; DEVICE NAME SEPARATOR - CALL COUT ; PRINT IT - RET ; DONE -; -DEVRAM .DB "RAM$" -DEVROM .DB "ROM$" -DEVIDE .DB "IDE$" -DEVPPIDE .DB "PPIDE$" -DEVSD .DB "SD$" -DEVDSD .DB "DSD$" -DEVUNK .DB "UNK$" -; -#ELSE -; -; PRINT LIST OF ALL DRIVES -; -PRTALL: -; - LD B,BF_SYSGET - LD C,BF_SYSGET_DIOCNT - RST 08 ; E := DISK UNIT COUNT - LD B,E ; COUNT TO B - LD A,B ; COUNT TO A - OR A ; SET FLAGS - RET Z ; BAIL OUT IF ZERO - LD C,0 ; INIT DEVICE INDEX -; -PRTALL1: - LD DE,STR_PREFIX ; FORMATTING - CALL WRITESTR ; PRINT IT - LD A,C ; INDEX TO A - ADD A,'0' ; MAKE NUMERIC CHAR - CALL COUT ; PRINT IT - LD A,')' ; FORMATTING - CALL COUT ; PRINT IT -; CALL PC_SPACE ; SPACING - PUSH BC ; SAVE LOOP CONTROL - LD B,BF_DIODEVICE ; HBIOS FUNC: REPORT DEVICE INFO - RST 08 ; CALL HBIOS - CALL PRTDRV ; PRINT IT - POP BC ; RESTORE LOOP CONTROL - INC C ; BUMP INDEX - DJNZ PRTALL1 ; LOOP AS NEEDED - RET ; DONE -; -; PRINT THE DRIVER DEVICE/UNIT INFO -; ON INPUT D HAS DRIVER ID, E HAS DRIVER MODE/UNIT -; DESTROY NO REGISTERS OTHER THAN A -; -PRTDRV: - PUSH DE ; PRESERVE DE - PUSH HL ; PRESERVE HL - LD A,D ; LOAD DEVICE/UNIT - RRCA ; ROTATE DEVICE - RRCA ; ... BITS - RRCA ; ... INTO - RRCA ; ... LOWEST 4 BITS - AND $0F ; ISOLATE DEVICE BITS - ADD A,A ; MULTIPLE BY TWO FOR WORD TABLE - LD HL,DEVTBL ; POINT TO START OF DEVICE NAME TABLE - CALL ADDHLA ; ADD A TO HL TO POINT TO TABLE ENTRY - LD A,(HL) ; DEREFERENCE HL TO LOC OF DEVICE NAME STRING - INC HL ; ... - LD D,(HL) ; ... - LD E,A ; ... - CALL WRITESTR ; PRINT THE DEVICE NMEMONIC - POP HL ; RECOVER HL - POP DE ; RECOVER DE - LD A,E ; LOAD DRIVER MODE/UNIT - AND $0F ; ISOLATE UNIT - CALL PRTDECB ; PRINT IT - CALL PC_SPACE ; FORMATTING - ;LD A,E ; LOAD LU - ;CALL PRTDECB ; PRINT IT - RET -; -DEVTBL: ; DEVICE TABLE - .DW DEV00, DEV01, DEV02, DEV03 - .DW DEV04, DEV05, DEV06, DEV07 - .DW DEV08, DEV09, DEV10, DEV11 - .DW DEV12, DEV13, DEV14, DEV15 -; -DEVUNK .DB "???$" -DEV00 .DB "MD$" -DEV01 .DB "FD$" -DEV02 .DB "RAMF$" -DEV03 .DB "IDE$" -DEV04 .DB "ATAPI$" -DEV05 .DB "PPIDE$" -DEV06 .DB "SD$" -DEV07 .DB "PRPSD$" -DEV08 .DB "PPPSD$" -DEV09 .DB "HDSK$" -DEV10 .EQU DEVUNK -DEV11 .EQU DEVUNK -DEV12 .EQU DEVUNK -DEV13 .EQU DEVUNK -DEV14 .EQU DEVUNK -DEV15 .EQU DEVUNK -; -#ENDIF -; -;__TEXT_STRINGS_________________________________________________________________________________________________________________ -; -; STRINGS -;_____________________________________________________________________________________________________________________________ -; -STR_BOOTDISK .DB "BOOT FROM DISK\r\n$" -STR_BOOTDISK1 .DB "\r\nReading disk information...$" -STR_BOOTMON .DB "START MONITOR FROM ROM\r\n$" -STR_BOOTBAS .DB "START BASIC FROM ROM\r\n$" -STR_BOOTTBC .DB "START TASTYBASIC FROM ROM\r\n$" -STR_BOOTCPM .DB "BOOT CPM FROM ROM\r\n$" -STR_BOOTZSYS .DB "BOOT ZSYSTEM FROM ROM\r\n$" -STR_LIST .DB "LIST DEVICES\r\n$" -STR_INVALID .DB "INVALID SELECTION\r\n$" -STR_SETUP .DB "SYSTEM SETUP\r\n$" -STR_SIG .DB "SIGNATURE=$" -STR_CPMLOC .DB "LOC=$" -STR_CPMEND .DB "END=$" -STR_CPMENT .DB "ENT=$" -STR_LABEL .DB "LABEL=$" -STR_DRVLIST .DB "\r\nDisk Devices:\r\n$" -STR_PREFIX .DB "($" -;STR_PREFIX .DB "\r\n $" -STR_LOADING .DB "\r\nLoading...$" -STR_NODISK .DB "\r\nNo disk!$" -STR_NOBOOT .DB "\r\nDisk not bootable!$" -STR_BOOTERR .DB "\r\nBoot failure!$" -STR_ITSRAM .DB "\r\n\RAM$" -STR_LAUNCH .DB "\r\nLaunching ...$" -; -STR_BANNER .DB "\r\n", PLATFORM_NAME, " Boot Loader$" -STR_BOOTMENU .DB "\r\n" - .DB "\r\nROM Boot: (B)ASIC, (C)PM, (M)onitor, (T)ASTYBASIC, (Z)System.\r\n" - .DB "Disk Boot: $" -; - .IF DSKYENABLE -BOOT: -; . . t o o b - .DB 00H, 00H, 80H, 80H, 094H, 09DH, 09DH, 09FH - .ENDIF -; -#DEFINE USEDELAY -#INCLUDE "util.asm" -; -#IF (DSKYENABLE) -#DEFINE DSKY_KBD -#INCLUDE "dsky.asm" -#ENDIF -; -;================================================================================================== -; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) -;================================================================================================== -; -#IF (PLATFORM != PLT_UNA) -; -; OUTPUT CHARACTER FROM A -; -COUT: - ; SAVE ALL INCOMING REGISTERS - PUSH AF - PUSH BC - PUSH DE - PUSH HL -; - ; OUTPUT CHARACTER TO CONSOLE VIA HBIOS - LD E,A ; OUTPUT CHAR TO E - LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C - LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR - RST 08 ; HBIOS OUTPUTS CHARACTDR -; - ; RESTORE ALL REGISTERS - POP HL - POP DE - POP BC - POP AF - RET -; -; INPUT CHARACTER TO A -; -CIN: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - ; INPUT CHARACTER FROM CONSOLE VIA HBIOS - LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C - LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR - RST 08 ; HBIOS READS CHARACTDR - LD A,E ; MOVE CHARACTER TO A FOR RETURN -; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) -; -CST: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - ; GET CONSOLE INPUT STATUS VIA HBIOS - LD C,CIODEV_CONSOLE ; CONSOLE UNIT TO C - LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS - RST 08 ; HBIOS RETURNS STATUS IN A -; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -#ENDIF -; -#IF (PLATFORM == PLT_UNA) -; -; OUTPUT CHARACTER FROM A -; -COUT: - ; SAVE ALL INCOMING REGISTERS - PUSH AF - PUSH BC - PUSH DE - PUSH HL -; - ; OUTPUT CHARACTER TO CONSOLE VIA UBIOS - LD E,A - LD BC,$12 - RST 08 -; - ; RESTORE ALL REGISTERS - POP HL - POP DE - POP BC - POP AF - RET -; -; INPUT CHARACTER TO A -; -CIN: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - ; INPUT CHARACTER FROM CONSOLE VIA UBIOS - LD BC,$11 - RST 08 - LD A,E -; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) -; -CST: - ; SAVE INCOMING REGISTERS (AF IS OUTPUT) - PUSH BC - PUSH DE - PUSH HL -; - ; GET CONSOLE INPUT STATUS VIA UBIOS - LD BC,$13 - RST 08 - LD A,E -; - ; RESTORE REGISTERS (AF IS OUTPUT) - POP HL - POP DE - POP BC - RET -; -#ENDIF -; -; READ A CONSOLE CHARACTER AND CONVERT TO UPPER CASE -; -CINUC: - CALL CIN - AND 7FH ; STRIP HI BIT - CP 'A' ; KEEP NUMBERS, CONTROLS - RET C ; AND UPPER CASE - CP 7BH ; SEE IF NOT LOWER CASE - RET NC - AND 5FH ; MAKE UPPER CASE - RET -; -;================================================================================================== -; FILL REMAINDER OF BANK -;================================================================================================== -; -SLACK: .EQU ($LDR_SIZ - $) - .FILL SLACK -; - .ECHO "LOADER space remaining: " - .ECHO SLACK - .ECHO " bytes.\n" -; -;================================================================================================== -; WORKING DATA STORAGE -;================================================================================================== -; - .ORG $8000 -; - .DS 64 ; 32 LEVEL STACK -BL_STACK .EQU $ ; ... TOP IS HERE -; -BL_COUNT .DS 1 ; LOAD COUNTER -BL_TIMEOUT .DS 2 ; AUTOBOOT TIMEOUT COUNTDOWN COUNTER -BL_BOOTID .DS 1 ; BOOT DEVICE ID CHOSEN BY USER -BL_DEVICE .DS 1 ; DEVICE TO LOAD FROM -BL_LU .DS 1 ; LU TO LOAD FROM -; -; BOOT INFO SECTOR IS READ INTO AREA BELOW -; THE THIRD SECTOR OF A DISK DEVICE IS RESERVED FOR BOOT INFO -; -BL_INFOSEC .EQU $ - .DS (512 - 128) -BB_METABUF .EQU $ -BB_SIG .DS 2 ; SIGNATURE (WILL BE 0A55AH IF SET) -BB_PLATFORM .DS 1 ; FORMATTING PLATFORM -BB_DEVICE .DS 1 ; FORMATTING DEVICE -BB_FORMATTER .DS 8 ; FORMATTING PROGRAM -BB_DRIVE .DS 1 ; PHYSICAL DISK DRIVE # -BB_LU .DS 1 ; LOGICAL UNIT (LU) - .DS 1 ; MSB OF LU, NOW DEPRECATED - .DS (BB_METABUF + 128) - $ - 32 -BB_PROTECT .DS 1 ; WRITE PROTECT BOOLEAN -BB_UPDATES .DS 2 ; UPDATE COUNTER -BB_RMJ .DS 1 ; RMJ MAJOR VERSION NUMBER -BB_RMN .DS 1 ; RMN MINOR VERSION NUMBER -BB_RUP .DS 1 ; RUP UPDATE NUMBER -BB_RTP .DS 1 ; RTP PATCH LEVEL -BB_LABEL .DS 16 ; 16 CHARACTER DRIVE LABEL -BB_TERM .DS 1 ; LABEL TERMINATOR ('$') -BB_BILOC .DS 2 ; LOC TO PATCH BOOT DRIVE INFO TO (IF NOT ZERO) -BB_CPMLOC .DS 2 ; FINAL RAM DESTINATION FOR CPM/CBIOS -BB_CPMEND .DS 2 ; END ADDRESS FOR LOAD -BB_CPMENT .DS 2 ; CP/M ENTRY POINT (CBIOS COLD BOOT) -; - .END From 39b7b089321cca6795431684e702fcabe4993842 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Tue, 30 Oct 2018 06:00:57 +0800 Subject: [PATCH 17/18] Cleanup, get ready for merge. No PIO support yet --- Source/HBIOS/cfg_sbc.asm | 4 ++-- Source/HBIOS/hbios.asm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/HBIOS/cfg_sbc.asm b/Source/HBIOS/cfg_sbc.asm index 8023fa6f..8e9813ea 100644 --- a/Source/HBIOS/cfg_sbc.asm +++ b/Source/HBIOS/cfg_sbc.asm @@ -93,5 +93,5 @@ BOOTTYPE .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTE BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE BOOT_DEFAULT .EQU 'Z' ; SELECTION TO INVOKE AT TIMEOUT -PIOENABLE .EQU TRUE ; TRUE FOR ZILOG PIO SUPPORT -PIOMODE .EQU PIOMODE_ZP ; PIOMODE_ZP=ECB-ZILOG PERIPHERALS BOARD PIOMODE_4P=ECB-4PIO +PIOENABLE .EQU FALSE ; TRUE FOR ZILOG PIO SUPPORT +PIOMODE .EQU PIOMODE_ZP ; PIOMODE_ZP=ECB-ZILOG PERIPHERALS BOARD PIOMODE_4P=ECB-4PIO diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 7311ac95..56116b9c 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -1322,7 +1322,7 @@ CIO_ADDENT: ; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) ; CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) -CIO_MAX .EQU 16 ; UP TO 16 UNITS +CIO_MAX .EQU 32 ; UP TO 32 UNITS CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES ; .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) From 164627f79432379a41934347155b05d5874853a5 Mon Sep 17 00:00:00 2001 From: b1ackmai1er <39449559+b1ackmai1er@users.noreply.github.com> Date: Tue, 30 Oct 2018 06:03:19 +0800 Subject: [PATCH 18/18] Ensure we have all Nascom changes --- Source/HBIOS/nascom.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/HBIOS/nascom.asm b/Source/HBIOS/nascom.asm index c83a33e1..6752614c 100644 --- a/Source/HBIOS/nascom.asm +++ b/Source/HBIOS/nascom.asm @@ -296,7 +296,7 @@ WORDS: .BYTE 'E'+80H,"ND" .BYTE 'L'+80H,"INES" .BYTE 'C'+80H,"LS" .BYTE 'W'+80H,"IDTH" - .BYTE 'M'+80H,"ONITOR" + .BYTE 'B'+80H,"YE" .BYTE 'S'+80H,"ET" .BYTE 'R'+80H,"ESET" .BYTE 'P'+80H,"RINT" @@ -385,7 +385,7 @@ WORDTB: .WORD PEND .WORD LINES .WORD CLS .WORD WIDTH - .WORD MONITR + .WORD MONITR ; BYE .WORD PSET .WORD RESET .WORD PRINT