diff --git a/Source/HBIOS/Build.cmd b/Source/HBIOS/Build.cmd index 7c8ccda7..0d92db82 100644 --- a/Source/HBIOS/Build.cmd +++ b/Source/HBIOS/Build.cmd @@ -89,6 +89,11 @@ call :asm usrrom || exit /b call :asm updater || exit /b call :asm imgpad2 || exit /b +:: +:: Build components in Sub folders +:: +pushd SysConfig && call Build || exit /b & popd + :: :: Create additional ROM bank images by assembling components into :: 32K chunks which can be concatenated later. Note that @@ -97,7 +102,7 @@ call :asm imgpad2 || exit /b :: copy /b romldr.bin + dbgmon.bin + ..\zsdos\zsys_wbw.bin + ..\cpm22\cpm_wbw.bin osimg.bin || exit /b -copy /b ..\Forth\camel80.bin + nascom.bin + ..\tastybasic\src\tastybasic.bin + game.bin + eastaegg.bin + netboot.mod + updater.bin + usrrom.bin osimg1.bin || exit /b +copy /b ..\Forth\camel80.bin + nascom.bin + ..\tastybasic\src\tastybasic.bin + game.bin + eastaegg.bin + netboot.mod + updater.bin + SysConfig/sysconfig.bin usrrom.bin osimg1.bin || exit /b if %Platform%==S100 ( zxcc slr180 -s100mon/fh diff --git a/Source/HBIOS/Makefile b/Source/HBIOS/Makefile index 97910740..9c384485 100644 --- a/Source/HBIOS/Makefile +++ b/Source/HBIOS/Makefile @@ -3,7 +3,7 @@ MOREDIFF = game.bin hbios_rom.bin nascom.bin usrrom.bin \ dbgmon.bin hbios_app.bin imgpad2.bin osimg1.bin osimg2.bin romldr.bin \ eastaegg.bin hbios_img.bin osimg.bin game.bin updater.bin usrrom.bin -SUBDIRS = +SUBDIRS = SysConfig DEST = ../../Binary TOOLS =../../Tools OTHERS = *.img *.rom *.com *.upd *.bin *.hex cpm.sys zsys.sys Build.inc font*.asm *.dat hbios_env.sh @@ -62,7 +62,7 @@ $(OBJECTS) : $(ROMDEPS) @cat romldr.bin dbgmon.bin ../ZSDOS/zsys_$(BIOS).bin ../CPM22/cpm_$(BIOS).bin >osimg.bin cat romldr.bin dbgmon.bin ../ZSDOS/zsys_$(BIOS).bin >osimg_small.bin if [ $(ROM_PLATFORM) != UNA ] ; then \ - cat camel80.bin nascom.bin tastybasic.bin game.bin eastaegg.bin netboot.mod updater.bin usrrom.bin >osimg1.bin ; \ + cat camel80.bin nascom.bin tastybasic.bin game.bin eastaegg.bin netboot.mod updater.bin SysConfig/sysconfig.bin usrrom.bin >osimg1.bin ; \ if [ $(ROM_PLATFORM) = S100 ] ; then \ cat s100mon.bin >osimg2.bin ; \ else \ @@ -102,7 +102,7 @@ s100mon.bin: tastybasic.bin: cp ../TastyBasic/src/$@ . - + hbios_rom.bin: hbios.asm build.inc $(DEPS) @$(TASM) -dROMBOOT hbios.asm hbios_rom.bin hbios_rom.lst @@ -114,7 +114,7 @@ hbios_img.bin: hbios.asm build.inc $(DEPS) hbios_env.com: hbios_env.asm build.inc @$(TASM) -dBASH hbios_env.asm hbios_env.com hbios_env.lst - + hbios_env.sh: hbios_env.com @$(ZXCC) hbios_env.com >hbios_env.sh diff --git a/Source/HBIOS/Makefile.new b/Source/HBIOS/Makefile.new index 9beb9d79..21191551 100644 --- a/Source/HBIOS/Makefile.new +++ b/Source/HBIOS/Makefile.new @@ -6,7 +6,7 @@ DIST_OBJECTS := \ DUO_std SCZ180_sc126 SCZ180_sc130 SCZ180_sc131 SCZ180_sc140 \ SCZ180_sc503 SCZ180_sc700 S100_std UNA_std Z80RETRO_std \ ZETA_std ZETA2_std HEATH_std EPITX_std GMZ180_std -# RCZ80_mt RCZ80_duart MON_std +# RCZ80_mt RCZ80_duart MON_std OBJECTS := $(DIST_OBJECTS) # OBJECTS := SBC_std MK4_std UNA_std S100_std @@ -41,6 +41,9 @@ camel80.bin: tastybasic.bin: cp ../TastyBasic/src/$@ . +sysconfig.bin: + cp SysConfig/$@ . + s100mon.bin: $(ZXCC) $(CPM)/SLR180 -s100mon/FH $(ZXCC) $(CPM)/MLOAD25 -s100mon.bin=s100mon @@ -100,8 +103,8 @@ UNA_%.osimg.bin: UNA_%.romldr.bin UNA_%.dbgmon.bin %.osimg_small.bin: %.romldr.bin %.dbgmon.bin cat $(*F).romldr.bin $(*F).dbgmon.bin ../ZSDOS/zsys_wbw.bin >$@ -%.osimg1.bin: camel80.bin %.nascom.bin tastybasic.bin %.game.bin %.eastaegg.bin netboot.mod %.updater.bin %.usrrom.bin - cat camel80.bin $(*F).nascom.bin tastybasic.bin $(*F).game.bin $(*F).eastaegg.bin netboot.mod $(*F).updater.bin $(*F).usrrom.bin >$@ +%.osimg1.bin: camel80.bin %.nascom.bin tastybasic.bin %.game.bin %.eastaegg.bin netboot.mod %.updater.bin sysconfig.bin %.usrrom.bin + cat camel80.bin $(*F).nascom.bin tastybasic.bin $(*F).game.bin $(*F).eastaegg.bin netboot.mod $(*F).updater.bin sysconfig.bin $(*F).usrrom.bin >$@ srec_cat $@ -Binary -Crop 0 0x7FFF -Checksum_Negative_Big_Endian 0x7FFF 1 1 -o $@ -Binary S100_%.imgpad2.bin: s100mon.bin diff --git a/Source/HBIOS/SysConfig/Build.cmd b/Source/HBIOS/SysConfig/Build.cmd new file mode 100644 index 00000000..b3bbe85a --- /dev/null +++ b/Source/HBIOS/SysConfig/Build.cmd @@ -0,0 +1,10 @@ +@echo off +setlocal + +set TOOLS=../../Tools +set PATH=%TOOLS%\tasm32;%PATH% +set TASMTABS=%TOOLS%\tasm32 + +tasm -t80 -g3 -fFF sysconfig.asm sysconfig.com sysconfig.lst || exit /b + +copy /Y sysconfig.com ..\..\Binary\Apps\ || exit /b diff --git a/Source/HBIOS/SysConfig/Clean.cmd b/Source/HBIOS/SysConfig/Clean.cmd new file mode 100644 index 00000000..f408cf0e --- /dev/null +++ b/Source/HBIOS/SysConfig/Clean.cmd @@ -0,0 +1,6 @@ +@echo off +setlocal + +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.bin del *.bin diff --git a/Source/HBIOS/SysConfig/Makefile b/Source/HBIOS/SysConfig/Makefile new file mode 100644 index 00000000..c44a90e0 --- /dev/null +++ b/Source/HBIOS/SysConfig/Makefile @@ -0,0 +1,12 @@ +OBJECTS = sysconfig.com sysconfig.bin +DEST = ../../../Binary/Apps +NOCOPY = sysconfig.bin +TOOLS = ../../../Tools + +include $(TOOLS)/Makefile.inc + +USETASM=1 + +sysconfig.bin: TASMFLAGS=-dROMWBW + +sysconfig.com: TASMFLAGS=-dCPM diff --git a/Source/HBIOS/SysConfig/README.md b/Source/HBIOS/SysConfig/README.md new file mode 100644 index 00000000..e9269771 --- /dev/null +++ b/Source/HBIOS/SysConfig/README.md @@ -0,0 +1,21 @@ +# System Configuration + +## Introduction + +An utility applicaton that sets NVR Attributes that affect HBIOS and +RomWBW Operation. Write to RTC NVRAM to store config is reliant on HBIOS + +## Building + +TASM (Telemark Assembler) ([Anderson, 1998](##References)). + +### RomWBW Version + +Is part of the SBCv2 RomWBW distribution. And deployed as a Rom Application +It is included in Rom Bank 1 + +### CP/M Version + +The resulting `sysconfig.com` command file can be run in CP/M. +It is copied in the Binary/Apps folder. + diff --git a/Source/HBIOS/SysConfig/sysconfig.asm b/Source/HBIOS/SysConfig/sysconfig.asm new file mode 100644 index 00000000..14229e18 --- /dev/null +++ b/Source/HBIOS/SysConfig/sysconfig.asm @@ -0,0 +1,1032 @@ +; +;======================================================================= +; HBIOS System Configuration via NVRAM +; ALLOWS CONFIG OF NVR TO SET OPTIONS FOR HBIOS CONFIGURATION +;======================================================================= +; +; Simple utility that sets NVR Attributes that affect HBIOS +; and RomWBW Operation. Write to RTC NVRAM to store config +; is reliant on HBIOS +; +; NOTE: This program is built as both a CP/M COM and Rom WBW Applicaton +; +; ROM APPLICATION THAT IS AUTOMATICALLY INCLUDED IN THE ROMWBW ROM. +; IT IS INVOKED FROM THE BOOT LOADER USING THE 'W' OPTION. (See RomLDR) +; +; Author: Mark Pruden +; +; BASED ON USEROM.ASM +; THANKS AND CREDIT TO MARTIN R. FOR PROVIDING THIS APPLICATION! +; Also Based on The Tasty Basic Configuration +; Utilitity function were also copied from RomLdr, Assign. +; +#include "../../ver.inc" +#include "../hbios.inc" +; +;======================================================================= +; +#ifdef CPM +#define PLATFORM "CP/M" +NVR_LOC .equ 0100h +#endif +; +#ifdef ROMWBW +; +#define PLATFORM "ROMWBW" +#include "../layout.inc" +#endif +; +;======================================================================= +; +cmdmax .EQU $20 ; Max cmd input length +stksiz .EQU $40 ; Working stack size +restart .EQU $0000 ; CP/M restart vector +bdos .EQU $0005 ; BDOS invocation vector +ident .EQU $FFFE ; loc of RomWBW HBIOS ident ptr +; +ETX .EQU 3 ; CTRL-C +BEL .EQU 7 ; ASCII bell +BS .EQU 8 ; ASCII backspace +LF .EQU 10 +CR .EQU 13 +DEL .EQU 127 ; ASCII del/rubout +; +;======================================================================= +; + .ORG NVR_LOC +; +#ifdef ROMWBW + ; PLACE STACK AT THE TOP OF AVAILABLE RAM (JUST BELOW THE HBIOS PROXY). + LD SP,HBX_LOC +#endif +#ifdef CPM + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +#endif +; + call main ; do the real work +; +exit: + ; clean up and return to command processor + ; call crlf ; formatting +; +#ifdef ROMWBW + LD B,BF_SYSRESET ; SYSTEM RESTART + LD C,BF_SYSRES_WARM ; WARM START + RST 08 ; CALL HBIOS (DOES NOT RETURN) +#endif +#ifdef CPM +; + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart +; +;======================================================================= +; CPM Specific Init +;======================================================================= +; +init: + ; check for UNA (UBIOS) + ld a,($FFFD) ; fixed location of UNA API vector + cp $C3 ; jp instruction? + jr nz,initwbw ; if not, not UNA + ld hl,($FFFE) ; get jp address + ld a,(hl) ; get byte at target address + cp $FD ; first byte of UNA push ix instruction + jr nz,initwbw ; if not, not UNA + inc hl ; point to next byte + ld a,(hl) ; get next byte + cp $E5 ; second byte of UNA push ix instruction + jr nz,initwbw ; if not, not UNA + jp err_una ; UNA not supported +; +initwbw: + ; get location of config data and verify integrity + ld hl,(ident) ; HL := adr or RomWBW HBIOS ident + ld a,(hl) ; get first byte of RomWBW marker + cp 'W' ; match? + jp nz,err_inv ; abort with invalid config block + inc hl ; next byte (marker byte 2) + ld a,(hl) ; load it + cp ~'W' ; match? + jp nz,err_inv ; abort with invalid config block + inc hl ; next byte (major/minor version) + ld a,(hl) ; load it + cp rmj << 4 | rmn ; match? + jp nz,err_ver ; abort with invalid os version +; +initz: + ; initialization complete + xor a ; signal success + ret ; return +; +err_una: + ld de,str_err_una + jr err_ret +err_inv: + ld de,str_err_inv + jr err_ret +err_ver: + ld de,str_err_ver + jr err_ret +; +str_err_una .db " ERROR: UNA not supported by application",0 +str_err_inv .db " ERROR: Invalid BIOS (signature missing)",0 +str_err_ver .db " ERROR: Unexpected HBIOS version",0 +; +#endif +; +;======================================================================= +; Main Program and Loop +; +; TODO Potentially turn this into CP/M command line driven app. +; TODO Ie it just processes a single command (if provided) by CPM. +;======================================================================= +; +main: + call prtcrlf + ld de,str_banner ; banner + call prtstr +; + CALL PRT_STATUS ; PRINT STATUS + ld de,MSG_MENU ; Print the Main Menu + CALL prtstr +; +mainloop: + ld DE,MSG_PROMPT + CALL prtstr ; Print a prompt > + CALL rdln ; READ INPUT +; + ; accept and pare input + ld de,cmdbuf ; point to start of buf + call skipws ; skip whitespace + JR z,mainloop ; if empty line, just loop back + call upcase +; + ; MENU OPTIONS (documented) + cp 'H' + JR Z,helpandloop ; get help + cp 'P' + JR Z,statusandloop ; print status + cp 'Q' + ret Z ; finished + cp 'R' + JR Z,resetandloop ; reset NVRAM + cp 'S' + JR Z,setvalueandloop ; todo set Value +; + ; COMMON ALTERNATES (undocumented) + cp 'L' + JR Z,statusandloop ; print status + cp 'X' + ret Z ; finished + cp 'Z' + ret Z ; finished + cp '?' + JR Z,helpandloop ; get help + cp '/' + JR Z,helpandloop ; get help +; + ; Main Loop + JR mainloop ; Noting Valid was entered +; +;======================================================================= +; General Functional Routines Called By Menu Options +;======================================================================= +; +; Print Help Menu +; +helpandloop: ; HELP MENU + CALL findskipws ; skip over WS to first char + JR z,printmainhelp ; if empty line, print main help + call upcase +; + ; the folloiwng is just testing a single charater + cp 'A' ; Auto Boot help menu + JP Z,HELP_AB + cp 'D' ; Default Boot help menu + JP Z,HELP_DB +; +printmainhelp: + ld de,MSG_MENU ; nothing found Print the Main Menu +printhelp: + CALL prtstr ; print the selected help message + JR mainloop +; +; ----------- +; RESET NVRAM +; +resetandloop: ; RESET NVRAM + LD BC,BC_SYSSET_SWITCH + LD D,$FF ; RESET SWITCH + RST 08 ; Reset NV RAM + JR statusandloop ; now reprint the status +; +; ------------- +; Set NV Ram Value +; +setvalueandloop: + CALL findskipws ; skip over WS to first char + JR z,setvalueerror ; if empty line, print ? + call upcase +; + ; the folloiwng is just testing a single charater + cp 'A' ; Auto Boot help menu + JP Z,SET_AB + cp 'D' ; Default Boot help menu + JP Z,SET_DB +; +setvalueerror: + ld de,MSG_QUESTION ; nothing found Print the Main Menu + CALL prtstr ; print the selected help message + JR mainloop +; +setvaluesave: + LD BC,BC_SYSSET_SWITCH ; SET THE VALUE + RST 08 ; HL is savd + ; JR statusandloop ; finish display status (FALL THROUGH) +; +; ------------ +; Print Status +; +statusandloop: + CALL PRT_STATUS ; print status + JR mainloop +; +; Call with Return to print status +; +PRT_STATUS: + LD de,MSG_STAT ; print status open mesg + CALL prtstr + LD BC,BC_SYSGET_SWITCH + LD D,$FF ; check for existence of switches + RST 08 + JR NZ,STAT_NOTFOUND ; error means switchs are not enabled +; +; print invdividual stats, on all per switch +; + CALL STAT_DEFBOOT + CALL STAT_AUTOB +; +; end individual stats +; + CALL prtcrlf + RET +STAT_NOTFOUND: + LD de,MSG_NOTF + CALL prtstr + RET +; +; ====================================================================== +; Specific Switches Below +; ====================================================================== +; +; DEFAULT BOOT +; Byte 1: (L) +; Bit 7-0 DISK BOOT SLice Number to Boot -> default = 0 +; Bit 7-0 ROM BOOT (alpha character) Application to boot -> default = 0 translates to "H" +; Byte 2: (H) +; Bit 7 - DISK/ROM - Disk or Rom Boot -> Default=ROM (BOOT_DEFAULT is Numeric/Alpha) +; Bit 6-0 - DISK BOOT Disk Unit to Boot (0-127) -> default = 0 +; +; PRINT CURRENT SWITCH VALUE +; +STAT_DEFBOOT: + LD BC,BC_SYSGET_SWITCH + LD D,NVSW_DEFBOOT + RST 08 ; Should return auto Boot in HL + RET NZ ; return if error + LD de,MSG_DEFBOOT + CALL prtstr + LD A,H ; Byte 2 + AND DBOOT_ROM ; DISK/ROM + JR NZ,STAT_AUTOROM ; is it ROM +STAT_AUTODISK: + LD de,MSG_DISK ; disk + CALL prtstr + LD A,H ; Byte 2 + AND DBOOT_UNIT ; Unit + CALL prtdecb + LD de,MSG_DISK2 ; Slice + CALL prtstr + LD A,L ; SLICE + CALL prtdecb + LD de,MSG_DISK3 ; close bracket + CALL prtstr + RET +STAT_AUTOROM: + LD de,MSG_ROM ; ROM + CALL prtstr + LD A,L ; ROM APP + call prtchr + LD de,MSG_ROM2 ; close bracket + CALL prtstr + RET +; +; SET SWITCH VALUE +; +SET_DB: + CALL findskipws ; skip over WS to first char + JR z,SET_DB_ERR ; if empty line, print main help + call upcase + cp 'R' ; ROM + JR Z,SET_DB_ROM + cp 'D' ; DISK + JR Z,SET_DB_DISK + JR SET_DB_ERR +SET_DB_ROM: + CALL findskipcomma + CALL skipws + JR z,SET_DB_ERR ; if empty line, print main help + LD L,A ; LOW BYTE ; next CHAR is the ROM App Name + LD A,DBOOT_ROM + LD H,A ; HIGH BYTE, has constant. DBOOT_ROM = $80 + JR SET_DB_SAVE ; SAVE +SET_DB_DISK: + CALL findskipcomma + CALL skipws + JR z,SET_DB_ERR ; if empty line, print main help + CALL getnum ; next CHAR is the DISK UNIT + JR C,SET_DB_ERR ; overflow + BIT 7,A ; is > 127 + JR NZ, SET_DB_ERR + LD H,A ; HIGH BYTE, has disk unit < $80 + CALL findskipcomma + CALL skipws + JR z,SET_DB_ERR ; if empty line, print main help + CALL getnum ; next CHAR is the SLICE + JR C,SET_DB_ERR ; overflow + LD L,A ; LOW BYTE, has the slice number + ;JR SET_DB_SAVE ; SAVE - Fall Through +SET_DB_SAVE: + LD D,NVSW_DEFBOOT ; DEFAULT BOOT + JP setvaluesave ; SAVE THE VALUE +SET_DB_ERR: + JP setvalueerror ; ERROR. Added this so can use JR above +; +; PRINT HELP TEST FOR SWITCH +; +HELP_DB: + ld de,MSG_DEFB_H + JP printhelp +; +MSG_DEFBOOT .DB CR,LF, " [DB] / Default Boot: ",0 +MSG_DISK .DB "Disk (Unit = ",0 +MSG_DISK2 .DB ", Slice = ",0 +MSG_DISK3 .DB ")",0 +MSG_ROM .DB "ROM (App = '",0 +MSG_ROM2 .DB "')",0 +; +MSG_DEFB_H .DB "\r\nDefault Boot - Disk or Rom App (DB):\r\n" + .DB " DB [R|D],[{romapp}|{unit},{slice}]\r\n" + .DB " e.g. S DB D,2,14 ; Disk Boot, unit 2, slice 14\r\n" + .DB " S DB R,M ; Rom Application 'M'onitor\r\n" + .DB " Note: Disk: Unit (0-127); Slice (0-255)\r\n",0 +; +;======================================================================= +; +; AUTO BOOT +; Byte 0: (L) +; Bit 7-6 - Reserved +; Bit 5 - AUTO BOOT Auto boot, default=false (i.e. BOOT_TIMEOUT != -1) +; Bit 4 - Reserved +; Bit 3-0 - BOOT_TIMEOUT in seconds (0-15) 0=immediate -> default=3 +; +; PRINT CURRENT SWITCH VALUE +; +STAT_AUTOB: + LD BC,BC_SYSGET_SWITCH + LD D,NVSW_AUTOBOOT + RST 08 ; Should return auto Boot in HL + RET NZ ; return if error + LD de,MSG_AUTOB + CALL prtstr + LD A,L ; Byte 1 + LD de,MSG_DISABLED + AND ABOOT_AUTO ; enabled + JR Z, STAT_AUTOB1 ; disabled + LD de,MSG_ENABLED ; enabled + CALL prtstr + LD A,L ; Byte 1 + AND ABOOT_TIMEOUT ; timeout + CALL prtdecb ; print timeout + LD de,MSG_ENABLED2 ; and closing bracket +STAT_AUTOB1: + CALL prtstr + RET +; +; SET SWITCH VALUE +; +SET_AB: + CALL findskipws ; skip over WS to first char + JR z,SET_AB_ERR ; if empty line, print main help + call upcase + cp 'E' ; Enabled + JR Z,SET_AB_ENAB + cp 'D' ; Disabled + JR Z,SET_AB_DISAB + JR SET_AB_ERR +SET_AB_ENAB: + CALL findskipcomma + CALL skipws + JR z,SET_AB_ERR ; if empty line, print main help + CALL getnum ; next NUMBER is the timout + JR C,SET_AB_ERR ; overflow + AND $F0 ; mask just the upper bits + JR NZ,SET_AB_ERR ; if any upper bit set > 15 then Error + LD A,C ; NOTE getnum also returns Value in C + OR ABOOT_AUTO ; set the enabled bit for auto boot + LD L,A ; LOW BYTE, has the timeout from getNum + JR SET_AB_SAVE ; SAVE +SET_AB_DISAB: + LD L,0 + ;JR SET_AB_SAVE ; SAVE - Fall Through +SET_AB_SAVE: + LD D,NVSW_AUTOBOOT ; AUTO BOOT + JP setvaluesave ; SAVE THE VALUE +SET_AB_ERR: + JP setvalueerror ; ERROR. Added this so can use JR above +; +; PRINT HELP TEST FOR SWITCH +; +HELP_AB: + ld de,MSG_AUTOB_H + JP printhelp +; +MSG_AUTOB: .DB CR,LF," [AB] / Auto Boot: ",0 +MSG_ENABLED: .DB "Enabled (Timeout = ",0 +MSG_ENABLED2: .DB ")",0 +MSG_DISABLED: .DB "Disabled",0 +; +MSG_AUTOB_H .DB "\r\nAutomatic Boot (AB):\r\n" + .DB " AB [,{timeout}]\r\n" + .DB " e.g. S AB E,3 ; enabled (show menu) with 3 second timout before boot\r\n" + .DB " S AB E,0 ; enabled with immediate effect, bypass menu\r\n" + .DB " S AB D ; disabled, just display menu\r\n",0 +; +;======================================================================= +; Error Handlers +;======================================================================= +; +err_unknown: + ld de,str_err_unknown + jr err_ret +; +err_ret: + call prtcrlf2 + call prtstr + or $FF ; signal error + ret +; +;======================================================================= +; GENERAL CONSTANTS +;======================================================================= +; +str_banner .db "\r\n" + .db "RomWBW System Config Utility, Version 1.0 Nov-2024\r\n",0 +; +MSG_MENU .DB "\r\n" + .DB "Commands:\r\n" + .DB " (P)rint - Display Current settings\r\n" + .DB " (S)et {SW},{val}[,{val}[,{val}]]- Set a switch value(s)\r\n" + .DB " (R)eset - Init NVRAM to Defaults\r\n" + .DB " (H)elp [{SW}] - This help menu, or help on a switch\r\n" + .DB " (Q)uit - Quit\r\n" + .DB 0 +MSG_PROMPT: .DB "\r\n" + .DB "$", 0 +MSG_STAT: .DB "\r\nCurrent Configuration: ",0 +MSG_NOTF: .DB "Config Not Found.\r\n",0 +MSG_QUESTION .DB "\r\n?\r\n",0 +; +;MSG_PAK: .DB "\r\nPress Any Key ...",0 +; +str_err_unknown .db "\r\nUnknown Error\r\n",0 +; +;======================================================================= +; Utility Routines +;======================================================================= +; +; Print a dot character without destroying any registers +; +prtdot: + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print Cr LF +; +prtcrlf2: + call prtcrlf ; two of them +prtcrlf: + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,13 + call prtchr ; print it + ld a,10 + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print a zero terminated string at (de) without destroying any registers +; +prtstr: + push af + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + pop af + ret +; +; Print a hex value prefix "0x" +; +prthexpre: + push af + ld a,'0' + call prtchr + ld a,'x' + call prtchr + pop af + ret +; +; Print the value in A in hex without destroying any registers +; +;prthex: +; call prthexpre +;prthex1: +; push af ; save AF +; push de ; save DE +; call hexascii ; convert value in A to hex chars in DE +; ld a,d ; get the high order hex char +; call prtchr ; print it +; ld a,e ; get the low order hex char +; call prtchr ; print it +; pop de ; restore DE +; pop af ; restore AF +; ret ; done +; +; print the hex word value in hl +; +;prthexword: +; call prthexpre +;prthexword1: +; push af +; ld a,h +; call prthex1 +; ld a,l +; call prthex1 +; pop af +; ret +; +; print the hex dword value in de:hl +; +;prthex32: +; call prthexpre +; push bc +; push de +; pop bc +; call prthexword1 +; push hl +; pop bc +; call prthexword1 +; pop bc +; ret +; +; Convert binary value in A to ascii hex characters in DE +; +;hexascii: +; ld d,a ; save A in D +; call hexconv ; convert low nibble of A to hex +; ld e,a ; save it in E +; ld a,d ; get original value back +; rlca ; rotate high order nibble to low bits +; rlca +; rlca +; rlca +; call hexconv ; convert nibble +; ld d,a ; save it in D +; ret ; done +; +; Convert low nibble of A to ascii hex +; +;hexconv: +; and $0F ; low nibble only +; add a,$90 +; daa +; adc a,$40 +; daa +; ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; 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 prtdot +; 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 prtchr +;prtd3m3: +; ret +; +; ------------------------------------------------------- +; +; Get the next non-blank character from (HL). +; +;nonblank: +; ld a,(ix) ; load next character +; or a ; string ends with a null +; ret z ; if null, return pointing to null +; cp ' ' ; check for blank +; ret nz ; return if not blank +; inc ix ; if blank, increment character pointer +; jr nonblank ; and loop +; +; Get alpha chars and save in tmpstr +; Length of string returned in A +; +;getalpha: +; +; ld hl,tmpstr ; location to save chars +; ld b,8 ; length counter (tmpstr max chars) +; ld c,0 ; init character counter +; +;getalpha1: +; ld a,(ix) ; get active char +; call upcase ; lower case -> uppper case, if needed +; cp 'A' ; check for start of alpha range +; jr c,getalpha2 ; not alpha, get out +; cp 'Z' + 1 ; check for end of alpha range +; jr nc,getalpha2 ; not alpha, get out +; ; handle alpha char +; ld (hl),a ; save it +; inc c ; bump char count +; inc hl ; inc string pointer +; inc ix ; increment buffer ptr +; djnz getalpha1 ; if space, loop for more chars +; +;getalpha2: ; non-alpha, clean up and return +; ld (hl),0 ; terminate string +; ld a,c ; string length to A +; or a ; set flags +; ret ; and return +; +;tmpstr .fill 9,0 ; temp string (8 chars, 0 term) +; +; Determine if byte in A is a numeric '0'-'9' +; Return with CF clear if it is numeric +; +isnum: + cp '0' + jr c,isnum1 ; too low + cp '9' + 1 + jr nc,isnum1 ; too high + or a ; clear CF + ret +isnum1: + or a ; clear CF + ccf ; set CF + ret +; +; Get numeric chars at DE and convert to number returned in A +; Carry flag set on overflow +; +getnum: + ld c,0 ; C is working register +getnum1: + ld a,(de) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getnum2 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getnum2 ; abort if above +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 10 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + add a,c ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(de) ; get new digit + sub '0' ; make binary + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc de ; bump to next char + jr getnum1 ; loop +; +getnum2: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Find (AND SKIP) whitespace at buffer adr in DE, returns with first +; NON whitespace character in A. +; +findskipws: + ld a,(de) ; get next char + or a ; check for eol + ret z ; done if so + cp ' ' ; blank? + JR z,skipws ; nope, done + inc de ; bump buffer pointer + jr findskipws ; and loop +; +; Skip whitespace at buffer adr in DE, returns with first +; non-whitespace character in A. +; +skipws: + ld a,(de) ; get next char + or a ; check for eol + ret z ; done if so + cp ' ' ; blank? + ret nz ; nope, done + inc de ; bump buffer pointer + jr skipws ; and loop +; +; Find (AND SKIP) "," at buffer adr in DE, returns with first +; NON "," character in A. +; +findskipcomma: + ld a,(de) ; get next char + or a ; check for eol + ret z ; done if so + cp ',' ; blank? + JR z,skipcomma ; nope, done + inc de ; bump buffer pointer + jr findskipcomma ; and loop +; +; Skip "," at buffer adr in DE, returns with first +; non-comma character in A. +; +skipcomma: + ld a,(de) ; get next char + or a ; check for eol + ret z ; done if so + cp ',' ; blank? + ret nz ; nope, done + inc de ; bump buffer pointer + jr skipcomma ; and loop +; +; Uppercase character in A +; +upcase: + cp 'a' ; below 'a'? + ret c ; if so, nothing to do + cp 'z'+1 ; above 'z'? + ret nc ; if so, nothing to do + and ~$20 ; convert character to lower + ret ; done +; +; ----------------------------- +; Add hl,a +; A register is destroyed! +; +;addhla: +; add a,l +; ld l,a +; ret nc +; inc h +; ret +; +;======================================================================= +; Read a string on the console +; (Code originally from RomLDR) +; +; Uses address $0080 in page zero for buffer +; Input is zero terminated +; +rdln: + ld de,cmdbuf ; init buffer address ptr +rdln_nxt: + call CIN ; get a character + cp BS ; backspace? + jr z,rdln_bs ; handle it if so + cp DEL ; del/rubout? + jr z,rdln_bs ; handle as backspace + cp CR ; return? + jr z,rdln_cr ; handle it if so +; + ; check for non-printing characters + cp ' ' ; first printable is space char + jr c,rdln_bel ; too low, beep and loop + cp '~'+1 ; last printable char + jr nc,rdln_bel ; too high, beep and loop +; + ; need to check for buffer overflow here!!! + ld hl,cmdbuf+cmdmax ; max cmd length + or a ; clear carry + sbc hl,de ; test for max + jr z,rdln_bel ; at max, beep and loop +; + ; good to go, echo and store character + call COUT ; echo character input + ld (de),a ; save in buffer + inc de ; inc buffer ptr + jr rdln_nxt ; loop till done +; +rdln_bs: + ld hl,cmdbuf ; start of buffer + or a ; clear carry + sbc hl,de ; subtract from cur buf ptr + jr z,rdln_bel ; at buf start, just beep + ;ld hl,str_bs ; backspace sequence + ld a,BS + call COUT + ld a,' ' + call COUT + ld a,BS + call COUT + ;call prtstr ; send it + dec de ; backup buffer pointer + jr rdln_nxt ; and loop +; +rdln_bel: + ld a,BEL ; Bell characters + call COUT ; send it + jr rdln_nxt ; and loop +; +rdln_cr: + xor a ; null to A + ld (de),a ; store terminator + ret +; +str_bs .db BS,' ',BS,0 +; +;======================================================================= +; Basic Input Output (Specific to Target) +;======================================================================= +; +; Print character in A without destroying any registers +; +COUT: +prtchr: + push af + push bc ; save registers + push de + push hl +#ifdef ROMWBW + LD BC, BF_CIOOUT<<8 | CIO_CONSOLE + LD E,A + RST 08 +#endif +#ifdef CPM + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it +#endif + pop hl ; restore registers + pop de + pop bc + pop af + ret +; +; WAIT FOR A CHARACTER FROM THE CONSOLE DEVICE AND RETURN IT IN A +; +CIN: PUSH BC + PUSH DE + PUSH HL +#ifdef ROMWBW + LD BC, BF_CIOIN << 8 | CIO_CONSOLE + RST 08 + LD A,E +#endif +#ifdef CPM + ; todo CONVERT TO BDOS CALL + LD BC, BF_CIOIN << 8 | CIO_CONSOLE + RST 08 + LD A,E +#endif + POP HL + POP DE + POP BC + RET +; +;======================================================================= +; General Working data +;======================================================================= +; +stksav .dw 0 ; stack pointer saved at start +; +cmdbuf: .FILL cmdmax,0 ; cmd inut buffer +; + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +#ifdef ROMWBW +; +;======================================================================= +; IT IS CRITICAL THAT THE FINAL BINARY BE EXACTLY NVR_SIZ BYTES. +; THIS GENERATES FILLER AS NEEDED. IT WILL ALSO FORCE AN ASSEMBLY +; ERROR IF THE SIZE EXCEEDS THE SPACE ALLOCATED. +;======================================================================= +; +SLACK .EQU (NVR_END - $) +; +#IF (SLACK < 0) + .ECHO "*** NVRCONFIG APP IS TOO BIG!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#endif +; + .FILL SLACK,$00 + .ECHO "NVRCONFIG space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; + .NOLIST +; +#endif + .END diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 375fe798..54144eba 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -458,6 +458,33 @@ CB_BOOTMODE .DB BOOTMODE ; HBIOS BOOTMODE CB_HEAP .DW 0 CB_HEAPTOP .DW 0 ; +; SWITCHES SHADOW COPY (FROM RTC/NVR) START AT $30 +; + .FILL (HCB + $30 - $),0 +; +; First byte (header) of NVRAM = "W" if fully initialised, or a ststus byte +; = 0 if no NVRAM detected, or = 1 If NVR exists, but not configured +CB_SWITCHES .DB 0 ; this byte is set during init +; +; Byte 0: (L) +; Bit 7-0 DISK BOOT SLice Number to Boot -> default = 0 +; Bit 7-0 ROM BOOT (alpha character) Application to boot -> default = "H" +; Byte 1: (H) +; Bit 7 - ROM/DISK - Rom or Disk Boot -> Default=ROM=1 (BOOT_DEFAULT is Numeric/Alpha) +; Bit 6-0 - DISK BOOT Disk Unit to Boot (0-127) -> default = 0 +CB_SWDEFBOOT .DB 'H' ; (WORD) DEFAULT BOOT NVR OPTIONS. USED By ROMLDR + .DB DBOOT_ROM ; Default Boot - ROM Application +; +; Byte 0: (L) +; Bit 7-6 - Reserved +; Bit 5 - AUTO BOOT Auto boot, default=false (BOOT_TIMEOUT != -1) +; Bit 4 - Reserved +; Bit 3-0 - BOOT_TIMEOUT in seconds (0-15) 0=immediate -> default=3 +CB_SWAUTOB .DB 0 ; AUTO BOOT NVR OPTIONS. USED By ROMLDR +; +; CHECKSUM +CB_SWITCHCK .DB 0 ; CHECKSUM (XOR=0), INCLUDES HEADER and CB_VERSION +; ; STANDARD BANK ID'S START AT $D8. DEFAULT VALUES FOR 512KB SYSTEM WITH NO RESERVED BANKS ; .FILL (HCB + $D8 - $),0 @@ -3349,6 +3376,32 @@ IS_REC_M1: CALL CALLLIST ; ;-------------------------------------------------------------------------------------------------- +; NV-SWITCH INITITIALISATION +; Requires functional RTC NVR +;-------------------------------------------------------------------------------------------------- +; +NVR_INIT: + ; Check for the existence of NV RAM by attempting to read a byte + LD B,BF_RTCGETBYT ; GET RTC BYTE + LD C,0 ; FIRST Byte address in RTC + CALL RTC_DISPATCH ; CALL RTC + JR NZ,NVR_INIT_END ; GET BYTE Failed; Noting to do, HCB is correct. Status =0 + ; + CALL NVSW_READ ; read the full data into hcb + JR NZ, NVR_INIT_DEF ; failed to correclty read data + ; + CALL NVSW_CHECKSUM ; checksum calc into A + LD HL,CB_SWITCHCK ; address of HCB value + CP (HL) ; compare Caculated Check, with hcb Check Value + JR Z,NVR_INIT_END ; The same so success +NVR_INIT_DEF: + ; failed Read or Checksum + CALL NVSW_DEFAULTS ; set defaults into HCB, which include the "W" first byte + LD HL,CB_SWITCHES ; which is incorrect, need the value of 1 + LD (HL),1 ; to indicate we while not inited, we do have NVRAM +NVR_INIT_END: +; +;-------------------------------------------------------------------------------------------------- ; WATCHDOG ACTIVATION ;-------------------------------------------------------------------------------------------------- ; @@ -5474,6 +5527,8 @@ SYS_GET: JP Z, SYS_GETSNDCNT CP BF_SYSGET_SNDFN JP Z,SYS_GETSNDFN + CP BF_SYSGET_SWITCH + JP Z,SYS_GETSWITCH CP BF_SYSGET_TIMER JP Z,SYS_GETTIMER CP BF_SYSGET_SECS @@ -5626,6 +5681,45 @@ SYS_GETFN: POP DE ; ... TO DE RET ; AF STILL HAS RESULT OF CALC ; +; GET SWITCH +; ON ENTRY: +; D: SWITCH KEY +; 0 -> ILLEGAL / RESERVED +; 1-FE -> SWITCH +; FF -> DONT GET VALUE CHECK THE STATUS OF NVRAM -> Returning +; A=0 if no NVRAM exists. with NZ flag set +; A=1 if NVRAM is present. with Z flag set +; A='W' if NVRAM is fullly inited. with Z flag set +; Note the NZ flag can be used to detect and return an error condition +; RETURNS: +; HL: SWITCH VALUE 8/16 BIT +; +SYS_GETSWITCH: +; PUSH DE +; CALL NVSW_CONFIG ; make sure shadow copy is inited +; POP DE ; +; RET NZ ; Configuration Failed, thus cant continue +; + LD A,D + CP $FF ; test if want to just get NVRAM status + JR Z,NVSW_STATUS ; Check the Status - Call and Return +; + CALL SWITCH_RES ; D SWITCH NUMBER -> OUT HL address, E FLAGS + RET NZ ; IF NZ FLAG SET THEN ISSUE +; + LD B,0 ; Clear upper byte + LD C,(HL) ; Get LOW Order Switch Data + LD A,1 ; Compare with 1 (byte) + CP E ; Compare The byte count from SWITCH_RES + JR NC,SYS_GETSWITCH2 ; 1 byte or less, skip over + INC HL ; next byte pos in a 2 Byte Switch + LD B,(HL) ; Get HIGH Order Switch Data +; +SYS_GETSWITCH2: + LD H,B ; retun Result in HL + LD L,C + XOR A ; signal success + RET #IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) ; IMPLEMENTED IN EZ80DRV.ASM ; @@ -5854,6 +5948,8 @@ SYS_GETAPPBNKS: ; SYS_SET: LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSSET_SWITCH + JP Z,SYS_SETSWITCH CP BF_SYSSET_TIMER JP Z,SYS_SETTIMER CP BF_SYSSET_SECS @@ -5867,6 +5963,76 @@ SYS_SET: SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR RET ; +; SET SWITCH +; ON ENTRY: +; D: SWITCH KEY +; 0 -> ILLEGAL / RESERVED +; 1-254 -> SWITCH +; FF -> REINIT DEFAULT VALUES +; HL: SWITCH VALUE 8/16 BIT +; +SYS_SETSWITCH: + CALL NVSW_STATUS ; Check the status of NV RAM + RET NZ ; IF NZ then we cant continue, return NZ at this point +; + LD A,D ; switch # argument + CP $FF ; test if want to reset NVRAM + JP Z,NVSW_RESET ; then perform reset function. CALL AND RETURN +; + LD B,H ; move value to write into BC + LD C,L + CALL SWITCH_RES ; IN D SWITCH NUMBER -> OUT HL address, E FLAGS + RET NZ ; RETURN IF NZ - swich number illegal +; + LD (HL),C ; Save LOW Order Switch Data + LD A,1 ; Compare with 1 (byte) switch + CP E ; Compare + JR NC,SYS_SETSWITCH1 ; 1 byte or less, skip over + INC HL ; next byte pos + LD (HL),B ; Save High Order Switch Data +; +SYS_SETSWITCH1: + JP NVSW_UPDATE ; do a write to NVR, CALL AND RETURN +; +; Utility function to convert switch number into lookup +; INPUT +; D SWITCH NUMBER +; OUTPUT +; E with Byte count (1,2) for switch, or 0 if switch illegal +; HL Memory Address (CB_SWITCHES + offset) +SWITCH_RES: + LD A,SWITCH_LEN ; lengt of target array (below) + CP D ; check we fit in the loop + JR C,SWITCH_RES1 ; overflow table to abort +; + LD HL,SWITCH_TAB ; Lookup table below + LD A,D ; plus the offset switch number + CALL ADDHLA ; get address of lookup table + LD E,(HL) ; E (OUT) nubmer of bytes in switch +; + LD HL,CB_SWITCHES ; BASE ADDRESS OF SHADDOW DATA + LD A,D ; Add The offset to the address + CALL ADDHLA ; Final address of Switch Data +; + XOR A ; signal success + RET +SWITCH_RES1: + OR $FF ; signal failure + RET +; +; Switch number maps drectly into the HCB data, so to account +; for double bytes words, we need a table (loopkup) +; to defines how to map Applicability of Each Swicth Number +; 0->Cant be Used; 1->Single Byte Value; 2->Double Byte Value +; +SWITCH_TAB: + .DB 0 ; Switch 0 is header, cant be used + .DB 2 ; Switch 1 - (WORD) + .DB 0 ; Switch (byte 2) of prior word, not used + .DB 1 ; Switch 3 - (BYTE) + .DB 0 ; Last byte is checksum, cant be used +SWITCH_LEN .EQU $ - SWITCH_TAB - 2 +; ; SET BOOT INFORMATION ; ON ENTRY: ; L: BOOT BANK ID @@ -7399,6 +7565,128 @@ Z2DMAADR2: ; #ENDIF ; +;-------------------------------------------------------------------------------------------------- +; ROUTINES FOR NON VOLITILE (NVRAM) SWITCHES +;-------------------------------------------------------------------------------------------------- +; +; Return Status +; A=0 if no NVRAM exists. with NZ flag set +; A=1 if NVRAM is present. with Z flag set +; A='W' if NVRAM is fullly inited. with Z flag set +; Note the NZ flag can be used to detect and return an error condition +; +NVSW_STATUS: + LD A,(CB_SWITCHES) ; the status byte + LD B,A ; save it + AND 1 ; applies to 'W' and $01 status, -> 1 + CP 1 ; set NZ based on A = 1 + LD A,B ; return the + RET +; +; RESET CONTENTS OF NVRAM, STORING INTO +; RETURN NONZERO IF WRITTEN - ZERO IF NOT WRITTEN +; +NVSW_RESET: + CALL NVSW_DEFAULTS ; copy defaults into HCB + ; Fall Through and Update (write) status + ; JP NVSW_UPDATE +; +; UPDATE HBIOS SHADOW TO NVRAM, AFTER SETTING HBIOS VALUE +; RETURN NONZERO IF WRITTEN - ZERO IF NOT WRITTEN +; +NVSW_UPDATE: + CALL NVSW_CHECKSUM ; CALC checksum into A + LD (CB_SWITCHCK),A ; store checksum in hcb + CALL NVSW_WRITE ; write the bytes to nvr + RET Z ; Successful write, return + ; write failed for some reason ??? + LD A,1 + LD (CB_SWITCHES),A ; ensure hcb signature=1 + OR $FF ; failure + RET ; return NZ flag +; +; PERFORM CHECKSUM CALC OF DATA IN HCB +; RETURN A REGISTER -> CONTAINING THE CHECKSUM +; +NVSW_CHECKSUM: + XOR A + LD B,NVSW_SIZE ; NUMBER OF BYTES TO CHECK + LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB) +NVSW_CHECKSM1: + XOR (HL) ; XOR The Byte + INC HL ; HL address + DJNZ NVSW_CHECKSM1 ; LOOP + XOR RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + XOR RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO + RET +; +; COPY DEFAULTS INTO HCB +; +NVSW_DEFAULTS: + LD HL,NVSW_DEFAULT ; Copy default bytes from + LD DE,CB_SWITCHES ; to hbios HCB location + LD BC,NVSW_SIZE ; number of bytes top copy + LDIR ; copy bytes + RET +; +; LOAD BYTES FROM NVR - INTO HBIOS DCB +; RETURN ZERO IF READ SUCCESS, NON-ZERO IF CANT READ +; +NVSW_READ: + LD B,NVSW_SIZE + 1 ; NUMBER OF BYTES, + 1 for CHECKSUM + LD C,0 ; FIRST Byte address in RTC + LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB) +NVSW_READ1: + PUSH HL ; SAVE ADDRESS + PUSH BC ; Save Loop counter + LD B,BF_RTCGETBYT ; GET RTC BYTE (at a time), requires loop + CALL RTC_DISPATCH ; CALL RTC + POP BC ; Restore Loop + POP HL ; restore Block pointer + RET NZ ; ERROR JUST RETURN + LD (HL),E ; store IT + INC C ; RTC Byte address + INC HL ; HL address + DJNZ NVSW_READ1 ; LOOP to the next byte +NVSW_READ2: + LD A,(CB_SWITCHES) ; FIRST BYTE + CP 'W' ; MUST BE 'W' + RET ; ZERO IF OK, NON-ZERO IF ISSUE +; +; SAVE BYTES FROM HBIOS DCB - INTO NVR +; RETURN ZERO IF SUCCESS, NON-ZERO IF CANT WRITE +; +NVSW_WRITE: + LD B,NVSW_SIZE + 1 ; NUMBER OF BYTES, + 1 for CHECKSUM + LD C,0 ; FIRST Byte address in RTC + LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB) +NVSW_WRITE1: + PUSH HL ; SAVE ADDRESS + PUSH BC ; Save Loop counter + LD E,(HL) ; Value to Write + LD B,BF_RTCSETBYT ; SET RTC BYTE + CALL RTC_DISPATCH ; CALL RTC + POP BC ; Restore Loop + POP HL ; restore Block pointer + RET NZ ; ERROR JUST RETURN + INC C ; RTC Byte address + INC HL ; HL address + DJNZ NVSW_WRITE1 ; LOOP, One Byte at a Time +NVSW_WRITE2: + XOR A ; SUCCESS + RET ; ZERO IF OK, NON-ZERO IF ISSUE +; +; DEFAULT VALUES FOR NVRAM, USED TO RESET NVR +; +NVSW_DEFAULT: + .DB 'W' ; Signature Byte + .DB 'H' ; Default Boot - Rom Application [H]elp + .DB DBOOT_ROM ; Default Boot - ROM Application + .DB 0 ; Auto Boot - NO auto boot + ; Configure above byte from (BOOT_TIMEOUT != -1) +; SIZE OF NVR BYTES +NVSW_SIZE .EQU $ - NVSW_DEFAULT +; HB_INTFUNC_END .EQU $ ; ;================================================================================================== diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index 78ac0aca..bac1c903 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -120,6 +120,8 @@ BF_SYSGET_VDACNT .EQU $40 ; GET VDA UNIT COUNT BF_SYSGET_VDAFN .EQU $41 ; GET VDA UNIT FN/DATA ADR BF_SYSGET_SNDCNT .EQU $50 ; GET VDA UNIT COUNT BF_SYSGET_SNDFN .EQU $51 ; GET SND UNIT FN/DATA ADR +; +BF_SYSGET_SWITCH .EQU $C0 ; GET NON VOLITILE SWITCH VALUE BF_SYSGET_TIMER .EQU $D0 ; GET CURRENT TIMER VALUE BF_SYSGET_SECS .EQU $D1 ; GET CURRENT SECONDS VALUE BF_SYSGET_BOOTINFO .EQU $E0 ; GET BOOT INFORMATION @@ -130,6 +132,7 @@ BF_SYSGET_CPUSPD .EQU $F3 ; GET CLOCK SPEED & WAIT STATES BF_SYSGET_PANEL .EQU $F4 ; GET FRONT PANEL SWITCHES VAL BF_SYSGET_APPBNKS .EQU $F5 ; GET APP BANK INFORMATION ; +BF_SYSSET_SWITCH .EQU $C0 ; SET NON VOLITILE SWITCH VALUE BF_SYSSET_TIMER .EQU $D0 ; SET TIMER VALUE BF_SYSSET_SECS .EQU $D1 ; SET SECONDS VALUE BF_SYSSET_BOOTINFO .EQU $E0 ; SET BOOT INFORMATION @@ -140,6 +143,38 @@ 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 ; +; 2 BYTE FUNCTION/SUBFUNCTION : BC_ => BIOS CALL +; e.g. LOAD BC, BC_SYSxxxx (avoid load B and C seperately) +; +BC_SYSGET_CIOCNT .EQU BF_SYSGET * $100 + BF_SYSGET_CIOCNT +BC_SYSGET_CIOFN .EQU BF_SYSGET * $100 + BF_SYSGET_CIOFN +BC_SYSGET_DIOCNT .EQU BF_SYSGET * $100 + BF_SYSGET_DIOCNT +BC_SYSGET_DIOFN .EQU BF_SYSGET * $100 + BF_SYSGET_DIOFN +BC_SYSGET_RTCCNT .EQU BF_SYSGET * $100 + BF_SYSGET_RTCCNT +BC_SYSGET_DSKYCNT .EQU BF_SYSGET * $100 + BF_SYSGET_DSKYCNT +BC_SYSGET_VDACNT .EQU BF_SYSGET * $100 + BF_SYSGET_VDACNT +BC_SYSGET_VDAFN .EQU BF_SYSGET * $100 + BF_SYSGET_VDAFN +BC_SYSGET_SNDCNT .EQU BF_SYSGET * $100 + BF_SYSGET_SNDCNT +BC_SYSGET_SNDFN .EQU BF_SYSGET * $100 + BF_SYSGET_SNDFN +; +BC_SYSGET_SWITCH .EQU BF_SYSGET * $100 + BF_SYSGET_SWITCH +BC_SYSGET_TIMER .EQU BF_SYSGET * $100 + BF_SYSGET_TIMER +BC_SYSGET_SECS .EQU BF_SYSGET * $100 + BF_SYSGET_SECS +BC_SYSGET_BOOTINFO .EQU BF_SYSGET * $100 + BF_SYSGET_BOOTINFO +BC_SYSGET_CPUINFO .EQU BF_SYSGET * $100 + BF_SYSGET_CPUINFO +BC_SYSGET_MEMINFO .EQU BF_SYSGET * $100 + BF_SYSGET_MEMINFO +BC_SYSGET_BNKINFO .EQU BF_SYSGET * $100 + BF_SYSGET_BNKINFO +BC_SYSGET_CPUSPD .EQU BF_SYSGET * $100 + BF_SYSGET_CPUSPD +BC_SYSGET_PANEL .EQU BF_SYSGET * $100 + BF_SYSGET_PANEL +BC_SYSGET_APPBNKS .EQU BF_SYSGET * $100 + BF_SYSGET_APPBNKS +; +BC_SYSSET_SWITCH .EQU BF_SYSSET * $100 + BF_SYSSET_SWITCH +BC_SYSSET_TIMER .EQU BF_SYSSET * $100 + BF_SYSSET_TIMER +BC_SYSSET_SECS .EQU BF_SYSSET * $100 + BF_SYSSET_SECS +BC_SYSSET_BOOTINFO .EQU BF_SYSSET * $100 + BF_SYSSET_BOOTINFO +BC_SYSSET_CPUSPD .EQU BF_SYSSET * $100 + BF_SYSSET_CPUSPD +BC_SYSSET_PANEL .EQU BF_SYSSET * $100 + BF_SYSSET_PANEL +; CIO_CONSOLE .EQU $80 ; CIO UNIT NUM FOR CUR CON ; ; PRIMARY HARDWARE PLATFORMS @@ -302,6 +337,21 @@ SW_DISK .EQU %00010000 ; DISK/ROM SW_FLOP .EQU %00001000 ; FLOP/HD SW_OPT .EQU %00000111 ; SLICE/ROM APP ; +; NVRAM SWITCHES +; +; used for identifying Non Volitile Switches +NVSW_DEFBOOT .EQU 1 ; Default Boot NVRAM Switch +NVSW_AUTOBOOT .EQU 3 ; Auto Boot NVRAM Switch +; +; NVRAM SWITCH BIT MASKS +; +; AUTO BOOT MASKS +ABOOT_AUTO .EQU %00100000 ; AUTO=1/MANUAL=0 BOOT +ABOOT_TIMEOUT .EQU %00001111 ; MENU TIMEOUT IN SECONDS, 0=IMMEDIAGE +; DEFAULT BOOT MASKS +DBOOT_ROM .EQU %10000000 ; ROM=1/DISK=0 FLAG +DBOOT_UNIT .EQU %01111111 ; DISK UNIT +; ; MEDIA ID VALUES ; MID_NONE .EQU 0 @@ -460,6 +510,9 @@ HCB_BOOTMODE .EQU $14 ; HBIOS BOOTMODE (BYTE) HCB_HEAP .EQU $20 ; DWORD ADDRESS OF START OF HEAP HCB_HEAPTOP .EQU $22 ; DWORD ADDRESS OF TOP OF HEAP ; +HCB_SW_DBOOT .EQU $31 ; DEFAULT BOOT CONFIG (WORD) +HCB_SW_AUTOB .EQU $33 ; AUTO BOOT CONFIG (BYTE) +; ; MEMORY BANK IDS (ONE BYTE EACH) HCB_BIDCOM .EQU $D8 ; COMMON BANK (UPPER 32K) HCB_BIDUSR .EQU $D9 ; USER BANK (TPA) diff --git a/Source/HBIOS/hbios_new.asm b/Source/HBIOS/hbios_new.asm new file mode 100644 index 00000000..b34b2e1b --- /dev/null +++ b/Source/HBIOS/hbios_new.asm @@ -0,0 +1,9722 @@ +; +;================================================================================================== +; 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). +; +; - 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 AUX RAM +; BANK AND LAUNCHED AFTER HBIOS HAS INSTALLED ITSELF. +; +; - IMGBOOT: BOOT FROM AN IMAGE FILE THAT HAS BEEN PLACED IN THE USER BANK +; +; NOTE: THIS BOOT MODE IS DEPRECATED. +; +; 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 FILE NESTING: +; +; - std.asm +; - ../ver.inc +; - build.inc +; - Config/_std.asm +; - cfg_.asm +; - cfg_MASTER.asm +; - hbios.inc +; - [z180.inc] +; - [z280.inc] +; - [eipc.inc] +; - util.asm +; - time.asm +; - bcd.asm +; - decode.asm +; - encode.asm +; - [xio.asm] +; - [mio.asm] +; - [unlzsa2s.asm] +; - .asm +; - .asm +; +; MEMORY LAYOUT: +; +; DESCRIPTION START LENGTH +; ----------------------------- ------- ------- +; Page Zero 0x0000 0x0100 +; HBIOS Control Block 0x0100 0x0100 +; Proxy Image 0x0200 0x0200 +; Entry Vectors / Stack 0x0400 0x0100 +; Interrupt Vector Table 0x0500 Varies +; System Initialization Varies Varies +; Function Dispatching Varies Varies +; Z280 Int Vector Table Varies Varies +; System API Varies Varies +; Internal Functions Varies Varies +; Utility Functions Varies Varies +; Print Summary Function Varies Varies +; Hardware Drivers Varies Varies +; Font Data Varies Varies +; HBIOS Data Varies Varies +; +; AUXILIARY CONTROL REGISTER +; -------------------------- +; +; SBC/MK4 N8 MBC VDP MBC PSG RPH DUO +; ------------ ------------ ------------ ------------ ------------ ------------ +; D7 ~ROM_ENABLE ~ROM_ENABLE +; D6 TTL1_RTS TTL1_RTS +; D5 PSG_GPIO PSG_GPIO PSG_GPIO ~STATUS_LED PSG_GPIO +; D4 ~PSG_RES ~PSG_RES ~PSG_RES ROM_A19 ~PSG_RES +; D3 STATUS_LED STATUS_LED VDP_LED PSG_LED ROM_A18 PSG_LED +; D2 VDP_A14 VDP_A14 ROM_A17 VDP_LED +; D1 ~VDP_SYN ~VDP_SYN ROM_A16 +; D0 ~VDP_RES ~VDP_RES VDP_RES ROM_A15 VDP_RES +; +; PORT SCG:0x9C 0x94 VDP:0x92 PSG:0xA2 0x80 MEDIA:0xA6 +; +#DEFINE HBIOS +; +; IF BUILDING FULL BOOT ROM, INCLUDE INFO MACROS +; +#IFDEF ROMBOOT + #DEFINE BNKINFO + #DEFINE MEMINFO + #DEFINE DEVINFO + #DEFINE SYSINFO +#ENDIF +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT, IMGBOOT IS DEFINED. +; +MODCNT .EQU 0 +BOOTMODE .EQU 0 +; +#IFDEF ROMBOOT +BOOTMODE .SET BM_ROMBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +; +#IFDEF APPBOOT +BOOTMODE .SET BM_APPBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +; +#IFDEF IMGBOOT ; *** DEPRECATED *** +BOOTMODE .SET BM_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 +; +; CONTROLS PRINTING OF DEVICE INFORMATION IN ASSEMBLY OUTPUT +; +#IFDEF DEVINFO + #DEFINE DEVECHO .ECHO +#ELSE + #DEFINE DEVECHO \; +#ENDIF +; +; CONTROLS PRINTING OF MEMORY USAGE INFORMATION IN ASSEMBLY OUTPUT +; +#IFDEF MEMINFO + #DEFINE MEMECHO .ECHO +#ELSE + #DEFINE MEMECHO \; +#ENDIF +; +SUPCTS .EQU FALSE ; SUPPRESS CTS DURING HBIOS BOOT +; +; HELPER MACROS +; +; SET FRONT PANEL LEDS +; +#IF (FPLED_ENABLE) + #DEFINE FPLEDS(N) PUSH AF + #DEFCONT \ LD A,N + #IF (FPLED_INV) + #DEFCONT \ XOR $FF ; INVERT BITS IF NEEDED + #ENDIF + #DEFCONT \ EZ80_IO + #DEFCONT \ OUT (FPLED_IO),A + #DEFCONT \ POP AF +#ELSE + #DEFINE FPLEDS(N) \; +#ENDIF +; +; SET DIAGNOSTIC LEDS +; +; SCxxx: LED Port=0x0E, bit 2, inverted, dedicated port (LEDMODE_SC) +; SC7xx/SC5xx: LED Port=0x0E, bit 0, inverted, dedicated port (LEDMODE_STD) +; TinyZ80: LED Port=0x6E, bit 0, inverted, dedicated port (LEDMODE_STD) +; Z80-512K: LED Port=0x6E, bit 0, inverted, dedicated port (LEDMODE_STD) +; MBC: LED Port=0x70, bits 1-0, normal, shared w/ RTC port (LEDMODE_RTC) +; DUO: LED Port=0x94, bits 1-0, normal, shared w/ RTC port (LEDMODE_RTC) +; S100: LED Port = $0E, bit 2, inverted, dedicated port (LEDMODE_SC) +; NABU: LED Port = $00, bits 5-3, normal, shared w/ control port (LEDMODE_NABU) +; +#IF (LEDENABLE) + #IF (LEDMODE == LEDMODE_STD) + #DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,~N + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF + #IF (LEDMODE == LEDMODE_SC) + #DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,+(((~N) << 2) & %00000100) + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF + #IF (LEDMODE == LEDMODE_RTC) + #DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,(HB_RTCVAL) + #DEFCONT \ AND %11111100 + #DEFCONT \ OR (N & %00000011) + #DEFCONT \ LD (HB_RTCVAL),A + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF + #IF (LEDMODE == LEDMODE_NABU) + #DEFINE DIAG(N) PUSH AF + ;#DEFCONT \ LD A,+((N << 3) & %00011000) + #DEFCONT \ LD A,+((N << 3) & %00111000) + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF +#ELSE + #DEFINE DIAG(N) \; +#ENDIF +; +; HANDLE SYSTEM CHECK ERRORS +; +#DEFINE SYSCHKERR(HB_ERR) \ + #DEFCONT \ CALL SYSCHKA + #DEFCONT \ LD A,HB_ERR + #DEFCONT \ OR A +; +; THE HB_EI AND HB_DI MACROS ARE USED TO GENERATE THE APPROPRIATE +; INTERRUPT ENABLE/DISABLE CODE DEPENDING ON THE INTERRUPT MODE +; BEING USED. +; +#IF (INTMODE == 0) + ; NO INTERRUPT HANDLING + #DEFINE HB_DI ; + #DEFINE HB_EI ; +#ELSE + #IF (CPUFAM == CPU_Z280) + #IF (INTMODE == 3) + ; Z280 MODE 3 INTERRUPT HANDLING (INTA, C/T 0, & UART RCVR ENABLED) + #DEFINE HB_DI DI + #DEFINE HB_EI EI $0B + #ELSE + ; Z280 MODE 1/2 INTERRUPT HANDLING + #DEFINE HB_DI DI + #DEFINE HB_EI EI + #ENDIF + #ELSE + #DEFINE HB_DI DI + #DEFINE HB_EI EI + #ENDIF +#ENDIF +; +; CONSISTENCY CHECKS +; +#IF (INTMODE > 3) + .ECHO "*** ERROR: INVALID INTMODE SETTING!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +#IF (INTMODE == 3) + #IF (CPUFAM != CPU_Z280) + .ECHO "*** ERROR: INTMODE 3 REQUIRES Z280 FAMILY CPU!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF + #IF (MEMMGR != MM_Z280) + .ECHO "*** ERROR: INTMODE 3 REQUIRES Z280 MEMORY MANAGER!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF +#ENDIF +; +#IF (MEMMGR == MM_Z280) + #IF (INTMODE != 3) + .ECHO "*** ERROR: Z280 MEMORY MANAGER REQUIRES INTMODE 3!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF + #IF (CPUFAM != CPU_Z280) + .ECHO "*** ERROR: Z280 MEMORY MANAGER REQUIRES Z280 FAMILY CPU!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF +#ENDIF +; +; CONVERT ROMWBW LOGICAL BANK ID TO PHYSICAL 32K BANK OFFSET +; +#DEFINE PBANK(X) (((X >> 7) * (RAMBIAS / 32)) + (X & $7F)) +; +; CONVERT ROMWBW LOGICAL BANK ID TO Z280 PHYSICAL BANK (4K) OFFSET +; +#DEFINE Z2_BANK(X) (PBANK(X) << 3) +; +; RTC LATCH +; +; MANY OF THE ROMWBW SYSTEMS USE A LATCH PORT PRIMARILY FOR BIT +; BANGING A DS-1302 RTC. HOWEVER, SINCE THE RTC ONLY NEEDS A COUPLE +; BITS, THE OTHER BITS OF THE LATCH ARE FREQUENTY USED FOR OTHER +; PURPOSES (LEDS, SD CARD BIT BANGING, ETC.). SEE DSRTC.ASM FOR +; A SUMMARY OF THE WAY THE RTC LATCH BITS ARE USED IN THE VARIOUS +; ROMWBW SYSTEMS. IT IS CRITICAL THAT WHEN MANIPULATING THE RTC +; LATCH THAT BITS ARE NOT FLIPPED INADVERTENTLY. THE RTC LATCH IS +; TYPICALLY WRITE-ONLY, SO WE NEED TO MAINTAIN A SHADOW COPY. +; THE SHADOW COPY IS CALLED HB_RTCVAL AND IS DECLARED AT THE END OF +; THIS FILE IN THE DATA AREA. +; +; INITIALIZING THE HB_RTCVAL SHADOW IS TRICKY BECAUSE DIFFERENT BITS +; ARE MANAGED IN DIFFERENT DRIVERS. TO HANDLE THIS, +; THE RTCDEF EQUATE IS INITIALIZED HERE AND UPDATED BY DRIVER INCLUDES +; THAT SHARE THE RTC LATCH. AS EACH DRIVER FILE IS INCLUDED, IT CAN +; USE .SET TO MODIFY THE DEFAULT VALUE OF ANY BITS THEY OWN. +; SINCE RTCDEF IS CHANGED *AFTER* IT NEEDS TO BE USED BY THE CODE, IT +; SHOULD NOT BE USED DIRECTLY TO SET THE LATCH. INSTEAD, THE FINAL VALUE +; OF RTCDEF IS USED TO INITIALIZE A STORAGE BYTE CALLED RTCDEFVAL AT +; THE END OF THIS FILE. SO (RTCDEFVAL) CAN BE USED ANYWHERE IN +; HBIOS.ASM TO ACCESS THE FINAL RTCDEF VALUE. IN MOST PLACES, THE +; SHADOW COPY (RTCVAL) SHOULD BE USED TO GET THE CURRENT VALUE OF THE +; LATCH AND MAINTAIN ALL BIT CHANGES. +; +RTCDEF .EQU 0 ; INIT DEF RTC LATCH VALUE +; +; THE SC126 HAS AN I2C CIRCUIT AND THERE IS NO ASSOCAITED +; DRIVER, SO WE SET THAT BIT HERE. IT IS SET FOR ALL OF THE SCXXX +; SYSTEMS, BUT IS UNUSED ON ALL BUT THE SC126. IT DOES NO HARM. +; +#IF (PLATFORM == PLT_SCZ180) +RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT +#ENDIF +; +; MBC PLATFORM IMPLEMENTS DYNAMIC SPEED SWITCH ON RTC LATCH +; BIT 3. SET THE BIT TO LOW SPEED AS DEFAULT HERE. +; +#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC)) +RTCDEF .SET RTCDEF & ~%00001000 ; INITIAL SPEED LOW +#ENDIF +; +; DUODYNE PLATFORM IMPLEMENTS DYNAMIC SPEED SWITCH ON RTC LATCH +; BIT 3. SET THE BIT TO LOW SPEED AS DEFAULT HERE. +; +#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC)) +RTCDEF .SET RTCDEF | %00001000 ; INITIAL SPEED LOW +#ENDIF +; +; EMIT FRONT PANEL CONFIGURATION TO ASSEMBLY OUTPUT +; +#IF (FPLED_ENABLE | FPSW_ENABLE) + DEVECHO "FP: " + #IF (FPLED_ENABLE) + DEVECHO "LEDIO=" + DEVECHO FPLED_IO + #ENDIF + #IF (FPLED_ENABLE & FPSW_ENABLE) + DEVECHO ", " + #ENDIF + #IF (FPSW_ENABLE) + DEVECHO "SWIO=" + DEVECHO FPSW_IO + #ENDIF + DEVECHO "\n" +#ENDIF + +#INCLUDE "ez80instr.inc" + +; +;================================================================================================== +; Z80 PAGE ZERO, VECTORS, ETC. +;================================================================================================== +; + .ORG 0 +; +HB_PGZERO_BEG .EQU $ +; +#IFNDEF APPBOOT +; + .FILL (000H - $),0FFH ; RST 0 + JP HB_START + .DB 0 ; SIG PTR STARTS AT $0004 + .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) + CALL HBX_INT ; HANDLE IM1 INTERRUPTS + .DB $10 << 2 ; USE SPECIAL VECTOR #16 + #ELSE + RET ; 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, ", ", CONFIG, ", ", TIMESTAMP, 0 +AUTH .DB "WBW",0 +DESC .DB "Copyright (C) 2024, Wayne Warthen, GNU GPL v3", 0 +; + .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO +; +#ENDIF +; + .ORG $100 +; +HB_PGZERO_END .EQU $ +; +;================================================================================================== +; HBIOS CONFIGURATION BLOCK (HCB) +;================================================================================================== +; + .ORG HCB_LOC +; +HB_HCB_BEG .EQU $ +; +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 +; +CB_DIAGLVL .DB DIAGLVL ; ROMWBW HBIOS DIAGNOSTIC LEVEL +CB_BOOTMODE .DB BOOTMODE ; HBIOS BOOTMODE +; +; MEMORY MANAGEMENT VARIABLES START AT $20 +; + .FILL (HCB + $20 - $),0 +; +CB_HEAP .DW 0 +CB_HEAPTOP .DW 0 +; +; SWITCHES SHADOW COPY (FROM RTC/NVR) START AT $30 +; + .FILL (HCB + $30 - $),0 +; +; First byte (header) of NVRAM = "W" if fully initialised, or a ststus byte +; = 0 if no NVRAM detected, or = 1 If NVR exists, but not configured +CB_SWITCHES .DB 'W' ; this byte is set during init +; +; Byte 0: (L) +; Bit 7-0 DISK BOOT SLice Number to Boot -> default = 0 +; Bit 7-0 ROM BOOT (alpha character) Application to boot -> default = "H" +; Byte 1: (H) +; Bit 7 - ROM/DISK - Rom or Disk Boot -> Default=ROM=1 (BOOT_DEFAULT is Numeric/Alpha) +; Bit 6-0 - DISK BOOT Disk Unit to Boot (0-127) -> default = 0 +CB_SWDEFBOOT .DB 'H' ; (WORD) DEFAULT BOOT NVR OPTIONS. USED By ROMLDR + .DB DBOOT_ROM ; Default Boot - ROM Application +; +; Byte 0: (L) +; Bit 7-6 - Reserved +; Bit 5 - AUTO BOOT Auto boot, default=false (BOOT_TIMEOUT != -1) +; Bit 4 - Reserved +; Bit 3-0 - BOOT_TIMEOUT in seconds (0-15) 0=immediate -> default=3 +CB_SWAUTOB .DB 0 ; AUTO BOOT NVR OPTIONS. USED By ROMLDR +; +; CHECKSUM +CB_SWITCHCK .DB 0 ; CHECKSUM (XOR=0), INCLUDES HEADER and CB_VERSION +; +; STANDARD BANK ID'S START AT $D8. DEFAULT VALUES FOR 512KB SYSTEM WITH NO RESERVED BANKS +; + .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_RAMD_BNKS .DB RAMD_BNKS +CB_BIDROMD0 .DB BID_ROMD0 +CB_ROMD_BNKS .DB ROMD_BNKS +CB_BIDAPP0 .DB BID_APP0 +CB_APP_BNKS .DB APP_BNKS +; + .FILL (HCB + HCB_SIZ - $),0 ; PAD REMAINDER OF HCB +; +HB_HCB_END .EQU $ +; +;================================================================================================== +; 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 +; +HB_PROXY_BEG .EQU $ +; + .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 (64 BYTES) +; HBIOS PROXY CODE $FF60 (64 BYTES) +; HBIOS PROXY COPY BUFFER $FFA0 (64 BYTES) +; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) +; +; DEFINITIONS +; +HBX_BUFSIZ .EQU $40 ; INTERBANK COPY BOUNCE 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 +; +; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR +; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE. +; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO +; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S +; USE WILL NEVER OVERLAP WITH BELOW. +; +; WARNING: HBX_INVOKE IS *NOT* REENTRANT! +; +HBX_INVOKE: +; +#IF (INTMODE == 0) + ; IF SOMETHING IN USERLAND ENABLES INTERRUPTS AND WE ARE NOT + ; CONFIGURED TO USE THEM, THEN SHUT THEM BACK OFF AGAIN FOR + ; SAFETY. + DI +#ENDIF +; +#IF (HBIOS_MUTEX == TRUE) + PUSH HL ; SAVE HL + LD HL,HB_LOCK ; POINT TO LOCK + SRA (HL) ; TEST/ACQUIRE MUTEX LOCK + JR C,$-2 ; KEEP TRYING ON FAILURE + POP HL ; RESTORE HL +#ENDIF +; +#IF (MEMMGR == MM_Z280) +; + LD A,(HB_CURBNK) ; GET CURRENT BANK + LD (HB_INVBNK),A ; SAVE INVOCATION BANK +; + LD A,BID_BIOS ; HBIOS BANK + LD (HB_CURBNK),A ; SET AS CURRENT BANK +; + SC HB_DISPATCH +; + PUSH AF + LD A,(HB_INVBNK) + LD (HB_CURBNK),A + POP AF +; +#ELSE +; + LD (HBX_INVSP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK +; + LD A,(HB_CURBNK) ; GET CURRENT BANK + LD (HB_INVBNK),A ; SAVE INVOCATION BANK +; + 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_BUF_END ; BORROW HBX_BUF FOR TEMP STACK + 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 +; +#ENDIF +; +#IF (HBIOS_MUTEX == TRUE) + PUSH HL ; SAVE HL + LD HL,HB_LOCK ; POINT TO LOCK + LD (HL),$FE ; RELEASE MUTEX LOCK + POP HL ; RESTORE HL +#ENDIF +; + RET ; RETURN TO CALLER +; +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +;; BNKSEL - Switch Memory Bank to Bank in A. +;; AF is destroyed, all other registers are preserved. +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +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 (MEMMGR == MM_SBC) + #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. + OR A ; SET FLAGS + JP P,HBX_ROM ; 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 (MEMMGR == MM_Z2) + +#IF (CPUFAM == CPU_EZ80) + 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_NN_A(MPGSEL_0) ; BANK_0: 0K - 16K + INC A ; + OUT_NN_A(MPGSEL_1) ; BANK_1: 16K - 32K + RET ; DONE + +#ELSE + + 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 + #IF (PLATFORM == PLT_DUO) + ADD A,64 ; ADD 64 x 32K - RAM STARTS FROM 2048K + #ELSE + ADD A,ROMSIZE / 32 ; STARTING RAM BANK NUMBER OFFSET + #ENDIF +; +HBX_ROM: + RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K + EZ80_IO() + OUT (MPGSEL_0),A ; BANK_0: 0K - 16K + INC A ; + EZ80_IO() + OUT (MPGSEL_1),A ; BANK_1: 16K - 32K + #IF (CPUFAM == CPU_Z280) + PCACHE + #ENDIF + RET ; DONE +#ENDIF +#ENDIF +; +#IF (MEMMGR == MM_N8) + BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM + JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE +; +HBX_RAM: + AND %00011111 ; AVOID WRAPPING BITS + 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 (MEMMGR == MM_Z180) + 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: + AND %00111111 ; AVOID WRAPPING BITS + 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 +; +#IF (MEMMGR == MM_Z280) + PUSH BC ; SAVE BC + PUSH HL ; SAVE HL + LD B,$00 ; FIRST USER PDR + SC Z280_BNKSEL ; SYSCALL + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_ZRC) + 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,ROMSIZE / 32 ; STARTING RAM BANK NUMBER OFFSET +; +HBX_ROM: + OUT ($1F),A ; HCS WRITE TO THE BANK CONTROL REGISTER + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_MBC) +; + #IF (INTMODE == 1) + LD (HBX_MMA),A ; SAVE ACCUM + LD A,I ; GET INT CTL REG + HB_DI ; DISABLE INTS + PUSH AF ; SAVE INT CTL REG + LD A,(HBX_MMA) ; RESTORE ACCUM + #ENDIF +; + OR A ; SET FLAGS + JP P,HBX_ROM ; BIT 7 INDICATES RAM + OUT (MPCL_ROM),A ; ENSURE ROM PAGE OUT OF MEMORY BEFORE SWITCH + ; SEE MBC BANK SELECT MASK SETUP ROUTINE ABOVE +HBX_MBCMSK .EQU $+1 ; FORCE TOP 32K ; MASK POPULATED + XOR %00000000 ; TO BE IN FIRST CHIP ; DURING INITIALIZATION + OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR + JR HBX_RAMX +HBX_ROM: + OUT (MPCL_RAM),A ; ENSURE RAM PAGE OUT OF MEMORY BEFORE SWITCH + OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR +; +HBX_RAMX: +; + #IF (INTMODE == 1) + POP AF ; RESTORE INT CTL REG + JP PO,$+4 ; WERE INTS DISABLED AT ENTRY? + EI ; *** DO NOT USE HB_EI HERE *** + LD A,(HBX_MMA) ; RESTORE INCOMING ACCUM + #ENDIF +; + RET +; +HBX_MMA .DB 0 ; TEMPORARY STORAGE FOR REG A +#ENDIF +; +#IF (MEMMGR == MM_RPH) + BIT 7,A ; TEST BIT 7 FOR RAM VS. ROM + JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE +; +HBX_RAM: + AND %00011111 ; AVOID WRAPPING BITS + 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,RPH_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 + OUT0 (RPH_ACR),A ; ... IN RPH ACR REGISTER + RET ; DONE +; +HBX_ROM: + OR RPH_DEFACR ; COMBINE WITH DEFAULT BITS + OUT0 (RPH_ACR),A ; BANK INDEX TO RPH ACR REGISTER + XOR A ; ZERO ACCUM + OUT0 (Z180_BBR),A ; ZERO BANK BASE + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_MON) +; +; CURRENTLY ASSUMES FIRST 16 PAGES ARE RAM FOLLOWED BY 16 PAGES OF ROM. +; SO, WE MAP HBIOS BANKS $00-$0F (ROM SELECT) TO $10-$%1F AND HBIOS +; BANKS $80-$8F (RAM SELECT) TO $00-$0F. +; + 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 + OUT ($FF),A ; DO IT + RET ; AND DONE +; +HBX_ROM: + ADD A,$10 ; OFFSET INTO ROM BANKS + OUT ($FF),A ; DO IT + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_Z280) +; +; REG A HAS BANK ID, REG B HAS INITIAL PDR TO PROGRAM +; REGISTERS AF, BC, HL DESTROYED +; +Z280_BNKSEL: + ;; *DEBUG* + ;CALL PC_LBKT + ;CALL PRTHEXBYTE + ;CALL PC_RBKT + + ; SELECT I/O PAGE $FE (SAVING PREVIOUS VALUE) + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL HL,(C) ; GET CURRENT I/O PAGE + PUSH HL ; SAVE IT + LD L,$FF ; NEW I/O PAGE + LDCTL (C),HL ; IMPLEMENT +; + ; CONVERT BANK ID TO TOP 12 BITS OF PHYSICAL ADDRESS + ; WITH $0A IN THE LOW ORDER NIBBLE: + ; BANK ID: R000 BBBB + ; PDR: R000 0BBB B000 1010 (RCBUS) + ; PDR: 0000 RBBB B000 1010 (ZZ80MB) +; + MULTU A,$80 ; HL=0R00 0BBB B000 0000 + BIT 6,H ; RAM BIT SET? + JR Z,Z280_BNKSEL2 ; IF NOT, ALL DONE + RES 6,H ; OTHERWISE, REMOVE RAM BIT + LD A,RAMBIAS >> 6 ; RAM OFFSET (TOP 8 BITS) + OR H ; RECOMBINE + LD H,A ; AND PUT BACK IN H +; +Z280_BNKSEL2: +; + ; SET LOW NIBBLE + LD A,$0A ; VALUE FOR LOW NIBBLE + ADD HL,A ; ADD HL,A ; HL=0000 RBBB B000 1010 +; + ; POINT TO FIRST PDR TO PROGRAM + LD A,B ; INITIAL PDR TO PROG + OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER +; + ; PROGRAM 8 PDRS + LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT + ;LD B,8 ; PROGRAM 8 PDRS + LD A,$10 ; PDR VALUE INCREMENT +Z280_BNKSEL3: + ; PROGRAM 8 PDR VALUES + ; LOOP UNROLLED FOR SPEED + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + OUTW (C),HL ; WRITE VALUE + ADD HL,A ; BUMP VALUE + ;DJNZ Z280_BNKSEL3 ; DO ALL PDRS +; + ; RESTORE I/O PAGE + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + POP HL ; RECOVER ORIGINAL I/O PAGE + LDCTL (C),HL +; + RET +; +Z280_BNKSEL_LEN .EQU $ - Z280_BNKSEL +; +#ENDIF +; +; Z280 SYSCALL VECTOR ENTRY POINT. TAKES STACK PARAMETER AS A BRANCH +; ADDRESS AND CALLS IT. ALLOWS ANY USER MODE CODE TO CALL INTO AN +; ARBITRARY LOCATION OF SYSTEM MODE CODE. +; +#IF (MEMMGR == MM_Z280) +Z280_SYSCALL: + EX (SP),HL + LD (Z280_SYSCALL_GO + 1),HL + POP HL +Z280_SYSCALL_GO: + CALL $FFFF ; PARM SET ABOVE + RETIL ; RETURN FROM INT +#ENDIF +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; Copy Data - Possibly between banks. This resembles CP/M 3, but +; usage of the HL and DE registers is reversed. +; Caller MUST preset HBX_SRCBNK and HBX_DSTBNK. +; IM1/IM2 interrupts are disabled during HBX_BNKCPY. +; Enter: +; HL = Source Address +; DE = Destination Address +; BC = Number of bytes to copy +; Exit : None +; Uses : AF,BC,DE,HL +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKCPY: +#IF (MEMMGR == MM_Z280) + SC Z280_BNKCPYX ; SYSCALL TO BNKCPYX + RET +; +IOPRSAV .DW 0 ; TEMP STORAGE FOR IOPR +; +#ELSE + #IF (CPUFAM == CPU_Z280) + PUSH HL + PUSH BC + LD C,Z280_MSR + LDCTL HL,(C) + POP BC + EX (SP),HL + HB_DI + #ELSE + LD A,I + HB_DI + PUSH AF + #ENDIF + 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 + #IF (CPUFAM == CPU_Z280) + EX (SP),HL ; SAVE HL, RECOVER MSR + PUSH BC ; SAVE BC + LD C,Z280_MSR + LDCTL (C),HL + POP BC ; RECOVER BC + POP HL ; RECOVER HL + #ELSE + POP AF + JP PO,$+4 + EI ; *** DO NOT USE HB_EI HERE *** + #ENDIF + 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 = UPDATED SRC, DE = UPDATED DEST, BC = 0 + RET +#ENDIF +; +; 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 TARGET BANK IS PREPARED FOR THEM. +; ON INPUT A=TARGET BANK, IX=TARGET ADDRESS +; +HBX_BNKCALL: +; +#IF (MEMMGR == MM_Z280) + CP BID_BIOS ; CALLING HBIOS? + JR NZ,HBX_BNKCALL3 ; NOPE, DO NORMAL PROCESSING + SC HBX_BNKCALL2 ; SYSCALL TO BNKCALL2 + RET ; THEN RETURN +; +HBX_BNKCALL2: + HB_EI ; INTS ARE OK + LD (HBX_BNKCALL_GO+1),IX ; SETUP DEST ADR + PCACHE ; CRITICAL!!! +HBX_BNKCALL_GO: + JP $FFFF ; DO THE REAL WORK AND RETURN +#ENDIF +; +HBX_BNKCALL3: + LD (HBX_BNKCALL_BNK+1),A ; STUFF TARGET BANK TO CALL INTO CODE BELOW + LD (HBX_BNKCALL_ADR+1),IX ; STUFF ADDRESS TO CALL INTO CODE BELOW + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; SAVE FOR RETURN +HBX_BNKCALL_BNK: + LD A,$FF ; LOAD BANK TO CALL ($FF OVERLAID AT ENTRY) + CALL HBX_BNKSEL ; ACTIVATE THE NEW BANK +HBX_BNKCALL_ADR: + 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 +; +; THESE ROUTINES ARE NOT INTENDED TO BE CALLED DIRECTLY -- THEY ARE +; HELPERS FOR THE HBIOS API AND ARE CALLED BY HBIOS BANK CODE. THE +; HBIOS BANK CODE BRACKETS THE USE OF THESE ROUTINES WITH DI/EI IF +; NECESSARY FOR THE CURRENT INTERRUPT MODE. +; +; NOTE: THE SIZE OF HBX_TMPSTK (TYPICALLY 20 BYTES) IS INSUFFICIENT FOR +; FREERTOS IF AN INTERRUPT STRIKES WHILE THE TEMPORARY STACK IS ACTIVE. +; BELOW, HBX_BUF HAS BEEN USURPED TO PROVIDE A LARGER TEMP STACK TO +; ACCOMMODATE FREERTOS. HBX_BUF IS ONLY USED AS A BOUNCE BUFFER, SO IT'S +; USE WILL NEVER OVERLAP WITH BELOW. +; +HBX_PEEK: + LD (HBX_PPSP),SP ; SAVE ORIGINAL STACK FRAME + ;;;LD SP,HBX_BUF_END ; BORROW HBX_BUF FOR TEMP STACK + LD SP,HBX_BUF_END - $20 ; BORROW HBX_BUF FOR TEMP STACK + 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_BUF_END ; BORROW HBX_BUF FOR TEMP STACK + LD SP,HBX_BUF_END - $20 ; BORROW HBX_BUF FOR TEMP STACK + LD A,(HB_CURBNK) + PUSH AF + LD A,D + CALL HBX_BNKSEL + LD (HL),E +; +HBX_PPRET: + POP AF +#IF (MEMMGR == MM_Z280) + LD A,(HB_INVBNK) ; SPECIAL CASE FOR Z280 MEM MGR +#ENDIF + CALL HBX_BNKSEL + LD SP,0 ; RESTORE ORIGINAL STACK FRAME +HBX_PPSP .EQU $ - 2 + RET +; +; PRIVATE STACK AT END OF HBIOS CODE +; OCCUPIES SPACE BEFORE IVT +; +#IF (MEMMGR != MM_Z280) +; +; HEATH FRONT PANEL WORK SPACE (4 BYTES) +; + #IF (H8PENABLE) +H8P_MEMLOC: + .DW 0 +H8P_MEMVAL: + .DB 0 +H8P_MEMCPY: + LD HL,(H8P_TICCNT) + LD ($000B),HL + LD HL,(H8P_MEMLOC) + LD A,(HL) + LD (H8P_MEMVAL),A + RET + #ENDIF +; +HBX_INTSTKSIZ .EQU $FF00 - $ + MEMECHO "HBIOS INT STACK space: " + MEMECHO HBX_INTSTKSIZ + MEMECHO " bytes.\n" + .FILL HBX_INTSTKSIZ,$FF +HBX_INTSTK .EQU $ +; + #IF (HBX_INTSTKSIZ < 22) + .ECHO "*** ERROR: INTERRUPT STACK IS TOO SMALL!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF +; +#ENDIF +; +; HBIOS INTERRUPT MODE 2 SLOT ASSIGNMENTS (SEE STD.ASM) +; +; # Z80/Z280 Z180 MBC DUO NABU +; --- -------------- -------------- -------------- -------------- -------------- +; 0 CTC0A INT1 -+ -+ -+ HCCARCV -+ +; 1 CTC0B INT2 | | | HCCASND | +; 2 CTC0C TIM0 | | IM2 | IM2 NABUKB | IM2 +; 3 CTC0D TIM1 | | INT | INT VDP | INT +; 4 UART0 DMA0 | Z180 UART0 | VEC UART0 | VEC OPTCRD0 | VEC +; 5 UART1 DMA1 | CPU UART1 | GEN UART1 | GEN OPTCRD1 | GEN +; 6 CSIO | | | OPTCRD2 | +; 7 SIO0 SER0 | -+ -+ OPTCRD3 -+ +; 8 SIO1 SER1 -+ SIO0 SIO0 +; 9 PIO0A PIO0A SIO1 SIO1 +; 10 PIO0B PIO0B PIO0A PIO0A +; 11 PIO1A PIO1A PIO0B PIO0B +; 12 PIO1B PIO1B CTC0A CTC0A +; 13 SIO0 CTC0B CTC0B +; 14 SIO1 CTC0C CTC0C +; 15 CTC0D CTC0D +; + ; IVT MUST START AT PAGE BOUNDARY + ALIGN($100) +; +HBX_IVT: + .DW HBX_IV00 + .DW HBX_IV01 + .DW HBX_IV02 + .DW HBX_IV03 + .DW HBX_IV04 + .DW HBX_IV05 + .DW HBX_IV06 + .DW HBX_IV07 + .DW HBX_IV08 + .DW HBX_IV09 + .DW HBX_IV0A + .DW HBX_IV0B + .DW HBX_IV0C + .DW HBX_IV0D + .DW HBX_IV0E + .DW HBX_IV0F +; +HBX_IVTCNT .EQU ($ - HBX_IVT) / 2 +; +HBX_IV00: CALL HBX_INT \ .DB $00 << 2 +HBX_IV01: CALL HBX_INT \ .DB $01 << 2 +HBX_IV02: CALL HBX_INT \ .DB $02 << 2 +HBX_IV03: CALL HBX_INT \ .DB $03 << 2 +HBX_IV04: CALL HBX_INT \ .DB $04 << 2 +HBX_IV05: CALL HBX_INT \ .DB $05 << 2 +HBX_IV06: CALL HBX_INT \ .DB $06 << 2 +HBX_IV07: CALL HBX_INT \ .DB $07 << 2 +HBX_IV08: CALL HBX_INT \ .DB $08 << 2 +HBX_IV09: CALL HBX_INT \ .DB $09 << 2 +HBX_IV0A: CALL HBX_INT \ .DB $0A << 2 +HBX_IV0B: CALL HBX_INT \ .DB $0B << 2 +HBX_IV0C: CALL HBX_INT \ .DB $0C << 2 +HBX_IV0D: CALL HBX_INT \ .DB $0D << 2 +HBX_IV0E: CALL HBX_INT \ .DB $0E << 2 +HBX_IV0F: CALL HBX_INT \ .DB $0F << 2 +; +HBX_INT: ; COMMON INTERRUPT ROUTING CODE +; +#IF (INTMODE > 0) +; + #IF (MEMMGR == MM_Z280) +; +; THIS CODE ASSUMES Z280 IM 3. IM 1 AND IM 2 ON Z280 +; DO NOT SAVE MSR AT INTERRUPT MAKING IT VIRTUALLY IMPOSSIBLE +; TO RETURN FROM THE INTERRUPT TO THE CORRECT MODE (SYSTEM +; OR USER). THIS IS BECAUSE THERE IS NO WAY TO KNOW WHETHER +; SYSTEM OR USER MODE WAS ACTIVE AT THE TIME OF THE INTERRUPT. +; + EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET + + ; 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 +; + ; HANDLE INT VIA JP TABLE IN HBIOS + LD L,(HL) ; OFFSET INTO JP TABLE FOR THIS INT + LD H,HB_IVT >> 8 ; MSB OF HBIOS INT JP TABLE + CALL JPHL ; CALL HANDLER VIA INT JP TABLE +; + ; RESTORE STATE + POP IY ; RESTORE IY + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF + POP HL ; RESTORE HL +; + ; BURN THE REASON CODE + EX (SP),HL ; HL TO STK, RC TO HL + POP HL ; RESTORE HL +; + CALL HBX_RETI ; RETI FOR Z80 PERIPHERALS + RETIL +; +HBX_RETI: + RETI +; + #ELSE +; +; COMMON INTERRUPT DISPATCHING CODE +; SETUP AND CALL HANDLER IN BIOS BANK +; + EX (SP),HL ; SAVE HL AND GET INT JP TABLE OFFSET +; + LD (HBX_INT_SP),SP ; SAVE ORIGINAL STACK FRAME + LD SP,HBX_INTSTK ; USE DEDICATED INT 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 +; + LD L,(HL) ; OFFSET INTO JP TABLE FOR THIS INT + LD H,HB_IVT >> 8 ; MSB OF HBIOS INT JP TABLE +; + CALL JPHL ; CALL HANDLER VIA INT JP TABLE +; + LD A,(HB_CURBNK) ; GET PRE-INT BANK + CALL HBX_BNKSEL ; SELECT IT +; + #IF (H8PENABLE) + CALL H8P_MEMCPY + #ENDIF +; + ; 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 +; + +#IF (CPUFAM == CPU_EZ80) + RET.L ; INTERRUPTS WILL BE ENABLED BY BY EZ80 FIRMWARE + ; CAN THEY BE ENABLED HERE - DOES THAT RISK RE-ENTRANT OF THE HANDLER? +#ELSE + HB_EI ; ENABLE INTERRUPTS + RETI ; AND RETURN +#ENDIF + +; + #ENDIF +; +#ELSE +; + RET +; +#ENDIF +; +; SMALL TEMPORARY STACK FOR USE BY HBX_BNKCPY +; +HBX_TMPSTKSIZ .EQU (HBX_XFC - HBX_BUFSIZ - $) + MEMECHO "HBIOS TEMP STACK space: " + MEMECHO HBX_TMPSTKSIZ + MEMECHO " bytes.\n" + .FILL HBX_TMPSTKSIZ,$CC +HBX_TMPSTK .EQU $ +; +; INTERBANK COPY BOUNCE BUFFER (64 BYTES) +; +; N.B., THIS BUFFER IS ALSO USED AS A TEMPORARY STACK BY INVOKE, PEEK, AND POKE. +; THEREFORE, THIS BUFFER *CANNOT* BE USED TO PASS DATA OUTSIDE OF +; HBIOS FUNCTION CALLS. +; +HBX_BUF .FILL HBX_BUFSIZ,0 +HBX_BUF_END .EQU $ +; +; HBIOS PROXY MGMT BLOCK (TOP 32 BYTES) +; + .DB BID_BOOT ; (+0) HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID + .DB $FF ; (+1) HB_INVBNK: BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION + .DW 0 ; (+2) HB_SRCADR: BNKCPY SOURCE ADDRESS + .DB BID_USR ; (+4) HB_SRCBNK: BNKCPY SOURCE BANK ID + .DW 0 ; (+5) HB_DSTADR: BNKCPY DESTINATION ADDRESS + .DB BID_USR ; (+7) HB_DSTBNK: BNKCPY DESTINATION BANK ID + .DW 0 ; (+8) HB_CPYLEN: BNKCPY LENGTH + .DW 0 ; (+10) RESERVED FOR OPTIONAL TICK CTR, PLATFORM DEPENDENT + .DW 0 ; (+12) RESERVED FOR FUTURE HBIOS USE + .DB 0 ; (+14) SHADOW VALUE FOR RTC LATCH PORT + .DB $FE ; (+15) HB_LOCK: HBIOS MUTEX LOCK + JP HBX_INVOKE ; (+16) HB_INVOKE: FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) + JP HBX_BNKSEL ; (+19) HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL + JP HBX_BNKCPY ; (+22) HB_BNKCPY: FIXED ADR ENTRY FOR HBX_BNKCPY + JP HBX_BNKCALL ; (+25) HB_BNKCALL: FIXED ADR ENTRY FOR HBX_BNKCALL + .DW HBX_IDENT ; (+28) ADDRESS OF HBIOS PROXY START (DEPRECATED) + .DW HBX_IDENT ; (+30) HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK +; + .FILL MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) + .ORG HBX_IMG + HBX_SIZ ; RESTORE ORG +; +HB_PROXY_END .EQU $ +; +;================================================================================================== +; ENTRY VECTORS (JUMP TABLE) AND INTERNAL PROCESSING STACK +;================================================================================================== +; +HB_ENTRY_BEG .EQU $ +HB_ENTRYTBL .EQU $ +; + JP HB_START ; HBIOS INITIALIZATION + JP HB_DISPATCH ; VECTOR TO DISPATCHER + JP PRTSUM + ; !!! DO NOT ADD ADDTIONAL VECTORS HERE WITHOUT + ; CHECKING W/ WAYNE !!! +; +HB_STKSIZ .EQU $100 - ($ & $FF) +; + .FILL HB_STKSIZ,$FF ; USE REMAINDER OF PAGE FOR HBIOS STACK +HB_STACK .EQU $ ; TOP OF HBIOS STACK +HB_ENTRY_END .EQU $ +; +;================================================================================================== +; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!) +;================================================================================================== +; +; IM2 INTERRUPTS ARRIVE HERE AFTER BANK SWITCH TO HBIOS BANK +; THE LIST OF JP TABLE ENTRIES MATCHES THE IM2 VECTORS ONE FOR +; ONE. ANY CALL TO THE PRIMARY IVT (HBX_IVT) WILL BE MAPPED TO +; THE CORRESPONDING JP TABLE ENTRY BELOW AFTER THE BANK SWITCH. +; +; NOTE THAT THE LIST IS INITIALLY FILLED WITH CALLS TO HB_BADINT. +; IT IS INTENDED THAT HARDWARE DRIVERS WILL DYNAMICALLY OVERLAY +; THE ADDRESS PORTION OF THE APPROPRIATE JP TO POINT TO THE +; DESIRED INTERRUPT HANDLER DURING THE DRIVERS INITIALIZATION. +; +; NOTE THAT EACH ENTRY HAS A FILLER BYTE OF VALUE ZERO. THIS BYTE +; HAS NO FUNCTION. IT IS JUST USED TO MAKE ENTRIES AN EVEN 4 BYTES. +; +HB_INTVEC_BEG .EQU $ +; +HB_IVT: +HB_IVT00: JP HB_BADINT \ .DB 0 +HB_IVT01: JP HB_BADINT \ .DB 0 +HB_IVT02: JP HB_BADINT \ .DB 0 +HB_IVT03: JP HB_BADINT \ .DB 0 +HB_IVT04: JP HB_BADINT \ .DB 0 +HB_IVT05: JP HB_BADINT \ .DB 0 +HB_IVT06: JP HB_BADINT \ .DB 0 +HB_IVT07: JP HB_BADINT \ .DB 0 +HB_IVT08: JP HB_BADINT \ .DB 0 +HB_IVT09: JP HB_BADINT \ .DB 0 +HB_IVT0A: JP HB_BADINT \ .DB 0 +HB_IVT0B: JP HB_BADINT \ .DB 0 +HB_IVT0C: JP HB_BADINT \ .DB 0 +HB_IVT0D: JP HB_BADINT \ .DB 0 +HB_IVT0E: JP HB_BADINT \ .DB 0 +HB_IVT0F: JP HB_BADINT \ .DB 0 +HB_IVT10: JP HB_IM1INT \ .DB 0 +; +; 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: + 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 +; +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 +; +HB_INTVEC_END .EQU $ +; +;================================================================================================== +; SYSTEM INITIALIZATION +;================================================================================================== +; +HB_SYSINIT_BEG .EQU $ +; +HB_START: +; +#IFDEF APPBOOT + ; THE CODE TO PREPARE FOR AN APPBOOT IS "HIDDEN" IN HB_WRKBUF. + ; WE ARE OPERATING ON THE (MINIMAL) BDOS STACK, BUT THAT + ; SHOULD BE FINE FOR THIS LIMITED ACTIVITY. + CALL HB_APPBOOT ; PREPARE APP BOOT + RET NZ ; RETURN ON ERROR +; +#ENDIF +; +HB_RESTART: +; + DI ; NO INTERRUPTS +#IF (CPUFAM != CPU_EZ80) + IM 1 ; INTERRUPT MODE 1 +#ENDIF +; +#IFDEF APPBOOT +; + ; IF THIS IS AN APPLICATION BOOT, WE CAPTURE THE CURRENT BANK ID + ; AND UPDATE THE PROXY IMAGE. LATER, WHEN THE PROXY IMAGE IS COPIED + ; TO IT'S RUNNING LOCATION AT TOP OF RAM, THE CORRECT HB_CURBNK + ; VALUE WILL BE INSTALLED. NOTE: THE ADDRESSES IN THE PROXY + ; IMAGE ARE FOR IT'S RUNNING LOCATION, SO WE NEED TO USE *MATH* + ; TO DERIVE THE LOCATION OF HB_CURBNK IN THE IMAGE. + LD A,(HB_CURBNK) + LD (HB_CURBNK - HBX_LOC + HBX_IMG),A +; +#ENDIF +; +#IF ((PLATFORM == PLT_DUO) & TRUE) + ; THIS ARBITRARY DELAY SEEMS TO HELP DUODYNE CPU V1.0 SYSTEMS + ; STARTUP CLEANLY. DOUDYNE CPU V1.1 INTRODUCES A RESET + ; SUPERVISOR AND THIS DELAY IS UNNECESSARY. WE DON'T KNOW + ; IF WE ARE ON A V1.1 THOUGH, SO WE ALWAYS DO THE DELAY. + LD HL,0 +BOOTWAIT: + DEC HL + LD A,H + OR L + JR NZ,BOOTWAIT +#ENDIF +; +; EARLY RTC LATCH BYTE INITIALIZATION +; FOR SOME PLATFORMS THIS CONTROLS HI/LO SPEED CIRCUIT +; NOTE: WE WANT TO USE (RTCDEFVAL) HERE, BUT THE Z2 MEMORY +; MANAGER STARTS UP WITH THE FIRST 16K OF ROM MAPPED TO ALL +; 4 16K BANKS OF CPU SPACE. SO, IF RTCDEVFAL IS LOCATED AFTER +; PAST 16K, WE DON'T HAVE ACCESS TO IT. FOR NOW, WE JUST USE +; RTCDEF WHICH IS SUBOPTIMAL, BUT PROBABLY DOES NOT CAUSE ANY +; PROBLEMS. +; + ;LD A,(RTCDEFVAL) ; GET DEFAULT VALUE + LD A,RTCDEF ; DEFAULT VALUE + EZ80_IO() + OUT (RTCIO),A ; SET IT +; +#IF (PLATFORM == PLT_N8) + LD A,N8_DEFACR ; ENSURE N8 ACR + OUT0 (N8_ACR),A ; ... REGISTER IS INITIALIZED +#ENDIF +; +#IF (PLATFORM == PLT_RPH) + LD A,RPH_DEFACR ; ENSURE RPH ACR + OUT0 (RPH_ACR),A ; ... REGISTER IS INITIALIZED +#ENDIF + +; +; INITIALIZE DIAGNOSTIC AND/OR FRONT PANEL LED(S) TO INDICATE THE +; SYSTEM IS ALIVE. WE HAVE NO RAM AT THIS TIME, SO WE CANNOT USE +; THE NORMAL DIAG() OR FPLEDS() MACROS WHICH DEPEND UPON A STACK. +; SO, JUST HACK THE VALUES IN PLACE. +; +#IF (FPLED_ENABLE) + #IF (FPLED_INV) + LD A,~DIAG_01 + #ELSE + LD A,DIAG_01 + #ENDIF +; + EZ80_IO() + OUT (FPLED_IO),A + +#ENDIF +; + +#IF (LEDENABLE) + #IF ((LEDMODE == LEDMODE_STD) | (LEDMODE == LEDMODE_SC)) + XOR A ; LED IS INVERTED, TURN IT ON + #ENDIF + #IF (LEDMODE == LEDMODE_RTC) + ; CAN'T USE (RTCDEFVAL) YET, SEE COMMENTS ABOVE + ;LD A,(RTCDEFVAL) ; DEFAULT LATCH VALUE + LD A,RTCDEF | %00000001 ; LED 0 ON + #ENDIF + #IF (LEDMODE == LEDMODE_NABU) + LD A,%00001000 ; LOW LED BIT ONLY + #ENDIF + OUT (LEDPORT),A +#ENDIF +; +; INITIALIZE SP +; +; WARNING: ALTHOUGH WE ARE INITIALIZING SP HERE, IT IS NOT YET +; SAFE TO PUSH VALUES TO THE STACK BECAUSE SOME PLATFORMS WILL +; NOT YET HAVE RAM MAPPED TO THE UPPER 32K YET! +; + LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY +; +; Z280 BARE METAL INIT +; +#IF (CPUFAM == CPU_Z280) + ; CLEAR THE MASTER STATUS REGISTER + LD C,Z280_MSR ; MASTER STATUS REGISTER + LD HL,$0000 ; SYS MODE, NO INTERRUPTS + LDCTL (C),HL ; DO IT +; + ; SET MAXIMUM I/O WAIT STATES FOR NOW + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER + LD HL,$0033 ; 3 I/O WAIT STATES ADDED + LDCTL (C),HL ; DO IT +; + ; SELECT I/O PAGE $FF FOR INTERNAL SYSTEM REGISTER ACCESS + LD L,$FF ; MMU AND DMA PAGE I/O REG IS $FF + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL (C),HL ; DO IT +; + ; DISABLE MEMORY REFRESH CYCLES + LD A,$08 ; REFRESH DISABLED + OUT (Z280_RRR),A ; DO IT +; + ; INITIALIZE CACHE CONTROL REGISTER + LD A,$20 ; CACHE INSTRUCTIONS, NOT DATA + OUT (Z280_CCR),A ; DO IT +; + ; INITIALIZE TRAP CONTROL REGISTER + LD A,$00 ; ALLOW USER I/O, NO EPU, NO STK WARN + OUT (Z280_TCR),A ; DO IT +; + #IF (MEMMGR == MM_Z280) +; + ; BEFORE ENABLING MMU W/ USER & SYSTEM PAGE TRANSLATION, + ; WE INITIALIZE ALL PDRS. HOWEVER, FOR AN APP + ; BOOT, THE LOW RAM PDRS ARE ALREADY CORRECT AND SHOULD BE + ; LEFT ALONE. +; + ; INITIALIZE ALL OF THE USER PAGE DESCRIPTORS WITH BLOCK MOVE + #IFDEF APPBOOT + LD A,$08 ; FIRST USER PDR IN HI MEM + #ELSE + LD A,$00 ; FIRST USER PDR + #ENDIF + OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER + LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE + LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT + LD B,Z280_PDRCNT ; NUMBER OF PDR ENTRIES TO PROG + OTIRW ; OTIRW PROGS PDRS SEQUENTIALLY +; + ; INITIALIZE ALL OF THE SYSTEM PAGE DESCRIPTORS WITH BLOCK MOVE + #IFDEF APPBOOT + LD A,$18 ; FIRST SYSTEM PDR IN HI MEM + #ELSE + LD A,$10 ; FIRST SYSTEM PDR + #ENDIF + OUT (Z280_MMUPDRPTR),A ; SET THE PDR POINTER + LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE + LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT + LD B,Z280_PDRCNT ; NUMBER OF PDR ENTRIES TO PROG + OTIRW ; OTIRW PROGS PDRS SEQUENTIALLY +; + ; ENABLE MMU (SYSTEM AND USER TRANSLATION) + LD C,Z280_MMUMCR ; MMU MASTER CONTROL REGISTER + LD HL,$BBFF ; ENABLE USER & SYSTEM TRANSLATE + OUTW (C),HL +; + JR Z280_INITZ ; JUMP TO CODE CONTINUATION +; + ALIGN(2) ; WORD ALIGN THE PDR TABLE +; +Z280_BOOTPDRTBL: + #IFNDEF APPBOOT + ; LOWER 32 K (BANKED) + .DW ((Z2_BANK(BID_BOOT) + 0) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 1) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 2) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 3) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 4) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 5) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 6) << 4) | $A + .DW ((Z2_BANK(BID_BOOT) + 7) << 4) | $A + #ENDIF + ; UPPER 32 K (COMMON) + .DW ((Z2_BANK(BID_COM) + 0) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 1) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 2) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 3) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 4) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 5) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 6) << 4) | $A + .DW ((Z2_BANK(BID_COM) + 7) << 4) | $A +; +Z280_PDRCNT .EQU ($ - Z280_BOOTPDRTBL) / 2 +; +Z280_INITZ: +; + #ENDIF +; + ; RESTORE I/O PAGE TO $00 FOR NORMAL USER I/O SPACE + LD L,$00 ; NORMAL I/O REG IS $00 + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL (C),HL +; +#ENDIF +; +; Z180 BARE METAL INIT +; +#IF (CPUFAM == CPU_Z180) + ; SET BASE FOR CPU IO REGISTERS + ; DO NOT USE Z180_ICR FROM Z180.INC BECAUSE THE ICR + ; IS NOT YET AT THE RUNNING LOCATION. AT RESET, THE Z180 + ; REGISTER BASE I/O ADDRESS IS ZERO, SO INITIALLY, ICR IS + ; AT $3F. + LD A,Z180_BASE + OUT0 ($3F),A ; AT RESET, ICR IS AT $3F + + ; DISABLE REFRESH + XOR A + OUT0 (Z180_RCR),A + + ; MASK OFF TIMER INTERRUPTS + XOR A + OUT0 (Z180_TCR),A + OUT0 (Z180_ITC),A + + ; SET DEFAULT CPU CLOCK MULTIPLIERS (XTAL / 2) + ; + ; BILL MCMULLEN REPORTED THAT CMR NEEDS TO BE SET PRIOR TO CCR + ; WHEN USING A CPU FREQUENCY (PHI) THAT IS XTAL * 2. + ; HERE WE ARE SETTING CPU FREQUENCY TO XTAL / 2, BUT JUST + ; FOR GOOD MEASURE, CMR IS SET PRIOR TO CCR BELOW. + ; https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=316&goto=5045&#msg_5045 + XOR A + OUT0 (Z180_CMR),A + OUT0 (Z180_CCR),A + + ; SET DEFAULT WAIT STATES + LD A,$F0 + OUT0 (Z180_DCNTL),A + + #IF ((MEMMGR == MM_Z180) | (MEMMGR == MM_N8) | (MEMMGR == MM_RPH)) + ; Z180 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 +; + ; SET DEFAULT CSIO SPEED (INTERNAL CLOCK, SLOW AS POSSIBLE) + LD A,Z180_CNTR_DEF ; DIV 1280, 14KHZ @ 18MHZ CLK + OUT0 (Z180_CNTR),A + #ENDIF +; +#ENDIF +; +; EIPC BARE METAL INIT +; +#IF (EIPCENABLE) + LD A,(EIPC_WDT_CONST | EIPC_HALT_RUN | EIPC_WDT_P2_22) + OUT (EIPC_WDTMR),A ; CLEAR WDTE BIT (DISABLE WATCHDOG) + LD A,EIPC_DIS_WDT ; DISABLE WDT - SECOND KEY + OUT (EIPC_WDTCR),A + LD A,EIPC_WCR ; SET SYSTEM CONTROL REGISTER POINTER + ; (SCRP) TO POINT TO WAIT STATE + OUT (EIPC_SCRP),A ; CONTROL REGISTER (WCR) + LD A,(EIPC_IO_0WS | EIPC_MEM_OWS | EIPC_OCF_0WS | EIPC_INT_0WS | EIPC_CHAIN_0WS) + OUT (EIPC_SCDP),A ; NO WAIT STATES + LD A,EIPC_MCR ; SET SCRP TO POINT TO MISCELLANEOUS + OUT (EIPC_SCRP),A ; CONTROL REGISTER (MCR) + LD A,EIPC_CLKDIV1 ; DIVIDE CLOCK BY 1, /CS0 DISABLE + OUT (EIPC_SCDP),A ; SET SYSTEM CONTROL DATA PORT (SCDP) +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; PLATFORM MEMORY MANAGEMENT INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; INITIALIZE MEMORY MANAGERS AS NEEDED TO ADDRESS BOOT ROM IN LOW 32K +; AND COMMON RAM IN HIGH 32K. SETUP MMU FOR BANKING IN LOWER 32K. +; +; Z180 MINI-ITX MADNESS TO INITIALIZE THE PPIO. WE HAVE THE MAIN RAM AT +; $8000 AND ROM AT $0 AT THIS POINT AND THE Z180 MMU SET UP. NOW +; GET THE 82C55 PROGRAMMED. +; +#IF (PLATFORM == PLT_EPITX) + ; THE 82C55 IS BRAINDEAD AND FLIPS OUTPUT LINES TO 0 WHEN WE SET + ; THE MODE. WE BOOT WITH THE ROM ENABLED BUT THE RESET WILL ENABLE + ; LOW RAM. SOME MENTAL BACKFLIPS REQUIRED TO MAKE THIS WORK + LD HL,BOOTFLIP + LD DE,$8000 + LD BC,$10 + LDIR + JP $8000 +; +BOOTFLIP: + ; SET THE MODE. ALSO CLEARS ALL THE OUTPUT BITS SO WE BLIP THE + ; I2C, KEYBOARD ETC BUT NOBODY WILL CARE. HOWEVER WE ALSO FLIP + ; TO ALL RAM MODE HENCE THIS IS EXECUTED HIGH + ; A OUT B IN C HIGH IN C LOW IN + LD A,$8B + OUT ($43),A + LD A,$FF + OUT ($40),A + JP ROMRESUME +; +ROMRESUME: + ; THIS WILL GLITCH EXTRAM ON SO WE MUST NOW BE IN ROM + LD A,$8A ; C LOW NOW OUTPUT + OUT ($43),A + LD A,$FF + OUT ($42),A ; EXTRAM OFF, RAM BACK IN, SPI 7 + ; AND DONE. MODE REMAINS THIS WAY FOREVER +; +#ENDIF +; +; SBC AND MBC MMU INITIALIZATION +; +#IF ((MEMMGR == MM_SBC) | (MEMMGR == MM_MBC)) + ; SET PAGING REGISTERS + #IFDEF ROMBOOT + XOR A + OUT (MPCL_RAM),A ; REMOVE RAM FIRST! + OUT (MPCL_ROM),A ; SELECT ROM PAGE 0 + #ENDIF +#ENDIF +; +; ZETA 2 AND DUO MMU INITIALIZATION +; +; ZETA 2 MMU USES 4 16K PAGES TO MAP PHYSICAL MEMORY TO CPU MEMORY. +; HBIOS USES THE LOWER 2 16K PAGES FOR BANKING AND UPPER 2 16K PAGES +; FOR COMMON. NORMALLY, A ZETA 2 BASED SYSTEM WILL CONTAIN 512K OF +; PHYSICAL ROM FOLLOWED BY 512K OF PHYSICAL RAM. DUO USES A PHYSICAL +; ADDRESS SPACE OF 4096K WITH THE FIRST 2048K AS ROM AND THE FOLLOWING +; 2048K AS RAM. THE SIZE OF ROM AND RAM CAN VARY FOR DUO, BUT THE +; RAM BOUNDARY IS ALWAYS AT 2048K. +; +#IF (MEMMGR == MM_Z2) +; + #IFDEF ROMBOOT + ; IF THIS IS A ROM BOOT, SETUP THE FIRST 2 16K MMU REGISTERS + ; TO MAP THE LOWEST 32K OF PHYSICAL ROM TO THE LOW 32K OF + ; CPU ADDRESS SPACE (BANKING AREA). THE FIRST 16K MAPPING IS + ; REDUNDANT BECAUSE WE ARE ALREADY RUNNING IN THIS AREA. THE + ; MAPPING OF THE SECOND 16K IS CRITICAL BECAUSE ALL ZETA 2 + ; MMU REGISTERS WILL BE 0 AT RESET! + + XOR A + EZ80_IO() + OUT (MPGSEL_0),A ; PROG FIRST 16K MMU REGISTER + INC A + EZ80_IO() + OUT (MPGSEL_1),A ; PROG SECOND 16K MMU REGISTER + #ENDIF +; + #IF (PLATFORM == PLT_DUO) + ; DUO HAS VARIABLE RAM SIZE. RAM ALWAYS STARTS AT 2048K. + ; SETUP COMMON RAM FOR HIGHEST 32K OF RAM BASED ON TOTAL RAM. + LD A,128 + (RAMSIZE / 16) - 2 + #ELSE + ; NORMAL ZETA 2 SYSTEM HAS FIXED 512K OF RAM. SETUP COMMON + ; FOR TOP 32K OF THIS. + ;LD A,64 - 2 + LD A,((ROMSIZE + RAMSIZE) / 16) - 2 + #ENDIF +; + EZ80_IO() + OUT (MPGSEL_2),A ; PROG THIRD 16K MMU REGISTER + INC A + EZ80_IO() + OUT (MPGSEL_3),A ; PROG FOURTH 16K MMU REGISTER + ; ENABLE PAGING + LD A,1 + EZ80_IO() + OUT (MPGENA),A ; ENABLE MMU NOW +; + #IF (PLATFORM == PLT_FZ80) + ; REMOVE FPGA ROM MONITOR FROM THE CPU ADDRESS SPACE + LD A,%00000010 + OUT ($07),A + #ENDIF +#ENDIF + +; +;-------------------------------------------------------------------------------------------------- +; PROXY INSTALLATION +;-------------------------------------------------------------------------------------------------- +; +; AT THIS POINT, RAM SHOULD BE AVAILABLE IN THE COMMON BANK +; (TOP 32K). +; +; WE USE THE TWO BYTES IMMEDIATELY BELOW THE PROXY TO STORE A COUPLE +; VALUES TEMPORARILY BECAUSE WE MAY BE OPERATING IN ROM AT THIS POINT. +; (HBX_LOC - 1) = BATCOND, (HBX_LOC - 2) = LOADBANK +; THERE IS NOTHING ON THE STACK AT THIS POINT SO, HERE, WE JUST RESET +; THE STACK TO HBX_LOC - 2. +; + LD SP,HBX_LOC - 2 +; +; CHECK BATTERY BACKUP STATUS BEFORE WE TOUCH RAM (UPPER MEMORY) +; +; IF A DS1210 POWER CONTROLLER IS INSTALLED AND BATTERY BACKUP IS NOT INSTALLED +; OR IS LESS THAN 2V THEN THE DS1210 WILL BLOCK THE *SECOND* RAM ACCESS. +; FAILURE TO COMPLETE TWO RAM ACCESSES BEFORE INSTALLING PROXY WILL RESULT +; IN THE ROM ID BYTES NOT BEING COPIED CORRECTLY AND CP/M APPLICATIONS +; WILL NOT START CORRECTLY WHEN THEY CHECK THE ROM ID VERSION BYTES. +; THE BATTERY CONDITION VALUE IS TEMPORARILY STORED AT HBX_LOC - 1 +; BECAUSE WE ARE CURRENTLY RUNNING IN ROM. AFTER WE TRANSITION HBIOS +; TO RAM, THE VALUE IS MOVED TO IT'S REAL LOCATION AT HB_BATCOND. +; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM. +; + LD HL,HBX_LOC - 1 ; POINT TO BYTE + XOR A ; ZERO MEANS LOW BAT + LD (HL),A ; FIRST RAM ACCESS + INC A ; 1 MEANS BAT OK + LD (HL),A ; SECOND RAM ACCESS (BLOCKED IF BATTERY ISSUE) +; +; INSTALL PROXY IN UPPER MEMORY +; + LD DE,HBX_LOC ; RUNNING LOCATION OF PROXY + LD HL,HBX_IMG ; LOCATION OF PROXY IMAGE + LD BC,HBX_SIZ ; SIZE OF PROXY + LDIR ; COPY IT +; +; NOTIFICATION THAT WE HAVE COMPLETED HARDWARE INIT. +; + FPLEDS(DIAG_02) +; +;-------------------------------------------------------------------------------------------------- +; S100 MONITOR LAUNCH +;-------------------------------------------------------------------------------------------------- +; +; S100 ROM CONTAINS A HARDWARE LEVEL MONITOR IN BANK ID 3 OF ROM. +; IF PORT $75 BIT 1 IS SET (SET IS ZERO), THEN WE IMMEDIATELY +; TRANSITION TO THIS MONITOR. PRIOR TO THE TRANSITION, WE ALSO +; CHECK THE VALUE IN THE Z180 RELOAD REGISTER LOW. IF IT IS ASCII 'W', +; THEN IT MEANS THE S100 MONITOR IS ATTEMPTING TO REBOOT INTO ROMWBW +; HBIOS AND WE ABORT THE TRANSITION TO THE S100 MONITOR. +; +#IF ((PLATFORM == PLT_S100) & TRUE) + ; CHECK S100 BOARD DIP SWITCH, BIT 1 + IN A,($75) ; READ SWITCHES + BIT 1,A ; CHECK BIT 1 + JR NZ,S100MON_SKIP ; IF NOT SET, CONT ROMWBW BOOT +; + ; CHECK RELOAD REGISTER LOW FOR SPECIAL VALUE + IN0 A,(Z180_RLDR1L) ; GET RELOAD REG 1 LOW + CP 'W' ; CHECK FOR SPECIAL VALUE + JR Z,S100MON_SKIP ; IF SO, DO ROMWBW BOOT +; + ; LAUNCH S100 MONITOR FROM ROM BANK 3 + LD A,BID_IMG2 ; S100 MONITOR BANK + LD IX,0 ; EXECUTION RESUMES HERE + CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN + HALT ; WE SHOULD NOT COME BACK HERE! +; +S100MON_SKIP: + ; RESTORE DEFAULT RELOAD REGISTER VALUE (PROBABLY NOT NEEDED) + XOR A + OUT0 (Z180_RLDR1L),A +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; RTC LATCH INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; WE CAN NOW DO THE REAL INITIALIZATION OF THE RTC LATCH BASED ON +; (RTCDEFVAL). AT THIS POINT WE SHOULD HAVE ACCESS TO THE ROM LOCATION +; WHERE RTCDEFVAL IS STORED AND THE PROXY IS INSTALLED IN UPPER RAM +; WHERE WE WILL STORE THE WORKING SHADOW COPY (HB_RTCVAL). +; SEE COMMENTS ABOVE REGARDING THE FUNKY WAY THAT THE RTCDEFVAL IS +; CREATED. +; + + LD A,(RTCDEFVAL) + LD (HB_RTCVAL),A + EZ80_IO() + OUT (RTCIO),A ; SET IT + DIAG(1) ; REAPPLY CURRENT DIAG LED SETUP +; +;-------------------------------------------------------------------------------------------------- +; DYNAMIC RAM SIZER (IN DEVELOPMENT) +;-------------------------------------------------------------------------------------------------- +; +#IFDEF SIZERAM +; +; THIS IS WHERE WE PROBE FOR THE ACTUAL NUMBER OF RAM +; BANKS AVAILABLE IN THE SYSTEM. THE PROBE CODE NEEDS +; TO BE COPIED TO AND RUN FROM THE COMMON RAM BANK. +; + + #IF (MEMMGR == MM_MBC) + ; MBC REQUIRES A BANK SELECT MASK TO BE SETUP IN THE MBC + ; BANK SELECT ROUTINE. HOWEVER, THE MASK IS DERIVED FROM THE + ; TOTAL SIZE OF THE RAM IN THE SYSTEM (SEE MBC BANK SELECT + ; MASK SETUP BELOW). SO, WE HAVE A CATCH-22 + ; HERE FOR MBC. THE DYNAMIC RAM SIZING REQUIRES THE THE MASK + ; AND THE MASK SETUP REQUIRES THE TOTAL RAM SIZE. SO, FOR MBC, + ; WE CAN'T DO DYNAMIC RAM SIZING. +; + .ECHO "*** ERROR: DYNAMIC RAM SIZING NOT POSSIBLE FOR MBC!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF +; + LD DE,$F000 + LD HL,RS_IMAGE + LD BC,RS_LEN + LDIR + CALL RS_START + LD ($FFEA),A ; STASH HERE TO PRINT LATER +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; MBC BANK SELECT MASK SETUP +;-------------------------------------------------------------------------------------------------- +; +; THE MBC RAM BOARD CAN CONTAIN 1 OR 2 RAM CHIPS. THE COMMON RAM BANK IS +; FIXED BY HARDWARE TO BE THE TOP 32K OF THE *FIRST* RAM CHIP. WHEN THERE +; ARE 2 RAM CHIPS INSTALLED, THE HARDWARE WILL THUS PLACE THE COMMON RAM IN +; THE MIDDLE OF PHYSICAL RAM. HBIOS REQUIRES THAT THE COMMON RAM BANK BE +; MAPPED TO THE VERY LAST 32K OF PHYSICAL RAM. THIS IS REQUIRED SO THAT +; THE RAM DISK BANKS CAN BE SEQUENTIAL. TO WORK AROUND THIS, WE USE AN +; XOR MASK THAT IS APPLIED DURING BANK SELECT. THIS MASK WILL FLIP THE +; HIGH ORDER BANK SELECT BIT (WHEN 2 RAM CHIPS ARE USED) SO THAT THE TWO +; RAM CHIPS WIND UP "REVERSED" AND THE FIXED COMMON BANK WINDS UP AT THE +; END OF THE RAM BANKS. THE MASK IS SETUP HERE BASED ON THE NUMBER OF RAM +; CHIPS AND THEIR SIZE. NOTE THAT THE NUMBER OF RAM CHIPS IS INFERRED BY +; THE TOTAL RAM SIZE. A SINGLE CHIP WILL BE EITHER 128K OR 512K. IF THE +; TOTAL RAM SIZE OF THE SYSTEM IS 256K OR 1M, THEN THERE MUST BE TWO CH +; IPS. THE RESULTING BANK SELECT MASK IS INSERTED INTO THE MBC BANK +; SELECT ROUTINE. +; +#IF (MEMMGR == MM_MBC) +; + ; ALTHOUGH DYNAMIC SYSTEM RAM SIZING IS NOT POSSIBLE FOR MBC + ; (SEE COMMENTS ABOVE), WE ARE STILL DOING THE MASK SETUP + ; DYNAMICALLY. THIS IS SIMPLY IN CASE WE EVER FIND A WAY TO + ; DYNAMICALLY SIZE THE RAM IN AN MBC SYSTEM. + ; + ; 128K: %00000000 ; 1 CHIP, FLIP NO BITS + ; 256K: %00000100 ; 2 CHIPS, 8 BANKS, FLIP BIT 2 + ; 512K: %00000000 ; 1 CHIP, FLIP NO BITS + ; 1024K: %00010000 ; 2 CHIPS, 32 BANKS, FLIP BIT 4 + ; + ; IF NUMBER OF RAMBANKS DETECTED FOR MBC IS 4 (128KB) OR + ; 16 (512KB) THEN ZERO THE BANK MASK, OTHERWISE CALCULATE + ; THE BANK MASK AS BANKS/2. +; + LD A,(CB_RAMBANKS) + LD E,A + LD A,%11101011 + AND E + JR Z,MBC_SINGLE + RRA +MBC_SINGLE: + LD (HBX_MBCMSK),A +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; HBIOS TRANSITION TO RAM +;-------------------------------------------------------------------------------------------------- +; +; COPY OURSELVES TO HBIOS BANK IN RAM +; + LD A,(HB_CURBNK) ; GET CURRENT BANK ID + LD (HBX_LOC - 2),A ; SAVE THE LOAD BANK +; + ; CHECK TO SEE IF WE ARE ALREADY RUNNING IN THE HBIOS RAM + ; BANK AND SKIP THE COPY IF SO (DON'T COPY OVER OURSELVES). + ; THIS SITUATION OCCURS ON A ROMLESS STARTUP OR WHEN DOING A + ; FULL RESTART OF A SYSTEM USING THE EXISTING HBIOS COPY. + ; NOTE THAT THIS TEST WORKS BECAUSE BID_BIOS == BID_BOOT + ; IN THESE SCENARIOS. + CP BID_BIOS ; SAME AS BIOS BANK? + JR Z,HB_START1 ; IF SO, SKIP +; + LD (HB_SRCBNK),A ; CURRENT BANK IS SOURCE + LD A,BID_BIOS ; GET BIOS BANK ID + LD (HB_DSTBNK),A ; ... AND MAKE IT THE DESTINATION + LD HL,0 ; START FROM ADDRESS ZERO + LD DE,0 ; SAME FOR DESTINATION + LD BC,$8000 ; COPY ENTIRE 32KB BANK +#IF (MEMMGR == MM_Z280) + ; WE CANNOT USE HBX_BNKCPY FOR Z280 BECAUSE HBX_BNKCPY WILL + ; SYSCALL Z280_BNKCPY. SYSCALL IS NOT SAFE YET BECAUSE THE + ; Z280 IVT ADDRESS HAS NOT BEEN SETUP. + CALL Z280_BNKCPY ; HANDLE Z280 SPECIAL +#ELSE + CALL HBX_BNKCPY ; ELSE NORMAL BANK COPY +#ENDIF +; +; TRANSITION TO HBIOS IN RAM BANK +; +#IF (MEMMGR == MM_Z280) + ; Z280 NEEDS TO BE HANDLED SPECIAL BECAUSE WE ARE SWITCHING + ; THE SYSTEM MODE BANK, NOT THE NORMAL USER MODE BANK. + LD A,BID_BIOS + LD B,$10 ; FIRST SYSTEM PDR + CALL Z280_BNKSEL + JR HB_START1 +#ELSE + ; JUST DOING A BANK CALL TO THE RAM BANK BANK. IF THIS IS A + ; ROMLESS BOOT OR AN IN-PLACE HBIOS RESTART, WE ARE ALREADY + ; RUNNING IN BID_BIOS BANK. HOWEVER, THIS WILL DO NO HARM. + LD A,BID_BIOS ; BIOS BANK ID + LD IX,HB_START1 ; EXECUTION RESUMES HERE + CALL HBX_BNKCALL ; CONTINUE IN RAM BANK, DO NOT RETURN + HALT ; WE SHOULD NOT COME BACK HERE! +#ENDIF +; +; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK +; +HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK +; + ; WE RESET THE STACK HERE BECAUSE WE ARE NOT GOING TO RETURN + ; FROM THE BNKCALL. REMEMBER THAT WE STORED A COUPLE BYTES + ; RIGHT BELOW HBX_LOC, SO THE STACK IS SET TO START JUST BELOW + ; THAT. + LD SP,HBX_LOC - 2 ; RESET STACK +; + ; NOTIFY THAT WE MADE THE TRANSITION! + FPLEDS(DIAG_03) + DIAG(2) +; + ; RECOVER DATA PASSED PRIOR TO RAM TRANSITION + ; (HBX_LOC - 1) = BATCOND + POP HL ; POP 2 BYTES + LD A,H ; GET FIRST BYTE PUSHED + LD (HB_BATCOND),A ; ... AND SAVE AS BAT COND +; +#IF FALSE +; +; POPULATE THE CRITICAL RAM BANK NUMBERS. +; +; ASSUME THAT CB_RAMBANKS IS THE NUMBER OF 32K RAM BANKS THAT HAS BEEN SET EITHER +; AT ASSEMBLY TIME OR BY PROBING THE ACTUAL AVAILABLE MEMORY (NOT IMPLEMENTED YET). +; + LD A,(CB_RAMBANKS) ; CALCULATE TOP RAMBANK + ADD A,BID_RAM0 ; AS FIRST RAMBANK + + DEC A ; #RAMBANKS - 1 +; + LD HL,CB_BIDCOM + LD B,4 +CB_IDS: LD (HL),A ; POPULATE CB_BIDCOM + INC HL ; POPULATE CB_BIDUSR + DEC A ; POPULATE CB_BIDBIOS + DJNZ CB_IDS ; POPULATE CB_BIDAUX +; + LD A,(CB_BIDUSR) + LD (HB_SRCBNK),A ; POPULATE HB_SRCBNK + LD (HB_DSTBNK),A ; POPULATE HB_DSTBNK +; + LD A,BID_RAM0 ; POPULATE CB_BIDRAMD0 ; START RAMBANK + LD (HL),A + INC HL +; + LD A,(CB_RAMBANKS) ; POPULATE CB_BIDRAMDN ; END RAMBANK + DEC A + SUB TOT_RAM_RB + LD (HL),A +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; INTERRUPT MANAGEMENT SETUP +;-------------------------------------------------------------------------------------------------- +; +; SETUP INTERRUPT VECTOR TABLE ADDRESS(ES) AND TRANSITION TO +; OPERATING INTERRUPT MODE. NOTE THAT INTERRUPTS REMAIN +; DISABLED AT THIS POINT. +; +#IF (CPUFAM != CPU_EZ80) +#IF ((INTMODE == 2) | ((INTMODE == 1) & (CPUFAM == CPU_Z180))) + ; 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 (CPUFAM == CPU_Z180) + ; SETUP Z180 IVT + XOR A ; SETUP LO BYTE OF IVT ADDRESS + OUT0 (Z180_IL),A ; ... AND PLACE IN Z180 IL REGISTER + #ENDIF + + #IF (INTMODE == 2) + IM 2 ; SWITCH TO INT MODE 2 + #ENDIF +#ENDIF +; +#IF (MEMMGR == MM_Z280) + ; NOW POINT TO RAM COPY OF Z280 INT/TRAP TABLE + ; HL IS TOP 16 BITS OF PHYSICAL ADDRESS OF IVT + ; IVT *MUST* BE ON A 4K BOUNDARY + LD C,Z280_VPR + LD HL,0 + (((PBANK(BID_BIOS) << 15) + Z280_IVT) >> 8) + LDCTL (C),HL +#ENDIF +; +#IF (INTMODE == 3) +; + ; SETUP Z280 INT A FOR VECTORED INTERRUPTS + LD HL,%0010000000000000 + LD C,Z280_ISR + LDCTL (C),HL +; + ; TRANSITION TO INTERRUPT MODE 3 + IM 3 +; +#ENDIF +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; APPLICATION BOOT INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO AND +; COPY THE PAYLOAD CONTAINING ROMLDR, MONITOR, AND ZSDOS TO AUX BANK. +; +#IFDEF APPBOOT +; + ;;; SHOULD THIS BE DONE FOR AN HBIOS RESTART IN PLACE??? + ; 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) + ; CALL HBX_INT ; HANDLE IM1 INTERRUPTS + ; .DB $10 << 2 ; USE SPECIAL VECTOR #16 + LD A,$CD ; CALL OPCODE + LD ($0038),A + LD HL,HBX_INT ; ADDRESS + LD ($0039),HL + LD A,$10 << 2 ; IM1 VECTOR + LD ($003B),A + #ELSE + ; RETI ($ED, $4D) IF NON-INTERRUPT MODE + LD HL,$0038 + LD (HL),$ED + INC HL + LD (HL),$4D + #ENDIF +; + ; CHECK TO SEE IF THIS IS AN IN-PLACE RESTART. IF SO, + ; WE NEED TO SKIP THE COPY OF THE CONCATENATED OS IMAGES BELOW. + LD A,(HB_RAMFLAG) ; GET THE FLAG + OR A ; TEST IT + JR NZ,HB_START2 ; IF SET, SKIP + DEC A ; SET FLAG + LD (HB_RAMFLAG),A ; SAVE IT +; + ; FOR AN APPLICATION BOOT, WE ALSO COPY THE CONCATENATED OS + ; IMAGES TO THE AUX BANK WHERE WE WILL JUMP TO ROMLDR LATER. + LD A,(HB_CURBNK) ; GET CURRENT BANK ID + LD (HB_SRCBNK),A ; SETUP SOURCE BANK + LD A,BID_AUX ; DEST BANK IS AUX BANK + LD (HB_DSTBNK),A ; SETUP DESTINATION BANK + LD HL,HB_END ; COPY FROM END OF HBIOS + LD DE,0 ; TO START OF TARGET BANK + LD BC,$8000 ; COPY ENTIRE 32KB BANK + CALL HBX_BNKCPY ; ELSE NORMAL BANK COPY + JR HB_START2 ; CONTINUE +; +;;; RELOCATE THIS DATA FIELD +HB_RAMFLAG .DB $00 +; +#ENDIF +; +HB_START2: +; +;-------------------------------------------------------------------------------------------------- +; GENERAL HBIOS INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; CLEAR DISPATCH TABLE ENTRIES +; + XOR A ; ZERO + LD (CIO_CNT),A ; CIO DEVICES + LD (DIO_CNT),A ; DIO DEVICES + LD (VDA_CNT),A ; VDA DEVICES + LD (SND_CNT),A ; SND DEVICES + LD (RTC_DISPACT),A ; RTC DEVICE + LD (DSKY_DISPACT),A ; DSKY DEVICE + LD HL,RTC_DISPERR ; DEFAULT RTC DISPADR + LD (RTC_DISPADR),HL ; SET IT + LD HL,DSKY_DISPERR ; DEFAULT DSKY DISPADR + LD (DSKY_DISPADR),HL ; SET IT +; +; INITIALIZE SOME HCB ENTRIES +; + OR $FF ; $FF TO ACCUM + LD (CB_CRTDEV),A ; RESET CRT DEVICE +; +; CLEAR INTERRUPT VECTOR TABLES +; +; THIS IS REALLY ONLY REQUIRED ON A RESTART, BUT IT DOESN'T HURT TO +; DO IT ALL THE TIME. +; + LD HL,HB_IVT + 1 ; FIRST VECTOR (IM2) + LD B,16 ; CLEAR 16 VECTORS + CALL HB_CLRIVT ; DO IT + LD HL,HB_IM1INT + 1 ; FIRST VECTOR (IM1) + LD B,8 ; CLEAR 8 VECTORS + CALL HB_CLRIVT ; DO IT + XOR A ; ZERO ACCUM + LD (HB_IM1CNT),A ; ... TO CLEAR IM1 VECTOR CNT + LD HL,HB_IM1INT ; POINTER TO START OF IM1 IVT + LD (HB_IM1PTR),HL ; ... TO CLEAR IM1 PTR + + LD HL,HB_TICK + LD (VEC_TICK + 1),HL + LD HL,HB_SECOND + LD (VEC_SECOND + 1),HL + + JR HB_CLRIVT_Z ; DONE, JUMP OVER SUBROUTINE +; +HB_CLRIVT: + LD (HL),HB_BADINT & $FF + INC HL + LD (HL),HB_BADINT >> 8 + INC HL + INC HL + INC HL + DJNZ HB_CLRIVT + RET +; +HB_CLRIVT_Z: +; +; 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 +; + FPLEDS(DIAG_04) +; +;-------------------------------------------------------------------------------------------------- +; CPU TYPE DISCOVERY +;-------------------------------------------------------------------------------------------------- +; +; SOME OF THIS CODE IS DERIVED FROM UNA BY JOHN COFFMAN +; +; 0: Z80 +; 1: Z80180 - ORIGINAL Z180 (EQUIVALENT TO HD64180) +; 2: Z8S180 - ORIGINAL S-CLASS, REV. K, AKA SL1960, NO ASCI BRG +; 3: Z8S180 - REVISED S-CLASS, REV. N, W/ ASCI BRG +; 4: Z8280 +; 5: eZ80 +; + LD HL,0 ; L = 0 MEANS Z80 +; +#IF (CPUFAM == CPU_Z180) +; + ; TEST FOR ORIGINAL Z180 USING MLT + LD DE,$0506 ; 5 X 6 + MLT DE ; DE = 30 IF Z180 + LD A,E ; CHECK IF MULTIPLY HAPPENED + CP 30 + JR NZ,HB_CPU1 ; IT IS A Z80 IF != 30 + INC L ; FLAG Z80180 OR BETTER +; + ; TEST FOR OLDER S-CLASS (REV K) + IN0 A,(Z180_CCR) ; SUPPOSEDLY ONLY ON S-CLASS + INC A ; FF -> 0 + JR Z,HB_CPU1 + INC L ; FLAG Z8S180 REV K (SL1960) OR BETTER +; + ; TEST FOR NEWER S-CLASS (REV N) + ; ON OLDER S-CLASS, ASCI TIME CONSTANT REG DOES NOT EXIST + ; AND WILL ALWYAS READ BACK AS $FF + OUT0 (Z180_ASTC1L),D ; D = 0 AT THIS POINT + IN0 A,(Z180_ASTC1L) ; ASCI TIME CONSTANT REG + INC A ; FF -> 0 + JR Z,HB_CPU1 + INC L ; FLAG Z8S180 REV N W/ ASCI BRG +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + ; TEST FOR Z280 PER ZILOG DOC + LD A,$40 ; INITIALIZE THE OPERAND + .DB $CB,$37 ; THIS INSTRUCTION WILL SET THE S FLAG + ; ON THE Z80 CPU AND CLEAR THE S FLAG + ; ON THE Z280 MPU. + JP M,HB_CPU1 ; IF Z80, SKIP AHEAD + LD L,4 ; WE ARE Z280 +; +#ENDIF +; +HB_CPU1: + LD A,L + LD (HB_CPUTYPE),A +; +;-------------------------------------------------------------------------------------------------- +; EARLY DRIVER INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; SOME DRIVERS NEED TO BE CALLED AS EARLY AS WE CAN ONE AN OPERATING +; ENVIRONMENT IS ESTABLISHED. +; +#IF (CPUFAM == CPU_EZ80) + ; THIS WILL RE-ASSIGN HB_CPUTYPE + CALL EZ80_PREINIT +#ENDIF +#IF (SN76489ENABLE) + ; SN76489 CHIP GENERATES UGLY NOISE AFTER HARDWARE RESET. + ; WE CALL THIS DRIVER'S PREINIT ASAP TO SHUT OFF THE NOISE. + CALL SN76489_PREINIT +#ENDIF +#IF (DSRTCENABLE) + ; THE DSRTC NEEDS TO BE INITIALIZED IN ORDER TO PERFROM THE + ; CPU SPEED DETECTION BELOW. + CALL DSRTC_PREINIT +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; DSKY INITIALIZATION AND ANNOUNCEMENT +;-------------------------------------------------------------------------------------------------- +; +;;;#IF (DSKYENABLE) +#IF (ICMENABLE) + CALL ICM_PREINIT +#ENDIF +#IF (PKDENABLE) + CALL PKD_PREINIT +#ENDIF +; + ;;;; ANNOUNCE OURSELVES ON DSKY + ;;;LD HL,MSG_HBVER + 5 + ;;;LD A,(DSKY_HEXMAP + RMJ) + ;;;OR $80 + ;;;LD (HL),A + ;;;INC HL + ;;;LD A,(DSKY_HEXMAP + RMN) + ;;;OR $80 + ;;;LD (HL),A + ;;;INC HL + ;;;LD A,(DSKY_HEXMAP + RUP) + ;;;LD (HL),A + ;;;LD HL,MSG_HBVER + ;;;LD B,BF_DSKYSHOWSEG + ;;;CALL DSKY_DISPATCH +;;;#ENDIF +#IF (LCDENABLE) + CALL LCD_PREINIT +#ENDIF +#IF (H8PENABLE) + CALL H8P_PREINIT +#ENDIF +#IF (GM7303ENABLE) + CALL GM7303_PREINIT +#ENDIF +; + FPLEDS(DIAG_05) +; +; INIT OSCILLATOR SPEED FROM CONFIG +; +#IF (CPUFAM != CPU_EZ80) + LD HL,CPUOSC / 1000 ; OSC SPD IN KHZ + LD (HB_CPUOSC),HL ; INIT HB_CPUOSC DEFAULT +; + ; ATTEMPT DYNAMIC CPU SPEED DERIVATION + ; NOTE THAT FOR PLATFORMS WITH SOFTWARE SELECTABLE CPU SPEED, + ; THIS IS BEING DONE WITH THE CPU SPEED SET TO THE LOWEST + ; POSSIBLE SETTING. THE FINAL CPU SPEED WILL BE ADJUSTED + ; LATER. +; + CALL HB_CPUSPD ; DYNAMIC CPU SPEED DETECTION + JR NZ,HB_CPU2 ; SKIP AHEAD IF FAILED +; + ; RECORD THE UPDATED CPU OSCILLATOR SPEED +; +#IF ((CPUFAM == CPU_Z180) | (CPUSPDCAP == SPD_HILO) | (PLATFORM=PLT_HEATH)) + ; SPEED MEASURED WILL BE HALF OSCILLATOR SPEED + ; SO RECORD DOUBLE THE MEASURED VALUE + ; FOR HEATH, WE ARE ASSUMING THAT THE CPU SPEED DIVISOR WAS + ; PREVIOUSLY SET TO $01 MEANING HALF OF OSCILLATOR SPEED. + SLA L + RL H +#ENDIF +; + LD (HB_CPUOSC),HL ; RECORD MEASURED SPEED +; +HB_CPU2: +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; FINALIZE OPERATING CPU SPEED +;-------------------------------------------------------------------------------------------------- +; +; TRANSITION TO FINAL DESIRED CPU SPEED FOR THOSE PLATFORMS +; THAT SUPPORT SOFTWARE SELECTABLE CPU SPEED. UPDATE CB_CPUKHZ +; IN HCB AS WE DO THIS. +; + LD HL,(HB_CPUOSC) +#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC)) + #IF (CPUSPDDEF==SPD_HIGH) + ; SET HIGH SPEED VIA RTC LATCH + LD A,(HB_RTCVAL) + OR %00001000 ; SET HI SPEED BIT + LD (HB_RTCVAL),A ; SAVE SHADOW + OUT (RTCIO),A ; IMPLEMENT + ; HL IS ALREADY CORRECT FOR FULL SPEED OPERATION + #ELSE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + #ENDIF +#ENDIF +; +#IF (PLATFORM == PLT_HEATH) + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION +#ENDIF +; +#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC)) + #IF (CPUSPDDEF==SPD_HIGH) + ; SET HIGH SPEED VIA RTC LATCH + LD A,(HB_RTCVAL) + AND ~%00001000 ; CLEAR HI SPEED BIT + LD (HB_RTCVAL),A ; SAVE SHADOW + OUT (RTCIO),A ; IMPLEMENT + ; HL IS ALREADY CORRECT FOR FULL SPEED OPERATION + #ELSE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + #ENDIF +#ENDIF +; +#IF (CPUFAM == CPU_Z180) +; + LD HL,(HB_CPUOSC) ; INIT HL TO CPU OSC FREQ (KHZ) +; + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION +; + #IF (Z180_CLKDIV >= 1) + LD A,(HB_CPUTYPE) ; GET CPU TYPE + CP 2 ; Z8S180 REV K OR BETTER? + JR C,HB_CPU3 ; IF NOT, NOT POSSIBLE! + ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED + LD A,$80 + OUT0 (Z180_CCR),A + ; ADJUST HL TO REFLECT FULL SPEED OPERATION + SLA L + RL H + #ENDIF +; + #IF (Z180_CLKDIV >= 2) + LD A,(HB_CPUTYPE) ; GET CPU TYPE + CP 3 ; Z8S180 REV N OR BETTER? + JR C,HB_CPU3 ; IF NOT, NOT POSSIBLE! + ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED + ; ALSO SET CCR AGAIN BECAUSE OF REPORTS THAT CCR + ; *MUST* BE SET AFTER CMR. + LD A,$80 + OUT0 (Z180_CMR),A ; CPU MULTIPLIER + OUT0 (Z180_CCR),A ; CLOCK DIVIDE + ; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION + SLA L + RL H + #ENDIF +; +HB_CPU3: +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + ; Z280 ALWAYS HALVES THE INPUT OSCILLATOR TO DERIVE + ; ACTUAL CPU SPEED. + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION +#ENDIF +; +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. +; + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT +; +;-------------------------------------------------------------------------------------------------- +; FINALIZE OPERATING WAIT STATES +;-------------------------------------------------------------------------------------------------- +; +; SET OPERATING WAIT STATE CONFIGURATION ON SYSTEMS THAT SUPPORT IT +; +#IF (CPUFAM == CPU_Z180) +; + ; SET FINAL DESIRED WAIT STATES PER CONFIG + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (Z180_DCNTL),A +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + ; SET FINAL DESIRED WAIT STATES PER CONFIG + ; BUS TIMING AND CONFIGURATION REGISTER + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REG + LDCTL HL,(C) + LD A,L ; PUT IN A + AND %00111100 ; CLEAR DC,HM, AND IO FIELDS + OR Z280_INTWAIT << 6 ; SET INT ACK WAIT STATE BITS (DC) + OR Z280_MEMHIWAIT << 2 ; SET HIGH 8MB WAIT STATE BITS (HM) + OR Z280_IOWAIT ; SET I/O WAIT STATE BITS + LD L,A ; BACK TO L + LDCTL (C),HL ; DO IT +; + ; BUS TIMING AND INITIALIZATION REGISTER + LD C,Z280_BTIR ; BUS TIMING AND INIT REG + LDCTL HL,(C) + LD A,L ; PUT IN A + AND %11110011 ; CLEAR LM FIELD + OR Z280_MEMLOWAIT << 2 ; SET LOW 8MB WAIT STATE BITS + LD L,A ; BACK TO L + LDCTL (C),HL ; DO IT +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; SK Z80-512K CLOCK INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +#IF (SKZENABLE) +; +;;; LOCATION OF THIS CODE??? +; + ; SET THE SK Z80-512K UART CLK2 DIVIDER AS + ; CONFIGURED. NOTE THAT THIS IMPLICITLY + ; CLEARS THE WATCHDOG BIT. THE WATCHDOG + ; WILL BE ENABLED LATER IF CONFIGURED. + LD A,SKZDIV ; GET DIVIDER CODE + OUT ($6D),A ; IMPLEMENT IT +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; INITIALIZE SPEED-COMPENSATED DELAY FUNCTIONS +;-------------------------------------------------------------------------------------------------- +; +;;; LOCATION OF THIS CODE??? +; +#IF (CPUFAM != CPU_EZ80) + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; SYSTEM TIMER INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +#IF (PLATFORM == PLT_SBC) +; + #IF (HTIMENABLE) ; SIMH TIMER +; + #IF (INTMODE == 1) + LD HL,HB_TIMINT + CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST + #ENDIF +; + #ENDIF +; +#ENDIF +; +#IF (KIOENABLE) + CALL KIO_PREINIT +#ENDIF +; +#IF (CTCENABLE) + CALL CTC_PREINIT +#ENDIF +; +#IF (PLATFORM == PLT_NABU) + CALL NABU_PREINIT +#ENDIF +; +#IF (CPUFAM == CPU_Z180) +; + #IF (INTMODE > 0) +; + ; FOR NOW, JUST ENABLE THE INT0 PIN WHICH IS GENERALLY + ; EQUIVALENT TO Z80 INTERRUPTS. + LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED + OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER +; + #IF (Z180_TIMER) +; + ; SETUP Z180 TIMER0 INTERRUPT VECTOR IN IVT + LD HL,HB_TIMINT + LD (IVT(INT_TIM0)),HL ; Z180 TIMER 0 + + ; SETUP PERIODIC TIMER INTERRUPT ON TIMER 0 + ; *** THIS ASSUMES A TICKFREQ OF 50HZ!!! *** +; +#IF (TICKFREQ != 50) + .ECHO "TICKFREQ *MUST* BE 50 FOR Z180 TIMER\n" + !!! +#ENDIF +; + ; Z180 PRESCALES THE COUNTER BY 20 SO, + ; RLDR = CPU CLK / 20 / TICKFREQ + ; IF WE ASSUME TICKFREQ = 50, WE CAN SIMPLIFY TO + ; RLDR = CPU CLK / 1000 + ; IF WE DIVIDE BOTH SIDES BY 1000, WE CAN USE + ; CPUKHZ VALUE AND SIMPLIFY TO + ; RLDR = CPUKHZ + XOR A ; ALL BITS ZERO + OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION + LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ + OUT0 (Z180_TMDR0L),L ; INITIALIZE TIMER 0 DATA REGISTER + OUT0 (Z180_TMDR0H),H + DEC HL ; RELOAD OCCURS *AFTER* ZERO + OUT0 (Z180_RLDR0L),L ; INITIALIZE TIMER 0 RELOAD REGISTER + OUT0 (Z180_RLDR0H),H + LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING + OUT0 (Z180_TCR),A +; + #ENDIF +; + #ENDIF +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + #IF (MEMMGR == MM_Z280) +; + #IF (Z280_TIMER) +; +Z280_TC .EQU CPUOSC / 4 / 50 / 2 ; TIME CONSTANT +; + LD HL,Z280_TIMINT + LD (Z280_IVT+$16),HL ; Z280 T/C VECTOR +; + ; SELECT I/O PAGE $FE + LD C,Z280_IOPR ; I/O PAGE REGISTER + LDCTL HL,(C) ; GET CURRENT I/O PAGE + PUSH HL ; SAVE IT + LD L,$FE ; I/O PAGE $FE + LDCTL (C),HL +; + LD A,%10100000 ; CONFIG: C, RE, IE + OUT (Z280_CT0_CFG),A ; SET C/T 0 + LD HL,CPUOSC / 50 / 16 ; TIME CONSTANT & COUNTER + LD C,Z280_CT0_TC ; SET C/T 0 + OUTW (C),HL + LD C,Z280_CT0_CT ; SET C/T 0 + OUTW (C),HL + LD A,%11100000 ; CMD: EN, GT + OUT (Z280_CT0_CMDST),A ; SET C/T 0 +; + ; RESTORE I/O PAGE + LD C,Z280_IOPR ; I/O PAGE REGISTER + POP HL ; RESTORE I/O PAGE + LDCTL (C),HL +; + #ENDIF +; + #ENDIF +; +#ENDIF +; + FPLEDS(DIAG_06) +; +;-------------------------------------------------------------------------------------------------- +; PRE-CONSOLE INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +#IF (WBWDEBUG == USEMIO) ; BUFFER OUTPUT UNTIL + CALL MIO_INIT ; WE GET TO BOOT MESSAGE +#ENDIF +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE + CALL REGDMP +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +; PLATFORM SPECIFIC CODE FOR DETECTING RECOVERY MODE SWITCH +; +#IF (BT_REC_TYPE != BT_REC_NONE) + #IF (BT_REC_TYPE == BT_REC_FORCE) + LD A,1 ; SET FOR RECOVERY MODE + LD (HB_BOOT_REC),A ; SAVE FOR LATER + #ENDIF + #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) + #IF (BT_REC_TYPE == BT_REC_SBC01) + LD A,%00100000 ; DISABLE RTC AND + OUT (RTCIO),A ; DRQ DRIVER READ + IN A,(RTCIO) ; BIT 0 (DRQ). + CPL ; PULLED HIGH + AND 1 ; IS RECOVERY MODE + LD (HB_BOOT_REC),A ; SAVE FOR LATER + #ENDIF + #IF (BT_REC_TYPE == BT_REC_SBC1B) + IN A,(RTCIO) ; RTC PORT, BIT 6 HAS THE + BIT 6,A ; STATE OF CONFIG JUMPER + LD A,1 ; JUMPER INSTALLED + JR Z,SAVE_REC_M ; IS RECOVERY MODE + LD A,0 +SAVE_REC_M: + LD (HB_BOOT_REC),A ; SAVE FOR LATER + #ENDIF + #IF (BT_REC_TYPE == BT_REC_SBCRI) + IN A,($68 + 6) ; UART_MSR MODEM + BIT 6,A ; STATUS REGISTER + LD A,0 ; BIT 6 + JR Z,SAVE_REC_M ; IS RECOVERY MODE + LD A,1 +SAVE_REC_M: + LD (HB_BOOT_REC),A ; SAVE FOR LATER + #ENDIF + #ENDIF +#ENDIF +; + LD DE,HB_PCINITTBL ; POINT TO PRECONSOLE INIT TABLE + LD B,HB_PCINITTBLLEN ; NUMBER OF ENTRIES +; +#IF (BT_REC_TYPE != BT_REC_NONE) + LD A,(HB_BOOT_REC) ; IF WE ARE IN RECOVERY MODE + OR A ; POINT TO THE RECOVER MODE + JR Z,NOT_REC_M0 ; INITIALIZATION TABLE + LD B,HB_PCINITRLEN + LD DE,HB_PCINIT_REC +NOT_REC_M0: +; +#ENDIF +; + ; CYCLE THROUGH THE INITIALIZATION TABLE CALLING THE PRE-INIT + ; ENTRY POINT OF ALL DRIVERS. + CALL CALLLIST ; PROCESS THE PRE-INIT CALL TABLE +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE + CALL REGDMP +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; + FPLEDS(DIAG_07) + DIAG(3) +; +;-------------------------------------------------------------------------------------------------- +; BOOT DELAY +;-------------------------------------------------------------------------------------------------- +; +; IF CONFIGURED, AN ARBITRARY BOOT DELAY IS IMPLEMENTED HERE. THIS IS +; TYPICALLY USED TO DELAY ACCESSING DEVICES THAT WILL NOT BE READY. +; +#IF (BOOT_DELAY > 100) + .ECHO "*** ERROR: INVALID BOOT_DELAY (BOOT_DELAY > 100)!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +#IF (BOOT_DELAY > 0) + LD B,BOOT_DELAY * 2 ; SCALE TO 1/2 SEC +HB_BOOTDLY: + CALL LDELAY ; 1/2 SECOND DELAY + DJNZ HB_BOOTDLY ; LOOP TILL DONE +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; ACTIVATE BOOT CONSOLE +;-------------------------------------------------------------------------------------------------- +; +; PRIOR TO THIS POINT, CONSOLE I/O WAS NOT AVAILABLE UNLESS DIRECTED TO DEBUG OUTPUT I.E. XIO +; NOW THAT HBIOS IS READY, SET THE CONSOLE UNIT TO ACTIVATE CONSOLE I/O +; VIA HBIOS. +; + XOR A ; FAILSAFE VALUE FOR BOOT CONSOLE DEVICE + LD (CB_CONDEV),A ; SAVE IT +; + LD A,(CIO_CNT) ; GET COUNT OF CHAR DEVICES + CP BOOTCON + 1 ; COUNT - (DEVICE + 1) + JR C,HB_CONRDY ; IF TOO HIGH, JUST USE FAILSAFE + LD A,BOOTCON ; GET REQUESTED CONSOLE DEV + LD (CB_CONDEV),A ; SAVE IT +; +HB_CONRDY: +; +; SUPPRESS HARDWARE FLOW CONTROL TEMPORARILY, IF NEEDED. THIS IS +; GENERALLY NOT USED ANYMORE BECAUSE THE UART DRIVER NOW CHECKS FOR +; A VALID CTS SIGNAL AND ADJUSTS AS NEEDED. +; +#IF (SUPCTS) +; +; MOST SERIAL PORTS ARE CONFIGURED WITH HARDWARE FLOW CONTROL ENABLED. +; IF THERE IS A PROBLEM WITH THE CTS SIGNAL, THEN OUTPUT TO THE CONSOLE +; WILL BE STALLED WHICH CAN LEAD A USER TO THINK THE SYSTEM IS TOTALLY +; DEAD WHEN, IN FACT, IT IS JUST WAITING FOR CTS TO BE ASSERTED. ALSO, +; IF THE USER IS BOOTING TO A CRT DEVICE AND DISCONNECTS THE CONSOLE +; SERIAL PORT, THE SYSTEM WILL WAIT FOR RTS AND NEVER BOOT. SO, HERE +; WE SAVE THE ACTIVE CONSOLE CONFIGURATION, THEN TURN OFF HARDWARE +; FLOW CONTROL. THE ORIGINAL CONFIGURATION WILL BE RESTORED BELOW +; PRIOR TO LAUNCING THE ROM LOADER. +; + ; RETRIEVE THE CONFIG FROM THE CONSOLE PORT + LD B,BF_CIOQUERY ; HBIOS QUERY CIO CONFIG + LD A,(CB_CONDEV) ; GET CONSOLE DEVICE + LD (HB_BOOTCONSAV),A ; SAVE IT FOR LATER + LD C,A ; BOOT CONSOLE TO C + CALL HB_DISPATCH ; INTERNAL HBIOS CALL + LD (HB_CONCFGSAV),DE ; SAVE CONFIG + RES 5,D ; CLEAR RTS BIT + LD B,BF_CIOINIT ; HBIOS CIO INIT + LD A,(CB_CONDEV) ; GET CONSOLE DEVICE + LD C,A ; BOOT CONSOLE TO C + CALL HB_DISPATCH ; INTERNAL HBIOS CALL +; +#ENDIF +; +#IF (WBWDEBUG == USEMIO) ; OUTPUT ANY CACHED DEBUG TEXT + LD HL,MIOOUTPTR + LD E,(HL) + INC HL + LD D,(HL) + INC HL +NXTMIO: LD A,(HL) + CALL COUT + INC HL + LD A,L + CP E + JR NZ,NXTMIO + LD A,H + CP D + JR NZ,NXTMIO +; CALL WRITESTR ; WRITESTR WILL WORK WILL ONLY PRINT UP TO FIRST $ +#ENDIF +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE2 + PRTS("DEBUG+IM1INT$") + LD DE,HB_IM1INT + CALL DUMP_BUFFER +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; ANNOUNCE HBIOS +;-------------------------------------------------------------------------------------------------- +; +; DISPLAY A BANNER ON THE BOOT CONSOLE NOW. NOTE THAT WE INTENTIONALLY +; LEAVE INTERRUPTS DISABLED UNTIL A BIT LATER. SINCE INTERRUPTS CAN +; DESTABILIZE A SYSTEM, IT IS DIAGNOSTICALLY USEFUL TO GET SOMETHING +; DISPLAYED BEFORE INTRODUCING INTERRUPTS. IF THE SYSTEM CRASHES +; AFTER DISPLAYING THE BANNER, INTERRUPT INTEGRITY SHOULD BE SUSPECTED. +; + PRTX(STR_BANNER) +; +; DISPLAY HBIOS MUTEX ENABLED MESSAGE +; +#IF (HBIOS_MUTEX == TRUE) + CALL NEWLINE + CALL PRTSTRD + .TEXT "HBIOS MUTEX ENABLED$" +#ENDIF +; +; DISPLAY RECOVERY MODE MESSAGE +; +#IF (BT_REC_TYPE != BT_REC_NONE) + LD A,(HB_BOOT_REC) ; IF WE ARE IN RECOVERY MODE + OR A ; DISPLAY RECOVERY MODE MESSAGE + JR Z,NOT_REC_M2 + CALL NEWLINE + CALL PRTSTRD + .TEXT "RECOVERY MODE$" +#ENDIF +NOT_REC_M2: +; + FPLEDS(DIAG_08) +; +#IF FALSE + LD DE,$0123 + LD HL,$4567 + LD B,BF_DSKYSHOWHEX + CALL DSKY_DISPATCH + CALL LDELAY + CALL LDELAY + LD DE,$89AB + LD HL,$CDEF + LD B,BF_DSKYSHOWHEX + CALL DSKY_DISPATCH + CALL LDELAY + CALL LDELAY +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; IO PORT SCAN +;-------------------------------------------------------------------------------------------------- +; +#IF FALSE +; +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 +; +;-------------------------------------------------------------------------------------------------- +; CPU SPEED DETECTION ALIGNMENT TEST +;-------------------------------------------------------------------------------------------------- +; +#IF FALSE +; +; IF ENABLED, THE CPU SPEED TEST WILL BE REPEATED INDEFINITELY. THIS +; IS USED TO ADJUST THE SPEED DETECTION LOOP. +; +HB_SPDTST: + CALL HB_CPUSPD ; CPU SPEED DETECTION + CALL NEWLINE + LD HL,(CB_CPUKHZ) + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA + JR HB_SPDTST +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; ENABLE INTERRUPTS +;-------------------------------------------------------------------------------------------------- +; + HB_EI ; INTERRUPTS SHOULD BE OK NOW +; +;-------------------------------------------------------------------------------------------------- +; DISPLAY PLATFORM INFORMATION +;-------------------------------------------------------------------------------------------------- +; + CALL NEWLINE2 + PRTX(STR_PLATFORM) +; + LD A,(HB_CPUTYPE) ; GET CPU TYPE + LD DE,HB_CPU_STR ; DISPLAY IT + CALL PRTIDXDEA +; + PRTS(" @ $") + LD HL,(CB_CPUKHZ) + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA + PRTS("MHz$") +; +#IF (CPUFAM == CPU_Z180) + PRTS(" IO=0x$") + LD A,Z180_BASE + CALL PRTHEXBYTE +#ENDIF +; +#IF (CPUFAM == CPU_Z280) + CALL PRTSTRD + .TEXT ", BUS @ $" + LD C,Z280_BTIR ; BUS TIMING AND CTL REG + LDCTL HL,(C) + LD A,L ; MOVE TO A + AND %00000011 ; ISOLATE CS FIELD + LD HL,(CB_CPUKHZ) ; GET CPU SPEED + CP %00000001 ; BUS @ 1/1 + JR Z,HB_Z280BUS ; GOT IT, SHOW IT + SRL H ; DIVIDE + RR L ; ... BY 2 + CP %00000000 ; BUS @ 1/2 + JR Z,HB_Z280BUS ; GOT IT, SHOW IT + SRL H ; DIVIDE + RR L ; ... BY 2 + CP %00000010 ; BUS @ 1/4 + JR Z,HB_Z280BUS ; GOT IT, SHOW IT + PRTS("???$") ; INVALID VALUE + JR HB_Z280BUS1 ; CONTINUE +HB_Z280BUS: + CALL PRTD3M ; PRINT AS DECIMAL WITH 3 DIGIT MANTISSA +HB_Z280BUS1: + PRTS("MHz$") ; SUFFIX +#ENDIF + +#IF (CPUFAM == CPU_EZ80) + CALL EZ80_RPT_FIRMWARE +#ENDIF + +; +;-------------------------------------------------------------------------------------------------- +; DISPLAY CPU CONFIGURATION +;-------------------------------------------------------------------------------------------------- +; + CALL NEWLINE +; +; DISPLAY MEMORY TIMINGS +; +#IF (CPUFAM == CPU_EZ80) + CALL EZ80_RPT_TIMINGS + +#ELSE +#IF (CPUFAM == CPU_Z280) + LD A,Z280_MEMLOWAIT + CALL PRTDECB + LD A,'/' + CALL COUT + LD A,Z280_MEMHIWAIT + CALL PRTDECB + CALL PRTSTRD + .TEXT " MEM W/S, $" +#ELSE + XOR A + #IF (CPUFAM == CPU_Z180) + LD A,Z180_MEMWAIT + #ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " MEM W/S, $" +#ENDIF +#ENDIF ; CPUFAM = CPU_EZ80 +; +; DISPLAY I/O TIMINGS +; +#IF (CPUFAM == CPU_EZ80) + ; ALREADY REPORTED BY DRIVER +#ELSE + LD A,1 +#IF (CPUFAM == CPU_Z180) + LD A,Z180_IOWAIT + 1 +#ENDIF +#IF (CPUFAM == CPU_Z280) + LD A,Z280_IOWAIT + 1 +#ENDIF + CALL PRTDECB + CALL PRTSTRD + .TEXT " I/O W/S$" +#IF (CPUFAM == CPU_Z280) + CALL PRTSTRD + .TEXT ", $" + LD A,Z280_INTWAIT + CALL PRTDECB + CALL PRTSTRD + .TEXT " INT W/S$" +#ENDIF +#ENDIF //CPUFAM = CPU_EZ80 +; +; DISPLAY INTERRUPT MODE +; +#IF (INTMODE > 0) + CALL PRTSTRD + .TEXT ", INT MODE $" + LD A,INTMODE + CALL PRTDECB +#ENDIF +; + CALL PRTSTRD + .TEXT ", $" + CALL PRTSTRD +#IF (MEMMGR == MM_NONE) + .TEXT "NONE$" +#ENDIF +#IF (MEMMGR == MM_SBC) + .TEXT "SBC$" +#ENDIF +#IF (MEMMGR == MM_Z2) + .TEXT "Z2$" +#ENDIF +#IF (MEMMGR == MM_N8) + .TEXT "N8$" +#ENDIF +#IF (MEMMGR == MM_Z180) + .TEXT "Z180$" +#ENDIF +#IF (MEMMGR == MM_Z280) + .TEXT "Z280$" +#ENDIF +#IF (MEMMGR == MM_ZRC) + .TEXT "ZRC$" +#ENDIF +#IF (MEMMGR == MM_MBC) + .TEXT "MBC$" +#ENDIF +#IF (MEMMGR == MM_RPH) + .TEXT "RPH$" +#ENDIF + CALL PRTSTRD + .TEXT " MMU$" +; +;-------------------------------------------------------------------------------------------------- +; DISPLAY MEMORY CONFIGURATION +;-------------------------------------------------------------------------------------------------- +; + CALL NEWLINE + LD HL,ROMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB ROM, $" +; + LD HL,(CB_RAMBANKS) ; GET NUMBER OF BANKS IN L + LD H,0 ; CALCULATE RAM SIZE + ADD HL,HL + ADD HL,HL ; X4 + ADD HL,HL ; X8 + ADD HL,HL ; X16 + ADD HL,HL ; X32 +; + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB RAM$" +; + CALL PRTSTRD + .TEXT ", HEAP=0x$" + LD HL,BNKTOP - HB_END + CALL PRTHEXWORDHL +; +#IFDEF SIZERAM +; + CALL PRTSTRD + .TEXT ", RAMBANKS=0x$" + LD A,($FFEA) + CALL PRTHEXBYTE +#ENDIF +; +#IFDEF TESTING +; + CALL PRTSTRD + .TEXT ", RTCDEF=0x$" + LD A,(RTCDEFVAL) + CALL PRTHEXBYTE +; +#ENDIF +; +#IF 0 +; +; DIAGNOSTIC DISPLAY OF BANK IDS IN HCB +; + CALL PRTSTRD + .TEXT ", BANK IDS:$" + LD DE,CB_BIDCOM + LD A,8 + CALL PRTHEXBUF +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) + CALL NEWLINE + PRTS("Z280: $") + PRTS("MSR=$") + LD C,Z280_MSR ; MASTER STATUS REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("ISR=$") + LD C,Z280_ISR ; INTERRUPT STATUS REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("BTCR=$") + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER + LDCTL HL,(C) + LD A,L + CALL PRTHEXBYTE + CALL PC_SPACE + PRTS("BTIR=$") + LD C,Z280_BTIR ; BUS TIMING AND CONTROL REGISTER + LDCTL HL,(C) + LD A,L + CALL PRTHEXBYTE + CALL PC_SPACE + PRTS("CCR=$") + LD C,Z280_CCR ; CACHE CONTROL REGISTER + LDCTL HL,(C) + LD A,L + CALL PRTHEXBYTE + CALL PC_SPACE + PRTS("TCR=$") + LD C,Z280_TCR ; CACHE CONTROL REGISTER + LDCTL HL,(C) + LD A,L + CALL PRTHEXBYTE +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; ROM CHECKSUM VERIFICATION +;-------------------------------------------------------------------------------------------------- +; +#IFDEF ROMBOOT + #IF (ROMSIZE > 0) +; +; ROM CHECKSUM VERIFICATION +; EACH OF THE FIRST 4 ROM BANKS HAS A CHECKSUM INJECTED SUCH THAT +; A COMPUTED CHECKSUM ACROSS THE ENTIRE BANK SHOULD ALWAYS BE ZERO +; +HB_ROMCK: + CALL NEWLINE + PRTS("ROM VERIFY:$") +; + ; COPY CHECKSUM ROUTINE TO UPPER RAM + LD HL,HB_CKBNK + LD DE,$F000 + LD BC,HB_CKBNKSIZ + LDIR +; + ; TEST FIRST 4 BANKS OF ROM + LD B,4 ; 4 BANKS + LD C,0 ; STARTING AT BANK 0 +HB_ROMCK1: + PUSH BC ; SAVE LOOP CONTROL + CALL $F000 ; TEST THE BANK + CALL PC_SPACE ; FORMATTING + CALL PRTHEXBYTE ; PRINT RESULT + POP BC ; RESTORE LOOP CONTROL + OR A ; SET FLAGS + JR NZ,HB_ROMCK2 ; HANDLE FAILURE + INC C ; NEXT BANK + DJNZ HB_ROMCK1 ; LOOP FOR BANKS + PRTS(" PASS$") ; DISPLAY SUCCESS + JR HB_ROMCKZ ; CONTINUE BOOT +HB_ROMCK2: + PRTS(" FAIL$") ; DISPLAY ERROR + JR HB_ROMCKZ ; CONTINUE BOOT +; +; VERIFY ROM CHECKSUM BANK SPECIFIED IN REG C +; THIS MUST BE COPIED TO UPPER RAM TO RUN +; INTERRUPTS ARE DISABLED SINCE PAGE ZERO VECTOR WILL BE +; SWAPPED OUT. ASSUMES THAT INTERRUPTS ARE ENABLED AT ENTRY. +; +HB_CKBNK: + HB_DI ; SUPPRESS INTERRUPTS + LD A,(HB_CURBNK) ; GET CURRENT BANK + LD E,A ; SAVE IN E + LD A,C ; BANK TO TEST + CALL HBX_BNKSEL ; SELECT BANK IT + LD HL,$7FFF ; START AT BANK END + LD BC,1 ; DECREMENT VALUE + XOR A ; ZERO ACCUM +HB_CKBNK1: + #IF (MEMMGR == MM_Z280) + LD D,A ; WORKING VALUE TO D + LDUD A,(HL) ; GRAB NEXT BYTE FROM USER SPACE + ADD A,D ; ADD NEXT BYTE + #ELSE + ADD A,(HL) ; ADD NEXT BYTE + #ENDIF + OR A ; CLEAR CARRY + SBC HL,BC ; DECREMENT + JR NC,HB_CKBNK1 ; LOOP TILL DONE + PUSH AF ; SAVE RESULT + LD A,E ; BANK TO RESTORE + CALL HBX_BNKSEL ; RESTORE ORIG BANK + POP AF ; RECOVER RESULT + HB_EI ; ALLOW INTERRUPTS AGAIN + RET ; AND DONE +; +HB_CKBNKSIZ .EQU $-HB_CKBNK ; SIZE OF ROUTINE +; +HB_ROMCKZ: +; + #ENDIF +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; LOW RAM BATTERY MESSAGE +;-------------------------------------------------------------------------------------------------- +; +#IF (BATCOND) + LD A,(HB_BATCOND) + OR A + LD DE,STR_LOWBAT + CALL Z,WRITESTR +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; FINAL DEVICE INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; + CALL NEWLINE + +#IF (BT_REC_TYPE != BT_REC_NONE) + LD A,(HB_BOOT_REC) ; IF WE ARE IN RECOVERY MODE + OR A ; POINT TO THE RECOVER MODE + JR Z,NOT_REC_M1 ; INITIALIZATION TABLE + LD B,HB_INITRLEN + LD DE,HB_INIT_REC + JR IS_REC_M1 +#ENDIF + +NOT_REC_M1: + LD B,HB_INITTBLLEN + LD DE,HB_INITTBL +IS_REC_M1: + CALL CALLLIST +; +;-------------------------------------------------------------------------------------------------- +; WATCHDOG ACTIVATION +;-------------------------------------------------------------------------------------------------- +; +; IF WATCHDOG FUNCTIONALITY IS REQUESTED, CHECK TO MAKE SURE +; WE ARE GETTING INTERRUPTS. IF SO, ENABLE THE WATCHDOG. +; +#IF (WDOGMODE != WDOG_NONE) + CALL NEWLINE + PRTS("WDOG: $") + PRTS("MODE=$") + + #IF (WDOGMODE == WDOG_EZZ80) + PRTS("EZZ80$") + #ENDIF + #IF (WDOGMODE == WDOG_SKZ) + PRTS("SKZ$") + #ENDIF +; + PRTS(" IO=0x$") + LD A,WDOGIO + CALL PRTHEXBYTE +; + #IF (WDOGMODE == WDOG_SKZ) + ; SKZ WATCHDOG IS DISABLED EARLY IN BOOT PROCESS + ; HERE, WE ONLY NEED TO ENABLE IT, IF APPROPRIATE + LD HL,(HB_TICKS) ; GET LOW WORD + LD A,H ; CHECK FOR + OR L ; ... ZERO + JR Z,HB_WDOFF ; SKIP IF NOT TICKING + IN A,($6D) ; GET PORT VALUE + SET 5,A ; SET THE WATCHDOG ENABLE BIT + OUT ($6D),A ; ACTIVATE WATCHDOG + #ENDIF +; + PRTS(" ENABLED$") + JR HB_WDZ +; +HB_WDOFF: + PRTS(" DISABLED$") +; +HB_WDZ: +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; HEAP CURB INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; 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 +; +;-------------------------------------------------------------------------------------------------- +; NV-SWITCH INITIALIZATION +;-------------------------------------------------------------------------------------------------- +; +; CALL NVR_INIT +; +;-------------------------------------------------------------------------------------------------- +; FINAL CONSOLE ACTIVATION +;-------------------------------------------------------------------------------------------------- +; +; ON SOME SYSTEMS, THE OPERATING CONSOLE IS DIFFERENT THAT THE BOOT +; CONSOLE. FOR EXAMPLE, IF A VIDEO CONSOLE IS DESIRED. A VIDEO +; CONSOLE CANNOT BE USED AS A BOOT CONSOLE BECAUSE IT WILL NOT BE +; INITIALIZED EARLY ENOUGH. SO, IF DESIRED, WE SWITCH TO THE FINAL +; RUNNING CONSOLE HERE. +; + LD A,(CB_CONDEV) ; GET CURRENT CONSOLE + LD (HB_NEWCON),A ; AND INIT NEW CONSOLE VAR +; +#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_SBC) | (PLATFORM == PLT_ZETA) | (PLATFORM == PLT_ZETA2) | (PLATFORM == PLT_MBC)) + IN A,(RTCIO) ; 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 +; + #IF (PLATFORM == PLT_S100) + IN A,($75) ; GET IO BYTE + AND %00000001 ; ISOLATE CONSOLE BIT + JR NZ,INITSYS3 ; NOT SET, BYPASS CONSOLE SWITCH + #ENDIF +; + #IF (PLATFORM == PLT_FZ80) + ; IOBYTE: XXXXXVVC + ; 00- FORCE ONBOARD VGA/PS2 KBD (FV) + ; --1 FORCE PROPELLER CONSOLE (SCON) + ; 110 NORMAL USB SERIAL BOOT + ; + ; WE ASSUME THAT THE ONBOARD VGA (FV) IS ALWAYS DETECTED AND + ; WILL BE THE CURRENT CRTDEV. SCON IS ASSUMED TO BE THE + ; DEVICE AT CRTDEV + 1. THESE ARE REASONABLE ASSUMPTIONS + ; UNLESS THE DRIVER DETECTION OR DRIVER ORDER IS CHANGED. + IN A,($36) ; GET IO BYTE + AND %00000110 ; ISOLATE BITS + JR Z,HB_CRTACT ; FORCE ONBOARD CRT + IN A,($36) ; GET IO BYTE + AND %00000001 ; ISOLATE BIT + JR Z,INITSYS3 ; NORMAL USB SERIAL BOOT + LD A,(CB_CRTDEV) ; GET CRT DEV + INC A ; SWITCH FROM FV -> SCON + LD (CB_CRTDEV),A ; SAVE IT AND DO CONSOLE SWITCH + #ENDIF +; +HB_CRTACT: + LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE + LD (HB_NEWCON),A ; AND QUEUE TO SWITCH +; +#ENDIF +; +#IF (FPSW_ENABLE) +; +; IF WE HAVE FRONT PANEL SWITCHES, THIS IS THE RIGHT PLACE TO HANDLE +; ANY CONSOLE CHANGE REQUESTS. THE FRONT PANEL HAS TWO SWITCHES +; RELATED TO THIS: 1) CRT/SER, AND 2) SEC/PRI. IF CRT/SER IS SET, +; THEN WE SWITCH TO THE CRT DEVICE (IF THERE IS ONE). IF THE SEC/PRI +; SWITCH IS SET, THEN WE ATTEMPT TO USE THE SECOND SERIAL OR CRT +; DEVICE. +; + PRTS("\r\nFP: IO=0x$") + LD A,FPSW_IO + CALL PRTHEXBYTE +; + CALL FP_DETECT +; + ; IF FP DOESN'T EXIST, BAIL OUT. + LD A,(FPSW_ACTIVE) ; GET FP EXISTENCE FLAG + OR A ; SET FLAGS + JR NZ,HB_FP1 ; IF WE HAVE ONE, CONTINUE +; + ; HANDLE NO FP + PRTS(" NOT PRESENT$") + JR HB_FPZ +; +HB_FP1: + ; WE NOW BELIEVE WE HAVE A VALID SWITCH SETTINGS VALUE. + ; CHECK FOR CRT SWITCH VALUE AND SWITCH TO CRT IF SET. + ; NOTE THAT CB_CRTDEV WILL BE ZERO IF THERE IS NO CRT DEVICE + ; IN THE SYSTEM, SO WE DON'T NEED TO CHECK FOR THE EXISTENCE + ; OF A CRT DEVICE -- IT WILL JUST FAILBACK TO FIRST SERIAL + ; PORT. + PRTS(" SWITCHES=0x$") ; TAG + CALL FP_GETSWITCHES ; GET SWITCH SETTINGS + CALL PRTHEXBYTE ; DISPLAY VALUE + LD B,A ; SAVE IN REG B + AND SW_CRT ; TEST CRT BIT + JR Z,HB_FP2 ; SKIP AHEAD IF NOT SET + LD A,(CB_CRTDEV) ; GET CRT DISPLAY DEVICE + CP $FF ; $FF MEANS NO CRT PRESENT + JR Z,HB_FP2 ; BYPASS IF SO + LD (HB_NEWCON),A ; QUEUE NEW CONSOLE UNIT +; +HB_FP2: + ; IF SEC SWITCH IS SET, WE WANT TO BUMP TO SECONDARY + ; CRT OR SERIAL DEVICE. IF AN OVERRIDE IS SPECIFIED USING + ; SECCON, USE THAT, OTHERWISE INCREMENT THE DEFAULT UNIT. + ; THIS SHOULD WORK ASSUMING NORMAL ORDERING OF THE + ; CHARACTER DEVICE UNITS. + LD A,B ; RECOVER SWITCH SETTINGS + AND SW_SEC ; TEST SEC BIT + JR Z,HB_FPZ ; IF NOT SET, THEN ALL DONE +; + LD A,(CIO_CNT) ; GET CHAR UNIT COUNT + LD B,A ; MOVE TO B + LD A,SECCON ; GET SEC CONSOLE SETTING + CP $FF ; $FF MEANS USE INCREMENT + JR NZ,HB_FP3 ; BYPASS IF NOT $FF +; + ; INCREMENT CONSOLE UNIT + LD A,(HB_NEWCON) ; GET NEW CONSOLE UNIT + INC A ; BUMP TO SECONDARY +; +HB_FP3: + ; MAKE SURE NEW CONSOLE UNIT DOES NOT EXCEED THE HIGHEST + ; CHAR UNIT IN SYSTEM. + CP B ; A (UNIT) >= B (CNT)? + JR NC,HB_FPZ ; ABORT IF UNIT TOO HIGH + LD (HB_NEWCON),A ; UPDATE NEW CONSOLE UNIT +; +HB_FPZ: +; +#ENDIF +; +INITSYS3: +; +#IF (SUPCTS) +; +; RESTORE BOOT CONSOLE CONFIGURATION +; + CALL LDELAY ; ALLOW SERIAL PORT TO FLUSH + LD B,BF_CIOINIT ; HBIOS CIO INIT + LD A,(HB_BOOTCONSAV) ; ORIGINAL BOOT CONSOLE DEVICE + LD C,A ; BOOT CONSOLE TO C + LD DE,(HB_CONCFGSAV) ; SAVED ORIGINAL CONSOLE CFG + CALL HB_DISPATCH ; INTERNAL HBIOS CALL +; +#ENDIF +; +; IF WE ARE GOING TO SWITCH CONSOLES, IT IS IMPLEMENTED HERE. A +; MESSAGE IS PRINTED ON THE OLD CONSOLE INDICATING WHERE THE NEW +; CONSOLE IS AND THE NEW CONSOLE RECEIVES AN HBIOS BANNER. +; + LD A,(HB_BOOTCON) ; GET ORIGINAL BOOT CONSOLE DEV + LD C,A ; PUT IN C + LD A,(HB_NEWCON) ; GET NEW CONSOLE DEVICE + CP C ; COMPARE + JR Z,INITSYS3A ; NO CHANGE, BYPASS +; + LD DE,STR_CONSOLE ; CONSOLE CHANGE NOTIFY + CALL WRITESTR ; PRINT IT + LD A,(HB_NEWCON) ; GET NEW CONSOLE UNIT NUM + CALL PRTDECB ; PRINT UNIT NUM + LD (CB_CONDEV),A ; IMPLEMENT NEW CONSOLE! + LD DE,STR_BANNER ; POINT TO BANNER + CALL NZ,WRITESTR ; OUTPUT IF CONSOLE MOVED +; +;-------------------------------------------------------------------------------------------------- +; PRINT DEVICE SUMMARY +;-------------------------------------------------------------------------------------------------- +; +INITSYS3A: + CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE +; +;-------------------------------------------------------------------------------------------------- +; DIAGNOSTIC ROUTINES +;-------------------------------------------------------------------------------------------------- +; +; DIGANOSTIC ROUTINE TO EXERCISE THE Z280 BNKCPY CODE +; +#IF FALSE +; + CALL NEWLINE + CALL NEWLINE + CALL NEWLINE + + ; SRC & DEST BELOW BND + CALL NEWLINE + LD HL,$4000 + LD DE,$5000 + LD BC,$3000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; SRC & DEST ABOVE BND + CALL NEWLINE + LD HL,$8000 + LD DE,$9000 + LD BC,$1000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; SRC CROSSOVER + CALL NEWLINE + LD HL,$7000 + LD DE,$9000 + LD BC,$2000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; DEST CROSSOVER + CALL NEWLINE + LD HL,$9000 + LD DE,$7000 + LD BC,$2000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; DOUBLE CROSSOVER + CALL NEWLINE + LD HL,$7800 + LD DE,$7000 + LD BC,$2000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; DOUBLE CROSSOVER SINGLE BYTES + CALL NEWLINE + LD HL,$7FFE + LD DE,$7FFF + LD BC,$0500 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + CALL NEWLINE + CALL NEWLINE + CALL NEWLINE +; +#ENDIF +; +; DIAGNOSTIC ROUTINE TO PLAY SERIES OF NOTES +; +#IF FALSE +; + LD HL,0 + CALL DBG_NOTE + LD HL,48 + CALL DBG_NOTE + LD HL,204 + CALL DBG_NOTE + LD HL,268 + CALL DBG_NOTE + LD HL,436 + CALL DBG_NOTE +; + JP INITSYS4 +; +DBG_NOTE: + PUSH HL + CALL NEWLINE + PRTS("AY: $") + CALL PRTDEC16 + PRTS("=$") + CALL AY_NOTE + LD HL,(AY_PENDING_PERIOD) + CALL PRTDEC16 + POP HL +; + PRTS(" SN: $") + CALL PRTDEC16 + PRTS("=$") + CALL SN7_NOTE + LD HL,(SN7_PENDING_PERIOD) + CALL PRTDEC16 +; + RET +; +#ENDIF +; + ; MAKE A LITTLE NOISE... + LD B,BF_SNDBEEP ; HBIOS BEEP FUNCTION + LD C,0 ; SOUND UNIT 0 + LD A,(SND_CNT) ; GET SOUND UNIT COUNT + OR A ; CHECK FOR ZERO + CALL NZ,HB_DISPATCH ; DO IT IF WE HAVE A SOUND UNIT +; +;-------------------------------------------------------------------------------------------------- +; TRANSITION TO USER LAND +;-------------------------------------------------------------------------------------------------- +; +INITSYS4: +; +; IF Z280, WE NEED TO SWITCH TO USER MODE NOW. +; +#IF (MEMMGR == MM_Z280) + ; LEAVE SYSTEM MODE STACK POINTING TO THE RIGHT PLACE + LD SP,HB_STACK ; DEDICATED HBIOS STACK LOC +; + ; ACTIVATE THE CORRECT USER MODE BANK + LD A,(HB_CURBNK) ; GET CURRENT BANK + CALL HBX_BNKSEL ; DO IT +; + ; PRESET THE USER MODE STACK + LD HL,HBX_LOC ; USER STACK JUST BELOW PROXY + LDCTL USP,HL ; DO IT +; + ; SWITCH TO USER MODE NOW + LD C,Z280_MSR ; MASTER STATUS REGISTER + LD HL,$4000 | $0B ; USER MODE W/ NORMAL INT MASK + LDCTL (C),HL ; DO IT +#ENDIF +; + DIAG(0) ; CLEAR BOOT DIAG LED(S) + FPLEDS(DIAG_00) ; CLEAR FP LEDS +; +; CHAIN TO LOADER +; +#IFDEF ROMBOOT + LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK +#ELSE + LD A,BID_AUX ; CHAIN TO AUX BANK +#ENDIF + LD IX,0 ; ENTER AT ADDRESS 0 + CALL HBX_BNKCALL ; GO THERE + HALT ; WE SHOULD NEVER COME BACK! +; +;-------------------------------------------------------------------------------------------------- +; TABLE OF RECOVERY MODE INITIALIZATION ENTRY POINTS +;-------------------------------------------------------------------------------------------------- +; +; USE "CALLDUMMY" IF NO ENTRY REQUIRED +; +#IF (BT_REC_TYPE != BT_REC_NONE) +; +HB_PCINIT_REC: +; + #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) + .DW UART_PREINIT +; .DW CALLDUMMY + #ENDIF +; +HB_PCINITRLEN .EQU (($ - HB_PCINIT_REC) / 2) +; +HB_INIT_REC: +; + #IF ((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) + .DW UART_INIT + .DW MD_INIT + .DW PPIDE_INIT + #ENDIF +; +HB_INITRLEN .EQU (($ - HB_INIT_REC) / 2) +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; TABLE OF PRE-CONSOLE INITIALIZATION ENTRY POINTS +;-------------------------------------------------------------------------------------------------- +; +HB_PCINITTBL: +; +#IF (SSERENABLE) + .DW SSER_PREINIT +#ENDIF +#IF (ASCIENABLE) + .DW ASCI_PREINIT +#ENDIF +#IF (Z2UENABLE) + .DW Z2U_PREINIT +#ENDIF +#IF (UARTENABLE) + .DW UART_PREINIT +#ENDIF +#IF (DUARTENABLE) + .DW DUART_PREINIT +#ENDIF +#IF (SIOENABLE) + .DW SIO_PREINIT +#ENDIF +#IF (EZ80UARTENABLE) + .DW EZUART_PREINIT +#ENDIF +#IF (ACIAENABLE) + .DW ACIA_PREINIT +#ENDIF +#IF (UFENABLE) + .DW UF_PREINIT +#ENDIF +#IF (TMSENABLE) + .DW TMS_PREINIT +#ENDIF + .DW TERM_PREINIT ; ALWAYS DO THIS ONE +#IF (PIOENABLE) + .DW PIO_PREINIT +#ENDIF +#IF (PIO_4P | PIO_ZP) + .DW PIO_PREINIT +#ENDIF +; +HB_PCINITTBLLEN .EQU (($ - HB_PCINITTBL) / 2) +; +;================================================================================================== +; TABLE OF INITIALIZATION ENTRY POINTS +;================================================================================================== +; +HB_INITTBL: +; +#IF (KIOENABLE) + .DW KIO_INIT +#ENDIF +#IF (CTCENABLE) + .DW CTC_INIT +#ENDIF +#IF (PCFENABLE) + .DW PCF_INIT +#ENDIF +;;;#IF (DSKYENABLE) +#IF (ICMENABLE) + .DW ICM_INIT +#ENDIF +#IF (PKDENABLE) + .DW PKD_INIT +#ENDIF +;;;#ENDIF +#IF (LCDENABLE) + .DW LCD_INIT +#ENDIF +#IF (H8PENABLE) + .DW H8P_INIT +#ENDIF +#IF (GM7303ENABLE) + .DW GM7303_INIT +#ENDIF +#IF (PLATFORM == PLT_NABU) + .DW NABU_INIT +#ENDIF +#IF (AY38910ENABLE) + .DW AY38910_INIT ; AUDIBLE INDICATOR OF BOOT START +#ENDIF +#IF (SN76489ENABLE) + .DW SN76489_INIT +#ENDIF +#IF (YM2612ENABLE) + .DW YM2612_INIT +#ENDIF +#IF (SPKENABLE) + .DW SP_INIT ; AUDIBLE INDICATOR OF BOOT START +#ENDIF +#IF (SSERENABLE) + .DW SSER_INIT +#ENDIF +#IF (ASCIENABLE) + .DW ASCI_INIT +#ENDIF +#IF (Z2UENABLE) + .DW Z2U_INIT +#ENDIF +#IF (UARTENABLE) + .DW UART_INIT +#ENDIF +#IF (DUARTENABLE) + .DW DUART_INIT +#ENDIF +#IF (SIOENABLE) + .DW SIO_INIT +#ENDIF +#IF (EZ80UARTENABLE) + .DW EZUART_INIT +#ENDIF +#IF (ACIAENABLE) + .DW ACIA_INIT +#ENDIF +#IF (UFENABLE) + .DW UF_INIT +#ENDIF +#IF (DSRTCENABLE) + .DW DSRTC_INIT +#ENDIF +#IF (DS1501RTCENABLE) + .DW DS1501RTC_INIT +#ENDIF +#IF (BQRTCENABLE) + .DW BQRTC_INIT +#ENDIF +#IF (SIMRTCENABLE) + .DW SIMRTC_INIT +#ENDIF +#IF (INTRTCENABLE) + .DW INTRTC_INIT +#ENDIF +#IF (DS7RTCENABLE) + .DW DS7RTC_INIT +#ENDIF +#IF (DS5RTCENABLE) + .DW DS5RTC_INIT +#ENDIF +#IF (RP5RTCENABLE) + .DW RP5RTC_INIT +#ENDIF +#IF (EZ80RTCENABLE) + .DW EZ80RTC_INIT +#ENDIF +#IF (CPUFAM == CPU_EZ80) + ; INITALISE ONE OF THE SUPPORTED SYSTEM TIMER TICKS DRIVERS + .DW EZ80_TMR_INIT +#ENDIF +#IF (VDUENABLE) + .DW VDU_INIT +#ENDIF +#IF (CVDUENABLE) + .DW CVDU_INIT +#ENDIF +#IF (VGAENABLE) + .DW VGA_INIT +#ENDIF +#IF (GDCENABLE) + .DW GDC_INIT +#ENDIF +#IF (TMSENABLE) + .DW TMS_INIT +#ENDIF +#IF (EFENABLE) + .DW EF_INIT +#ENDIF +#IF (VRCENABLE) + .DW VRC_INIT +#ENDIF +#IF (FVENABLE) + .DW FV_INIT +#ENDIF +#IF (SCONENABLE) + .DW SCON_INIT +#ENDIF +#IF (LPTENABLE) + .DW LPT_INIT +#ENDIF +#IF (PIOENABLE) + .DW PIO_INIT +#ENDIF +#IF (PIO_4P | PIO_ZP) + .DW PIO_INIT +#ENDIF +#IF (DMAENABLE) + .DW DMA_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 (PPAENABLE) + .DW PPA_INIT +#ENDIF +#IF (IMMENABLE) + .DW IMM_INIT +#ENDIF +#IF (SYQENABLE) + .DW SYQ_INIT +#ENDIF +#IF (CHENABLE) + .DW CH_INIT +#ENDIF +#IF (PRPENABLE) + .DW PRP_INIT +#ENDIF +#IF (PPPENABLE) + .DW PPP_INIT +#ENDIF +#IF (ESPENABLE) + .DW ESP_INIT +#ENDIF +; +HB_INITTBLLEN .EQU (($ - HB_INITTBL) / 2) +; +HB_SYSINIT_END .EQU $ +; +;================================================================================================== +; BIOS FUNCTION DISPATCHER +;================================================================================================== +; +HB_DISP_BEG .EQU $ +; +;-------------------------------------------------------------------------------------------------- +; HIGH LEVEL FUNCTION DISPATCHER +;-------------------------------------------------------------------------------------------------- +; +; JUMP TO FUNCTION GROUP SPECIFIC DISPATCHER. THE FUNCTION GROUP +; IS BASED ON THE TOP NIBBLE OF THE FUNCTION NUMBER. +; +; ENTRY: B=FUNCTION +; +HB_DISPATCH: +; +#IF (MEMMGR == MM_Z280) + ; FOR Z280 MEMMGR, WE DISPATCH VIA THE Z280 SYSCALL. + ; THE SYSCALL MECHANISM WILL DISABLE INTERRUPTS. IN + ; GENERAL, INTERRUPTS ARE OK DURING API PROCESSING, + ; SO ENABLE THEM HERE. + HB_EI +#ENDIF +; +; STACK INTEGRITY DIAGNOSTIC CHECK +; +#IF FALSE ; *DEBUG* START +; + CALL HB_DISPATCH1 ; DO THE WORK +; + ; CHECK STACK INTEGRITY + PUSH AF + LD A,(HB_STACK - HB_STKSIZ + $08) + CP $FF + SYSCHKERR(ERR_INTERNAL) + LD A,$FF + LD (HB_STACK - HB_STKSIZ + $08),A + POP AF + RET +; +HB_DISPATCH1: +; +#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_DSKY + $10 ; $30-$3F: DSKY + JP C,DSKY_DISPATCH + CP BF_VDA + $10 ; $40-$4F: VIDEO DISPLAY ADAPTER + JP C,VDA_DISPATCH + CP BF_SND + $10 ; $50-$5F: SOUND DRIVERS + JP C,SND_DISPATCH + ; GAP TO E0 + CP BF_EXT ; SKIP TO BF_EXT VALUE AT $E0 + JR C,HB_DISPERR ; ERROR IF LESS THAN BF_EXT + CP BF_EXT + $10 ; $E0-$EF: EXTENDED + JP C,EXT_DISPATCH + JP SYS_DISPATCH ; OTHERWISE SYS CALL + ; FALL THRU +; +HB_DISPERR: + SYSCHKERR(ERR_NOFUNC) + 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 CIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; SPECIAL HANDLING FOR DEDICATED UNIT CODES +; +CIO_SPECIAL: + ; FOR NOW, ONLY SPECIAL CODE IS A CONSOLE REQUEST + ; SO JUST SWAP IN ACTIVE CONSOLE UNIT + LD A,(CB_CONDEV) ; GET ACTIVE CONSOLE + LD C,A ; OVERLAY UNIT CODE IN C + RET ; AND REJOIN MAIN DISPATCH FLOW +; +; ADD AN ENTRY TO THE CIO UNIT TABLE (SEE HB_ADDENT FOR DETAILS) +; +CIO_ADDENT: + LD HL,CIO_TBL ; POINT TO CIO TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS CHARACTER DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF CIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +CIO_FNCNT .EQU 7 ; NUMBER OF CIO FUNCS (FOR RANGE CHECK) +CIO_MAX .EQU 32 ; UP TO 32 UNITS +CIO_SIZ .EQU CIO_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB CIO_FNCNT ; CIO FUNCTION COUNT (FOR RANGE CHECK) + .DB CIO_MAX ; MAX ENTRY COUNT TABLE PREFIX +CIO_CNT .DB 0 ; ENTRY COUNT PREFIX +CIO_TBL .FILL CIO_SIZ,0 ; SPACE FOR ENTRIES +; +; CRT TYPE CHAR DEVICES CALL THIS TO REGISTER THAT THEY WANT TO BE THE +; DEFAULT CRT DEVICE. THIS ROUTINE WILL SET CB_CRTDEV WHEN CALLED THE +; FIRST TIME. SUBSEQUENT CALLS ARE IGNORED. THIS ENSURES THAT THE +; *FIRST* CRT DEVICE WINS. +; +CIO_SETCRT: + PUSH AF ; SAVE INCOMING CRT DEV NUM + LD A,(CB_CRTDEV) ; GET CURRENT CRT DEV NUM + INC A ; $FF -> $00 + JR NZ,CIO_SETCRT_Z ; IF ALREADY SET, LEAVE IT ALONE + POP AF ; RESTORE AF + LD (CB_CRTDEV),A ; SAVE CRT DEV NUM + RET ; AND DONE +; +CIO_SETCRT_Z: + POP AF ; RESTORE AF + RET ; AND DONE +; +;-------------------------------------------------------------------------------------------------- +; DISK I/O DEVICE FUNCTION DISPATCHER +;-------------------------------------------------------------------------------------------------- +; +; ROUTE CALL TO SPECIFIED DISK I/O DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +DIO_DISPATCH: +; +#IF FALSE ; *DEBUG* START +; + ; DUMP INCOMING CALL + CALL NEWLINE + PRTS("DIO>$") + CALL REGDMP ; DUMP REGS, NONE DESTROYED +; + ; DO THE ACTUAL DISPATCH PROCESSING + CALL DIO_DISPCALL +; + ; DUMP CALL RESULTS AND RETURN + CALL NEWLINE + PRTS("DIO<$") + CALL REGDMP ; DUMP REGS, NONE DESTROYED + RET +; +#ENDIF ; *DEBUG* END +; +DIO_DISPCALL: + PUSH IY ; SAVE INCOMING IY + + LD IY,DIO_TBL ; POINT IY TO START OF DIO TABLE + CALL HB_DISPCALL ; GO TO GENERIC API CALL CODE + + POP IY ; RESTORE IY + RET ; AND DONE +; +; ADD AN ENTRY TO THE DIO UNIT TABLE +; +DIO_ADDENT: + LD HL,DIO_TBL ; POINT TO DIO TABLE + JP HB_ADDENT ; ... AND GO TO COMMON CODE +; +; HBIOS DISK DEVICE UNIT TABLE +; +; TABLE IS BUILT DYNAMICALLY BY EACH DRIVER DURING INITIALIZATION. +; THE TABLE IS PREFIXED BY TWO BYTES. TABLE - 1 CONTAINS THE CURRENT +; NUMBER OF ENTRIES. TABLE - 2 CONTAINS THE MAXIMUM NUMBER OF ENTRIES. +; TABLE - 3 CONTAINS THE NUMBER OF DIO FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +DIO_FNCNT .EQU 12 ; NUMBER OF DIO FUNCS (FOR RANGE CHECK) +DIO_MAX .EQU 16 ; UP TO 16 UNITS +DIO_SIZ .EQU DIO_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB DIO_FNCNT ; DIO FUNCTION COUNT (FOR RANGE CHECK) + .DB DIO_MAX ; MAX ENTRY COUNT TABLE PREFIX +DIO_CNT .DB 0 ; ENTRY COUNT PREFIX +DIO_TBL .FILL DIO_SIZ,0 ; SPACE FOR ENTRIES +; +;-------------------------------------------------------------------------------------------------- +; DISK READ HELPER +;-------------------------------------------------------------------------------------------------- +; +;;; RELOCATE THIS CODE??? +; +; IMPLEMENTS MULTI SECTOR READS AND I/O TO/FROM +; BANKED RAM VIA BOUNCE BUFFER +; +; ON ENTRY: +; TOS=READ FN ADR +; HL=BUF ADR +; E=SEC COUNT +; D=BUF BANK ID +; +HB_DSKREAD: +; + ; THE ACTUAL SECTOR READ FUNCTION ADDRESS IS ON TOS, SAVE IT + EX (SP),HL ; SAVE HL TO TOS, HL := READ FN ADR + LD (HB_DSKFNADR),HL ; IMBED IN CALL OP BELOW + POP HL ; RECOVER HL +; + LD (HB_DSKCMD),BC ; SAVE HBIOS FUNC & UNIT +; +#IF (FPLED_ENABLE & FPLED_DSKACT) + ; SAVE DISK UNIT NUMBER BIT MASK + LD A,C ; GET DISK UNIT NUMBER + LD B,A ; PUT IN B FOR LOOP COUNTER + INC B ; LOOP ONE EXTRA TIME TO HANDLE UNIT=0 + XOR A ; START WITH ACCUM ZERO + SCF ; ... AND CF SET +HB_DSKREAD0: + RLA ; ROTATE BIT + DJNZ HB_DSKREAD0 ; ... UNTIL IN PROPER LOCATION + LD (HB_DSKBIT),A ; SAVE IT FOR DIAGNOSTICS +#ENDIF +; +#IF TRUE + ; CHECK TO SEE IF INTER-BANK I/O NEEDED. + BIT 7,H ; TGT BUF IN UPPER 32K? + JP NZ,HB_DSKIO ; IF SO, NON-BANKED + LD A,D ; GET TGT BANK + CP BID_BIOS ; BIOS BANK? + JP Z,HB_DSKIO ; IF SO, NON-BANKED +#ENDIF +; +#IF TRUE + ; RAM BANK RANGE CHECK + LD A,D ; GET TGT BANK + CP BID_RAMN ; BANK IN RANGE 0-N? + CALL NC,PANIC ; IF >N, PANIC +#ENDIF +; + ; SAVE TGT BUF BNK/ADR + LD (HB_IOBUF),HL + LD A,D + LD (HB_IOBNK),A +; + ; SETUP READ AND LOOP COUNT + LD B,E ; SEC LOOP COUNTER + LD C,0 ; SEC COMPLETE COUNTER +; +HB_DSKREAD1: + LD HL,HB_WRKBUF ; USE WORK BUF REAL I/O +; + ; CALL READ FN + CALL HB_DSKFN ; READ ONE SECTOR +; + ; IF FAIL, RETURN ERR + JR NZ,HB_DSKREADX ; BAIL OUT ON ERROR +; + ; BNKCPY SEC DATA TO REAL BANK/BUF & INC BUF ADR + PUSH BC ; SAVE COUNTERS + LD A,(HB_IOBNK) ; DEST BANK + LD (HB_DSTBNK),A ; ... TO PROXY + LD A,BID_BIOS ; SRC BANK + LD (HB_SRCBNK),A ; ... TO PROXY + LD BC,512 ; COPY 512 BYTES (1 SEC) + LD DE,(HB_IOBUF) ; TGT BUFFER ADR + LD HL,HB_WRKBUF ; SOURCE BUFFER + CALL HBX_BNKCPY ; DO BANK COPY + LD (HB_IOBUF),DE ; SAVE UPDATED TGT BUF ADR + POP BC ; RESTORE COUNTERS +; + ; INC READ COUNT + INC C ; BUMP SEC READ COUNT + DJNZ HB_DSKREAD1 ; LOOP AS NEEDED + XOR A ; SIGNAL SUCCESS +; +HB_DSKREADX: + LD HL,(HB_IOBUF) ; NEXT BUF ADR + JR HB_DSKIOX ; DONE +; +;-------------------------------------------------------------------------------------------------- +; DISK WRITE HELPER +;-------------------------------------------------------------------------------------------------- +; +; IMPLEMENTS MULTI SECTOR WRITES AND I/O TO/FROM +; BANKED RAM VIA BOUNCE BUFFER +; +; TOS=WRITE FN ADR +; HL=BUF ADR +; E=SEC COUNT +; D=BUF BANK ID +; +HB_DSKWRITE: +; + ; THE ACTUAL SECTOR READ FUNCTION ADDRESS IS ON TOS, SAVE IT + EX (SP),HL ; SAVE HL TO TOS, HL := READ FN ADR + LD (HB_DSKFNADR),HL ; IMBED IN CALL OP BELOW + POP HL ; RECOVER HL +; + LD (HB_DSKCMD),BC ; SAVE HBIOS FUNC & UNIT +; +#IF (FPLED_ENABLE & FPLED_DSKACT) + ; SAVE DISK UNIT NUMBER BIT MASK + LD A,C ; GET DISK UNIT NUMBER + LD B,A ; PUT IN B FOR LOOP COUNTER + INC B ; LOOP ONE EXTRA TIME TO HANDLE UNIT=0 + XOR A ; START WITH ACCUM ZERO + SCF ; ... AND CF SET +HB_DSKWRITE0: + RLA ; ROTATE BIT + DJNZ HB_DSKWRITE0 ; ... UNTIL IN PROPER LOCATION + LD (HB_DSKBIT),A ; SAVE IT FOR DIAGNOSTICS +#ENDIF +; +#IF TRUE + ; CHECK TO SEE IF INTER-BANK I/O NEEDED. + BIT 7,H ; TGT BUF IN UPPER 32K? + JP NZ,HB_DSKIO ; IF SO, NON-BANKED + LD A,D ; GET TGT BANK + CP BID_BIOS ; BIOS BANK? + JP Z,HB_DSKIO ; IF SO, NON-BANKED +#ENDIF +; +#IF TRUE + ; RAM BANK RANGE CHECK + LD A,D ; GET TGT BANK + CP BID_RAMN ; BANK IN RANGE 0-N? + CALL NC,PANIC ; IF >N, PANIC +#ENDIF +; + ; SAVE TGT BUF BNK/ADR + LD (HB_IOBUF),HL + LD A,D + LD (HB_IOBNK),A +; + ; SETUP WRITE AND LOOP COUNT + LD B,E ; SEC LOOP COUNTER + LD C,0 ; SEC COMPLETE COUNTER +; +HB_DSKWRITE1: + ; BNKCPY SEC DATA TO WORK BANK/BUF & INC BUF ADR + PUSH BC ; SAVE COUNTERS + LD A,BID_BIOS ; DEST BANK + LD (HB_DSTBNK),A ; ... TO PROXY + LD A,(HB_IOBNK) ; SRC BANK + LD (HB_SRCBNK),A ; ... TO PROXY + LD BC,512 ; COPY 512 BYTES (1 SEC) + LD DE,HB_WRKBUF ; TGT BUFFER ADR + LD HL,(HB_IOBUF) ; SOURCE BUFFER + CALL HBX_BNKCPY ; DO BANK COPY + LD (HB_IOBUF),HL ; SAVE UPDATED SRC BUF ADR + POP BC ; RESTORE COUNTERS +; + ; CALL WRITE FN + LD HL,HB_WRKBUF ; WRITE FROM WORK BUFFER + CALL HB_DSKFN ; WRITE ONE SECTOR +; + ; IF FAIL, RETURN ERR + JR NZ,HB_DSKWRITEX ; BAIL OUT ON ERROR +; + ; INC WRITE COUNT + INC C ; BUMP SEC WRITE COUNT + DJNZ HB_DSKWRITE1 ; LOOP AS NEEDED + XOR A ; SIGNAL SUCCESS +; +HB_DSKWRITEX: + LD HL,(HB_IOBUF) ; NEXT BUF ADR + JR HB_DSKIOX ; DONE +; +;-------------------------------------------------------------------------------------------------- +; NON-BANKED DISK READ/WRITE +;-------------------------------------------------------------------------------------------------- +; +HB_DSKIO: +; + ; SETUP LOOP COUNT + LD B,E ; SEC LOOP COUNTER + LD C,0 ; SEC COMPLETE COUNTER +; +HB_DSKIO1: + ; CALL READ/WRITE FN + CALL HB_DSKFN ; READ/WRITE ONE SECTOR +; + ; IF FAIL, RETURN ERR + JR NZ,HB_DSKIOX ; BAIL OUT ON ERROR +; + ; INC SECTOR COUNT + INC C ; BUMP SEC READ/WRITE COUNT + DJNZ HB_DSKIO1 ; LOOP AS NEEDED + XOR A ; SIGNAL SUCCESS +; +HB_DSKIOX: + LD E,C ; WRITE COUNT TO E + OR A ; SET RESULT FLAGS + RET ; DONE +; +;-------------------------------------------------------------------------------------------------- +; INVOKE DRIVER DISK I/O FUNCTION +;-------------------------------------------------------------------------------------------------- +; +HB_DSKFN: + PUSH BC ; SAVE COUNTERS +#IF (FPLED_ENABLE & FPLED_DSKACT) + LD A,(HB_DSKBIT) ; LOAD UNIT DISK BIT MASK + CALL FP_SETLEDS ; DISPLAY ON FP LEDS +#ENDIF +#IF (LEDENABLE & LEDDISKIO) + DIAG(1) ; BIT 0 FOR TINY Z80 & MBC, BIT 2 FOR SCXXX +#ENDIF + LD E,1 ; ONE SECTOR +HB_DSKFNADR .EQU $+1 + CALL PANIC ; READ ONE SECTOR +#IF (FPLED_ENABLE & FPLED_DSKACT) + FPLEDS($00) ; CLEAR FP LEDS +#ENDIF +#IF (LEDENABLE & LEDDISKIO) + DIAG(0) +#ENDIF + POP BC ; RESTORE COUNTERS + RET ; RETURN +; +HB_DSKBIT .DB 0 ; ACTIVE DISK UNIT +HB_IOBUF .DW 0 ; CURRENT IO BUFFER ADR +HB_IOBNK .DB 0 ; CURRENT IO BUFFER BANK ID +HB_DSKCMD: +HB_DSKUNIT .DB 0 ; CURRENT DISK UNIT +HB_DSKFUNC .DB 0 ; CURRENT DISK FUNCTION +HB_DSKADR .FILL 4,0 ; CURRENT DISK BLOCK ADDRESS +; +;-------------------------------------------------------------------------------------------------- +; DSKY DISK ACTIVITY MONITOR +;-------------------------------------------------------------------------------------------------- +; +; THIS FUNCTION IS CALLED BY DISK DRIVERS JUST PRIOR TO +; THE START OF A DISK I/O OPERATION. +; +; THE CURRENT DISK UNIT NUMBER WILL BE DISPLAYED IN THE FIRST +; 2 SEG DISPLAYS. THE LOWER 24 BITS OF THE SECTOR WILL BE +; DISPLAYED IN THE LAST 6 SEG DISPLAYS. +; +; A DOT IS DISPLAYED TO SEPARATE THE UNIT NUMBER FROM THE ADDRESS +; DISPLAY. ALSO, A TRAILING DOT IS DISPLAYED IF THE I/O FUNCTION +; IS A WRITE. +; +; HL: ADDRESS OF 32-BIT SECTOR NUMBER (LITTLE-ENDIAN) +; ALL REGISTERS PERSERVED +; +#IF (DSKYDSKACT) +HB_DSKACT: +; + ; SAVE EVERYTHING + PUSH AF + PUSH BC + PUSH DE + PUSH HL +; + ; COPY VALUE TO LOCAL HB_DSKADR + CALL LD32 +; +HB_DSKACT1: + LD BC,HB_DSKADR + CALL ST32 +; + LD B,BF_DSKYEVENT + LD C,DSKY_EVT_DSKACT + CALL DSKY_DISPATCH +; + ; CLEAN UP AND GO AWAY + POP HL + POP DE + POP BC + POP AF + JR HB_DSKACT_Z ; DONE +; +; THIS IS THE CHS VARIANT OF THE ABOVE. THIS IS USED BY CHS ORIENTED +; DISK DRIVERS (BASICALLY JUST FLOPPY). +; +; THE CURRENT DISK UNIT NUMBER WILL BE DISPLAYED IN THE FIRST +; 2 SEG DISPLAYS. THE TRACK, HEAD, AND SECTOR WILL BE DISPLAYED IN +; THE LAST 6 SEG DISPLAYS +; +; HL: ADDRESS OF CYL,HD,SEC IN THE FORMAT CCSH +; ALL REGISTERS PRESERVED +; +HB_DSKACTCHS: + PUSH AF + PUSH BC + PUSH DE + PUSH HL + CALL LD32 ; DE:HL = HSCC + ; MAP HSCC -> CCHS + EX DE,HL + JR HB_DSKACT1 +; +HB_DSKACT_Z: + RET +; +#ELSE +; +HB_DSKACT: +HB_DSKACTCHS: + RET +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; REAL TIME CLOCK DEVICE DISPATCHER +;-------------------------------------------------------------------------------------------------- +; +; ROUTE CALL TO REAL TIME CLOCK DRIVER +; B: FUNCTION +; +RTC_DISPATCH: + PUSH HL ; SAVE INCOMING HL + LD HL,(RTC_DISPADR) ; + EX (SP),HL + RET +; +RTC_DISPERR: + SYSCHKERR(ERR_NOHW) + RET +; +; SET RTC DISPATCH ADDRESS, USED BY RTC DRIVERS DURING INIT +; BC HAS ADDRESS OF DISPATCH ADDRESS +; WILL ONLY SAVE THE FIRST ADDRESS SET +; +RTC_SETDISP: + LD A,(RTC_DISPACT) ; GET ACTIVE FLAG + OR A ; IS IT ACTIVE? + RET NZ ; ABORT IF ALREADY ACTIVE + LD (RTC_DISPADR),BC ; SAVE THE ADDRESS + OR $FF ; FLAG ACTIVE VALUE + LD (RTC_DISPACT),A ; SAVE IT + RET ; AND DONE +; +RTC_DISPADR .DW RTC_DISPERR ; RTC DISPATCH ADDRESS +RTC_DISPACT .DB 0 ; SET WHEN DISPADR SET +; +;-------------------------------------------------------------------------------------------------- +; DSKY DEVICE DISPATCHER +;-------------------------------------------------------------------------------------------------- +; +; ROUTE CALL TO DSKY DRIVER +; B: FUNCTION +; +DSKY_DISPATCH: + PUSH HL ; SAVE INCOMING HL + LD HL,(DSKY_DISPADR) ; + EX (SP),HL + RET +; +DSKY_DISPERR: + SYSCHKERR(ERR_NOHW) + RET +; +; SET DSKY DISPATCH ADDRESS, USED BY DSKY DRIVERS DURING INIT +; BC HAS ADDRESS OF DISPATCH ADDRESS +; WILL ONLY SAVE THE FIRST ADDRESS SET +; +DSKY_SETDISP: + LD A,(DSKY_DISPACT) ; GET ACTIVE FLAG + OR A ; IS IT ACTIVE? + RET NZ ; ABORT IF ALREADY ACTIVE + LD (DSKY_DISPADR),BC ; SAVE THE ADDRESS + OR $FF ; FLAG ACTIVE VALUE + LD (DSKY_DISPACT),A ; SAVE IT + RET ; AND DONE +; +DSKY_DISPADR .DW DSKY_DISPERR ; DSKY DISPATCH ADDRESS +DSKY_DISPACT .DB 0 ; SET WHEN DISPADR SET +; +;================================================================================================== +; 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 16 ; 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 +; +;-------------------------------------------------------------------------------------------------- +; SOUND ADAPTER DEVICE DISPATCHER +;-------------------------------------------------------------------------------------------------- +; +; ROUTE CALL TO SPECIFIED SOUND DEVICE DRIVER +; B: FUNCTION +; C: UNIT NUMBER +; +SND_DISPATCH: + PUSH IY ; SAVE INCOMING IY +; + LD IY, SND_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 SND UNIT TABLE (SEE HB_ADDENT FOR DETAILS) +; +SND_ADDENT: + LD HL, SND_TBL ; POINT TO SND 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 SND FUNCTION IDS +; EACH ENTRY IS DEFINED AS: +; +; WORD DRIVER FUNCTION TABLE ADDRESS +; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS) +; +SND_FNCNT .EQU 9 ; NUMBER OF SND FUNCS (FOR RANGE CHECK) +SND_MAX .EQU 5 ; UP TO 5 UNITS +SND_SIZ .EQU SND_MAX * 4 ; EACH ENTRY IS 4 BYTES +; + .DB SND_FNCNT ; SND FUNCTION COUNT (FOR RANGE CHECK) + .DB SND_MAX ; MAX ENTRY COUNT TABLE PREFIX +SND_CNT .DB 0 ; ENTRY COUNT PREFIX +SND_TBL .FILL SND_SIZ,0 ; SPACE FOR ENTRIES +; +;-------------------------------------------------------------------------------------------------- +; SPEAKER BEEP ROUTINE +;-------------------------------------------------------------------------------------------------- +; +; ROUTINE TO BEEP A SOUND UNIT +; THE SOUND DRIVERS CAN DEFER THEIR BEEP FUNCTION TO THIS FUNCTION +; ON ENTRY, B = SOUND UNIT +; WHICH CHANNEL SHOULD BE USED? IS THERE A GOOD DEFAULT CHANNEL? +; +SND_BEEP: + ; RESET THE SOUND DEVICE TO START + LD B,$50 ; SOUND RESET FUNCTION + CALL SND_BEEP_DISP ; DO IT +; + ; SET VOLUME TO MAX + LD B,$51 ; VOLUME + LD L,$FF ; MAX + CALL SND_BEEP_DISP ; DO IT +; + ; SET NOTE TO PLAY + LD B,$53 ; SELECT NOTE + LD HL,244 ; B5 (CLOSE TO 1 KHZ) + CALL SND_BEEP_DISP ; DO IT +; + ; START PLAYING THE SOUND + LD B,$54 ; PLAY SOUND + LD D,0 ; CHANNEL 0 + CALL SND_BEEP_DISP ; DO IT +; + ; WAIT A BIT FOR SOUND TO PLAY + LD DE,23436 ; PLAY FOR 1/3 SECOND + CALL VDELAY ; WAIT WHILE TONE IS PLAYED +; + LD B,$50 ; SOUND RESET FUNCTION + CALL SND_BEEP_DISP ; DO IT +; + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +SND_BEEP_DISP: + ; CALL SOUND DISPATCHER PRESERVING BC ACROSS CALL + PUSH BC + CALL SND_DISPATCH + POP BC + RET +; +;-------------------------------------------------------------------------------------------------- +; EXTENDED FUNCTION DISPATCHER +;-------------------------------------------------------------------------------------------------- +; +; B: FUNCTION +; +EXT_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JP Z,EXT_SLICE ; $E0 + DEC A + JP HB_DISPERR ; ERROR COULD NOT FIND FUNCTION +; +;-------------------------------------------------------------------------------------------------- +; 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 + DEC A + JP HB_DISPERR ; ERROR COULD NOT FIND FUNCTION +; +HB_DISP_END .EQU $ +; +;================================================================================================== +; Z280 INTERRUPT VECTOR TABLE +;================================================================================================== +; +HB_Z280IVT_BEG .EQU $ +; +; THE Z280 IVT MUST BE ON A 4K BOUNDARY. IT HAS BEEN LOCATED +; HERE IN AN EFFORT TO MINIMIZE WASTED SPACE. THERE SHOULD BE +; A LITTLE LESS THAN 4K OF CODE ABOVE. +; +#IF (MEMMGR == MM_Z280) +; +Z280_IVT_SLACK_ORG .EQU $ + ALIGN($1000) +Z280_IVT_SLACK .EQU $ - Z280_IVT_SLACK_ORG + .ECHO "Z280 IVT SLACK = " + .ECHO Z280_IVT_SLACK + .ECHO " bytes.\n" +; +Z280_IVT: + .DW 0, 0 ; RESERVED + .DW 0 ; NMI MSR + .DW 0 ; NMI VECTOR + .DW $0000 ; INT A MSR + .DW Z280_BADINT ; INT A VECTOR + .DW $0000 ; INT B MSR + .DW Z280_BADINT ; INT B VECTOR + .DW $0000 ; INT C MSR + .DW Z280_BADINT ; INT C VECTOR + .DW $0000 ; COUNTER/TIMER 0 MSR + .DW Z280_BADINT ; COUNTER/TIMER 0 VECTOR + .DW $0000 ; COUNTER/TIMER 1 MSR + .DW Z280_BADINT ; COUNTER/TIMER 1 VECTOR + .DW 0, 0 ; RESERVED + .DW $0000 ; COUNTER/TIMER 2 MSR + .DW Z280_BADINT ; COUNTER/TIMER 2 VECTOR + .DW $0000 ; DMA CHANNEL 0 MSR + .DW Z280_BADINT ; DMA CHANNEL 0 VECTOR + .DW $0000 ; DMA CHANNEL 1 MSR + .DW Z280_BADINT ; DMA CHANNEL 1 VECTOR + .DW $0000 ; DMA CHANNEL 2 MSR + .DW Z280_BADINT ; DMA CHANNEL 2 VECTOR + .DW $0000 ; DMA CHANNEL 3 MSR + .DW Z280_BADINT ; DMA CHANNEL 3 VECTOR + .DW $0000 ; UART RECEIVER MSR + .DW Z280_BADINT ; UART RECEIVER VECTOR + .DW $0000 ; UART TRANSMITTER MSR + .DW Z280_BADINT ; UART TRANSMITTER VECTOR + .DW $0000 ; SINGLE STEP TRAP MSR + .DW Z280_SSTEP ; SINGLE STEP TRAP VECTOR + .DW $0000 ; BREAK ON HALT TRAP MSR + .DW Z280_BRKHLT ; BREAK ON HALT TRAP VECTOR + .DW $0000 ; DIVISION EXCEPTION TRAP MSR + .DW Z280_DIVEXC ; DIVISION EXCEPTION TRAP VECTOR + .DW $0000 ; STACK OVERFLOW WARNING TRAP MSR + .DW Z280_STKOVR ; STACK OVERFLOW WARNING TRAP VECTOR + .DW $0000 ; ACCESS VIOLATION TRAP MSR + .DW Z280_ACCVIO ; ACCESS VIOLATION TRAP VECTOR + .DW $0000 ; SYSTEM CALL TRAP MSR + .DW Z280_SYSCALL ; SYSTEM CALL TRAP VECTOR + .DW $0000 ; PRIVILEGED INSTRUCTION TRAP MSR + .DW Z280_PRIVINST ; PRIVILEGED INSTRUCTION TRAP VECTOR + .DW $0000 ; EPU <- MEMORY EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; EPU <- MEMORY EXTENDED INSTRUCTION TRAP VECTOR + .DW $0000 ; MEMORY <- EPU EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; MEMORY <- EPU EXTENDED INSTRUCTION TRAP VECTOR + .DW $0000 ; A <- EPU EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; A <- EPU EXTENDED INSTRUCTION TRAP VECTOR + .DW $0000 ; EPU INTERNAL OPERATION EXTENDED INSTRUCTION TRAP MSR + .DW $0000 ; EPU INTERNAL OPERATION EXTENDED INSTRUCTION TRAP VECTOR + .DW 0, 0 ; RESERVED + .DW 0, 0 ; RESERVED + ; PROGRAM COUNTER VALUES FOR NMI/INTA (16) + .DW HBX_IV00 + .DW HBX_IV01 + .DW HBX_IV02 + .DW HBX_IV03 + .DW HBX_IV04 + .DW HBX_IV05 + .DW HBX_IV06 + .DW HBX_IV07 + .DW HBX_IV08 + .DW HBX_IV09 + .DW HBX_IV0A + .DW HBX_IV0B + .DW HBX_IV0C + .DW HBX_IV0D + .DW HBX_IV0E + .DW HBX_IV0F +; + ; THE REMAINDER OF THE Z280 IVT IS TRUNCATED HERE BECAUSE IT + ; TAKES A BUNCH OF SPACE AND IS NOT USED. WE SUPPORT ONLY + ; 16 VECTORED INTERRUPTS AND THEY MUST BE CONNECTED TO INTA. +; +#ENDIF +; +HB_Z280IVT_END .EQU $ +; +;================================================================================================== +; EXTENSION API FUNCTIONS +;================================================================================================== +; +HB_EXTAPI_BEG .EQU $ +; +;-------------------------------------------------------------------------------------------------- +; SLICE CALCULATE - GET DISK EXTENDED HARD DISK MEDIA INFORMATION +;-------------------------------------------------------------------------------------------------- +; This function is specificly intended for Hard Drives, where it will scan +; the partition table and return a Media ID, including hd1k (MID_HDNEW). +; It will also return the absolute LBA offset of the first sector in the slice +; If the slice number is invalid (wont fit) the Status will return an error +; If the Unit is not a hard disk the Media ID will be returned and slice ignored. +;-------------------------------------------------------------------------------------------------- +; ENTRY: +; B: FUNCTION 0xE0 EXT_SLICE +; D: DISK UNIT, preferably for a hard disk. +; E: SLICE, ignored if media is not a hard disk +; RETURNS: +; A: STATUS, -6 (parameter out of range) - if Slice is invalid +; Other errors Include ERR_NOUNIT, ERR_NOMEDIA, +; If any error is raised the other return values are undefined +; B: DEVICE ATTRIBUTES, as reported by DIODEVICE +; C: MEDIAID, including MID_HDNEW if hd1k partition is found +; DEHL: LBAOFFSET, of Slice if valid, 0 otherwise. +;-------------------------------------------------------------------------------------------------- +; +SLICE_SLICE .DB 0 ; SLICE ARGUMENT (E) +SLICE_UNIT .DB 0 ; UNIT ARGUMENT (D) +SLICE_DEVATT .DB 0 ; DEVICE ATTRIBUTES +SLICE_MID .DB 0 ; DISCOVERED MEDIAID +; +SLICE_WRKSTA .EQU $ +SLICE_LBAOFF .FILL 4,0 ; START OF PARTITION / SLICE (SECTORS) +SLICE_LBASIZ .FILL 4,0 ; SIZE OF MEDIA / PARTITION (SECTORS) +SLICE_SPS .DW 0 ; DISCOVERED SECTORS PER SLICE (16BIT) +SLICE_FND .DB 0 ; DID WE FIND A NON CPM PARTITION +SLICE_WRKSIZ .EQU $ - SLICE_WRKSTA ; SIZE OF WORKING DATA +; +EXT_SLICE: + ; SAVE CALL ARGUMENTS + LD (SLICE_SLICE),DE ; STORES DE -> SLICE/UNIT PARAMETERS + + ; READ DEVICE INFORMATION USING DIODEVICE FUNCTION + LD A,(SLICE_UNIT) + LD C,A ; UNIT ID PARAMETER INTO C + LD B,BF_DIODEVICE ; DRIVER FUNCTION = DISK MEDIA + CALL DIO_DISPATCH ; CALL DIO TO GET DEVICE ATTRIBUTES + RET NZ ; ABORT ON ERROR +; + ; DEVICE ATTRIBUTES IN C + LD A,C + LD (SLICE_DEVATT),A ; STORE DEVICE ATTRIBUTES +; + ; DETERMINE MEDIA IN DRIVE USING DIOMEDIA FUNCTION + LD A,(SLICE_UNIT) + LD C,A ; UNIT ID PARAMETER INTO C + LD E,1 ; ENABLE MEDIA CHECK/DISCOVERY + LD B,BF_DIOMEDIA ; DRIVER FUNCTION = DISK MEDIA + CALL DIO_DISPATCH ; CALL DIO TO GET MEDIAID (RESULT IN E) + RET NZ ; ABORT ON ERROR +; + ; CHECK MEDIA TYPE, ONLY HD IS APPLICABLE + LD A,E ; RESULTANT MEDIA ID TO ACCUM + LD (SLICE_MID),A ; INIT VALUE, MAY BE USED LATER + OR A ; SET FLAGS + JR Z,EXT_SLICE1A ; BAIL IF NO MEDIA + CP MID_HD ; IS IT A HARD DISK + JR Z,EXT_SLICE1B ; IS HD, CONTINUE TO PROCESS HD +; + ; NOT A HARD DISK, CHECK SLICE = 0 + LD A,(SLICE_SLICE) ; GET THE SLICE + OR A ; SET FLAGS + JP NZ,EXT_SLICE5C ; SLICE NOT ZERO - SIGNAL ERROR AND RETURN +; +EXT_SLICE1A: + ; RETURN MEDIA ID (NOT HD) WITH SUCCESS + LD DE,0 ; LBA VALUE WILL BE ZERO + LD HL,0 + JP EXT_SLICE6A ; RETURN SUCCESS +; +EXT_SLICE1B: + ; FOUND HD, NEED TO PROCESS MBR / PART TABLE + ; CLEAR WORKING STORAGE + LD HL,SLICE_WRKSTA ; HL SET TO FIRST BYTE + LD (HL),0 ; CLEAR FIRST BYTE + LD D,H + LD E,L + INC DE ; DE SET TO SECOND BYTE + LD BC,SLICE_WRKSIZ - 1 ; NUMBER OF LDIR COPIES + LDIR ; BLOCK COPY TO CLEAR WORKING STORAGE +; + ; SEEK TO SECTOR ZERO (MBR TABLE) + LD B,BF_DIOSEEK ; SEEK FUNCTION + LD A,(SLICE_UNIT) ; GET UNIT + LD C,A ; PUT IN C + LD DE,$8000 ; LBA SECTOR ZERO + LD HL,0 ; ASSUME LBA ACCESS FOR NOW + CALL DIO_DISPATCH ; DO IT + RET NZ ; ABORT ON ERROR +; + ; READ SECTOR ZERO (MBR TABLE) + LD B,BF_DIOREAD ; READ FUNCTION + LD A,(SLICE_UNIT) ; GET UNIT + LD C,A ; PUT IN C + LD A,(HB_CURBNK) ; GET CURRENT BANK ID + LD D,A ; PUT IN D + LD E,1 ; SECTOR COUNT + LD HL,HB_WRKBUF ; IO BUFFER TO USE + CALL DIO_DISPATCH ; DO IT + RET NZ ; ABORT ON ERROR +; + ; CHECK MBR OF DISK TO SEE IF IT HAS A PARTITION TABLE. + LD HL,HB_WRKBUF ; DSKBUF ADR + LD DE,$1FE ; OFFSET TO SIGNATURE + ADD HL,DE ; POINT TO SIGNATURE + LD A,(HL) ; GET FIRST BYTE + CP $55 ; CHECK FIRST BYTE + JR NZ,EXT_SLICE3C ; NO MATCH, NO PART TABLE + INC HL ; NEXT BYTE + LD A,(HL) ; GET SECOND BYTE + CP $AA ; CHECK SECOND BYTE + JR NZ,EXT_SLICE3C ; NO MATCH, NO PART TABLE +; + ; FOUND PARTITION TABLE - LOOP AND PROCESS PARTITION TABLE + LD HL,HB_WRKBUF ; DSKBUF ADR + LD DE,$1BE+4 ; OFFSET OF FIRST ENTRY PART TYPE + ADD HL,DE ; POINT TO IT + LD B,4 ; FOUR ENTRIES IN PART TABLE LOOP +EXT_SLICE2A: + LD A,(HL) ; GET PART TYPE + LD DE,4 + ADD HL,DE ; MOVE HL FWD TO GET TO LBA OFFSET + CP $2E ; CP/M PARTITION? + JR Z,EXT_SLICE3B ; HD1K, GRAB THE LBA OFFSET + CP $00 ; IS ANOTHER PARTITION TYPE, NOT CPM + JR NZ,EXT_SLICE3A ; OTHER VALID PART TYPE +EXT_SLICE2B: + LD DE,12 ; REMAINING SIZE TO GET TO NEXT PARTITION +EXT_SLICE2C: + ADD HL,DE ; BUMP TO NEXT PARTITION ENTRY - TYPE + DJNZ EXT_SLICE2A ; LOOP THRU TABLE + JR EXT_SLICE3C ; READ ALL - NO CP/M PARTITION FOUND +; +EXT_SLICE3A + ; FOUND OTHER (NOT CPM) PARTITION + LD A,(SLICE_FND) ; HAVE WE ALREADY FOUND PROCESSED NON CPM + OR A ; PARTITION, AND CAPTURED ITS START SECTOR, SO + JR NZ,EXT_SLICE2B ; IGNORE AND CONTINUTE TO NEXT PARTITION ENTRY +; +; NOTE THERE SLIGHT ISSUE HERE THAT WE ONLY CONSIDER THE FIRST NON-CPM PARTITION +; TO GET THE UPPER SIZE OF MEDIA, IDEALLY WE WOULD CONSIDER ALL, AND TAKE THE LOWEWST +; STARTING SECTOR - THIS IS A COMPRIMISE - OUT OF SEQUENCE PARTITIONS ARE UNLIKELY. +; + PUSH BC ; SAVE IT, BEING USED IN PARTITION LOOP + LD BC,4 ; IF NOT ALREADY SET - COPY 4 BYTES + LD DE,SLICE_LBASIZ ; FROM PARTION LBA OFFSET (HL) - TO WORKING LBA SIZE (DE) + LDIR ; COPY 4 BYTES + POP BC ; RESTORE +; + LD A,$FF + LD (SLICE_FND),A ; SET FOUND FLAG, SO DONT PROCESS ANY OTHERS + LD DE,8 ; AND INC HL BY 8 TO GET TO NEXT PARITION + JR EXT_SLICE2C ; CONTINUE TO NEXT PARTITION +; +EXT_SLICE3B: + ; FOUND CP/M (HD1K) PARTITION - RECORD THIS + LD A,MID_HDNEW ; DISCOVERED HD1K MEDIA + LD (SLICE_MID),A ; STORE IT + LD BC,SPS_HD1K ; DISCOVERED HD1K MEDIA + LD (SLICE_SPS),BC ; STORE IT +; + ; CAPTURE THE LBA OFFSET AND SECTOR COUNT FROM PARTITION + ; HL POINTS TO PART LBA OFFSET FIELD OF PART ENTRY + LD DE,SLICE_LBAOFF ; LOC TO STORE OFFSET AND SIZE + LD BC,8 ; 8 BYTES - LBA OFFSET AND SIZE + LDIR ; COPY IT +; + JR EXT_SLICE4A ; CONTINUE AND COMPUTE THE SLICE +; +EXT_SLICE3C: + ; NO PARTITION TABLE FOUND / NO CPM PARTITION + LD A,(SLICE_SLICE) ; IF SLICE = 0, WE BOOT THE DISK ITSELF. IGNORE SLICE(S) + OR A ; SET FLAGS FOR SLICE ARGUMENT, IF SLICE==0 + JR Z,EXT_SLICE5Z ; BYPASS ALL CALCS / CHECKS - JUST BOOT THE DISK + + ; BOOT SLICE WITH LEGACY SPS + LD BC,SPS_HD512 ; WITH HD512 SECTORS PER SLICE + LD (SLICE_SPS),BC ; STORE IT + + ; DID WE FIND AN OTHER (NOT CPM) PARTITION + LD A,(SLICE_FND) ; HAVE WE ALREADY FOUND PROCESSED NON CPM + OR A ; PARTITION, AND CAPTURED ITS START SECTOR, SO + JR NZ,EXT_SLICE4A ; MEDIA SIZE IS KNOWN BASED ON START OF PARTITION + + ; FIND THE PHYSICAL CAPCITY OF THE MEDIA CALL (DIOCAP) + LD B,BF_DIOCAP ; HBIOS FUNC: TO GET DISK LBA CAPACITY + LD A,(SLICE_UNIT) + LD C,A ; PUT DISK UNIT IN C FOR FUNC CALL + CALL DIO_DISPATCH ; DO IT - RETURNS SIZE in DE:HL + RET NZ ; ABORT ON ERROR + + ; UPDATE LBA SIZE FROM MEDIA SIZE + LD (SLICE_LBASIZ),HL ; LOWER ORDER BYTES - HL + EX DE,HL + LD (SLICE_LBASIZ+2),HL ; HIGHER ORDER BYTES - DE +; +EXT_SLICE4A: + ; COMPUTE THE START SECTOR (RELATIVE) FOR SLICE -> DE:HL + LD HL,0 ; STARTING SECTOR NUMBER + LD DE,0 ; ASSUMING A 0 OFFSET, SO CAN COMPARE TO SIZE + LD BC,(SLICE_SPS) + LD A,(SLICE_SLICE) + OR A ; SLICE NUMBER - SET FLAGS TO CHECK LOOP CTR + JR Z,EXT_SLICE5A ; NOTHING TO COUNT +EXT_SLICE4B: + ADD HL,BC ; ADD ONE SLICE (SPS) TO LOW WORD + JR NC,EXT_SLICE4C ; CHECK FOR CARRY + INC DE ; IF SO, BUMP HIGH WORD +EXT_SLICE4C: + DEC A ; DEC LOOP (SLICE) COUNTER + JR NZ,EXT_SLICE4B ; AND LOOP +; +EXT_SLICE5A: + ; DE:HL NOW CONTAINS THE STARTING SECTOR FOR SLICE + PUSH HL ; SAVE THE SECTOR OFFSET (SPS * SLICE NUMBER) + PUSH DE +; + ADD HL,BC ; ADD SPS, GET REQUIRED CAPCITY (UPPER SECTOR) + JR NC,EXT_SLICE5B + INC DE +EXT_SLICE5B: + ; DEHL HAS THE REQUIRED NUMBER OF SECTORS (ON MEDIA) FOR THE SLICE + PUSH DE ; SAVE DSK_REQ (MSW) + PUSH HL ; SAVE DSK_REQ (LSW) +; + ; CHECK DSK_CAPACITY >= CAP_REQUIRED, CF SET ON OVERFLOW + ; NO NEED SAVE ACTUAL RESULT + OR A ; CLEAR CARRY FOR SBC + LD HL,(SLICE_LBASIZ+0) ; CAPACITY LSW + POP DE ; REQUIRED LSW + SBC HL,DE ; CAPACITY - REQUIRED (LSW) + LD HL,(SLICE_LBASIZ+2) ; CAPAITY MSW + POP DE ; REQUIRED MSW + SBC HL,DE ; CAPACITY - REQUIRED (MSW) +; + ; POP STARTING OFSETT SECTOR + POP DE + POP HL +; + ; REQUIRE - CAPACITY -> GENERATES BORROW IF CAPITY > REQUIREMENT + JR NC,EXT_SLICE6 ; IF WE HAVE ENOUGH CAPACITY +; +EXT_SLICE5C: + ; SLICE WONT FIT - STOP AND RETURN ERROR + LD DE,0 + LD HL,0 ; EMTY OFFSET IN DEHL + LD A,(SLICE_DEVATT) + LD B,A ; DEVICE ATTRIBUTES IN B + LD A,(SLICE_MID) + LD C,A ; RETURN MEDIA ID IN C + LD A,ERR_RANGE ; OTHERWISE SIGNAL NOT ENOUGH CAPACITY + OR A + RET +; +EXT_SLICE5Z: + LD HL,0 ; BOOT THE DISK TO LBA = 0 + LD DE,0 ; +; +EXT_SLICE6: + ; FINAL CALC AND RETURN SUCCESS + ; ADD PARTITION OFFSET (START) TO DEHL TO GET ABSOLUTE SLICE OFFSET + LD BC,(SLICE_LBAOFF+0) ; LSB OF LBA OFFSET + ADD HL,BC ; ADD LSB OFFSET + EX DE,HL ; FLIP DE INTO HL + LD BC,(SLICE_LBAOFF+2) ; MSB OF LBA OFFSET + ADC HL,BC ; ADD MSB + EX DE,HL ; FLIP BACK DE:HL AS SLICE OFFSET +; +EXT_SLICE6A: + ; SLICE FITS - RETURN CORRECTLY + LD A,(SLICE_DEVATT) + LD B,A ; DEVICE ATTRIBUTES IN B + LD A,(SLICE_MID) + LD C,A ; RETURN MEDIA ID IN C + XOR A ; CLEAR FLAGS + RET ; RETUNING DE:HL AND C +; +;-------------------------------------------------------------------------------------------------- +; +HB_EXTAPI_END .EQU $ +; +;================================================================================================== +; SYSTEM API FUNCTIONS +;================================================================================================== +; +HB_SYSAPI_BEG .EQU $ +; +;-------------------------------------------------------------------------------------------------- +; SYSTEM RESET +;-------------------------------------------------------------------------------------------------- +; +; RESTART SYSTEM +; SUBFUNCTION IN C +; +SYS_RESET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSRES_INT + JR Z,SYS_RESINT + CP BF_SYSRES_WARM + JR Z,SYS_RESWARM + CP BF_SYSRES_COLD + JR Z,SYS_RESCOLD + CP BF_SYSRES_USER + JR Z,SYS_RESUSER + SYSCHKERR(ERR_NOFUNC) + RET +; +; SOFT RESET HBIOS, RELEASE HEAP MEMORY NOT USED BY HBIOS +; +SYS_RESINT: +; + ; RESET THE HEAP + LD HL,(HEAPCURB) ; GET HBIOS HEAP THRESHOLD + LD (CB_HEAPTOP),HL ; RESTORE HEAP TOP +; + XOR A + RET +; +; GO BACK TO ROM BOOT LOADER +; +SYS_RESWARM: +; + CALL SYS_RESINT ; HBIOS INTERNAL RESET +; +#IF (MEMMGR == MM_Z280) + JP INITSYS4 +#ELSE + ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM + LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY + #IFDEF APPBOOT + LD A,BID_AUX ; IF APPBOOT, CHAIN TO AUX BANK + #ELSE + LD A,BID_IMG0 ; ELSE CHAIN TO OS IMAGES BANK + #ENDIF + LD IX,0 ; ENTER AT ADDRESS 0 + CALL HBX_BNKCALL ; GO THERE + HALT ; WE SHOULD NEVER COME BACK! +#ENDIF +; +; RESTART SYSTEM AS THOUGH POWER HAD JUST BEEN TURNED ON +; +SYS_RESCOLD: +; +#IFDEF APPBOOT + JP HB_RESTART +#ELSE +; +; MAKE ROM BOOT BANK ACTIVE IN LOW SYS MEM +; + #IF (MEMMGR == MM_Z280) + ; FOR Z280, NEED TO REMAP THE LOW 32K IN SYSTEM MODE AND + ; CONTINUE AT ADDRESS ZERO. WE CANNOT RETURN HERE AFTER THE + ; BNKSEL IS DONE BECAUSE THE SYSTEM BANK HAS BEEN CHANGED! + ; SO, WE PRESET THE STACK TO CAUSE A JUMP TO THE RESTART + ; ADDRESS ON RETURN FROM THE BNKSEL. SLICK, RIGHT? + DI ; KILL INTERRUPTS + LD SP,HBX_LOC ; STACK IN HIGH MEMORY + LD HL,HB_RESTART ; RESUME AT RESTART ADDRESS + PUSH HL ; ... IS PRESET ON STACK + LD A,BID_BOOT ; BANK TO LAUNCH RESTART + LD B,$10 ; FIRST SYS PDR + JP Z280_BNKSEL ; DO IT AND RESUME FROM STACK + #ELSE + ; FOR OTHER THAN Z280, JUST DO AN INTERBANK CALL TO THE + ; RESTART ADDRESS. + DI + LD SP,HBX_LOC ; STACK JUST BELOW HBIOS PROXY + LD A,BID_BOOT ; BANK TO LAUNCH RESTART + LD IX,HB_RESTART ; RESUME AT RESTART ADDRESS + CALL HB_BNKCALL ; DOES NOT RETURN + #ENDIF +#ENDIF +; +; HOOK CALLED WHEN A USERLAND RESET IS INVOKED, TYPICALLY VIA A JUMP +; TO CPU ADDRESS $0000 +; +; CREDIT TO PHILLIP STEVENS FOR SUGGESTING AND SIGNIFICANT CONTRIBUTIONS +; TO THE Z180 INVALID OPCODE TRAP ENHANCEMENT. +; +SYS_RESUSER: +; +#IF (CPUFAM == CPU_Z180) +; +; IF Z180 CPU, CHECK FOR INVALID OPCODE FLAG AND HANDLE IF SO +; + IN0 A,(Z180_ITC) ; GET ITC REGISTER + XOR $80 ; PRECLEAR TRAP BIT + RET M ; IF TRAP BIT NOT SET, DONE +; + ; HANDLE INVALID OPCODE + DEC HL ; BACK UP TO OPCODE START + BIT 6,A ; CHECK UFO BIT (2 BYTE OPCODE) + JR Z,SYS_RESUSER1 ; IF NOT, ALL SET + DEC HL ; OTHERWISE, BACK UP 1 MORE BYTE +; +SYS_RESUSER1: + OUT0 (Z180_ITC),A ; SAVE IT +; + CALL PRTSTRD ; PRINT ERROR TAG + .TEXT "\r\n\r\n+++ INVALID Z180 OPCODE @$" + CALL PRTHEXWORDHL ; PRINT OPCODE ADDRESS + PRTS("H:$") ; FORMATTING +; + LD B,8 ; SHOW 8 BYTES +SYS_RESUSER2: + PUSH BC ; SAVE BC + PUSH HL ; SAVE HL + LD A,(HB_INVBNK) ; GET BYTE FROM INVOKING BANK + LD D,A ; PUT IN D + CALL SYS_PEEK ; PEEK TO GET BYTE VALUE + LD A,E ; PUT IN A + CALL PC_SPACE ; FORMATTING + CALL PRTHEXBYTE ; DISPLAY BYTE + POP HL ; RECOVER HL + POP BC ; RECOVER BC + INC HL ; NEXT BYTE + DJNZ SYS_RESUSER2 ; LOOP TIL DONE + JP NEWLINE ; FORMATTING & EXIT +; +#ENDIF +; + ; RESET ACTIVE VIDEO DISPLAY ATTACHED TO EMULATOR + CALL TERM_RESET +; + RET ; ELSE RETURN WITH USER RESET VECTOR IN HL +; +;-------------------------------------------------------------------------------------------------- +; SYSTEM VERSION +;-------------------------------------------------------------------------------------------------- +; +; 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 BANK +;-------------------------------------------------------------------------------------------------- +; +; 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 ESTABLISH UPPER MEMORY STACK BEFORE INVOKING THIS FUNCTION! +; +SYS_SETBNK: +#IF (MEMMGR == MM_Z280) + ; FOR Z280 MEMMGR, WE ARE IN SYSTEM MODE HERE, SO WE CAN UPDATE + ; THE USER MODE BANK WITHOUT IMPACTING THE RUNNING CODE. IT + ; WILL TAKE EFFECT UPON RETURN TO USER MODE. + LD A,(HB_INVBNK) ; GET PREVIOUS BANK + PUSH AF ; SAVE IT + LD A,C ; NEW BANK TO A + LD (HB_INVBNK),A ; UPDATE INVBNK + LD B,$00 ; FIRST USER PDR + CALL Z280_BNKSEL ; DO IT + POP AF ; RECOVER PREV BANK + LD C,A ; PREVIOUS BANK TO C + XOR A ; SIGNAL SUCCESS + RET ; DONE +#ELSE + 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 +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; GET BANK +;-------------------------------------------------------------------------------------------------- +; +SYS_GETBNK: + LD A,(HB_INVBNK) ; GET THE ACTIVE MEMORY BANK + LD C,A ; MOVE TO C + XOR A ; SIGNAL SUCCESS + RET +; +;-------------------------------------------------------------------------------------------------- +; SETUP INTERBANK COPY +;-------------------------------------------------------------------------------------------------- +; +; 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 INTERBANK COPY +;-------------------------------------------------------------------------------------------------- +; +; 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 + CALL HB_BNKCPY + XOR A + RET +; +;-------------------------------------------------------------------------------------------------- +; ALLOCATE HEAP SPACE +;-------------------------------------------------------------------------------------------------- +; +; 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 SPACE +;-------------------------------------------------------------------------------------------------- +; +; 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: + SYSCHKERR(ERR_NOTIMPL) ; NOT YET IMPLEMENTED + RET +; +;-------------------------------------------------------------------------------------------------- +; GET SYSTEM INFORMATION +;-------------------------------------------------------------------------------------------------- +; +; GET SYSTEM INFORMATION +; ITEM TO RETURN INDICATED IN C +; +SYS_GET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSGET_CIOCNT + JP Z,SYS_GETCIOCNT + CP BF_SYSGET_CIOFN + JP Z,SYS_GETCIOFN + CP BF_SYSGET_DIOCNT + JP Z,SYS_GETDIOCNT + CP BF_SYSGET_DIOFN + JP Z,SYS_GETDIOFN + CP $12 ; LEFT FOR BACKWRD COMPATABILITY + JP Z,EXT_SLICE ; FUNCTION MOVED TO TOP LEVEL $E0 + ; REMOVING THE ABOVE CAUSED UPGRADE ISSUES FOR EARLY ADOPTERS + ; SINCE OS BOOT LOADERS DEPEND ON IT. WITHOUT CAN LEAVE OS + ; UNBOOTABLE AND MIGRATION HARDER - Oct 2024 + CP BF_SYSGET_RTCCNT + JP Z,SYS_GETRTCCNT + CP BF_SYSGET_DSKYCNT + JP Z,SYS_GETDSKYCNT + CP BF_SYSGET_VDACNT + JP Z,SYS_GETVDACNT + CP BF_SYSGET_VDAFN + JP Z,SYS_GETVDAFN + CP BF_SYSGET_SNDCNT + JP Z, SYS_GETSNDCNT + CP BF_SYSGET_SNDFN + JP Z,SYS_GETSNDFN + CP BF_SYSGET_SWITCH + JP Z,SYS_GETSWITCH + CP BF_SYSGET_TIMER + JP Z,SYS_GETTIMER + CP BF_SYSGET_SECS + JP Z,SYS_GETSECS + CP BF_SYSGET_BOOTINFO + JP Z,SYS_GETBOOTINFO + CP BF_SYSGET_CPUINFO + JP Z,SYS_GETCPUINFO + CP BF_SYSGET_MEMINFO + JP Z,SYS_GETMEMINFO + CP BF_SYSGET_BNKINFO + JP Z,SYS_GETBNKINFO + CP BF_SYSGET_CPUSPD + JP Z,SYS_GETCPUSPD + CP BF_SYSGET_PANEL + JP Z,SYS_GETPANEL + CP BF_SYSGET_APPBNKS + JP Z,SYS_GETAPPBNKS + SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR + 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 SERIAL UNIT API FN ADR AND DATA ADR +; ENTRY: +; D: FUNCTION +; E: UNIT +; RETURNS: +; HL: FUNCTION ADDRESS +; DE: DATA BLOB ADDRESS +; +SYS_GETCIOFN: + BIT 7,E ; CHECK FOR SPECIAL UNIT CODE + CALL NZ,SYS_GETCIOFN1 ; IF SO, HANDLE IT + LD IY,CIO_TBL ; POINT TO UNIT TABLE + JP SYS_GETFN ; GO TO COMMON CODE +; +SYS_GETCIOFN1: + LD A,(CB_CONDEV) ; UNIT $80 -> CONSOLE UNIT + LD E,A ; REPLACE UNIT VALUE IN C + RET ; AND BACK TO REGULAR FLOW +; +; +; 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 DISK UNIT API FN ADR AND DATA ADR +; ENTRY: +; D: FUNCTION +; E: UNIT +; RETURNS: +; HL: FUNCTION ADDRESS +; DE: DATA BLOB ADDRESS +; +SYS_GETDIOFN: + LD IY,DIO_TBL ; POINT TO UNIT TABLE + JP SYS_GETFN ; GO TO COMMON CODE +; +; GET RTC UNIT COUNT +; +SYS_GETRTCCNT: + LD E,0 ; ASSUME 0 RTC DEVICES + LD A,(RTC_DISPACT) ; IS RTC ACTIVE? + OR A ; SET FLAGS + JR Z,SYS_GETRTCCNT1 ; IF NONE, DONE + INC E ; SET ONE DEVICE +SYS_GETRTCCNT1: + XOR A ; SIGNALS SUCCESS + RET +; +; GET DSKY UNIT COUNT +; +SYS_GETDSKYCNT: + LD E,0 ; ASSUME 0 RTC DEVICES + LD A,(DSKY_DISPACT) ; IS DSKY ACTIVE? + OR A ; SET FLAGS + JR Z,SYS_GETDSKYCNT1 ; IF NONE, DONE + INC E ; SET ONE DEVICE +SYS_GETDSKYCNT1: + 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 +; +; GET VIDEO UNIT API FN ADR AND DATA ADR +; ENTRY: +; D: FUNCTION +; E: UNIT +; RETURNS: +; HL: FUNCTION ADDRESS +; DE: DATA BLOB ADDRESS +; +SYS_GETVDAFN: + LD IY,VDA_TBL ; POINT TO UNIT TABLE + JP SYS_GETFN ; GO TO COMMON CODE +; +; GET SOUND UNIT COUNT +; +SYS_GETSNDCNT: + LD A,(SND_CNT) ; GET DEVICE COUNT (FIRST BYTE OF LIST) + LD E,A ; PUT IT IN E + XOR A ; SIGNALS SUCCESS + RET +; +; GET SOUND UNIT API FN ADR AND DATA ADR +; ENTRY: +; D: FUNCTION +; E: UNIT +; RETURNS: +; HL: FUNCTION ADDRESS +; DE: DATA BLOB ADDRESS +; +SYS_GETSNDFN: + LD IY,SND_TBL ; POINT TO UNIT TABLE + JP SYS_GETFN ; GO TO COMMON CODE +; +; SHARED CODE TO COMPLETE A FUNCTION LOOKUP +; ENTRY: +; IY: DISPATCH FUNCTION TABLE +; D: FUNCTION ID +; E: UNIT NUMBER +; EXIT: +; HL: DRIVER FUNCTION ADDRESS +; DE: DRIVER UNIT DATA ADDRESS +; +SYS_GETFN: + LD A,D ; GET FUNC NUM FROM D + LD B,A ; AND PUT IN B + LD A,E ; GET UNIT NUM FROM E + LD C,A ; AND PUT IN C + CALL HB_DISPCALC ; CALC FN ADR & BLOB ADR + PUSH IY ; MOVE DATA ADR + POP DE ; ... TO DE + RET ; AF STILL HAS RESULT OF CALC +; +; GET SWITCH +; ON ENTRY: +; D: SWITCH KEY +; 0 -> ILLEGAL / RESERVED +; 1-FE -> SWITCH +; FF -> DONT GET VALUE CHECK THE STATUS OF NVRAM -> Returning +; A=0 if no NVRAM exists. with NZ flag set +; A=1 if NVRAM is present. with Z flag set +; A='W' if NVRAM is fullly inited. with Z flag set +; Note the NZ flag can be used to detect and return an error condition +; RETURNS: +; HL: SWITCH VALUE 8/16 BIT +; +SYS_GETSWITCH: +; PUSH DE +; CALL NVR_INIT ; FUNCTION IS NOT CORRECT WRONG !!!!!!!!!! +; POP DE ; +; RET NZ ; Configuration Failed, thus cant continue +; + LD A,D + CP NVSW_STATUS ; test if want to just get NVRAM status + JR Z,NVSW_STATUS ; Check the Status - Call and Return +; + CALL SWITCH_RES ; D SWITCH NUMBER -> OUT HL address, E FLAGS + RET NZ ; IF NZ FLAG SET THEN ISSUE +; + LD B,0 ; Clear upper byte + LD C,(HL) ; Get LOW Order Switch Data + LD A,1 ; Compare with 1 (byte) + CP E ; Compare The byte count from SWITCH_RES + JR NC,SYS_GETSWITCH2 ; 1 byte or less, skip over + INC HL ; next byte pos in a 2 Byte Switch + LD B,(HL) ; Get HIGH Order Switch Data +; +SYS_GETSWITCH2: + LD H,B ; retun Result in HL + LD L,C + XOR A ; signal success + RET +#IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) +; IMPLEMENTED IN EZ80DRV.ASM +; +#ELSE +; +; GET TIMER +; RETURNS: +; DE:HL: TIMER VALUE (32 BIT) +; +SYS_GETTIMER: + LD HL,HB_TICKS + HB_DI + CALL LD32 + HB_EI + LD C, TICKFREQ + XOR A + RET +#ENDIF +; +#IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) +; IMPLEMENTED IN EZ80DRV.ASM +; +#ELSE +; +; GET SECONDS +; RETURNS: +; DE:HL: SECONDS VALUE (32 BIT) +; C: NUM TICKS WITHIN CURRENT SECOND +; +SYS_GETSECS: + LD HL,HB_SECS + HB_DI + CALL LD32 + LD A,(HB_SECTCK) + HB_EI + NEG ; CONVERT DOWNCOUNTER TO UPCOUNTER + ADD A,TICKFREQ + LD C,A + XOR A + RET +#ENDIF +; +; 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 A,(HB_CPUTYPE) + LD H,A + LD A,(CB_CPUMHZ) + LD L,A + LD DE,(CB_CPUKHZ) + LD BC,(HB_CPUOSC) + XOR A + RET +; +; GET MEMORY INFORMATION +; RETURNS: +; D: COUNT OF ROM BANKS +; E: COUNT OF RAM BANKS +; +SYS_GETMEMINFO: + LD A,(CB_ROMBANKS) + LD D,A + LD A,(CB_RAMBANKS) + LD E,A + XOR A + RET +; +; GET BANK CONFIGURATION INFORMATION +; RETURNS: +; D: HBIOS BANK ID +; E: USER BANK ID +; H: FIRST APP BANK ID +; L: APP BANK COUNT +; +SYS_GETBNKINFO: + LD A,(CB_BIDBIOS) + LD D,A + LD A,(CB_BIDUSR) + LD E,A + XOR A + RET +; +; GET SYSTEM CPU SPEED PERFORMANCE ATTRIBUTES +; RETURNS: +; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE) +; D: MEMORY WAIT STATES +; E: I/O WAIT STATES +; +SYS_GETCPUSPD: +; +#IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO)) + LD A,(HB_RTCVAL) + #IF (PLATFORM == PLT_SBC) + XOR %00001000 ; SBC SPEED BIT IS INVERTED + #ENDIF + BIT 3,A + LD L,0 ; ASSUME HALF SPEED + JR Z,SYS_GETCPUSPD1 + LD L,1 +SYS_GETCPUSPD1: + LD DE,$FFFF ; UNKNOWN WAIT STATES +; + XOR A + RET +#ENDIF +; +#IF (PLATFORM == PLT_HEATH) + LD A,(H8P_SPEED) ; GET HEATH SPEED BITS SHADOW + XOR $03 ; CONVERT TO HBIOS VALUE + LD L,A ; PUT IN L FOR RETURN + LD DE,$FFFF ; UNKNOWN WAIT STATES +; + XOR A + RET +#ENDIF +; +#IF (CPUFAM == CPU_Z180) + LD HL,0 ; INIT CPU SPEED TO HALF + LD A,(HB_CPUTYPE) ; LOAD CPUTYPE + CP 2 ; S-CLASS OR ABOVE? + JR C,SYS_GETCPUSPD1 ; IF NOT, NO CCR/CMR +; + ; GET CCR BIT + IN0 A,(Z180_CCR) ; GET CLOCK CONTROL + RLCA ; ROTATE BIT TO BIT 0 + AND %00000001 ; ISOLATE IT + LD L,A ; SAVE IN L +; + LD A,(HB_CPUTYPE) ; LOAD CPUTYPE + CP 3 ; REV. N? + JR C,SYS_GETCPUSPD1 ; IF NOT, NO CMR +; + ; GET CMR BIT + IN0 A,(Z180_CMR) ; GET CLOCK MULTIPLIER + RLCA ; ROTATE BIT TO BIT 0 + AND %00000001 ; ISOLATE IT + LD H,A ; SAVE IN H +; +SYS_GETCPUSPD1: + ; CALC FINAL MULTIPLIER TO L + XOR A ; CLEAR ACCUM + ADD A,H ; ADD IN CMR BIT + ADD A,L ; ADD IN CCR BIT + LD L,A ; SAVE RESULT IN L + ; DCNTL = MMII???? + IN0 A,(Z180_DCNTL) ; GET WAIT STATES + RLCA ; ROTATE MEM WS BITS + RLCA ; ... TO LOW BITS + PUSH AF ; SAVE FOR NOW + AND %00000011 ; ISOLATE BITS + LD D,A ; PUT IN D + POP AF ; RECOVER A + RLCA ; ROTATE I/O WS BITS + RLCA ; ... TO LOW BITS + AND %00000011 ; ISOLATE BITS + INC A ; ADD 1 FOR BUILT-IN WS + LD E,A ; PUT IN E +; + XOR A + RET +#ENDIF +; + OR $FF + RET +; +; GET FRONT PANEL SWITCH VALUES BYTE +; RETURNS: +; L: SWITCH VALUES BYTE +; +SYS_GETPANEL: +; +#IF (FPSW_ENABLE) + LD A,(FPSW_ACTIVE) ; FP SWITCHES ACTIVE? + OR A ; SET FLAGS + JR Z,SYS_GETPANEL1 ; HANDLE NOT EXISTS + CALL FP_GETSWITCHES ; READ SWITCHES + LD H,0 ; FOR FUTURE + LD L,A ; PUT SWITCHES VALUE IN L + XOR A ; SIGNAL SUCCESS + RET ; DONE +#ENDIF +SYS_GETPANEL1: ; HANDLE NON-EXISTENT FRONT PANEL + LD HL,0 ; ZERO RESULT VALUE + LD A,ERR_NOHW ; NO HARDWARE ERR + OR A ; SET FLAGS + RET ; DONE +; +; GET APPLICATION BANK INFORMATION +; RETURNS: +; H: FIRST APP BANK ID +; L: APP BANK COUNT +; E: BANK SIZE (IN 256-BYTE PAGES) +; +SYS_GETAPPBNKS: + LD A,(CB_BIDAPP0) ; FIRST BANK ID + LD H,A + LD A,(CB_APP_BNKS) ; NUMBER OF BANKS + LD L,A + LD E,$80 ; (256 * $80) = 32KB +; + XOR A + RET +; +;-------------------------------------------------------------------------------------------------- +; SET SYSTEM PARAMETERS +;-------------------------------------------------------------------------------------------------- +; +; SET SYSTEM PARAMETERS +; PARAMETER(S) TO SET INDICATED IN C +; +SYS_SET: + LD A,C ; GET REQUESTED SUB-FUNCTION + CP BF_SYSSET_SWITCH + JP Z,SYS_SETSWITCH + CP BF_SYSSET_TIMER + JP Z,SYS_SETTIMER + CP BF_SYSSET_SECS + JP Z,SYS_SETSECS + CP BF_SYSSET_BOOTINFO + JP Z,SYS_SETBOOTINFO + CP BF_SYSSET_CPUSPD + JP Z,SYS_SETCPUSPD + CP BF_SYSSET_PANEL + JP Z,SYS_SETPANEL + SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR + RET +; +; SET SWITCH +; ON ENTRY: +; D: SWITCH KEY +; 0 -> ILLEGAL / RESERVED +; 1-254 -> SWITCH +; FF -> REINIT DEFAULT VALUES +; HL: SWITCH VALUE 8/16 BIT +; +SYS_SETSWITCH: + + CALL PC_ASTERISK + + CALL NVSW_STATUS ; Check the status of NV RAM + RET NZ ; IF NZ then we cant continue, return NZ at this point +; + CALL PC_ASTERISK + + LD A,D ; switch # argument + CP NVSW_RESET ; test if want to reset NVRAM + JP Z,NVSW_RESET ; then perform reset function. CALL AND RETURN +; + CALL PC_ASTERISK + + LD B,H ; move value to write into BC + LD C,L + CALL SWITCH_RES ; IN D SWITCH NUMBER -> OUT HL address, E FLAGS + RET NZ ; RETURN IF NZ - swich number illegal +; + CALL PC_ASTERISK + + LD (HL),C ; Save LOW Order Switch Data + LD A,1 ; Compare with 1 (byte) switch + CP E ; Compare + JR NC,SYS_SETSWITCH1 ; 1 byte or less, skip over + INC HL ; next byte pos + LD (HL),B ; Save High Order Switch Data + + CALL PC_ASTERISK +; +SYS_SETSWITCH1: + JP NVSW_UPDATE ; do a write to NVR, CALL AND RETURN +; +; Utility function to convert switch number into lookup +; INPUT +; D SWITCH NUMBER +; OUTPUT +; E with Byte count (1,2) for switch, or 0 if switch illegal +; HL Memory Address (CB_SWITCHES + offset) +SWITCH_RES: + LD A,SWITCH_LEN ; lengt of target array (below) + CP D ; check we fit in the loop + JR C,SWITCH_RES1 ; overflow table to abort +; + LD HL,SWITCH_TAB ; Lookup table below + LD A,D ; plus the offset switch number + CALL ADDHLA ; get address of lookup table + LD E,(HL) ; E (OUT) nubmer of bytes in switch +; + LD HL,CB_SWITCHES ; BASE ADDRESS OF SHADDOW DATA + LD A,D ; Add The offset to the address + CALL ADDHLA ; Final address of Switch Data +; + XOR A ; signal success + RET +SWITCH_RES1: + OR $FF ; signal failure + RET +; +; Switch number maps drectly into the HCB data, so to account +; for double bytes words, we need a table (loopkup) +; to defines how to map Applicability of Each Swicth Number +; 0->Cant be Used; 1->Single Byte Value; 2->Double Byte Value +; +SWITCH_TAB: + .DB 0 ; Switch 0 is header, cant be used + .DB 2 ; Switch 1 - (WORD) + .DB 0 ; Switch (byte 2) of prior word, not used + .DB 1 ; Switch 3 - (BYTE) + .DB 0 ; Last byte is checksum, cant be used +SWITCH_LEN .EQU $ - SWITCH_TAB - 2 +; +; 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 +; +#IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) +; IMPLEMENTED IN EZ80DRV.ASM +; +#ELSE +; +; 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 +#ENDIF +#IF ((CPUFAM == CPU_EZ80) & (EZ80TIMER == EZ80TMR_FIRM)) +; IMPLEMENTED IN EZ80DRV.ASM +; +#ELSE +; +; SET SECS +; ON ENTRY: +; DE:HL: SECONDS VALUE (32 BIT) +; +SYS_SETSECS: + LD BC,HB_SECS + HB_DI + CALL ST32 + HB_EI + XOR A + RET +#ENDIF +; +; SET SYSTEM CPU SPEED ATTRIBUTES +; ON ENTRY: +; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE, 3: QUAD) +; D: MEMORY WAIT STATES +; E: I/O WAIT STATES +; +SYS_SETCPUSPD: +; +#IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO)) +; +; NOTE: WAIT STATE SETTINGS ARE IGNORED FOR Z80 +; + LD A,L ; CLK SPD TO ACCUM + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD3 ; DONE IF SO + LD C,%00000000 ; HALF SPEED + CP 0 + JR Z,SYS_SETCPUSPD1 + LD C,%00001000 ; FULL SPEED + CP 1 + JR Z,SYS_SETCPUSPD1 + JR SYS_SETCPUSPD_ERR ; SPD NOT SUPPORTED +SYS_SETCPUSPD1: + LD A,(HB_RTCVAL) + AND ~%00001000 ; CLEAR SPEED BIT + OR C ; IMPLEMENT NEW SPEED BIT +#IF (PLATFORM == PLT_SBC) + ; SBC SPEED BIT IS INVERTED, ADJUST IT + LD A,C + XOR %00001000 + LD C,A +#ENDIF + LD (HB_RTCVAL),A ; SAVE IN SHADOW REGISTER + OUT (RTCIO),A ; UPDATE HARDWARE REGISTER +; + ; UPDATE THE CURRENT CPU SPEED IN HCB! + LD A,L + LD HL,(HB_CPUOSC) ; ASSUME FULL SPEED + CP 1 ; CHECK FOR 1 (FULL SPEED) + JR Z,SYS_SETCPUSPD2 ; IF SO, ALL DONE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION +; +SYS_SETCPUSPD2: +; +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. +; + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT +; +#IF (CPUFAM != CPU_EZ80) + ; REINIT DELAY ROUTINE + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +#ENDIF +; +SYS_SETCPUSPD3: + XOR A + RET +#ENDIF +; +#IF (PLATFORM == PLT_HEATH) + ; PORT $30: + ; 0=16MHZ, 1=8MHZ, 2=4MHZ, 3=2MHZ + LD A,L ; REQUESTED SPEED TO ACCUM + XOR $03 ; CONVERT TO HEATH BITS + AND $03 ; ONLY 2 LS BITS +; +H8P_SETSPD: ; INVOKED BY H8P.ASM WHEN SPEED CHANGED VIA FRONT PANEL + OUT (H8P_SPDIO),A ; DO IT + LD (H8P_SPEED),A ; UPDATE FP SHADOW +; + ; UPDATE CPUKHZ/CPMHZ + LD HL,(HB_CPUOSC) ; START WITH OSC VALUE IN KHZ + LD B,A ; USE BITS FOR LOOP COUNT + OR A ; CHECK FOR ZERO + JR Z,SYS_SETCPUSPD2 ; IF SO, SKIP ADJUSTMENT LOOP +SYS_SETCPUSPD1: + SRL H ; DIVIDE + RR L ; ... BY TWO + DJNZ SYS_SETCPUSPD1 ; LOOP AS NEEDED +; +SYS_SETCPUSPD2: +; +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. +; + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT +; +#IF (CPUFAM != CPU_EZ80) + ; REINIT DELAY ROUTINE + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +#ENDIF +; + XOR A ; SIGNAL SUCCESS + RET +#ENDIF +; +#IF (CPUFAM == CPU_Z180) + ; VERIFY THAT REQUESTED SETTINGS ARE ALLOWED BY HARDWARE + LD A,L ; GET SPEED REQUESTED + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD0A ; SKIP CHECK + LD A,(HB_CPUTYPE) ; 1=ORIG, 2=REVK, 3=REVN + INC L ; 1=HALF,2=FULL,3=DOUBLE + CP L ; TOO HIGH FOR CPU TYPE? + JP C,SYS_SETCPUSPD_ERR ; CPU CAN'T DO SPD MULT + DEC L ; RESTORE ORIG REQUEST +SYS_SETCPUSPD0A: + LD A,D ; MEM WS + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD0B ; SKIP CHECK + CP 4 ; TOO HIGH? + JP NC,SYS_SETCPUSPD_ERR ; >3 IS TOO HIGH +SYS_SETCPUSPD0B: + LD A,D ; I/O WS + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD0C ; SKIP CHECK + CP 4 ; TOO HIGH? + JP NC,SYS_SETCPUSPD_ERR ; >3 IS TOO HIGH +SYS_SETCPUSPD0C: +; + PUSH DE ; SAVE WAIT STATES FOR NOW + ; BEFORE IMPLEMENTING THE NEW CPU SPEED, WE SWITCH THE + ; WAIT STATES TO MAXIMUM BECAUSE WE MAY BE IMPLEMENTING + ; SLOWER WAIT STATES REQUIRED BY THE NEW SPEED. WE SAVE + ; THE ORIGINAL WAIT STATES REGISTER VALUE ON STACK + IN0 A,(Z180_DCNTL) ; GET CURRENT REGISTER VALUE + LD E,A ; PUT IN E + PUSH DE ; SAVE FOR LATER + OR %11110000 ; MAX WAIT STATES + OUT0 (Z180_DCNTL),A ; DO IT +; + LD A,L ; NEW CLK SPD TO ACCUM + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD2B ; IF SO, SKIP TO WAIT STATES +; + LD B,0 ; B HAS BIT FOR CMR + LD C,0 ; C HAS BIT FOR CCR + CP 2 ; DOUBLE SPEED? + JR C,SYS_SETCPUSPD1 ; <2?, SKIP AHEAD + LD B,%10000000 ; SET CMR BIT +SYS_SETCPUSPD1: + CP 1 ; FULL SPEED? + JR C,SYS_SETCPUSPD2 ; <1?, SKIP AHEAD + LD C,%10000000 ; SET CCR BIT +SYS_SETCPUSPD2: +; + ; IMPLEMENT THE NEW CPU SPEED + IN0 A,(Z180_CMR) + AND ~%10000000 + OR B + OUT0 (Z180_CMR),A + IN0 A,(Z180_CCR) + AND ~%10000000 + OR C + OUT0 (Z180_CCR),A +; + ; UPDATE THE CURRENT CPU SPEED IN HCB! + LD A,L ; SETTING TO A + LD HL,(HB_CPUOSC) ; START WITH CPU OSC VALUE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + OR A ; CHECK FOR HALF SPEED + JR Z,SETCPUSPD2A ; IF SO, DONE + ; ADJUST HL TO REFLECT FULL SPEED OPERATION + SLA L + RL H + CP 1 ; CHECK FOR FULL SPEED + JR Z,SETCPUSPD2A ; IF SO DONE + ; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION + SLA L + RL H +; +SETCPUSPD2A: +; +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. +; + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT +; +SYS_SETCPUSPD2B: + ; NOW IMPLEMENT ANY WAIT STATE CHANGES. + POP HL ; INIT L WITH ORIG DCNTL VALUE + POP DE ; RECOVER WAIT STATES + LD A,D ; GET MEM WS + CP $FF ; SKIP? + JR Z,SYS_SETCPUSPD3 ; IF SO, GO AHEAD + AND %00000011 ; JUST TWO BITS + RRCA ; MEM WS IS TOP TWO BITS + RRCA + LD H,A ; MOVE WS BITS TO H + LD A,L ; CUR VALUE TO A + AND %00111111 ; MASK OFF MEM WS BITS + OR H ; SET NEW MEM WS BITS + LD L,A ; BACK TO L +; +SYS_SETCPUSPD3: +; + LD A,E ; GET I/O WS + CP $FF ; SKIP? + JR Z,SYS_SETCPUSPD4 ; IF SO, GO AHEAD + DEC A ; ADJUST FOR BUILT-IN I/O WS + AND %00000011 ; JUST TWO BITS + RRCA ; I/O WS IS BITS 5-4 + RRCA + RRCA + RRCA + LD H,A ; MOVE WS BITS TO H + LD A,L ; CUR VALUE TO A + AND %11001111 ; MASK OFF I/O WS BITS + OR H ; SET NEW I/O WS BITS + LD L,A ; BACK TO L +; +SYS_SETCPUSPD4: + LD A,L ; WORKING VALUE TO A + OUT0 (Z180_DCNTL),A ; IMPLEMENT NEW VALUE +; +#IF (CPUFAM != CPU_EZ80) + ; REINIT DELAY ROUTINE + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +#ENDIF +; + #IF ((INTMODE == 2) & (Z180_TIMER)) + ; THE Z180 TIMER IS BASED ON CPU SPEED. SO HERE + ; WE RECOMPUTE THE TIMER CONSTANTS BASED ON THE NEW SPEED. + XOR A ; ALL BITS ZERO + OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION + LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ + OUT0 (Z180_TMDR0L),L ; INITIALIZE TIMER 0 DATA REGISTER + OUT0 (Z180_TMDR0H),H + DEC HL ; RELOAD OCCURS *AFTER* ZERO + OUT0 (Z180_RLDR0L),L ; INITIALIZE TIMER 0 RELOAD REGISTER + OUT0 (Z180_RLDR0H),H + LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING + OUT0 (Z180_TCR),A + #ENDIF +; + #IF (ASCIENABLE) + ; RESET THE ASCI PORTS IN CASE SPEED CHANGED! + ; N.B., THIS WILL FAIL IF THE CURRENT BAUD RATE + ; IS IMPOSSIBLE TO IMPLEMENT AT THE NEW CPU SPEED!!! + LD DE,-1 + LD IY,ASCI0_CFG + CALL ASCI_INITDEV + LD DE,-1 + LD IY,ASCI1_CFG + CALL ASCI_INITDEV + #ENDIF +; + XOR A + RET +#ENDIF +; +SYS_SETCPUSPD_ERR: + OR $FF ; NOT SUPPORTED + RET +; +; SET FRONT PANEL LEDS +; ON ENTRY: +; L: LED VALUES BYTE +; +SYS_SETPANEL: +; +#IF (FPLED_ENABLE) + LD A,L + CALL FP_SETLEDS + XOR A + RET +#ELSE + LD A,ERR_NOHW ; NO HARDWARE ERR + OR A ; SET FLAGS + RET +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; INTERBANK MEMORY PEEK +;-------------------------------------------------------------------------------------------------- +; +; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK +; ENTRY: D=BANK ID, HL=ADDRESS +; RETURN: E=BYTE VALUE +; +; IF WE ARE USING INTERRUPT MODE 1, WE NEED TO PREVENT INTERRUPTS +; BECAUSE THE LOW MEMORY BANK CONTAINING THE IM1 VECTOR WILL PROBABLY +; GET BANKED OUT DURING THE PEEK PROCESSING. +; +SYS_PEEK: +#IF (INTMODE == 1) + #IF (CPUFAM == CPU_Z280) + PUSH IY + LD C,Z280_MSR + LDCTL IY,(C) + PUSH IY + HB_DI + #ELSE + LD A,I ; SAVE THE INTERRUPT STATUS + DI ; COPY IFF2 TO P/V FLAG + PUSH AF + #ENDIF +#ENDIF + CALL HBX_PEEK ; IMPLEMENTED IN PROXY +#IF (INTMODE == 1) + #IF (CPUFAM == CPU_Z280) + LD C,Z280_MSR + POP IY + LDCTL (C),IY + POP IY + #ELSE + POP AF ; RECALL INITIAL INTERRUPT STATUS + JP PO,$+4 ; RETURN TO INITIAL STATE + EI ; *** DO NOT USE HB_EI HERE *** + #ENDIF +#ENDIF + XOR A + RET +; +;-------------------------------------------------------------------------------------------------- +; INTERBANK MEMORY POKE +;-------------------------------------------------------------------------------------------------- +; +; WRITE A BYTE OF MEMORY TO SPECIFIED BANK +; ENTRY: D=BANK ID, HL=ADDRESS IN HBIOS BANK, E=BYTE VALUE +; +; IF WE ARE USING INTERRUPT MODE 1, WE NEED TO PREVENT INTERRUPTS +; BECAUSE THE LOW MEMORY BANK CONTAINING THE IM1 VECTOR WILL PROBABLY +; GET BANKED OUT DURING THE POKE PROCESSING. +; +SYS_POKE: +#IF (INTMODE == 1) + #IF (CPUFAM == CPU_Z280) + PUSH IY + LD C,Z280_MSR + LDCTL IY,(C) + PUSH IY + HB_DI + #ELSE + LD A,I ; SAVE THE INTERRUPT STATUS + HB_DI ; COPY IFF2 TO P/V FLAG + PUSH AF + #ENDIF +#ENDIF + CALL HBX_POKE ; IMPLEMENTED IN PROXY +#IF (INTMODE == 1) + #IF (CPUFAM == CPU_Z280) + LD C,Z280_MSR + POP IY + LDCTL (C),IY + POP IY + #ELSE + POP AF ; RECALL INITIAL INTERRUPT STATUS + JP PO,$+4 ; RETURN TO INITIAL STATE + EI ; *** DO NOT USE HB_EI HERE *** + #ENDIF +#ENDIF + XOR A + RET +; +;-------------------------------------------------------------------------------------------------- +; INTERRUPT MANAGEMENT FUNCTIONS +;-------------------------------------------------------------------------------------------------- +; +; 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 + SYSCHKERR(ERR_NOFUNC) ; 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) | (INTMODE == 3)) + 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) + SYSCHKERR(ERR_BADCFG) ; SIGNAL ERROR. INVALID FOR INT MODE 0 + 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) | (INTMODE == 3)) + 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 + SYSCHKERR(ERR_RANGE) ; ELSE ERROR + RET +SYS_INTGET1: + OR A ; CLEAR CARRY + RLA ; ADJUST FOR TABLE ENTRY + RLA ; SIZE OF 4 BYTES + INC A ; BUMP TO ADR FIELD + LD H,0 + LD L,A +#IF (INTMODE == 1) + LD DE,HB_IM1INT ; DE := START OF VECTOR TABLE +#ENDIF +#IF ((INTMODE == 2) | (INTMODE == 3)) + LD DE,HB_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 +; +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 + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +HB_SYSAPI_END .EQU $ +; +;================================================================================================== +; GLOBAL INTERNAL HBIOS FUNCTIONS +;================================================================================================== +; +HB_INTFUNC_BEG .EQU $ +; +;-------------------------------------------------------------------------------------------------- +; PRINT DECIMAL VALUE WITH 3 DIGIT MANTISSA +;-------------------------------------------------------------------------------------------------- +; +; 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 +; +;-------------------------------------------------------------------------------------------------- +; INITIALIZATION VECTOR PROCESSING SUPPORT +;-------------------------------------------------------------------------------------------------- +; +; CALL A LIST OF ROUTINES POINTED TO BY DE OF LENGTH B. +; +CALLLIST: + 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 CALLLIST +CALLDUMMY: + RET +; +;-------------------------------------------------------------------------------------------------- +; GLOBAL IDLE PROCESSING +;-------------------------------------------------------------------------------------------------- +; +; GLOBAL HBIOS IDLE PROCESSING IS DONE HERE. THIS ROUTINE SHOULD +; BE CALLED WHENEVER WAITING FOR USER INPUT. +; +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 +; +; 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 +; +; 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 +; +;-------------------------------------------------------------------------------------------------- +; CHS TO LBA CONVERSION +;-------------------------------------------------------------------------------------------------- +; +; 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 +; +;-------------------------------------------------------------------------------------------------- +; SYSTEM CHECK / PANIC +;-------------------------------------------------------------------------------------------------- +; +; SYSTEM CHECK: DUMP MACHINE STATE AND CONTINUE? +; +SYSCHKA: + ; CHECK DIAG LEVEL TO SEE IF WE SHOULD DISPLAY + PUSH AF ; PRESERVE INCOMING AF VALUE + LD A,(CB_DIAGLVL) ; GET DIAGNOSTIC LEVEL + CP DL_ERROR ; >= ERROR LEVEL + JR C,SYSCHK1 ; IF NOT, GO HOME + POP AF ; RESTORE INCOMING AF VALUE +; + ; DISPLAY SYSCHK MESSAGE + PUSH DE ; PRESERVE DE VALUE + LD DE,STR_SYSCHK ; POINT TO PREFIX STRING + CALL WRITESTR ; PRINT IT + POP DE ; RESTORE DE VALUE + CALL XREGDMP ; DUMP REGISTERS + + ; DISPLAY ERROR CODE. IT IS AT RETURN ADDRESS+1 .. LD A,XX + EX (SP),HL ; GET RETURN ADDRESS + INC HL ; POINT TO THE ERROR CODE + PUSH AF + LD A,(HL) ; DISPLAY + CALL PRTHEXBYTE + POP AF + DEC HL ; RESTORE RETURN ADDRESS + EX (SP),HL +; + JR CONTINUE ; CHECK W/ USER +; +SYSCHK1: + ; RETURN IF MESSAGING BYPASSED BY DIAG LEVEL + POP AF + RET +; +CONTINUE: + PUSH AF +CONTINUE1: + PUSH DE + LD DE,STR_CONTINUE + CALL WRITESTR + POP DE + CALL CIN + RES 5,A ; FORCE UPPERCASE (IMPERFECTLY) + CALL COUT ; ECHO + CP 'Y' + JR Z,CONTINUE3 + CP 'N' + JR Z,SYSHALT + JR CONTINUE1 +CONTINUE3: + CALL NEWLINE + POP AF + RET +; +; PANIC: DUMP MACHINE STATE AND HALT +; +PANIC: + PUSH DE + LD DE,STR_PANIC + CALL WRITESTR + POP DE + CALL XREGDMP ; DUMP REGISTERS + JR SYSHALT ; FULL STOP +; +; ISSUE MESSAGE AND HALT SYSTEM +; +SYSHALT: + LD DE,STR_HALT + CALL WRITESTR + DI + HALT +; +;-------------------------------------------------------------------------------------------------- +; INTERRUPT MANAGEMENT SUPPORT +;-------------------------------------------------------------------------------------------------- +; +#IF (INTMODE == 1) +; +; 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 +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; SYSTEM TIMER INTERRUPT HANDLER +;-------------------------------------------------------------------------------------------------- +; +HB_TIMINT: +; +#IF FALSE ; *DEBUG* + LD HL,HB_TIMDBGCNT + INC (HL) + LD A,(HL) + OUT (DIAGPORT),A + JR HB_TIMDBG1 +HB_TIMDBGCNT .DB 0 +HB_TIMDBG1: +#ENDIF ; *DEBUG* +; +; TIMER HANDLER VECTORS +; THESE CAN BE HOOKED AS DESIRED BY DRIVERS +; +VEC_TICK: + JP HB_TICK ; TICKS PROCESSING VECTOR +VEC_SECOND: + JP HB_SECOND ; SECONDS PROCESSING VECTOR +; +; TIMER HANDLERS +; +HB_TICK: + ; INCREMENT TICK COUNTER (32 BIT) + LD HL,HB_TICKS ; POINT TO TICK COUNTER + CALL INC32HL + LD HL,HB_SECTCK ; POINT TO SECONDS TICK COUNTER + DEC (HL) ; COUNTDOWN ONE SECOND OF TICKS + JR NZ,HB_TICK1 ; NOT DONE, SKIP AHEAD + LD A,TICKFREQ ; TICKS PER SECOND + LD (HL),A ; RESET COUNTDOWN REGISTER + CALL VEC_SECOND ; DO SECONDS PROCESSING VIA VECTOR +; +HB_TICK1: +; +#IF (CPUFAM == CPU_Z180) + ; ACK/RESET Z180 TIMER INTERRUPT + IN0 A,(Z180_TCR) + IN0 A,(Z180_TMDR0L) +#ENDIF +; +#IF (WDOGMODE != WDOG_NONE) + ; PULSE WATCHDOG + OUT (WDOGIO),A ; VALUE IS IRRELEVANT +#ENDIF +; + OR $FF ; NZ SET TO INDICATE INT HANDLED + RET +; +HB_SECOND: + ; INCREMENT SECONDS COUNTER + LD HL,HB_SECS ; POINT TO SECONDS COUNTER + JP INC32HL ; INCREMENT AND RETURN +; +; BAD INTERRUPT HANDLER +; +HB_BADINT: + +#IF FALSE ; *DEBUG* + LD HL,HB_BADINTCNT + INC (HL) + LD A,(HL) + OUT (DIAGPORT),A + OR $FF + RET +HB_BADINTCNT .DB 0 +#ENDIF ; *DEBUG* + + CALL NEWLINE2 + PRTS("+++ BAD INT $") + LD A,L + RRCA + RRCA + ;CALL PRTHEXBYTE + ;PRTS("H: $") + CALL XREGDMP + CALL NEWLINE + ;CALL CONTINUE + OR $FF ; SIGNAL INTERRUPT HANDLED + RET +; +;-------------------------------------------------------------------------------------------------- +; API FUNCTION DISPATCH SUPPORT +;-------------------------------------------------------------------------------------------------- +; +; ON ENTRY B IS API FUNCTION NUMBER AND 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: + PUSH HL ; SAVE INCOMING HL VALUE + CALL HB_DISPCALC ; IY = BLOB ADR, HL = FN ADR + JR NZ,HB_DISPCALL1 ; ABORT ON ERROR + EX (SP),HL ; RESTORE HL & FN ADR TO TOS + RET ; JUMP TO FN ADR +HB_DISPCALL1: + POP HL ; RECOVER HL + RET ; AND DONE +; +; ENTRY: BC=FUNC/UNIT, IY=DISPATCH TABLE +; EXIT: HL=FUNC ADR, IY=DATA BLOB ADR +; +HB_DISPCALC: + ; CHECK INCOMING UNIT INDEX IN C FOR VALIDITY + LD A,C ; A := INCOMING DISK UNIT INDEX + CP (IY-1) ; COMPARE TO COUNT + JR NC,HB_UNITERR ; 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_FUNCERR ; HANDLE FN NUM OUT OF RANGE ERROR + + ; BUMP IY TO ACTUAL XXX_TBL ENTRY FOR INCOMING UNIT INDEX + PUSH BC ; SAVE BC + 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 + POP BC ; RESTORE BC + + ; 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 + PUSH HL ; SAVE FUNC ADR + 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 + + XOR A ; SIGNAL SUCCESS + RET ; JUMP TO DRIVER FUNC ADR ON TOS +; +HB_FUNCERR: + SYSCHKERR(ERR_NOFUNC) ; SIGNAL ERROR + RET +; +HB_UNITERR: + SYSCHKERR(ERR_NOUNIT) ; SIGNAL ERROR + RET +; +; 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 +; +;-------------------------------------------------------------------------------------------------- +; HEAP MEMORY ALLOCATION +;-------------------------------------------------------------------------------------------------- +; +; 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 MEMORY ALLOCATED (DOES NOT INCLUDE 4 BYTE HEADER) +; - DWORD: ADDRESS WHERE ALLOC WAS CALLED (VALUE ON TOP OF STACK AT CALL) +; +HB_ALLOC: +; +#IFDEF MEMDBG + CALL PRTSTRD + .TEXT "\r\n>>> ALLOC SIZE=0x$") + CALL PRTHEXWORDHL +#ENDIF +; + ; 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 +; +#IFDEF MEMDBG + CALL PRTSTRD + .TEXT " TOP=0x$") + CALL PRTHEXWORDHL +#ENDIF +; + ; 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 + SYSCHKERR(ERR_NOMEM) ; SIGNAL ERROR + RET +; +HB_TMPSZ .DW 0 +HB_TMPREF .DW 0 +; +;-------------------------------------------------------------------------------------------------- +; Z280 SUPPORT ROUTINES +;-------------------------------------------------------------------------------------------------- +; +; Z280 SYSTEM TIMER INTERRUPT HANDLER +; +#IF (MEMMGR == MM_Z280) +; +Z280_TIMINT: + ; DISCARD REASON CODE + INC SP + INC SP +; + ; SAVE INCOMING REGISTERS + PUSH AF + PUSH BC + PUSH DE + PUSH HL +; + ; CALL PRIMARY TIMER LOGIC ON EVERY OTHER INT + LD A,(Z280_TIMCTR) + XOR $FF + LD (Z280_TIMCTR),A + CALL Z,HB_TIMINT +; + ; SELECT I/O PAGE $FE (SAVING PREVIOUS VALUE) + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + LDCTL HL,(C) ; GET CURRENT I/O PAGE + PUSH HL ; SAVE IT + LD L,$FE ; NEW COUNTER/TIMER I/O PAGE + LDCTL (C),HL +; + ; CLEAR END OF COUNT CONDITION TO RESET INTERRUPT + IN A,(Z280_CT0_CMDST) ; GET STATUS + RES 1,A ; CLEAR CC + OUT (Z280_CT0_CMDST),A ; SET C/T 0 +; + ; RESTORE I/O PAGE + LD C,Z280_IOPR ; REG C POINTS TO I/O PAGE REGISTER + POP HL ; RECOVER ORIGINAL I/O PAGE + LDCTL (C),HL +; + ; RESTORE REGISTERS + POP HL + POP DE + POP BC + POP AF +; + RETIL +; +Z280_TIMCTR .DB 0 ; USED TO DIVIDE TIMER INTS +; +#ENDIF +; +#IF (MEMMGR == MM_Z280) +; +Z280_BADINT: + ; SAVE REASON CODE FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_RCSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK + ; SAVE MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_BADINTSTR + CALL NEWLINE2 + PRTS("+++ $") + CALL WRITESTR + POP DE + CALL XREGDMP +; + ; RECOVER MSR, THEN RETURN VIA RETIL + PUSH HL ; SAVE HL + LD HL,(HB_RCSAV) ; GET SAVED REASON CODE + PRTS(" RC=$") + CALL PRTHEXWORDHL ; DUMP MSR + LD HL,(HB_MSRSAV) ; GET SAVED MSR + PRTS(" MSR=$") + CALL PRTHEXWORDHL ; DUMP MSR + EX (SP),HL ; MSR TO STK, RECOVER HL +; + RETIL ; RETURN FROM INT +; +Z280_SSTEP: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_SSTEPSTR + JP Z280_DIAG +; +Z280_BRKHLT: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_BRKHLTSTR + JP Z280_DIAG +; +Z280_DIVEXC: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_DIVEXCSTR + JP Z280_DIAG +; +Z280_STKOVR: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_STKOVRSTR + JP Z280_DIAG +; +Z280_ACCVIO: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK +; + PUSH DE + LD DE,Z280_ACCVIOSTR + JP Z280_DIAG +; +Z280_DIAG: + CALL NEWLINE2 + PRTS("+++ $") + CALL WRITESTR + POP DE + CALL XREGDMP +; + ; RECOVER MSR, THEN RETURN VIA RETIL + PUSH HL ; SAVE HL + LD HL,(HB_MSRSAV) ; GET SAVED MSR + PRTS(" MSR=$") + CALL PRTHEXWORDHL ; DUMP MSR + EX (SP),HL ; MSR TO STK, RECOVER HL +; + ;RETIL + DI + HALT +; +Z280_BADINTSTR .TEXT "BAD INT $" +Z280_SSTEPSTR .TEXT "SINGLE STEP $" +Z280_BRKHLTSTR .TEXT "BREAK HALT $" +Z280_DIVEXCSTR .TEXT "DIVISION EXCEPTION $" +Z280_STKOVRSTR .TEXT "STACK OVERFLOW $" +Z280_ACCVIOSTR .TEXT "ACCESS VIOLATION $" +; +#ENDIF +; +; Z280 PRIVILEGED INSTRUCTION HANDLER +; +#IF (MEMMGR == MM_Z280) +; +Z280_PRIVINST: + ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL + EX (SP),HL ; GET MSR, SAVE HL + LD (HB_MSRSAV),HL ; SAVE IT + POP HL ; RECOVER HL, POP STACK + EX (SP),HL ; GET ADR, SAVE HL +; + PUSH AF + PUSH BC ; NEEDED? + PUSH DE ; NEEDED? +; + LDUP A,(HL) ; BYTE FROM USER SPACE +; + ; HANDLE USER MODE Z80 DI + CP $F3 ; DI? + JR NZ,Z280_PRIVINST2 + + ;;;HB_DI ; DO THE DI + XOR A ; NO INTERRUPTS + LD (HB_MSRSAV),A ; UPDATE SAVED MSR LSB + + INC HL ; BUMP PAST IT + JR Z280_PRIVINSTX +; +Z280_PRIVINST2: + ; HANDLE USER MODE Z80 EI + CP $FB ; EI? + JR NZ,Z280_PRIVINST3 + + ;;;HB_EI ; DO THE EI + LD A,$0B ; NORMAL INTERRUPTS + LD (HB_MSRSAV),A ; UPDATE SAVED MSR LSB + + INC HL ; BUMP PAST IT + JR Z280_PRIVINSTX +; +Z280_PRIVINST3: + ; SOMETHING ELSE, DIAGNOSE & HALT SYSTEM + LD DE,Z280_PRIVSTR + CALL WRITESTR + CALL PRTHEXWORDHL +; + ; DUMP 16 BYTES OF USER ADDRESS SPACE + CALL PC_SPACE + CALL PC_LBKT + LD B,$10 +Z280_PRIVINST4: + LDUP A,(HL) ; BYTE FROM USER SPACE + CALL PRTHEXBYTE + INC HL + DJNZ Z280_PRIVINST4 + CALL PC_RBKT +; + ; GO NO FURTHER + DI + HALT +; +Z280_PRIVINSTX: + ; RESTORE REGISTERS + POP DE ; NEEDED? + POP BC ; NEEDED? + POP AF +; + ; RECOVER HL AND MSR, THEN RETURN VIA RETIL + EX (SP),HL ; RECOVER HL, ADR TO STK + PUSH HL ; SAVE HL + LD HL,(HB_MSRSAV) ; GET SAVED MSR + EX (SP),HL ; MSR TO STK, RECOVER HL + RETIL ; RETURN FROM INT +; +HB_MSRSAV .DW 0 ; SAVED MSR +HB_RCSAV .DW 0 ; SAVED REASON CODE +; +Z280_PRIVSTR .TEXT "\r\n\r\n*** Privileged Instruction @$" +; +#ENDIF +; +; Z280 BANK COPY (CALLED FROM PROXY) +; +; USE Z280 PHYSICAL MEMORY DMA COPY TO PERFORM AN INTERBANK COPY. +; COPY FROM (HB_SRCBNK):(HL) TO (HB_DSTBNK):(DE) FOR BC BYTES. BOTH +; HB_SRCBNK AND HB_DSTBNK MUST BE INITIALIZED PRIOR TO CALLING THIS +; ROUTINE. +; +; ADDRESSES ARE TRANSLATED FROM LOGICAL (Z80) TO PHYSICAL (Z280) TO +; SETUP THE DMA COPY PARAMETERS. IF THE SOURCE OR DESTINATION RANGE +; CROSSES OVER THE BANKED/COMMON BOUNDARY AT $8000, THEN SPECIAL STEPS +; MUST BE TAKEN BECAUSE THE BANKED AND COMMON AEAS ARE PROBABLY NOT +; SEQUENTIALLY LOCATED IN PHYSICAL MEMORY. TWO ENTRY POINTS ARE +; PROVIDED. Z280_BNKCPY IS MUCH FASTER, BUT DOES NOT ACCOUNT FOR THE +; COPY RANGES CROSSING OVER THE BANKED/COMMON BOUNDARY (WORKS GREAT +; FOR ANY COPY KNOWN TO STAY WITHIN IT'S OWN AREA). Z280_BNKCPYX +; WILL HANDLE COPIES WHERE THE SOURCE AND/OR DESTINATION RANGES +; CROSS OVER THE BANKED/COMMON MEMORY BOUNDARY. IT DOES THIS BY +; BREAKING UP THE COPY REQUESTS INTO MULTIPLE REQUESTS THAT ALL FIT +; WITHIN A SINGLE BANKED/COMMON MEMORY SEGMENT AND CALLING Z280_BNKCPY +; ITERATIVELY UNTIL THE COPY IS COMPLETE. +; +; THERE IS ESSENTIALLY NO PROTECTION FOR CALLING THESE ROUTINES WITH +; INVALID PARAMETERS. FOR EXAMPLE, A REQUEST TO COPY $2000 BYTES +; STARTING AT $F000 EXCEEDS THE SIZE OF THE Z80 MEMORY SPACES AND +; RESULTS IN UNDEFINED BEHAVIOR. +; +; THE COPY IS ALWAYS DONE FROM START TO END. IF THE SOURCE AND +; DESTINATION RANGES OVERLAP, THEN YOU MUST TAKE THIS INTO ACCOUNT. +; +; THE ROUTINE FUNCTIONS LOGICALLY LIKE THE Z80 LDIR INSTRUCTION. ON +; RETURN THE SOURCE (HL) AND DESTINATION (DE) REGISTERS WILL BE LEFT +; POINTING TO THE NEXT BYTE THAT WOULD BE COPIED IF THE COPY ROUTINE +; CONTINUED. BC WILL BE 0. AF IS UNDEFINED. +; +#IF (MEMMGR == MM_Z280) +; +; ADJUST THE LENGTH OF THE COPY SUCH THAT BOTH THE SOURCE AND +; DESTINATION RANGES DO NOT CROSS OVER THE BANKED/COMMON MEMORY +; BOUNDARY. CALL Z280_BNKCPY TO DO AS MANY ITERATIONS AS NEEDED TO +; COMPLETE THE COPY. +; +; +Z280_BNKCPYX: + LD (Z280_BNKCPY_LEN),BC ; SAVE LENGTH +; + CALL Z280_BNKCPY_XOVER ; ADJUST FOR XOVER AS NEEDED + EX DE,HL ; SWAP SOURCE/DEST + CALL Z280_BNKCPY_XOVER ; ADJUST FOR XOVER AS NEEDED + EX DE,HL ; SWAP BACK +; + ; DO THE WORK, SAVE THE LEN OF THIS ITERATION + PUSH BC ; SAVE ITER LENGTH + CALL Z280_BNKCPY ; DO THE WORK +; + ;;; *DEBUG* SIMULATE CALL TO Z280_BNKCPY + ;;CALL NEWLINE + ;;CALL REGDMP ; *DEBUG* + ;;ADD HL,BC ; INCREMENT SRC ADR BY COUNT + ;;EX DE,HL ; SWAP + ;;ADD HL,BC ; INCREMENT DST ADR BY COUNT + ;;EX DE,HL ; SWAP BACK + ;;LD BC,0 ; COUNT IS NOW ZERO + ;;; END *DEBUG* +; + POP BC ; RECOVER ITER LENGTH +; + ; ACCUNT FOR WORK ACTUALLY PERFORMED + PUSH HL ; SAVE SOURCE ADR + LD HL,(Z280_BNKCPY_LEN) ; GET PENDING LENGTH + OR A ; CLEAR CARRY + SBC HL,BC ; SUBTRACT WHAT WE DID + PUSH HL ; MOVE NEW PENDING LEN + POP BC ; TO BC + POP HL ; RECOVER SOURCE ADR +; + ; SEE IF WE NEED TO ITERATE + LD A,B ; IS LENGTH + OR C ; ... NOW ZERO? + RET Z ; IF SO, ALL DONE + JR Z280_BNKCPYX ; ELSE ITERATE UNTIL DONE +; +Z280_BNKCPY_LEN .DW 0 ; TEMP STORAGE FOR BC +; +Z280_BNKCPY_XOVER: + ; DETECT XOVER IN RANGE AND ADJUST COPY LEN IF SO + ; HL=START, BC=LEN + ; BC IS REDUCED AS NEEDED TO AVOID XOVER + BIT 7,H ; START ABOVE 32K? + RET NZ ; YES, NO XOVER + PUSH HL ; SAVE START ADR + ADD HL,BC ; ADD COPY LEN + DEC HL ; CONVERT TO "LAST" BYTE OF RANGE + BIT 7,H ; ABOVE 32K? + POP HL ; RESTORE HL + RET Z ; IF NOT, NO XOVER +; + ; START IS BELOW 32K, END IS OVER 32K, XOVER IN SOURCE! + ; REDUCE LENGTH TO AVOID IT + ; COMPUTE (32K - START) FOR NEW LEN + PUSH DE ; SAVE DEST (DE) + PUSH HL ; SAVE START (HL) + LD DE,$8000 + EX DE,HL ; DE=START, HL=32K + OR A ; CLEAR CARRY + SBC HL,DE ; HL = NEW LEN + PUSH HL ; MOVE NEW LEN + POP BC ; ... TO BC + POP HL ; RECOVER START + POP DE ; RECOVER DEST + RET ; RETURN +; +Z280_BNKCPY: + ; Z280 MEMORY TO MEMORY DMA + ; USE FLOW THROUGH MODE + ; SINGLE BYTE TRANSFER + ; TRANSACTION DESCRIPTION REGISTER (TDR) + ; %0000 0000 0000 0000 + ; - AUTO INCREMENT MEMORY + ; - FLOWTHROUGH OPERATION + ; - SINGLE TRANSACTION (CAN WE USE CONTINUOUS???) + ; - 1 BYTE XFER SIZE +; + ; SAVE INCOMING REGISTERS + PUSH HL + PUSH DE + PUSH BC +; + PUSH BC ; SAVE COUNT + PUSH HL ; SAVE SOURCE ADDRESS +; + ; SELECT I/O PAGE $FF + LD C,Z280_IOPR ; I/O PAGE REGISTER + LDCTL HL,(C) ; GET CURRENT I/O PAGE + LD (IOPRSAV),HL ; SAVE IT + LD L,$FF ; I/O PAGE $FF + LDCTL (C),HL +; + LD C,Z280_DMA0_DSTL ; START WITH DEST REG LO +; + LD A,(HB_DSTBNK) ; DEST BANK TO ACCUM + CALL Z2DMAADR ; SETUP DEST ADR REGS +; + POP DE ; SRC ADR TO DE + LD A,(HB_SRCBNK) ; DEST BANK TO ACCUM + CALL Z2DMAADR ; SETUP SOURCE ADR REGS +; + POP HL ; COUNT TO HL + OUTW (C),HL + INC C ; BUMP TO TDR +; + LD HL,$8000 ; ENABLE DMA0 TO RUN! + OUTW (C),HL +; + ; WAIT FOR XFER TO COMPLETE +Z2DMALOOP: + INW HL,(C) ; WORD INPUT + BIT 7,H ; CHECK EN BIT OF TDR + JR NZ,Z2DMALOOP ; LOOP WHILE ACTIVE +; + ; RESTORE I/O PAGE + LD C,Z280_IOPR ; I/O PAGE REGISTER + LD HL,(IOPRSAV) ; RESTORE I/O PAGE + LDCTL (C),HL +; + ; SETUP RETURN VALUES + POP BC ; RECOVER ORIGINAL BC + POP DE ; RECOVER ORIGINAL DE + POP HL ; RECOVER ORIGINAL HL + ADD HL,BC ; INCREMENT SRC ADR BY COUNT + EX DE,HL ; SWAP + ADD HL,BC ; INCREMENT DST ADR BY COUNT + EX DE,HL ; SWAP BACK + LD BC,0 ; COUNT IS NOW ZERO +; + RET +; +Z2DMAADR: + ; SET ADDRESS REGISTERS, BANK IN A, ADDRESS IN DE + ; C POINTS TO FIRST DMA ADR PORT TO SET + ; A=R000 BBBB, DE=0AAA AAAA AAAA AAAA + ; RC: DMA HI=0000 RBBB BAAA 1111 LO=1111 AAAA AAAA AAAA + ; ZZ: DMA HI=R000 0BBB BAAA 1111 LO=1111 AAAA AAAA AAAA + BIT 7,D ; HIGH RAM? + JR Z,Z2DMAADR1 ; NO, SKIP + LD A,$8F ; SUBSTITUTE COMMON RAM BANK ID +; +Z2DMAADR1: + ; ADR HI FROM A:DE + LD L,D ; L=?AAA AAAA + LD H,A ; H=R000 BBBB + SLA L ; L=AAAA AAA0 ? + SRL H ; H=0R00 0BBB B + RR L ; L=BAAA AAAA 0 + LD A,$0F ; A=0000 1111 + OR L ; A=BAAA 1111 + LD L,A ; L=BAAA 1111 +; + ; MOVE THE RAM/ROM BIT. + ; RCBUS DMA HI=0000 RBBB BAAA 1111 LO=1111 AAAA AAAA AAAA + ; ZZ80MB DMA HI=R000 0BBB BAAA 1111 LO=1111 AAAA AAAA AAAA + BIT 6,H ; RAM BIT SET? + JR Z,Z2DMAADR2 ; IF NOT, ALL DONE + RES 6,H ; OTHERWISE, REMOVE RAM BIT + LD A,RAMBIAS >> 6 ; RAM OFFSET (TOP 8 BITS) + OR H ; RECOMBINE + LD H,A ; AND PUT BACK IN H +; +Z2DMAADR2: + PUSH HL ; SAVE IT FOR NOW + + ; ADR LO FROM DE: + LD L,E ; L=AAAA AAAA + LD A,$F0 ; A=1111 0000 + OR D ; A=1111 AAAA + LD H,A ; HL=1111 AAAA AAAA AAAA +; + ; SET ADR LO REG + OUTW (C),HL + INC C ; BUMP TO ADR HI REG +; + ; SET ADR HI REG + POP HL ; RECOVER THE HI VAL + OUTW (C),HL + INC C ; BUMP TO NEXT REG +; + RET +; +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; ROUTINES FOR NON VOLITILE (NVRAM) SWITCHES +;-------------------------------------------------------------------------------------------------- +; +; Initial Initialisation +; +NVR_INIT: + ; Check for the existence of NV RAM by attempting to read a byte + LD B,BF_RTCGETBYT ; GET RTC BYTE + LD C,0 ; FIRST Byte address in RTC + CALL HB_DISPATCH ; CALL RTC + RET NZ ; GET BYTE Failed; Noting to do, HCB is correct. Status =0 + ; + CALL NVSW_READ ; read the full data into hcb + JR NZ, NVR_INIT_DEF ; failed to correclty read data + ; + CALL NVSW_CHECKSUM ; checksum calc into A + LD HL,CB_SWITCHCK ; address of HCB value + CP (HL) ; compare Caculated Check, with hcb Check Value + JR Z,NVR_INIT_END ; The same so success +NVR_INIT_DEF: + ; failed Read or Checksum + CALL NVSW_DEFAULTS ; set defaults into HCB, which include the "W" first byte + LD HL,CB_SWITCHES ; which is incorrect, need the value of 1 + LD (HL),1 ; to indicate we while not inited, we do have NVRAM +NVR_INIT_END: + RET +; +; Return Status +; A=0 if no NVRAM exists. with NZ flag set +; A=1 if NVRAM is present. with Z flag set +; A='W' if NVRAM is fullly inited. with Z flag set +; Note the NZ flag can be used to detect and return an error condition +; +NVSW_STATUS: + LD A,(CB_SWITCHES) ; the status byte + LD B,A ; save it + AND 1 ; applies to 'W' and $01 status, -> 1 + CP 1 ; set NZ based on A = 1 + LD A,B ; return the + RET +; +; RESET CONTENTS OF NVRAM, STORING INTO +; RETURN NONZERO IF WRITTEN - ZERO IF NOT WRITTEN +; +NVSW_RESET: + CALL NVSW_DEFAULTS ; copy defaults into HCB + ; Fall Through and Update (write) status + ; JP NVSW_UPDATE +; +; UPDATE HBIOS SHADOW TO NVRAM, AFTER SETTING HBIOS VALUE +; RETURN NONZERO IF WRITTEN - ZERO IF NOT WRITTEN +; +NVSW_UPDATE: + + CALL PC_ASTERISK + + CALL NVSW_CHECKSUM ; CALC checksum into A + LD (CB_SWITCHCK),A ; store checksum in hcb + CALL NVSW_WRITE ; write the bytes to nvr + RET Z ; Successful write, return + + CALL PC_ASTERISK + + ; write failed for some reason ??? + LD A,1 + LD (CB_SWITCHES),A ; ensure hcb signature=1 + OR $FF ; failure + + CALL PC_ASTERISK + + RET ; return NZ flag +; +; PERFORM CHECKSUM CALC OF DATA IN HCB +; RETURN A REGISTER -> CONTAINING THE CHECKSUM +; +NVSW_CHECKSUM: + XOR A + LD B,NVSW_SIZE ; NUMBER OF BYTES TO CHECK + LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB) +NVSW_CHECKSM1: + XOR (HL) ; XOR The Byte + INC HL ; HL address + DJNZ NVSW_CHECKSM1 ; LOOP + XOR RMJ << 4 | RMN ; FIRST BYTE OF VERSION INFO + XOR RUP << 4 | RTP ; SECOND BYTE OF VERSION INFO + RET +; +; COPY DEFAULTS INTO HCB +; +NVSW_DEFAULTS: + LD HL,NVSW_DEFAULT ; Copy default bytes from + LD DE,CB_SWITCHES ; to hbios HCB location + LD BC,NVSW_SIZE ; number of bytes top copy + LDIR ; copy bytes + RET +; +; LOAD BYTES FROM NVR - INTO HBIOS DCB +; RETURN ZERO IF READ SUCCESS, NON-ZERO IF CANT READ +; +NVSW_READ: + LD B,NVSW_SIZE + 1 ; NUMBER OF BYTES, + 1 for CHECKSUM + LD C,0 ; FIRST Byte address in RTC + LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB) +NVSW_READ1: + PUSH HL ; SAVE ADDRESS + PUSH BC ; Save Loop counter + LD B,BF_RTCGETBYT ; GET RTC BYTE (at a time), requires loop + CALL HB_DISPATCH ; CALL RTC + POP BC ; Restore Loop + POP HL ; restore Block pointer + RET NZ ; ERROR JUST RETURN + LD (HL),E ; store IT + INC C ; RTC Byte address + INC HL ; HL address + DJNZ NVSW_READ1 ; LOOP to the next byte +NVSW_READ2: + LD A,(CB_SWITCHES) ; FIRST BYTE + CP 'W' ; MUST BE 'W' + RET ; ZERO IF OK, NON-ZERO IF ISSUE +; +; SAVE BYTES FROM HBIOS DCB - INTO NVR +; RETURN ZERO IF SUCCESS, NON-ZERO IF CANT WRITE +; +NVSW_WRITE: + LD B,NVSW_SIZE + 1 ; NUMBER OF BYTES, + 1 for CHECKSUM + LD C,0 ; FIRST Byte address in RTC + LD HL,CB_SWITCHES ; First Byte in HBIOS (HCB) +NVSW_WRITE1: + PUSH HL ; SAVE ADDRESS + PUSH BC ; Save Loop counter + LD E,(HL) ; Value to Write + LD B,BF_RTCSETBYT ; SET RTC BYTE + CALL HB_DISPATCH ; CALL RTC + POP BC ; Restore Loop + POP HL ; restore Block pointer + RET NZ ; ERROR JUST RETURN + INC C ; RTC Byte address + INC HL ; HL address + DJNZ NVSW_WRITE1 ; LOOP, One Byte at a Time +NVSW_WRITE2: + XOR A ; SUCCESS + RET ; ZERO IF OK, NON-ZERO IF ISSUE +; +; DEFAULT VALUES FOR NVRAM, USED TO RESET NVR +; +NVSW_DEFAULT: + .DB 'W' ; Signature Byte + .DB 'H' ; Default Boot - Rom Application [H]elp + .DB DBOOT_ROM ; Default Boot - ROM Application + .DB 0 ; Auto Boot - NO auto boot + ; Configure above byte from (BOOT_TIMEOUT != -1) +; SIZE OF NVR BYTES +NVSW_SIZE .EQU $ - NVSW_DEFAULT +; +HB_INTFUNC_END .EQU $ +; +;================================================================================================== +; UTILITY FUNCTIONS +;================================================================================================== +; +HB_UTIL_BEG .EQU $ +; +#DEFINE USEDELAY +#INCLUDE "util.asm" +#INCLUDE "time.asm" +#INCLUDE "bcd.asm" +#INCLUDE "decode.asm" +#INCLUDE "encode.asm" +; +#IF (WBWDEBUG == USEXIO) +#INCLUDE "xio.asm" +#ENDIF +#IF (WBWDEBUG == USEMIO) +#INCLUDE "mio.asm" +#ENDIF +; +; INCLUDE LZSA2 decompression engine if required. +; +#IF ((CVDUENABLE | GDCENABLE | TMSENABLE | VGAENABLE | VRCENABLE) & USELZSA2) +#INCLUDE "unlzsa2s.asm" +#ENDIF +; +;-------------------------------------------------------------------------------------------------- +; 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, TRY DEBUG OUTPUT +; + ; 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: +; +#IF (WBWDEBUG == USEXIO) + LD A,E ; GET OUTPUT CHAR BACK TO ACCUM + CALL XIO_OUTC ; OUTPUT VIA XIO +#ENDIF +; +#IF (WBWDEBUG == USEMIO) + LD A,E + CALL MIO_OUTC ; OUTPUT VIA MIO +#ENDIF +; +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, TRY DEBUG INPUT +; + ; 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: +; +#IF (WBWDEBUG == USEXIO) + CALL XIO_INC ; GET CHAR +#ENDIF +; +#IF (WBWDEBUG == USEMIO) + CALL MIO_INC ; GET CHAR +#ENDIF +; +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, TRY DEBUG DEBUG STATUS +; + ; 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: +; +#IF (WBWDEBUG == USEXIO) + CALL XIO_IST ; GET STATUS +#ENDIF +; +#IF (WBWDEBUG == USEMIO) + CALL MIO_IST ; GET STATUS +#ENDIF +; +CST2: + ; RESTORE REGISTERS (AF IS OUTPUT) + POP HL + POP DE + POP BC + RET +; +;================================================================================================== +; DYNAMIC RAM SIZE DETECTION ROUTINE +;================================================================================================== +; +; THIS CODE IS COPIED TO $F000 TO PERFORM RAM SIZE DETECTION. +; +#IFDEF SIZERAM +; +RS_IMAGE: + .ORG $F000 +RS_START: + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; SAVE IT + + LD C,0 ; RUNNING BANK COUNT + LD HL,$7FFF ; BYTE TEST ADDRESS + LD IX,RS_ARY ; ORIG BYTE STORAGE ARRAY PTR +RS_LOOP1: + LD A,C + ADD A,$80 ; OFFSET BY START OF RAM BANKS + CALL RS_BNKSEL ; SELECT THE BANK + + LD A,(HL) ; GET ORIGINAL VALUE + LD (IX),A ; SAVE IT TO RESTORE LATER + INC IX ; BUMP IX + + LD A,$AA ; TEST LOC WITH $AA + LD (HL),A ; AVOID PROBLEMS WITH + LD (HL),A ; ... DS1210 + LD (HL),A + LD A,(HL) + CP $AA + JR NZ,RS_DONE + + LD A,$55 ; TEST LOC WITH $55 + LD (HL),A + LD A,(HL) + CP $55 + JR NZ,RS_DONE + + ; STORE A UNIQUE VALUE + LD A,C + LD (HL),A + OR A ; ZERO? + JR Z,RS_NEXT ; SKIP STORED VALUE CHECK + + ; VERIFY ALL STORED VALUES + LD B,C ; INIT LOOP COUNTER + LD E,0 ; INIT BANK ID +RS_LOOP3: + LD A,E + ADD A,$80 + CALL RS_BNKSEL + LD A,(HL) + CP E ; VERIFY + JR NZ,RS_DONE ; ABORT IF MISCOMPARE + INC E ; NEXT BANK + DJNZ RS_LOOP3 +; +RS_NEXT: + INC C ; ADD 1 TO RAM BANK COUNT + JR RS_LOOP1 ; AND LOOP TILL DONE +; +RS_DONE: + LD E,C ; FINAL BANK COUNT TO E + LD A,C + OR A + JR Z,RS_LOOPZ + ; RESTORE SAVED VALUES + LD IX,RS_ARY + LD B,C ; LOOP COUNT + LD C,$80 ; BANK ID +RS_LOOP2: + LD A,C + CALL RS_BNKSEL + INC C + LD A,(IX) ; GET VALUE + LD (HL),A ; RESTORE IT + INC IX + DJNZ RS_LOOP2 ; ALL BANKS +RS_LOOPZ: +; + ; RETURN TO ORIGINAL BANK + POP AF + CALL RS_BNKSEL + LD A,E ; RETURN BANK COUNT + RET +; +; SPECIAL BANK SELECT FOR MEMORY SIZING +; +RS_BNKSEL: + #IF (MEMMGR == MM_Z280) + ; IF Z280 MEMMGR, THEN WE ARE IN SYSTEM MODE, SO WE NEED TO + ; BANK SELECT THE SYSTEM PDRS INSTEAD OF THE NORMAL USER PDRS. + PUSH BC ; SAVE BC + PUSH HL ; SAVE HL + LD B,$10 ; FIRST SYSTEM PDR + CALL Z280_BNKSEL ; DO IT + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET ; DONE + #ELSE + ; NORMAL BANK SELECT + JP HBX_BNKSEL + #ENDIF +; +RS_ARY .EQU $ +; +RS_LEN .EQU $ - RS_START + .ORG RS_IMAGE + RS_LEN +; +#ENDIF +; +;================================================================================================== +; FRONT PANEL SUPPORT +;================================================================================================== +; +; FRONT PANEL HARDWARE DETECTION +; +; WE ARE REALLY JUST CHECKING FOR SWITCHES. NO WAY TO QUERY FOR +; LEDS. WE CHECK FOR I/O CONFLICT WITH VGARC IF ACTIVE. +; +FP_DETECT: + ; D: LEDS ACTIVE, E: SWITCHES ACTIVE + LD D,TRUE ; ASSUME ACTIVE FOR NOW + LD E,TRUE ; ASSUME ACTIVE FOR NOW +; + ; IF VGARC IS ENABLED, CHECK IF IT IS ACTIVE. IF SO AND THE + ; I/O PORTS CONFLICT, DEACTIVATE FRONT PANEL. +; + #IF (VRCENABLE) + LD A,(VRC_ACTIVE) ; GET VGARC ACTIVE STATUS + OR A ; SET FLAGS + JR Z,FP_DETECT1 ; IF NO, CONTINUE + #IF ((FPLED_IO >= $00) & (FPLED_IO <= $0F)) + ; CONFLICT, DEACTIVATE LEDS + LD D,FALSE ; FP LEDS NOT ACTIVE + #ENDIF + #IF ((FPSW_IO >= $00) & (FPSW_IO <= $0F)) + ; CONFLICT, DEACTIVATE SWITCHES + LD E,FALSE ; FP SWITCHES NOT ACTIVE + #ENDIF + #ENDIF +; +FP_DETECT1: + ; THE SWITCH HARDWARE MAY OR MAY NOT BE INSTALLED. SO, HERE WE + ; ATTEMPT TO CONFIRM WE HAVE A VALID PORT. CREDIT TO STEPHEN + ; COUSINS FOR THIS APPROACH. + LD C,FPSW_IO ; ADR OF SWITCH PORT + EZ80_IO + IN C,(C) ; READ IT USING IN (C) + EZ80_IO + IN A,(FPSW_IO) ; READ IT USING IN (PORT) + CP C ; PORT FLOATING ON MISMATCH + JR NZ,FP_DETECT2 ; NO H/W, SET FLAG + CP $FF ; PORT FLOATING ON $FF + JR Z,FP_DETECT2 ; NO H/W, SET FLAG + JR FP_DETECTZ ; H/W EXISTS, DONE +; +FP_DETECT2: + LD E,FALSE ; RECORD NOT PRESENT +; +FP_DETECTZ: + LD (FP_ACTIVE),DE ; RECORD RESULTS + RET ; DONE +; +#IF (FPLED_ENABLE) +; +; SET FRONT PANEL LEDS FROM VALUE IN A +; +FP_SETLEDS: + PUSH HL ; SAVE HL + LD L,A ; LED VALUE TO L + LD A,(FPLED_ACTIVE) ; LEDS ACTIVE? + OR A ; SET FLAGS + LD A,L ; RESTORE REG A + JR Z,FP_SETLEDS1 ; BAIL OUT IF NOT ACTIVE + #IF (FPLED_INV) + XOR $FF ; INVERT BITS IF NEEDED + #ENDIF + + EZ80_IO + OUT (FPLED_IO),A ; WRITE +FP_SETLEDS1: + POP HL ; RESTORE HL + RET ; DONE +; +#ENDIF +; +#IF (FPSW_ENABLE) +; +; GET FRONT PANEL SWITCH SETTINGS +; +FP_GETSWITCHES: + LD A,(FPSW_ACTIVE) ; SWITCHES ACTIVE? + OR A ; SET FLAGS + RET Z ; BAIL OUT IF NOT ACTIVE + EZ80_IO + IN A,(FPSW_IO) ; READ SWITCHES + #IF (FPSW_INV) + XOR $FF ; INVERT BITS IF NEEDED + #ENDIF + RET ; DONE +; +; +#ENDIF +; +FP_ACTIVE: +FPSW_ACTIVE .DB TRUE +FPLED_ACTIVE .DB TRUE + +#IF (CPUFAM != CPU_EZ80) ; eZ80 WILL RETURNED ITS MEASURED CPUOSC - SO NO NEED FOR DETECTION HERE +; +;================================================================================================== +; CPU SPEED DETECTION USING DS-1302 RTC +;================================================================================================== +; +HB_CPUSPD: +; +#IF (DSRTCENABLE & ((CPUFAM == CPU_Z80) | (CPUFAM == CPU_Z180))) +; + LD A,(DSRTC_STAT) ; GET RTC STATUS + OR A ; SET FLAGS + RET NZ ; NOT ZERO IS ERROR +; +HB_CPUSPD1: + #IF (CPUFAM == CPU_Z180) + ; USE MEM W/S = 2 AND I/O W/S = 3 FOR TEST + IN0 A,(Z180_DCNTL) + PUSH AF + LD A,$B0 + ;LD A,$F0 + OUT0 (Z180_DCNTL),A + #ENDIF + + ; WAIT FOR AN INITIAL TICK TO ALIGN, THEN WAIT + ; FOR A SECOND TICK TO GET A FULL ONE SECOND LOOP COUNT. + ; WAITSEC WILL SET ZF IF AN OVERFLOW OCCURS (MEANING THAT THE + ; CLOCK IS NOT TICKING). THERE IS NO + ; POINT IN CALLING HB_WAITSEC AGAIN IN THAT CASE, SO WE ONLY + ; CALL HB_WAITSEC AGAIN IF ZF IS NOT SET. + CALL DSRTC_START + 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 AGAIN, BUT ONLY IF ZF IS NOT SET + CALL NZ,HB_WAITSEC ; WAIT FOR SECONDS TICK +; + #IF (CPUFAM == CPU_Z180) + ; RESTORE W/S SETTINGS FROM BEFORE TEST + POP AF + OUT0 (Z180_DCNTL),A + #ENDIF +; + ; MOVE LOOP COUNT TO HL + PUSH DE + POP HL +; + ; CHECK FOR OVERFLOW (NOT TICKING) + LD A,H + OR L + JR Z,HB_CPUSPD2 ; FAILURE, USE DEFAULT CPU SPEED +; + ; TIMES 4 FOR CPU SPEED IN KHZ +; RES 0,L ; GRANULARITY + SLA L + RL H + SLA L + RL H +; + ; RETURN CURRENT CPU SPD (KHZ) IN HL + XOR A ; SIGNAL SUCCESS + RET +; +HB_WAITSEC: + ; WAIT FOR SECONDS TICK + ; RETURN SECS VALUE IN A, LOOP COUNT IN DE + ; ZF IS SET ON OVERFLOW (CLOCK NOT TICKING) + LD DE,0 ; INIT LOOP COUNTER +HB_WAITSEC1: +; + #IF (CPUFAM == CPU_Z80) + ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 + CALL DLY32 + CALL DLY16 + CALL DLY1 ; 27 TSTATES + SBC HL,HL ; 15 TSTATES + SBC HL,HL ; 15 TSTATES + INC HL ; 6 TSTATES + INC HL ; 6 TSTATES + #ENDIF +; + #IF (CPUFAM == CPU_Z180) + ; LOOP TARGET IS 4000 T-STATES, SO CPU FREQ IN KHZ = LOOP COUNT * 4 + CALL DLY2 + ADD IX,BC ; 10 + 4 = 14 TSTATES + NOP ; 5 TSTATES + NOP ; 5 TSTATES + NOP ; 5 TSTATES + NOP ; 5 TSTATES + #ENDIF +; + PUSH DE ; SAVE COUNTER + CALL HB_RDSEC ; GET SECONDS + POP DE ; RESTORE COUNTER + 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 DE + OR E ; ... FOR OVERFLOW + RET Z ; TIMEOUT, SOMETHING IS WRONG + JR HB_WAITSEC1 ; LOOP +; +HB_RDSEC: + ; READ SECONDS BYTE INTO A + LD E,$81 ; SECONDS REGISTER + CALL DSRTC_CMD ; SEND THE COMMAND + CALL DSRTC_GET ; READ THE REGISTER + CALL DSRTC_END ; FINISH IT + LD A,E ; VALUE TO A + RET +; +#ENDIF +; +HB_CPUSPD2: + ; HANDLE NO RTC OR NOT TICKING + OR $FF ; SIGNAL ERROR + RET ; AND DONE +#ENDIF ; CPUFAM != CPU_EZ80 +; +HB_UTIL_END .EQU $ +; +;================================================================================================== +; DISPLAY SUMMARY OF ATTACHED UNITS/DEVICES +;================================================================================================== +; +HB_PRTSUM_BEG .EQU $ +; +PRTSUM: + CALL NEWLINE2 ; SKIP A LINE + LD DE,PS_STRHDR ; POINT TO HEADER + CALL WRITESTR ; PRINT IT +; + LD C,BF_SYSGET_CIOCNT ; CHARACTER DEVICES + LD HL,PS_SERIAL + CALL PRT_ALLD +; + LD C,BF_SYSGET_DIOCNT ; DISK DRIVES + LD HL,PS_DISK + CALL PRT_ALLD +; + LD C,BF_SYSGET_VDACNT ; VIDEO DEVICES + LD HL,PS_VIDEO + CALL PRT_ALLD +; + LD C,BF_SYSGET_SNDCNT ; SOUND DEVICES + LD HL,PS_SOUND + CALL PRT_ALLD + RET +; +PRT_ALLD: + LD B,BF_SYSGET ; FUNC: SYSTEM INFO GET + RST 08 ; E := UNIT COUNT + LD B,E ; MOVE TO B FOR LOOP COUNT + LD A,E ; MOVE TO ACCUM + OR A ; SET FLAGS + RET Z ; IF NONE, JUST RETURN + LD C,0 ; C WILL BE UNIT INDEX +PRT_ALLD1: + PUSH BC ; SAVE LOOP CONTROL + PUSH DE + PUSH HL + CALL JPHL ; CALL THE ROUTINE PASSED IN HL + POP HL + POP DE + POP BC ; RESTORE LOOP CONTROL + INC C ; BUMP UNIT INDEX + DJNZ PRT_ALLD1 ; LOOP THRU ALL DEVICES + RET +; +; 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 + CP 10 ; CHECK FOR MULTIPLE DIGITS + CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED + 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, C:=DISK ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_DDMD ; 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 + JP NZ,PS_PRT18 ; IF FLOPPY, JUMP AHEAD + LD C,E + LD DE,PS_DTHARD + LD A,00001111B + CALL PRTIDXMSK + CALL PS_PAD18 ; PAD TO 18 SPACES + 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 + AND $0F ; ISOLATE TYPE BITS + CP 4 ; ROM DISK? + JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB + CP 5 ; RAM DISK? + JR Z,PS_PRTDC1 ; PRINT CAPACITY IN KB + CP 7 ; FLASH 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 PRTDEC32 ; PRINT DWORD IN DECIMAL + PRTS("MB$") ; PRINT SUFFIX + CALL PC_COMMA + PRTS("LBA$") ; FOR NOW, WE ASSUME HARD DISK DOES LBA + RET ; DONE +; +PS_PRTDC1: + ; PRINT ROM/RAM 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 PRTDEC32 ; PRINT DWORD IN DECIMAL + 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 +; + LD A,%00011000 ; DISPLAY FORM FACTOR + LD DE,PS_FLP_FSTR ; WHICH IS DEFINED IN + CALL PRTIDXMSK ; BITS 5 AND 6. +; + LD A,%00000100 ; DISPLAY SIDES + LD DE,PS_FLP_SSTR ; WHICH IS DEFINED + CALL PRTIDXMSK ; IN BIT 4 +; + LD A,%00000011 ; DISPLAY DENSITY + LD DE,PS_FLP_DSTR ; WHICH IS DEFINED IN + CALL PRTIDXMSK ; BITS 2 AND 3. +; + 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("Char $") + 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_SDUART ; 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 CHARACTER TYPE (SERIAL ATTRIBUTE IN E) +; +PS_PRTST: + LD HL,PS_STPPT + BIT 6,C + JP NZ,PS_PRT18 ; PARALLEL TYPE? + LD HL,PS_STRS232 ; ASSUME RS-232 + BIT 7,C ; 0=RS-232, 1=TERMINAL + JP Z,PS_PRT18 ; HANDLE TERMINAL TYPE + LD HL,PS_STTERM ; TYPE IS TERMINAL + JP PS_PRT18 +; +; PRINT SERIAL CONFIG (UNIT IN E, ATTRIBUTE IN C) +; +PS_PRTSC: + BIT 6,C ; PARALLEL TYPE? + JR NZ,PSPRTPC0 + + BIT 7,C ; 0=RS-232, 1=TERMINAL + JP NZ,PS_PRTSC1 ; PRINT TERMINAL CONFIG +; + ; PRINT RS-232 CONFIG + LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG + LD C,E ; SET SERIAL UNIT NUM + RST 08 ; DE:HL := BAUD RATE + LD A,D ; TEST FOR $FF + AND E + INC A ; SET Z IF DE == $FF + JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED +; +PS_PRTSC0: + ; PRINT BAUD RATE + PUSH DE ; PRESERVE DE + LD A,D + AND $1F ; ISOLATE ENCODED BAUD RATE + LD L,A ; PUT IN L + LD H,0 ; H IS ALWAYS ZERO + LD DE,75 ; BAUD RATE DECODE CONSTANT + CALL DECODE ; DE:HL := BAUD RATE + LD BC,HB_BCDTMP ; POINT TO TEMP BCD BUF + CALL BIN2BCD ; CONVERT TO BCD + CALL PRTBCD ; AND PRINT IN DECIMAL + POP DE ; RESTORE DE +; + ; PRINT DATA BITS + PUSH DE ; PRESERVE DE + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + AND $03 ; ISOLATE DATA BITS VALUE + ADD A,'5' ; CONVERT TO CHARACTER + CALL COUT ; AND PRINT + POP DE ; RESTORE DE +; + ; PRINT PARITY + PUSH DE ; PRESERVE DE + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + RRCA ; SHIFT RELEVANT BITS + RRCA ; ... + RRCA ; ... + AND $07 ; AND ISOLATE DATA BITS VALUE + LD HL,PS_STPARMAP ; CHARACTER LOOKUP TABLE + CALL ADDHLA ; APPLY OFFSET + LD A,(HL) ; GET CHARACTER + CALL COUT ; AND PRINT + POP DE ; RESTORE DE +; + ; PRINT STOP BITS + CALL PC_COMMA ; FORMATTING + LD A,E ; GET CONFIG BYTE + RRCA ; SHIFT RELEVANT BITS + RRCA ; ... + AND $01 ; AND ISOLATE DATA BITS VALUE + ADD A,'1' ; MAKE IT A CHARACTER + CALL COUT ; AND PRINT +; + RET +; +PSPRTPC0: + LD B,BF_CIOQUERY ; HBIOS FUNC: GET CIO CONFIG + LD C,E ; SET PARALLEL UNIT NUM + RST 08 ; DE:HL := I/O SETTING + LD A,D ; TEST FOR $FF + AND E + INC A ; SET Z IF DE == $FF + JP Z,PS_PRTNUL ; $FF == NO CONFIG DEFINED +; +PS_PRTPC0: + LD C,E ; DISPLAY PIO TYPE + LD A,11000000B ; WHICH IS DEFINE BY + LD DE,PIO_MODE_STR ; BITS 6 AND 7 + JP PRTIDXMSK +; RET ; TRICK RETURN +; +PS_PRTSC1: + ; PRINT TERMINAL CONFIG + LD A,C ; GET ATTRIBUTE VALUE + CP $BF ; 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("Term Module$") + CALL PC_COMMA + PRTS("ANSI$") + RET +; +; PRINT ONE LINE VIDEO UNIT/DEVICE INFO, VIDEO UNIT INDEX IN C +; +PS_VIDEO: + PUSH BC ; SAVE UNIT INDEX FOR LATER +; + ; UNIT COLUMN + PRTS("Video $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT, ASSUME SINGLE DIGIT + PRTS(" $") ; PAD TO NEXT COLUMN +; + ; DEVICE COLUMN + LD B,BF_VDADEV ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + RST 08 ; DE:=DEVTYP/NUM, H:=DISK ATTRIBUTES + PUSH BC ; SAVE ATTRIBUTES + LD HL,PS_VDVDU ; 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 + JP PS_PRT18 ; PRINT +; +; 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 SOUND CONFIG +; +PS_SOUND: + PUSH BC + + ; UNIT COLUMN + PRTS("Sound $") + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT + CP 10 ; CHECK FOR MULTIPLE DIGITS + CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED + PRTS(" $") ; PAD TO NEXT COLUMN + + ; DEVICE COLUMN + + PUSH BC + LD E,C + XOR A + LD DE,PS_SDSND ; POINT TO DEVICE TYPE NAME TABLE + CALL PRTIDXDEA ; PRINT DEVICE NMEMONIC PADDED TO FIELD WIDTH + LD A,C ; MOVE UNIT NUM TO A + CALL PRTDECB ; PRINT IT + CALL PC_COLON + LD A,(PRTIDXCNT) + SUB 12-1 ; SUBTRACT FIELD WIDTH (LESS THE COLON) + NEG ; MAKE IT A POSITIVE NUMBER + CALL PS_PAD ; PAD AS NEEDED + POP BC + + ; DEVICE TYPE +; + LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + LD E,BF_SNDQ_DEV + RST 08 + PUSH BC + LD A,B + LD DE,PS_SDSN76489 + CALL PRTIDXDEA + CALL PS_PAD18 + POP BC +; + ; DEVICE CHARACTERISTICS +; + LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C + LD E,BF_SNDQ_CHCNT + RST 08 + LD A,B + CALL PRTDECB + LD A,'+' + CALL COUT + LD A,C + CALL PRTDECB + PRTS(" CHANNELS$") + CALL NEWLINE +; + POP BC + RET +; +; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE +; +PS_PRTDEV: + EX DE,HL + LD A,H ; TYPE ID + CALL PRTIDXDEA ; PRINT TYPE LABEL + LD A,L ; UNIT NUMBER + CALL PRTDECB ; PRINT NUM, ASSUME 1 CHAR + CALL PC_COLON ; PRINT COLON + LD A,(PRTIDXCNT) + SUB 12-2+1 ; 12 CHAR FIELD - 1 POS FOR UNIT NUM AND 1 POS FOR COLON + NEG + CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) + RET +; +; PRINT DEVICE MNEMONIC, DEVTYP/NUM SPECIFIED IN DE +; +PS_PRTNUL: + LD HL,PS_STRNUL + ; FALL THRU TO PS_PRT +; +; PRINT STRING AT (HL), $ TERM, RETURN CHARS PRINTED IN C +; +PS_PRT: 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 +; +; PAD 18 CHARACTER FIELD +; +PS_PAD18: + LD A,(PRTIDXCNT) + LD C,A + JR PS_PRT18A +; +; PRINT STRING AT HL IN 18 CHARACTER FIELD +; +PS_PRT18: + CALL PS_PRT ; PRINT $ TERM STRING AT (HL), C:=CHARS PRINTED +PS_PRT18A: + LD A,18 ; 18 CHAR FIELD + SUB C +; CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A) +; +; PAD N SPACES SPECIFIED IN A +; +PS_PAD: LD B,A + LD A,' ' +PS_PAD1: + CALL COUT + DJNZ PS_PAD1 + RET +; +HB_CPU_STR: .TEXT " Z80$" + .TEXT " Z80180$" + .TEXT " Z8S180-K$" + .TEXT " Z8S180-N$" + .TEXT " Z80280$" + .TEXT " eZ80$" +; +PS_STRNUL .TEXT "--$" ; DISPLAY STRING FOR NUL VALUE +; +; DISK DEVICE STRINGS +; +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$" +PS_DDPPA .TEXT "PPA$" +PS_DDIMM .TEXT "IMM$" +PS_DDSYQ .TEXT "SYQ$" +PS_DDCHUSB .TEXT "CHUSB$" +PS_DDCHSD .TEXT "CHSD$" +; +; DISK TYPE STRINGS +; +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_DTFSH .TEXT "Flash Drive$" +PS_DTCD .TEXT "CD-ROM$" +PS_DTCRT .TEXT "Cartridge$" +PS_DTOTHER .TEXT "???$" +; +; FLOPPY ATTRIBUTE STRINGS +; +PS_FLP_FSTR: .TEXT "8\",$" ; PS_FLP8 + .TEXT "5.25\",$" ; PS_FLP5 + .TEXT "3.5\",$" ; PS_FLP3 + .TEXT "???\",$" ; PS_FLPN +; +PS_FLP_SSTR: .TEXT "SS/$" ; PS_FLPSS + .TEXT "DS/$" ; PS_FLPDS +; +PS_FLP_DSTR: .TEXT "SD$" ; PS_FLPSD + .TEXT "DD$" ; PS_FLPDD + .TEXT "HD$" ; PS_FLPHD + .TEXT "ED$" ; PS_FLPED +; +; CHARACTER DEVICE STRINGS +; +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 "PIO$" +PS_SDUF .TEXT "UF$" +PS_SDDUART .TEXT "DUART$" +PS_SDZ2U .TEXT "Z2U$" +PS_SDLPT .TEXT "LPT$" +PS_SDESPCON .TEXT "ESPCON$" +PS_SDESPSER .TEXT "ESPSER$" +PS_SDSCON .TEXT "SCON$" +PS_SDEF .TEXT "EF$" +PS_SDSSER .TEXT "SSER$" +; +; CHARACTER SUB TYPE STRINGS +; +PS_STRS232 .TEXT "RS-232$" +PS_STTERM .TEXT "Terminal$" +PS_STPPT .TEXT "Parallel$" +; +PS_STPARMAP .DB "NONENMNS" +; +; PARALLEL TYPE STRINGS +; +PIO_MODE_STR: .TEXT "Output$" + .TEXT "Input$" + .TEXT "Bidirectional$" + .TEXT "BitCtrl$" +; +; VIDEO DEVICE STRINGS +; +PS_VDVDU .TEXT "VDU$" +PS_VDCVDU .TEXT "CVDU$" +PS_VDGDC .TEXT "GDC$" +PS_VDTMS .TEXT "TMS$" +PS_VDVGA .TEXT "VGA$" +PS_VDVRC .TEXT "VRC$" +PS_VDEF .TEXT "EF$" +PS_VDFV .TEXT "FV$" +; +; VIDEO TYPE STRINGS +; +PS_VTCRT .TEXT "CRT$" +; +; SOUND DEVICE STRINGS +; +PS_SDSND .TEXT "SND$" +; +; SOUND TYPE STRINGS +; +PS_SDSN76489 .TEXT "SN76489$" +PS_SDAY38910 .TEXT "AY-3-8910$" +PS_SDBITMODE .TEXT "I/O PORT$" +PS_SDYM2612 .TEXT "YM2612$" +; +; 0 1 2 3 4 5 6 7 +; 01234567890123456789012345678901234567890123456789012345678901234567890123456789 +PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n" + .TEXT "---------- ---------- ---------------- --------------------\r\n$" +; +HB_PRTSUM_END .EQU $ +; +;================================================================================================== +; DEVICE DRIVERS +;================================================================================================== +; +HB_DRIVERS_BEG .EQU $ +; +;;;#IF (DSKYENABLE) +#IF (ICMENABLE) +ORG_ICM .EQU $ + #INCLUDE "icm.asm" +SIZ_ICM .EQU $ - ORG_ICM + MEMECHO "ICM occupies " + MEMECHO SIZ_ICM + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PKDENABLE) +ORG_PKD .EQU $ + #INCLUDE "pkd.asm" +SIZ_PKD .EQU $ - ORG_PKD + MEMECHO "PKD occupies " + MEMECHO SIZ_PKD + MEMECHO " bytes.\n" +#ENDIF +;;;#ENDIF +; +#IF (LCDENABLE) +ORG_LCD .EQU $ + #INCLUDE "lcd.asm" +SIZ_LCD .EQU $ - ORG_LCD + MEMECHO "LCD occupies " + MEMECHO SIZ_LCD + MEMECHO " bytes.\n" +#ENDIF +; +#IF (GM7303ENABLE) +ORG_GM7303 .EQU $ + #INCLUDE "gm7303.asm" +SIZ_GM7303 .EQU $ - ORG_GM7303 + MEMECHO "GM7303 occupies " + MEMECHO SIZ_GM7303 + MEMECHO " bytes.\n" +#ENDIF +; +#IF (H8PENABLE) +ORG_H8P .EQU $ + #INCLUDE "h8p.asm" +SIZ_H8P .EQU $ - ORG_H8P + MEMECHO "H8P occupies " + MEMECHO SIZ_H8P + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PLATFORM == PLT_NABU) +ORG_NABU .EQU $ + #INCLUDE "nabu.asm" +SIZ_NABU .EQU $ - ORG_NABU + MEMECHO "NABU occupies " + MEMECHO SIZ_NABU + MEMECHO " bytes.\n" +#ENDIF +; +#IF (DSRTCENABLE) +ORG_DSRTC .EQU $ + #INCLUDE "dsrtc.asm" +SIZ_DSRTC .EQU $ - ORG_DSRTC + MEMECHO "DSRTC occupies " + MEMECHO SIZ_DSRTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (DS1501RTCENABLE) +ORG_DS1501RTC .EQU $ + #INCLUDE "ds1501rtc.asm" +SIZ_DS1501RTC .EQU $ - ORG_DS1501RTC + MEMECHO "DS1501RTC occupies " + MEMECHO SIZ_DS1501RTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (BQRTCENABLE) +ORG_BQRTC .EQU $ + #INCLUDE "bqrtc.asm" +SIZ_BQRTC .EQU $ - ORG_BQRTC + MEMECHO "BQRTC occupies " + MEMECHO SIZ_BQRTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (SIMRTCENABLE) +ORG_SIMRTC .EQU $ + #INCLUDE "simrtc.asm" +SIZ_SIMRTC .EQU $ - ORG_SIMRTC + MEMECHO "SIMRTC occupies " + MEMECHO SIZ_SIMRTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PCFENABLE) +ORG_PCF .EQU $ + #INCLUDE "pcf.asm" +SIZ_PCF .EQU $ - ORG_PCF + MEMECHO "PCF occupies " + MEMECHO SIZ_PCF + MEMECHO " bytes.\n" +#ENDIF +; +#IF (DS5RTCENABLE) +ORG_DS5RTC .EQU $ + #INCLUDE "ds5rtc.asm" +SIZ_DS5RTC .EQU $ - ORG_DS5RTC + MEMECHO "DS5RTC occupies " + MEMECHO SIZ_DS5RTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (INTRTCENABLE) +ORG_INTRTC .EQU $ + #INCLUDE "intrtc.asm" +SIZ_INTRTC .EQU $ - ORG_INTRTC + MEMECHO "INTRTC occupies " + MEMECHO SIZ_INTRTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (RP5RTCENABLE) +ORG_RP5RTC .EQU $ + #INCLUDE "rp5rtc.asm" +SIZ_RP5RTC .EQU $ - ORG_RP5RTC + MEMECHO "RP5RTC occupies " + MEMECHO SIZ_RP5RTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (SSERENABLE) +ORG_SSER .EQU $ + #INCLUDE "sser.asm" +SIZ_SSER .EQU $ - ORG_SSER + MEMECHO "SSER occupies " + MEMECHO SIZ_SSER + MEMECHO " bytes.\n" +#ENDIF +; +#IF (ASCIENABLE) +ORG_ASCI .EQU $ + #INCLUDE "asci.asm" +SIZ_ASCI .EQU $ - ORG_ASCI + MEMECHO "ASCI occupies " + MEMECHO SIZ_ASCI + MEMECHO " bytes.\n" +#ENDIF +; +#IF (Z2UENABLE) +ORG_Z2U .EQU $ + #INCLUDE "z2u.asm" +SIZ_Z2U .EQU $ - ORG_Z2U + MEMECHO "Z2U occupies " + MEMECHO SIZ_Z2U + MEMECHO " bytes.\n" +#ENDIF +; +#IF (UARTENABLE) +ORG_UART .EQU $ + #INCLUDE "uart.asm" +SIZ_UART .EQU $ - ORG_UART + MEMECHO "UART occupies " + MEMECHO SIZ_UART + MEMECHO " bytes.\n" +#ENDIF +; +#IF (DUARTENABLE) +ORG_DUART .EQU $ + #INCLUDE "duart.asm" +SIZ_DUART .EQU $ - ORG_DUART + MEMECHO "DUART occupies " + MEMECHO SIZ_DUART + MEMECHO " bytes.\n" +#ENDIF +; +#IF (SIOENABLE) +ORG_SIO .EQU $ + #INCLUDE "sio.asm" +SIZ_SIO .EQU $ - ORG_SIO + MEMECHO "SIO occupies " + MEMECHO SIZ_SIO + MEMECHO " bytes.\n" +#ENDIF +; +#IF (ACIAENABLE) +ORG_ACIA .EQU $ + #INCLUDE "acia.asm" +SIZ_ACIA .EQU $ - ORG_ACIA + MEMECHO "ACIA occupies " + MEMECHO SIZ_ACIA + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PIOENABLE) +ORG_PIO .EQU $ + #INCLUDE "pio.asm" +SIZ_PIO .EQU $ - ORG_PIO + MEMECHO "PIO occupies " + MEMECHO SIZ_PIO + MEMECHO " bytes.\n" +#ENDIF +; +#IF (LPTENABLE) +ORG_LPT .EQU $ + #INCLUDE "lpt.asm" +SIZ_LPT .EQU $ - ORG_LPT + MEMECHO "LPT occupies " + MEMECHO SIZ_LPT + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PIO_4P | PIO_ZP | PIO_SBC) +ORG_PIO .EQU $ + #INCLUDE "pio.asm" +SIZ_PIO .EQU $ - ORG_PIO + MEMECHO "PIO occupies " + MEMECHO SIZ_PIO + MEMECHO " bytes.\n" +#ENDIF +; +#IF (UFENABLE) +ORG_UF .EQU $ + #INCLUDE "uf.asm" +SIZ_UF .EQU $ - ORG_UF + MEMECHO "UF occupies " + MEMECHO SIZ_UF + MEMECHO " bytes.\n" +#ENDIF +; +#IF (VGAENABLE) +ORG_VGA .EQU $ + #INCLUDE "vga.asm" +SIZ_VGA .EQU $ - ORG_VGA + MEMECHO "VGA occupies " + MEMECHO SIZ_VGA + MEMECHO " bytes.\n" +#ENDIF +; +#IF (CVDUENABLE) +ORG_CVDU .EQU $ + #INCLUDE "cvdu.asm" +SIZ_CVDU .EQU $ - ORG_CVDU + MEMECHO "CVDU occupies " + MEMECHO SIZ_CVDU + MEMECHO " bytes.\n" +#ENDIF +; +#IF (VDUENABLE) +ORG_VDU .EQU $ + #INCLUDE "vdu.asm" +SIZ_VDU .EQU $ - ORG_VDU + MEMECHO "VDU occupies " + MEMECHO SIZ_VDU + MEMECHO " bytes.\n" +#ENDIF +; +#IF (TMSENABLE) +ORG_TMS .EQU $ + #INCLUDE "tms.asm" +SIZ_TMS .EQU $ - ORG_TMS + MEMECHO "TMS occupies " + MEMECHO SIZ_TMS + MEMECHO " bytes.\n" +#ENDIF +; +#IF (EFENABLE) +ORG_EF .EQU $ + #INCLUDE "ef.asm" +SIZ_EF .EQU $ - ORG_EF + MEMECHO "EF occupies " + MEMECHO SIZ_EF + MEMECHO " bytes.\n" +#ENDIF +; +#IF (GDCENABLE) +ORG_GDC .EQU $ + #INCLUDE "gdc.asm" +SIZ_GDC .EQU $ - ORG_GDC + MEMECHO "GDC occupies " + MEMECHO SIZ_GDC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (VRCENABLE) +ORG_VRC .EQU $ + #INCLUDE "vrc.asm" +SIZ_VRC .EQU $ - ORG_VRC + MEMECHO "VRC occupies " + MEMECHO SIZ_VRC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (FVENABLE) +ORG_FV .EQU $ + #INCLUDE "fv.asm" +SIZ_FV .EQU $ - ORG_FV + MEMECHO "FV occupies " + MEMECHO SIZ_FV + MEMECHO " bytes.\n" +#ENDIF +; +#IF (DMAENABLE) +ORG_DMA .EQU $ +#INCLUDE "dma.asm" +SIZ_DMA .EQU $ - ORG_DMA + MEMECHO "DMA occupies " + MEMECHO SIZ_DMA + MEMECHO " bytes.\n" +#ENDIF +; +#IF (KBDENABLE) +ORG_KBD .EQU $ + #INCLUDE "kbd.asm" +SIZ_KBD .EQU $ - ORG_KBD + MEMECHO "KBD occupies " + MEMECHO SIZ_KBD + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PPKENABLE) +ORG_PPK .EQU $ + #INCLUDE "ppk.asm" +SIZ_PPK .EQU $ - ORG_PPK + MEMECHO "PPK occupies " + MEMECHO SIZ_PPK + MEMECHO " bytes.\n" +#ENDIF +; +#IF (MKYENABLE) +ORG_MKY .EQU $ + #INCLUDE "mky.asm" +SIZ_MKY .EQU $ - ORG_MKY + MEMECHO "MKY occupies " + MEMECHO SIZ_MKY + MEMECHO " bytes.\n" +#ENDIF +; +#IF (NABUKBENABLE) +ORG_NABUKB .EQU $ + #INCLUDE "nabukb.asm" +SIZ_NABUKB .EQU $ - ORG_NABUKB + MEMECHO "NABUKB occupies " + MEMECHO SIZ_NABUKB + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PRPENABLE) +ORG_PRP .EQU $ + #INCLUDE "prp.asm" +SIZ_PRP .EQU $ - ORG_PRP + MEMECHO "PRP occupies " + MEMECHO SIZ_PRP + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PPPENABLE) +ORG_PPP .EQU $ + #INCLUDE "ppp.asm" +SIZ_PPP .EQU $ - ORG_PPP + MEMECHO "PPP occupies " + MEMECHO SIZ_PPP + MEMECHO " bytes.\n" +#ENDIF +; +#IF (SCONENABLE) +ORG_SCON .EQU $ + #INCLUDE "scon.asm" +SIZ_SCON .EQU $ - ORG_SCON + MEMECHO "SCON occupies " + MEMECHO SIZ_SCON + MEMECHO " bytes.\n" +#ENDIF +; +#IF (CHENABLE) +ORG_CH .EQU $ + #INCLUDE "ch.asm" +SIZ_CH .EQU $ - ORG_CH + MEMECHO "CH occupies " + MEMECHO SIZ_CH + MEMECHO " bytes.\n" +#ENDIF +; +#IF (ESPENABLE) +ORG_ESP .EQU $ + #INCLUDE "esp.asm" +SIZ_ESP .EQU $ - ORG_ESP + MEMECHO "ESP occupies " + MEMECHO SIZ_ESP + MEMECHO " bytes.\n" +#ENDIF +; +#IF (MDENABLE) +ORG_MD .EQU $ + #INCLUDE "md.asm" +SIZ_MD .EQU $ - ORG_MD + MEMECHO "MD occupies " + MEMECHO SIZ_MD + MEMECHO " bytes.\n" +#ENDIF +; +#IF (FDENABLE) +ORG_FD .EQU $ + #INCLUDE "fd.asm" +SIZ_FD .EQU $ - ORG_FD + MEMECHO "FD occupies " + MEMECHO SIZ_FD + MEMECHO " bytes.\n" +#ENDIF +; +#IF (RFENABLE) +ORG_RF .EQU $ + #INCLUDE "rf.asm" +SIZ_RF .EQU $ - ORG_RF + MEMECHO "RF occupies " + MEMECHO SIZ_RF + MEMECHO " bytes.\n" +#ENDIF +; +#IF (IDEENABLE) +ORG_IDE .EQU $ + #INCLUDE "ide.asm" +SIZ_IDE .EQU $ - ORG_IDE + MEMECHO "IDE occupies " + MEMECHO SIZ_IDE + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PPIDEENABLE) +ORG_PPIDE .EQU $ + #INCLUDE "ppide.asm" +SIZ_PPIDE .EQU $ - ORG_PPIDE + MEMECHO "PPIDE occupies " + MEMECHO SIZ_PPIDE + MEMECHO " bytes.\n" +#ENDIF +; +#IF (SDENABLE) +ORG_SD .EQU $ + #INCLUDE "sd.asm" +SIZ_SD .EQU $ - ORG_SD + MEMECHO "SD occupies " + MEMECHO SIZ_SD + MEMECHO " bytes.\n" +#ENDIF +; +#IF (HDSKENABLE) +ORG_HDSK .EQU $ + #INCLUDE "hdsk.asm" +SIZ_HDSK .EQU $ - ORG_HDSK + MEMECHO "HDSK occupies " + MEMECHO SIZ_HDSK + MEMECHO " bytes.\n" +#ENDIF +; +#IF (PPAENABLE) +ORG_PPA .EQU $ + #INCLUDE "ppa.asm" +SIZ_PPA .EQU $ - ORG_PPA + MEMECHO "PPA occupies " + MEMECHO SIZ_PPA + MEMECHO " bytes.\n" +#ENDIF +; +#IF (IMMENABLE) +ORG_IMM .EQU $ + #INCLUDE "imm.asm" +SIZ_IMM .EQU $ - ORG_IMM + MEMECHO "IMM occupies " + MEMECHO SIZ_IMM + MEMECHO " bytes.\n" +#ENDIF +; +#IF (SYQENABLE) +ORG_SYQ .EQU $ + #INCLUDE "syq.asm" +SIZ_SYQ .EQU $ - ORG_SYQ + MEMECHO "SYQ occupies " + MEMECHO SIZ_SYQ + MEMECHO " bytes.\n" +#ENDIF +; +; TERM IS ALWAYS INCLUDED +ORG_TERM .EQU $ + #INCLUDE "term.asm" +SIZ_TERM .EQU $ - ORG_TERM + MEMECHO "TERM occupies ") + MEMECHO SIZ_TERM + MEMECHO " bytes.\n" +; +;#IF (SPKENABLE & DSRTCENABLE +#IF (SPKENABLE) +ORG_SPK .EQU $ + #INCLUDE "spk.asm" +SIZ_SPK .EQU $ - ORG_SPK + MEMECHO "SPK occupies " + MEMECHO SIZ_SPK + MEMECHO " bytes.\n" +#ENDIF +#IF (KIOENABLE) +ORG_KIO .EQU $ + #INCLUDE "kio.asm" +SIZ_KIO .EQU $ - ORG_KIO + MEMECHO "KIO occupies " + MEMECHO SIZ_KIO + MEMECHO " bytes.\n" +#ENDIF +#IF (CTCENABLE) +ORG_CTC .EQU $ + #INCLUDE "ctc.asm" +SIZ_CTC .EQU $ - ORG_CTC + MEMECHO "CTC occupies " + MEMECHO SIZ_CTC + MEMECHO " bytes.\n" +#ENDIF +#IF (SN76489ENABLE) +ORG_SN76489 .EQU $ + #INCLUDE "sn76489.asm" +SIZ_SN76489 .EQU $ - ORG_SN76489 + MEMECHO "SN76489 occupies " + MEMECHO SIZ_SN76489 + MEMECHO " bytes.\n" +#ENDIF +#IF (AY38910ENABLE) +ORG_AY38910 .EQU $ + #INCLUDE "ay38910.asm" +SIZ_AY38910 .EQU $ - ORG_AY38910 + MEMECHO "AY38910 occupies " + MEMECHO SIZ_AY38910 + MEMECHO " bytes.\n" +#ENDIF +#IF (YM2612ENABLE) +ORG_YM2612 .EQU $ + #INCLUDE "ym2612.asm" +SIZ_YM2612 .EQU $ - ORG_YM2612 + MEMECHO "YM2612 occupies " + MEMECHO SIZ_YM2612 + MEMECHO " bytes.\n" +#ENDIF +; +; +#IF (CPUFAM == CPU_EZ80) + MEMECHO "EZ80 DRIVERS\n" +ORG_EZ80DRVS .EQU $ +; +ORG_EZ80CPUDRV .EQU $ + #INCLUDE "ez80cpudrv.asm" +SIZ_EZ80CPUDRV .EQU $ - ORG_EZ80CPUDRV + MEMECHO " EZ80 CPU DRIVER occupies " + MEMECHO SIZ_EZ80CPUDRV + MEMECHO " bytes.\n" +; +ORG_EZ80SYSTMR .EQU $ + #INCLUDE "ez80systmr.asm" +SIZ_EZ80SYSTMR .EQU $ - ORG_EZ80SYSTMR + MEMECHO " EZ80 SYS TIMER occupies " + MEMECHO SIZ_EZ80SYSTMR + MEMECHO " bytes.\n" +; +#IF (EZ80RTCENABLE) +ORG_EZ80RTC .EQU $ + #INCLUDE "ez80rtc.asm" +SIZ_EZ80RTC .EQU $ - ORG_EZ80RTC + MEMECHO " EZ80 RTC occupies " + MEMECHO SIZ_EZ80RTC + MEMECHO " bytes.\n" +#ENDIF +; +#IF (EZ80UARTENABLE) +ORG_EZU .EQU $ + #INCLUDE "ez80uart.asm" +SIZ_EZU .EQU $ - ORG_EZU + MEMECHO " EZ80 UART occupies " + MEMECHO SIZ_EZU + MEMECHO " bytes.\n" +#ENDIF + +SIZ_EZ80DRVS .EQU $ - ORG_EZ80DRVS + MEMECHO " Total " + MEMECHO SIZ_EZ80DRVS + MEMECHO " bytes.\n" + +#ENDIF + + MEMECHO "RTCDEF=" + MEMECHO RTCDEF + MEMECHO "\n" +; +HB_DRIVERS_END .EQU $ +; +;================================================================================================== +; FONTS +;================================================================================================== +; +HB_FONTS_BEG .EQU $ +; +ORG_FONTS .EQU $ +; + MEMECHO "FONTS" +; +#IFDEF USEFONT8X8 +FONT8X8: +; +; FOR NOW, WE NEVER COMPRESS THE 8X8 FONT. SEE TMS DRIVER. +; + #IF USELZSA2 & FALSE + #INCLUDE "font8x8c.asm" + #ELSE + #INCLUDE "font8x8u.asm" + #ENDIF + MEMECHO " 8X8" +#ENDIF +; +#IFDEF USEFONT8X11 +FONT8X11: + #IF USELZSA2 + #INCLUDE "font8x11c.asm" + #ELSE + #INCLUDE "font8x11u.asm" + #ENDIF + MEMECHO " 8X11" +#ENDIF +; +#IFDEF USEFONT8X16 +FONT8X16: + #IF USELZSA2 + #INCLUDE "font8x16c.asm" + #ELSE + #INCLUDE "font8x16u.asm" + #ENDIF + MEMECHO " 8X16" +#ENDIF +; +#IFDEF USEFONTCGA +FONTCGA: + #IF USELZSA2 + #INCLUDE "fontcgac.asm" + #ELSE + #INCLUDE "fontcgau.asm" + #ENDIF + MEMECHO " CGA" +#ENDIF +; +#IFDEF USEFONTVGARC +FONTVGARC: + #IF USELZSA2 + #INCLUDE "fontvgarcc.asm" + #ELSE + #INCLUDE "fontvgarcu.asm" + #ENDIF + MEMECHO " VGARC" +#ENDIF +; +SIZ_FONTS .EQU $ - ORG_FONTS + MEMECHO " occupy " + MEMECHO SIZ_FONTS + MEMECHO " bytes.\n" +; +HB_FONTS_END .EQU $ +; +;================================================================================================== +; HBIOS GLOBAL DATA +;================================================================================================== +; +HB_DATA_BEG .EQU $ +; +IDLECOUNT .DB 0 +; +HEAPCURB .DW 0 ; MARK HEAP ADDRESS AFTER INITIALIZATION +; +HB_TICKS .FILL 4,0 ; 32 BIT TICK COUNTER +HB_SECTCK .DB TICKFREQ ; TICK COUNTER FOR FRACTIONAL SECONDS +HB_SECS .FILL 4,0 ; 32 BIT SECONDS COUNTER +; +HB_CPUTYPE .DB 0 ; 0=Z80, 1=Z180, 2=Z180-K, 3=Z180-N, 4=Z280 +HB_CPUOSC .DW CPUOSC ; ACTUAL CPU HARDWARE OSC FREQ IN KHZ +; +HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK) +; +RTCDEFVAL .DB RTCDEF ; STORAGE FOR RTC DEFAULT VALUE +; +#IF (BT_REC_TYPE != BT_REC_NONE) +HB_BOOT_REC .DB 0 ; BOOT MODE (0=NORMAL, 1=RECOVERY MODE) +#ENDIF +; +STR_BANNER .DB "\r\n\r\nRomWBW HBIOS v", BIOSVER, ", ", TIMESTAMP +#IFDEF APPBOOT + .DB " (App Boot)" +#ENDIF + .DB "$" +STR_PLATFORM .DB PLATFORM_NAME, "$" +STR_CONSOLE .DB "\r\n\r\n Console on Unit #$" +STR_BADINT .DB "\r\n*** BAD INT ***\r\n$" +STR_LOWBAT .DB "\r\n\r\n+++ LOW BATTERY +++$" +; +STR_PANIC .TEXT "\r\n>>> PANIC: $" +STR_SYSCHK .TEXT "\r\n>>> SYSCHK: $" +STR_CONTINUE .TEXT "\r\nContinue (Y/N)? $" +; +HB_CURSEC .DB 0 ; CURRENT SECOND (TEMP) +; +HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) +; +HB_BOOTCON .DB 0 ; INITIAL BOOT CONSOLE SAVE AREA +HB_BOOTCFG .DW 0 ; CONSOLE CONFIG SAVE AREA +HB_NEWCON .DB 0 ; NEW CONSOLE TO SWITCH TO +; +#IF (SUPCTS) +HB_BOOTCONSAV .DB 0 ; INITIAL BOOT CONSOLE SAVE AREA +HB_CONCFGSAV .DW 0 ; CONSOLE CONFIG SAVE AREA +#ENDIF +; +HB_HASFP .DB 0 ; NON-ZERO MEANS FP EXISTS +; +HB_WRKBUF .EQU $ ; INTERNAL DISK BUFFER +; +; THIS AREA IS USED AS A TEMPORARY DISK BUFFER. IT IS ALSO USED +; FOR THE APPBOOT STARTUP CODE SINCE THAT CODE CAN BE DISCARDED +; AFTER STARTUP. +; +HB_APPBOOT: +; +#IFDEF APPBOOT + ; APPBOOT IS ONLY SUPPORTED ON A RUNNING ROMWBW SYSTEM. + ; CONFIRM AND DIAGNOSE IF NOT. + LD HL,(HB_IDENT) ; HL := ADR OR ROMWBW HBIOS IDENT + LD A,(HL) ; GET FIRST BYTE OF ROMWBW MARKER + CP 'W' ; MATCH? + JR NZ,HB_APPBOOTERR ; ABORT WITH INVALID CONFIG BLOCK + INC HL ; NEXT BYTE (MARKER BYTE 2) + LD A,(HL) ; LOAD IT + CP ~'W' ; MATCH? + JR NZ,HB_APPBOOTERR ; ABORT WITH INVALID CONFIG BLOCK + JR HB_APPBOOT1 ; WE ARE RUNNING ROMWBW, CONTINUE +; +HB_APPBOOTERR: + LD DE,STR_APPBOOTERR ; POINT TO ERROR MESSAGE + LD C,9 ; BDOS FUNC 9: WRITE STR + CALL $0005 ; DO IT + OR $FF ; SIGNAL ERROR + RET ; AND RETURN +; +STR_APPBOOTERR .DB "\r\n\r\n*** App Boot is only possible on running RomWBW system!\r\n\r\n$" +; +HB_APPBOOT1: + ; APPBOOT REQUIRES THAT THE COMMON BANK IS NOT CHANGED BY + ; THE NEW CONFIG. TEST FOR THIS AND DIAGNOSE IF SO. + LD A,(HCB_BIDCOM) ; RUNNING COMMON BANK ID + + LD B,BF_SYSGET ; HBIOS SYSGET + LD C,BF_SYSGET_BNKINFO ; BANK INFORMATION + RST 08 ; D = BIOS BANK ID + LD B,BF_SYSPEEK ; HBIOS FUNC: PEEK + LD HL,HCB_LOC + HCB_BIDCOM ; COMMON BANK ID + RST 08 ; E = COMMON BANK ID + LD A,E ; PUT IN A + CP BID_COM ; COMPARE TO NEW CONFIG + JR Z,HB_APPBOOT2 ; IF SAME, CONTINUE +; + ; DIAGNOSE COMMON BANK ID MISMATCH + LD DE,STR_COMBANKERR ; POINT TO ERROR MESSAGE + LD C,9 ; BDOS FUNC 9: WRITE STR + CALL $0005 ; DO IT + OR $FF ; SIGNAL ERROR + RET ; AND RETURN +; +STR_COMBANKERR .DB "\r\n\r\n*** Common Bank Mismatch!\r\n\r\n$" +; +HB_APPBOOT2: + ; ANNOUNCE THE APPLICATION BOOT + LD DE,STR_APPBOOT ; POINT TO MESSAGE + LD C,9 ; BDOS FUNC 9: WRITE STR + CALL $0005 ; DO IT + CALL LDELAY ; SERIAL PORT FLUSH TIME + JR HB_APPBOOT3 ; AND CONTINUE +; +STR_APPBOOT .DB "\r\n\r\n*** Launching RomWBW HBIOS v", BIOSVER, ", ", TIMESTAMP, " for" + .DB "\r\n\r\n ", PLATFORM_NAME, "$" +; +HB_APPBOOT3: +; + #IF (MEMMGR == MM_Z280) + ; WE NEED TO SWITCH FROM USER MODE TO SYSTEM MODE, BUT CONTINUE + ; RUNNING IN THE CURRENT BANK. THIS IS A LITTLE MESSY. +; + ; FIRST, OVERLAY PROXY CODE WITH FRESH CODE SO WE CAN USE THE + ; PROXY ROUTINES SAFELY. + LD A,(HB_CURBNK) ; GET CURBNK + LD DE,HBX_LOC ; RUNNING LOCATION + LD HL,HBX_IMG ; LOCATION IN IMAGE + LD BC,HBX_SIZ ; SIZE + LDIR ; INSTALL IT + LD (HB_CURBNK),A ; RESTORE CURBNK +; + ; NEXT, COPY A BIT OF CODE TO DO THE SYSTEM TRANSITION TO + ; UPPER MEM. WE CAN BORROW THE PROXY BOUNCE BUFFER FOR THIS. + LD HL,Z280_GOSYS + LD DE,HBX_BUF + LD BC,Z280_GOSYS_LEN + LDIR +; + ; THEN SYSCALL IT. NOTE THAT THE ROUTINE CALLED DOES NOT + ; (RET)URN, IT JUMPS TO HB_RESTART SO THAT THE SYSCALL DOES + ; NOT RETURN TO USER MODE. + SC HBX_BUF ; SYSCALL ROUTINE +; +Z280_GOSYS: + ; THIS BIT OF CODE RUNS IN UPPER MEM. IT REMAPS THE LOW MEM + ; SYSTEM PAGES TO THE CURRENT BANK. WE LOSE STACK CONTEXT IN + ; THE PROCESS, SO IN THIS CASE WE NEED TO JUMP BACK TO CONTINUE + ; THE APP BOOT. + DI ; NO INTERRUPTS + LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY + LD A,(HB_CURBNK) ; CURRENT BANK + LD B,$10 ; FIRST SYSTEM PDR + CALL Z280_BNKSEL ; DO THE SWITCH + JP HB_RESTART ; AND RESUME BOOT +; +Z280_GOSYS_LEN .EQU $ - Z280_GOSYS +; + #ENDIF +; + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +#ENDIF +; + .FILL (512 - ($ - HB_WRKBUF)) ; PAD REMAINDER OF WORK BUF +; +#IFDEF MG014_MAP +; + ; ALIGN TO 32 BYTE BOUNDARY + ALIGN($20) +; +MG014_STATMAPLO: + ; LOWER NIBBLE + .DB $08 ; 00 + .DB $0C ; 01 + .DB $00 ; 02 + .DB $04 ; 03 + .DB $0A ; 04 + .DB $0E ; 05 + .DB $02 ; 06 + .DB $06 ; 07 + .DB $09 ; 08 + .DB $0D ; 09 + .DB $01 ; 0A + .DB $05 ; 0B + .DB $0B ; 0C + .DB $0F ; 0D + .DB $03 ; 0E + .DB $07 ; 0F +; +MG014_STATMAPHI: + ; UPPER NIBBLE + .DB $80 ; 00 + .DB $C0 ; 01 + .DB $00 ; 02 + .DB $40 ; 03 + .DB $A0 ; 04 + .DB $E0 ; 05 + .DB $20 ; 06 + .DB $60 ; 07 + .DB $90 ; 08 + .DB $D0 ; 09 + .DB $10 ; 0A + .DB $50 ; 0B + .DB $B0 ; 0C + .DB $F0 ; 0D + .DB $30 ; 0E + .DB $70 ; 0F +; +#ENDIF +; +HB_DATA_END .EQU $ +; +HB_END .EQU $ +; +SLACK .EQU BNKTOP - $ +; +; +; +#IFDEF MEMINFO + .ECHO "SECTION \tSTART\tLENGTH\n" + .ECHO "-------------- \t-------\t-------\n" + + .ECHO "PAGE ZERO \t" \ .ECHO HB_PGZERO_BEG \ .ECHO "\t" \ .ECHO HB_PGZERO_END - HB_PGZERO_BEG \ .ECHO "\n" + .ECHO "HCB \t" \ .ECHO HB_HCB_BEG \ .ECHO "\t" \ .ECHO HB_HCB_END - HB_HCB_BEG \ .ECHO "\n" + .ECHO "PROXY \t" \ .ECHO HB_PROXY_BEG \ .ECHO "\t" \ .ECHO HB_PROXY_END - HB_PROXY_BEG \ .ECHO "\n" + .ECHO "ENTRY \t" \ .ECHO HB_ENTRY_BEG \ .ECHO "\t" \ .ECHO HB_ENTRY_END - HB_ENTRY_BEG \ .ECHO "\n" + .ECHO "INTVEC \t" \ .ECHO HB_INTVEC_BEG \ .ECHO "\t" \ .ECHO HB_INTVEC_END - HB_INTVEC_BEG \ .ECHO "\n" + .ECHO "SYSINIT \t" \ .ECHO HB_SYSINIT_BEG \ .ECHO "\t" \ .ECHO HB_SYSINIT_END - HB_SYSINIT_BEG \ .ECHO "\n" + .ECHO "DISP \t" \ .ECHO HB_DISP_BEG \ .ECHO "\t" \ .ECHO HB_DISP_END - HB_DISP_BEG \ .ECHO "\n" + .ECHO "Z280IVT \t" \ .ECHO HB_Z280IVT_BEG \ .ECHO "\t" \ .ECHO HB_Z280IVT_END - HB_Z280IVT_BEG \ .ECHO "\n" + .ECHO "EXTAPI \t" \ .ECHO HB_EXTAPI_BEG \ .ECHO "\t" \ .ECHO HB_EXTAPI_END - HB_EXTAPI_BEG \ .ECHO "\n" + .ECHO "SYSAPI \t" \ .ECHO HB_SYSAPI_BEG \ .ECHO "\t" \ .ECHO HB_SYSAPI_END - HB_SYSAPI_BEG \ .ECHO "\n" + .ECHO "INTFUNC \t" \ .ECHO HB_INTFUNC_BEG \ .ECHO "\t" \ .ECHO HB_INTFUNC_END - HB_INTFUNC_BEG \ .ECHO "\n" + .ECHO "UTIL \t" \ .ECHO HB_UTIL_BEG \ .ECHO "\t" \ .ECHO HB_UTIL_END - HB_UTIL_BEG \ .ECHO "\n" + .ECHO "PRTSUM \t" \ .ECHO HB_PRTSUM_BEG \ .ECHO "\t" \ .ECHO HB_PRTSUM_END - HB_PRTSUM_BEG \ .ECHO "\n" + .ECHO "DRIVERS \t" \ .ECHO HB_DRIVERS_BEG \ .ECHO "\t" \ .ECHO HB_DRIVERS_END - HB_DRIVERS_BEG \ .ECHO "\n" + .ECHO "FONTS \t" \ .ECHO HB_FONTS_BEG \ .ECHO "\t" \ .ECHO HB_FONTS_END - HB_FONTS_BEG \ .ECHO "\n" + .ECHO "DATA \t" \ .ECHO HB_DATA_BEG \ .ECHO "\t" \ .ECHO HB_DATA_END - HB_DATA_BEG \ .ECHO "\n" + .ECHO "SLACK \t" \ .ECHO HB_END \ .ECHO "\t" \ .ECHO SLACK \ .ECHO "\n" +; +#ENDIF +; + .ECHO "HBIOS space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +; DIAGNOSE HBIOS BANK OVERFLOW +; +#IF (SLACK < 0) + .ECHO "*** ERROR: HBIOS too big!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +; CHECK TO SEE IF WE HAVE ENOUGH HEAP TO CACHE THE CP/M CCP +; AND ONE DISK SECTOR. ALTHOUGH SOME OPERATING SYSTEMS OR APPS +; MAY NOT NEED THIS, THE MOST COMMON ONES DO. CREATING AN HBIOS +; WITHOUT SPACE FOR THIS WILL NOT BE USEFUL. +; +#IF ((CCP_SIZ + 512 + 8) > SLACK) + .ECHO "*** ERROR: Insufficient HEAP space!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +;;;#IF (SLACK < (1024 * 3)) +;;; .ECHO "*** ERROR: Low HEAP space!!!\n" +;;; !!! ; FORCE AN ASSEMBLY ERROR +;;;#ENDIF +; +#IFDEF ROMBOOT + #IF (ROMSIZE > 0) + .FILL SLACK + #ENDIF +#ENDIF +; + .END diff --git a/Source/HBIOS/layout.inc b/Source/HBIOS/layout.inc new file mode 100644 index 00000000..5b6f0143 --- /dev/null +++ b/Source/HBIOS/layout.inc @@ -0,0 +1,101 @@ +; +; The was extracted out of STD.ASM, so can be included +; in BIOS apps that are NOT in HBIOS directory! +; +; ============= +; MEMORY LAYOUT +; ============= +; +SYS_SIZ .EQU $3000 ; COMBINED SIZE OF SYSTEM AREA (OS + HBIOS PROXY) +HBBUF_SIZ .EQU 1024 ; INVARIANT HBIOS PHYSICAL DISK BUFFER, 1K +HBX_SIZ .EQU $200 ; HBIOS PROXY SIZE (SUBJECT TO CHANGE) +CPM_SIZ .EQU SYS_SIZ - HBX_SIZ ; NET SIZE OF ALL OS COMPONENTS (EXCLUDING HBIOS PROXY) +CCP_SIZ .EQU $800 ; INVARIANT SIZE OF CCP +BDOS_SIZ .EQU $E00 ; INVARIANT SIZE OF BDOS +CBIOS_SIZ .EQU CPM_SIZ - CCP_SIZ - BDOS_SIZ ; CBIOS IS THE REMAINDER +; +MEMTOP .EQU $10000 ; INVARIANT TOP OF Z80 ADDRESSABLE MEMORY +BNKTOP .EQU $8000 ; BANK MEMORY BARRIER +; +HBX_IMG .EQU $200 ; LOC OF HBX IMAGE IN HBIOS IMAGE BANK +; +HBBUF_END .EQU BNKTOP ; END OF PHYSICAL DISK BUFFER IN HBIOS +HBBUF_LOC .EQU HBBUF_END - HBBUF_SIZ ; START OF PHYSICAL DISK BUFFER +HBX_END .EQU MEMTOP ; END OF HBIOS PROXY +HBX_LOC .EQU HBX_END - HBX_SIZ ; START OF HBIOS PROXY +CPM_END .EQU HBX_LOC ; END OF CPM COMPONENTS (INCLUDING CBIOS) +CPM_LOC .EQU CPM_END - CPM_SIZ ; START OF CPM COMPONENTS +CBIOS_END .EQU HBX_LOC ; END OF CBIOS +CBIOS_LOC .EQU CBIOS_END - CBIOS_SIZ ; START OF CBIOS +; +CPM_ENT .EQU CBIOS_LOC ; CPM ENTRY POINT (IN CBIOS) +; +CPM_IMGSIZ .EQU $3000 +; +; ================= +; ROM BANK 1 LAYOUT +; ================= +; +LDR_LOC .EQU $0000 +LDR_SIZ .EQU $1000 +LDR_END .EQU LDR_LOC +LDR_SIZ +LDR_IMGLOC .EQU $0000 +; +MON_LOC .EQU $EE00 ; LOCATION OF MONITOR FOR RUNNING SYSTEM +MON_SIZ .EQU $1000 ; SIZE OF MONITOR BINARY IMAGE +MON_END .EQU MON_LOC + MON_SIZ ; END OF MONITOR +MON_IMGLOC .EQU LDR_IMGLOC + LDR_SIZ +; +ZSYS_IMGLOC .EQU MON_IMGLOC + MON_SIZ +; +CPM_IMGLOC .EQU ZSYS_IMGLOC + CPM_IMGSIZ +; +; ================= +; ROM BANK 2 LAYOUT +; ================= +; +FTH_LOC .EQU $0200 ; CAMEL FORTH +FTH_SIZ .EQU $1700 +FTH_END .EQU FTH_LOC + FTH_SIZ +FTH_IMGLOC .EQU $0000 + +BAS_LOC .EQU $0200 ; NASCOM BASIC +BAS_SIZ .EQU $2000 +BAS_END .EQU BAS_LOC + BAS_SIZ +BAS_IMGLOC .EQU FTH_IMGLOC + FTH_SIZ +; +; NOTE FOLLOWING ARE COPY/PASTED INTO tastybasic.asm !!!!!!!! +TBC_LOC .EQU $0A00 ; TASTYBASIC +TBC_SIZ .EQU $0A00 +TBC_END .EQU TBC_LOC + TBC_SIZ +TBC_IMGLOC .EQU BAS_IMGLOC + BAS_SIZ +; +GAM_LOC .EQU $0200 ; GAME 2048 +GAM_SIZ .EQU $0900 +GAM_END .EQU GAM_LOC + GAM_SIZ +GAM_IMGLOC .EQU TBC_IMGLOC + TBC_SIZ +; +EGG_LOC .EQU $F000 ; EASTER EGG +EGG_SIZ .EQU $0200 +EGG_END .EQU EGG_LOC + EGG_SIZ +EGG_IMGLOC .EQU GAM_IMGLOC + GAM_SIZ +; +NET_LOC .EQU $0100 ; NETWORK BOOT +NET_SIZ .EQU $1000 +NET_END .EQU NET_LOC + NET_SIZ +NET_IMGLOC .EQU EGG_IMGLOC + EGG_SIZ +; +UPD_LOC .EQU $0200 ; ROM UPDATER +UPD_SIZ .EQU $0D00 +UPD_END .EQU UPD_LOC + UPD_SIZ +UPD_IMGLOC .EQU NET_IMGLOC + NET_SIZ +; +NVR_LOC .EQU $0100 ; NVRAM CONFIG +NVR_SIZ .EQU $0800 +NVR_END .EQU NVR_LOC + NVR_SIZ +NVR_IMGLOC .EQU UPD_IMGLOC + UPD_SIZ +; +USR_LOC .EQU $0200 ; USER +USR_SIZ .EQU BNKTOP - NVR_IMGLOC - NVR_SIZ +USR_END .EQU USR_LOC + USR_SIZ +USR_IMGLOC .EQU NVR_IMGLOC + NVR_SIZ diff --git a/Source/HBIOS/romldr.asm b/Source/HBIOS/romldr.asm index e9374054..8d256b70 100644 --- a/Source/HBIOS/romldr.asm +++ b/Source/HBIOS/romldr.asm @@ -1835,10 +1835,10 @@ getnum32a: ; X * 10 = (((x * 2 * 2) + x)) * 2 push de push hl -; +; call getnum32e ; DE:HL *= 2 jr c,getnum32d ; if overflow, ret w/ CF & stack pop -; +; call getnum32e ; DE:HL *= 2 jr c,getnum32d ; if overflow, ret w/ CF & stack pop ; @@ -1849,7 +1849,7 @@ getnum32a: adc hl,bc ex de,hl ret c ; if overflow, ret w/ CF -; +; call getnum32e ; DE:HL *= 2 ret c ; if overflow, ret w/ CF ; @@ -2456,6 +2456,7 @@ ra_ent(str_fth, 'F', KY_EX, BID_IMG1, FTH_IMGLOC, FTH_LOC, FTH_SIZ, FTH_LO ra_ent(str_play, 'P', $FF, BID_IMG1, GAM_IMGLOC, GAM_LOC, GAM_SIZ, GAM_LOC) ra_ent(str_net, 'N', $FF, BID_IMG1, NET_IMGLOC, NET_LOC, NET_SIZ, NET_LOC) ra_ent(str_upd, 'X', $FF, BID_IMG1, UPD_IMGLOC, UPD_LOC, UPD_SIZ, UPD_LOC) +ra_ent(str_nvr, 'W', $FF, BID_IMG1, NVR_IMGLOC, NVR_LOC, NVR_SIZ, NVR_LOC) ra_ent(str_user, 'U', $FF, BID_IMG1, USR_IMGLOC, USR_LOC, USR_SIZ, USR_LOC) #endif #if (DSKYENABLE) @@ -2484,6 +2485,7 @@ str_bas .db "BASIC",0 str_tbas .db "Tasty BASIC",0 str_play .db "Play a Game",0 str_upd .db "XModem Flash Updater",0 +str_nvr .db "RomWBW Configure", 0 str_user .db "User App",0 str_egg .db "",0 str_net .db "Network Boot",0 diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index 535af315..a582f19c 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -26,7 +26,7 @@ ; 22. NABU NABU w/ Les Bird's RomWBW Option Board ; 23. FZ80 S100 Computers FPGA Z80 ; 24. RCZ80 RCBus eZ80 -; +; ; ; INCLUDE BUILD VERSION ; @@ -938,92 +938,13 @@ APP_BNKS .SET 0 .ECHO "----------------------------------------\n" #ENDIF ; -; MEMORY LAYOUT +; --------------------------- +; Memory and ROM Bank Layouts +; --------------------------- +; +#INCLUDE "layout.inc" +; ; -SYS_SIZ .EQU $3000 ; COMBINED SIZE OF SYSTEM AREA (OS + HBIOS PROXY) -HBBUF_SIZ .EQU 1024 ; INVARIANT HBIOS PHYSICAL DISK BUFFER, 1K -HBX_SIZ .EQU $200 ; HBIOS PROXY SIZE (SUBJECT TO CHANGE) -CPM_SIZ .EQU SYS_SIZ - HBX_SIZ ; NET SIZE OF ALL OS COMPONENTS (EXCLUDING HBIOS PROXY) -CCP_SIZ .EQU $800 ; INVARIANT SIZE OF CCP -BDOS_SIZ .EQU $E00 ; INVARIANT SIZE OF BDOS -CBIOS_SIZ .EQU CPM_SIZ - CCP_SIZ - BDOS_SIZ ; CBIOS IS THE REMAINDER - -MEMTOP .EQU $10000 ; INVARIANT TOP OF Z80 ADDRESSABLE MEMORY -BNKTOP .EQU $8000 ; BANK MEMORY BARRIER - -HBX_IMG .EQU $200 ; LOC OF HBX IMAGE IN HBIOS IMAGE BANK - -HBBUF_END .EQU BNKTOP ; END OF PHYSICAL DISK BUFFER IN HBIOS -HBBUF_LOC .EQU HBBUF_END - HBBUF_SIZ ; START OF PHYSICAL DISK BUFFER -HBX_END .EQU MEMTOP ; END OF HBIOS PROXY -HBX_LOC .EQU HBX_END - HBX_SIZ ; START OF HBIOS PROXY -CPM_END .EQU HBX_LOC ; END OF CPM COMPONENTS (INCLUDING CBIOS) -CPM_LOC .EQU CPM_END - CPM_SIZ ; START OF CPM COMPONENTS -CBIOS_END .EQU HBX_LOC ; END OF CBIOS -CBIOS_LOC .EQU CBIOS_END - CBIOS_SIZ ; START OF CBIOS - -CPM_ENT .EQU CBIOS_LOC ; CPM ENTRY POINT (IN CBIOS) - -CPM_IMGSIZ .EQU $3000 - -; ROM BANK 1 - -LDR_LOC .EQU $0000 -LDR_SIZ .EQU $1000 -LDR_END .EQU LDR_LOC +LDR_SIZ -LDR_IMGLOC .EQU $0000 - -MON_LOC .EQU $EE00 ; LOCATION OF MONITOR FOR RUNNING SYSTEM -MON_SIZ .EQU $1000 ; SIZE OF MONITOR BINARY IMAGE -MON_END .EQU MON_LOC + MON_SIZ ; END OF MONITOR -MON_IMGLOC .EQU LDR_IMGLOC + LDR_SIZ - -ZSYS_IMGLOC .EQU MON_IMGLOC + MON_SIZ - -CPM_IMGLOC .EQU ZSYS_IMGLOC + CPM_IMGSIZ - -; ROM BANK 2 - -FTH_LOC .EQU $0200 ; CAMEL FORTH -FTH_SIZ .EQU $1700 -FTH_END .EQU FTH_LOC + FTH_SIZ -FTH_IMGLOC .EQU $0000 - -BAS_LOC .EQU $0200 ; NASCOM BASIC -BAS_SIZ .EQU $2000 -BAS_END .EQU BAS_LOC + BAS_SIZ -BAS_IMGLOC .EQU FTH_IMGLOC + FTH_SIZ - -TBC_LOC .EQU $0A00 ; TASTYBASIC -TBC_SIZ .EQU $0A00 -TBC_END .EQU TBC_LOC + TBC_SIZ -TBC_IMGLOC .EQU BAS_IMGLOC + BAS_SIZ - -GAM_LOC .EQU $0200 ; GAME 2048 -GAM_SIZ .EQU $0900 -GAM_END .EQU GAM_LOC + GAM_SIZ -GAM_IMGLOC .EQU TBC_IMGLOC + TBC_SIZ - -EGG_LOC .EQU $F000 ; EASTER EGG -EGG_SIZ .EQU $0200 -EGG_END .EQU EGG_LOC + EGG_SIZ -EGG_IMGLOC .EQU GAM_IMGLOC + GAM_SIZ - -NET_LOC .EQU $0100 ; NETWORK BOOT -NET_SIZ .EQU $1000 -NET_END .EQU NET_LOC + NET_SIZ -NET_IMGLOC .EQU EGG_IMGLOC + EGG_SIZ - -UPD_LOC .EQU $0200 ; ROM UPDATER -UPD_SIZ .EQU $0D00 -UPD_END .EQU UPD_LOC + UPD_SIZ -UPD_IMGLOC .EQU NET_IMGLOC + NET_SIZ - -USR_LOC .EQU $0200 ; USER -USR_SIZ .EQU BNKTOP - UPD_IMGLOC - UPD_SIZ -USR_END .EQU USR_LOC + USR_SIZ -USR_IMGLOC .EQU UPD_IMGLOC + UPD_SIZ - MON_DSKY .EQU MON_LOC + (0 * 3) ; MONITOR ENTRY (DSKY) MON_SERIAL .EQU MON_LOC + (1 * 3) ; MONITOR ENTRY (SERIAL PORT) ; diff --git a/Source/Images/hd_bp.txt b/Source/Images/hd_bp.txt index 099aa264..0db9f373 100644 --- a/Source/Images/hd_bp.txt +++ b/Source/Images/hd_bp.txt @@ -24,6 +24,7 @@ ../../Binary/Apps/mode.com 15: ../../Binary/Apps/rtc.com 15: ../../Binary/Apps/survey.com 15: +../../Binary/Apps/sysconfig.com 15: ../../Binary/Apps/syscopy.com 15: ../../Binary/Apps/sysgen.com 15: ../../Binary/Apps/talk.com 15: diff --git a/Source/Images/hd_cpm22.txt b/Source/Images/hd_cpm22.txt index 99ab40c2..cacbf227 100644 --- a/Source/Images/hd_cpm22.txt +++ b/Source/Images/hd_cpm22.txt @@ -20,6 +20,7 @@ d_cpm22/ReadMe.txt 0: ../../Binary/Apps/mode.com 0: ../../Binary/Apps/rtc.com 0: ../../Binary/Apps/survey.com 0: +../../Binary/Apps/sysconfig.com 0: ../../Binary/Apps/syscopy.com 0: ../../Binary/Apps/sysgen.com 0: ../../Binary/Apps/talk.com 0: diff --git a/Source/Images/hd_cpm3.txt b/Source/Images/hd_cpm3.txt index 010417c3..005cf6b4 100644 --- a/Source/Images/hd_cpm3.txt +++ b/Source/Images/hd_cpm3.txt @@ -39,6 +39,7 @@ d_cpm3/ReadMe.txt 0: ../../Binary/Apps/mode.com 0: ../../Binary/Apps/rtc.com 0: ../../Binary/Apps/survey.com 0: +../../Binary/Apps/sysconfig.com 0: ../../Binary/Apps/syscopy.com 0: #../../Binary/Apps/sysgen.com 0: #../../Binary/Apps/talk.com 0: diff --git a/Source/Images/hd_nzcom.txt b/Source/Images/hd_nzcom.txt index cf97e497..53d826c4 100644 --- a/Source/Images/hd_nzcom.txt +++ b/Source/Images/hd_nzcom.txt @@ -35,6 +35,7 @@ d_zsdos/u0/*.DAT 15: ../../Binary/Apps/mode.com 15: ../../Binary/Apps/rtc.com 15: ../../Binary/Apps/survey.com 15: +../../Binary/Apps/sysconfig.com 15: ../../Binary/Apps/syscopy.com 15: ../../Binary/Apps/sysgen.com 15: ../../Binary/Apps/talk.com 15: diff --git a/Source/Images/hd_qpm.txt b/Source/Images/hd_qpm.txt index 3aad64c4..436941b4 100644 --- a/Source/Images/hd_qpm.txt +++ b/Source/Images/hd_qpm.txt @@ -24,6 +24,7 @@ d_cpm22/u0/*.* 0: ../../Binary/Apps/mode.com 0: ../../Binary/Apps/rtc.com 0: ../../Binary/Apps/survey.com 0: +../../Binary/Apps/sysconfig.com 0: ../../Binary/Apps/syscopy.com 0: ../../Binary/Apps/sysgen.com 0: ../../Binary/Apps/talk.com 0: diff --git a/Source/Images/hd_z3plus.txt b/Source/Images/hd_z3plus.txt index 1dd901ca..879219e2 100644 --- a/Source/Images/hd_z3plus.txt +++ b/Source/Images/hd_z3plus.txt @@ -46,6 +46,7 @@ d_cpm3/u0/HELP.HLP 0: ../../Binary/Apps/mode.com 15: ../../Binary/Apps/rtc.com 15: ../../Binary/Apps/survey.com 15: +../../Binary/Apps/sysconfig.com 15: ../../Binary/Apps/syscopy.com 15: ../../Binary/Apps/sysgen.com 15: ../../Binary/Apps/talk.com 15: diff --git a/Source/Images/hd_zpm3.txt b/Source/Images/hd_zpm3.txt index f6f8ab47..28009fd0 100644 --- a/Source/Images/hd_zpm3.txt +++ b/Source/Images/hd_zpm3.txt @@ -45,6 +45,7 @@ d_cpm3/u0/HELP.HLP 0: ../../Binary/Apps/mode.com 15: ../../Binary/Apps/rtc.com 15: ../../Binary/Apps/survey.com 15: +../../Binary/Apps/sysconfig.com 15: ../../Binary/Apps/syscopy.com 15: ../../Binary/Apps/sysgen.com 15: ../../Binary/Apps/talk.com 15: diff --git a/Source/Images/hd_zsdos.txt b/Source/Images/hd_zsdos.txt index 9babd296..d2c389ea 100644 --- a/Source/Images/hd_zsdos.txt +++ b/Source/Images/hd_zsdos.txt @@ -24,6 +24,7 @@ d_cpm22/u0/*.* 0: ../../Binary/Apps/mode.com 0: ../../Binary/Apps/rtc.com 0: ../../Binary/Apps/survey.com 0: +../../Binary/Apps/sysconfig.com 0: ../../Binary/Apps/syscopy.com 0: ../../Binary/Apps/sysgen.com 0: ../../Binary/Apps/talk.com 0: