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] 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