diff --git a/Doc/ROM Applications.pdf b/Doc/ROM Applications.pdf index b63d58e9..5ed0a996 100644 Binary files a/Doc/ROM Applications.pdf and b/Doc/ROM Applications.pdf differ diff --git a/Doc/RomWBW Applications.pdf b/Doc/RomWBW Applications.pdf index 4be462cf..cc4978a5 100644 Binary files a/Doc/RomWBW Applications.pdf and b/Doc/RomWBW Applications.pdf differ diff --git a/Doc/RomWBW Architecture.pdf b/Doc/RomWBW Architecture.pdf index 5602cd88..b8bf2c3c 100644 Binary files a/Doc/RomWBW Architecture.pdf and b/Doc/RomWBW Architecture.pdf differ diff --git a/Doc/RomWBW Disk Catalog.pdf b/Doc/RomWBW Disk Catalog.pdf index e502e946..07550de7 100644 Binary files a/Doc/RomWBW Disk Catalog.pdf and b/Doc/RomWBW Disk Catalog.pdf differ diff --git a/Doc/RomWBW Getting Started.pdf b/Doc/RomWBW Getting Started.pdf index ffe23080..a233805a 100644 Binary files a/Doc/RomWBW Getting Started.pdf and b/Doc/RomWBW Getting Started.pdf differ diff --git a/Source/Apps/DMAmon/Readme.txt b/Source/Apps/DMAmon/Readme.txt new file mode 100644 index 00000000..1d6ab543 --- /dev/null +++ b/Source/Apps/DMAmon/Readme.txt @@ -0,0 +1 @@ +DMAmon is a program to verify operation of the Z80 MBC DMA board diff --git a/Source/BuildShared.cmd b/Source/BuildShared.cmd index fd88b2c1..df961d93 100644 --- a/Source/BuildShared.cmd +++ b/Source/BuildShared.cmd @@ -1,6 +1,7 @@ @echo off setlocal +pushd HDIAG && call Build || exit /b & popd pushd CBIOS && call Build || exit /b & popd pushd CPM22 && call Build || exit /b & popd pushd ZCPR && call Build || exit /b & popd diff --git a/Source/Clean.cmd b/Source/Clean.cmd index a5e88c6c..6f2cf842 100644 --- a/Source/Clean.cmd +++ b/Source/Clean.cmd @@ -1,6 +1,7 @@ @echo off setlocal +pushd HDIAG && call Clean.cmd & popd pushd Apps && call Clean.cmd & popd pushd CPM22 && call Clean.cmd & popd pushd ZCPR && call Clean.cmd & popd diff --git a/Source/Doc/ROM_Applications.md b/Source/Doc/ROM_Applications.md index fbafa486..14c35eca 100644 --- a/Source/Doc/ROM_Applications.md +++ b/Source/Doc/ROM_Applications.md @@ -355,7 +355,7 @@ ROMWBW contains two versions of ROM BASIC, a full implementation and a "tiny" BA The full implementation is a version of Microsoft BASIC from the NASCOM Computer. -A comprehensive instruction manual is available in the Doc\Contrib directory. +A comprehensive instruction manual is available in the Doc\\Contrib directory. ## ROMWBW specific features diff --git a/Source/HDIAG/Build.cmd b/Source/HDIAG/Build.cmd new file mode 100644 index 00000000..a3d35a56 --- /dev/null +++ b/Source/HDIAG/Build.cmd @@ -0,0 +1,19 @@ +@echo off +setlocal + +set TOOLS=../../Tools +set BIN=..\..\Binary + +set PATH=%TOOLS%\tasm32;%PATH% + +set TASMTABS=%TOOLS%\tasm32 + +set ZXBINDIR=%TOOLS%/cpm/bin/ +set ZXLIBDIR=%TOOLS%/cpm/lib/ +set ZXINCDIR=%TOOLS%/cpm/include/ + +tasm -t180 -g3 -fFF -DAPPBOOT hdiag.asm hdiag.com hdiag_com.lst || exit /b +tasm -t180 -g3 -fFF -DROMBOOT hdiag.asm hdiag.rom hdiag_rom.lst || exit /b + +copy hdiag.rom %BIN% || exit /b +copy hdiag.com %BIN% || exit /b diff --git a/Source/HDIAG/Clean.cmd b/Source/HDIAG/Clean.cmd new file mode 100644 index 00000000..c9c917a4 --- /dev/null +++ b/Source/HDIAG/Clean.cmd @@ -0,0 +1,7 @@ +@echo off +setlocal + +if exist *.bin del *.bin +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.hex del *.hex \ No newline at end of file diff --git a/Source/HDIAG/Makefile b/Source/HDIAG/Makefile new file mode 100644 index 00000000..18895f67 --- /dev/null +++ b/Source/HDIAG/Makefile @@ -0,0 +1,20 @@ +OBJECTS = hdiag.com hdiag.rom +DEST = ../../Binary +TOOLS = ../../Tools +include $(TOOLS)/Makefile.inc + +TASMFLAGS=-t hd64180 + +hdiag.com: hdiag.asm + $(TASM) $(TASMFLAGS) -dAPPBOOT $< $@ $*.lst + + +hdiag.rom: hdiag.asm + $(TASM) $(TASMFLAGS) -dROMBOOT $< $@ $*.lst + +#cbios_wbw.bin: cbios.asm +# $(TASM) -dPLTWBW $< $@ cbios_wbw.lst +# +#cbios_una.bin: cbios.asm +# $(TASM) -dPLTUNA $< $@ cbios_una.lst + diff --git a/Source/HDIAG/acia.asm b/Source/HDIAG/acia.asm new file mode 100644 index 00000000..c69c5f6d --- /dev/null +++ b/Source/HDIAG/acia.asm @@ -0,0 +1,70 @@ +; +;======================================================================= +; HDIAG ACIA Driver +;======================================================================= +; +acia_cmd .equ $80 +acia_dat .equ $81 +; +; +; +acia_jptbl: + jp acia_cinit ; Initialize serial port + jp acia_cin ; Read byte + jp acia_cout ; Write byte + jp acia_cist ; Input status + jp acia_cost ; Output Status +; +; +; +acia_cinit: + ; Detect ACIA + ld a,$03 ; master reset + out (acia_cmd),a ; apply it + in a,(acia_cmd) ; get status + or a ; check for zero (expected) + ret nz ; abort if not + ld a,$02 ; clear master reset + out (acia_cmd),a ; apply it + in a,(acia_cmd) ; get status again + and %00001110 ; isolate reliable bits + cp %00000010 ; check for expected value + ret nz ; abort if not + ; Initialize ACIA + ld a,%00010110 ; default config + out (acia_cmd),a ; apply it + xor a ; signal success + ret +; +; +; +acia_cin: + call acia_cist ; check for char ready + jr z,acia_cin ; if not, loop + in a,(acia_dat) ; read byte + ret ; done +; +; +; +acia_cout: + push af ; save incoming +acia_cout1: + call acia_cost ; ready for char? + jr z,acia_cout1 ; loop if not + pop af ; restore incoming + out (acia_dat),a ; write byte + ret ; and done +; +; +; +acia_cist: + in a,(acia_cmd) ; get status + and $01 ; isolate rx ready + ret ; done +; +; +; +acia_cost: + in a,(acia_cmd) ; get status + and $02 ; isolate tx empty + ret ; done diff --git a/Source/HDIAG/asci.asm b/Source/HDIAG/asci.asm new file mode 100644 index 00000000..d5dc8bd0 --- /dev/null +++ b/Source/HDIAG/asci.asm @@ -0,0 +1,89 @@ +; +;======================================================================= +; HDIAG ASCI Driver +;======================================================================= +; +; ASCI0 is programmed with a fixed divisor of 480, resulting in a +; baud rate of 38400 at the standard cpu frequency of 18.432 MHz +; +; The Z180 may relocate it's internal I/O to begin at different +; starting port addresses. This driver relies upon an HDIAG global +; variable to dynamically adjust to the right port address. +; +; +asci_jptbl: + jp asci_cinit ; Initialize serial port + jp asci_cin ; Read byte + jp asci_cout ; Write byte + jp asci_cist ; Input status + jp asci_cost ; Output Status +; +; +; +asci_cinit: + ; Detect ASCI + ld a,(hd_cpu) ; get cpu type + cp 1 + jr c, asci_cinit1 ; less than Z180, abort + cp 4 + jr nc, asci_cinit1 ; greater than Z180, abort +; + ; Initialize ASCI + ld a,%01100100 ; rcv enable, xmit enable, no parity + out0 (z180_cntla0),a ; set cntla + ld a,%00100000 ; div 30, div 16, div 1 (38400 baud for 18.432mhz cpu) + out0 (z180_cntlb0),a ; set cntlb + ld a,%01100110 ; no cts, no dcd, no break detect + out0 (z180_asext0),a ; set asext + xor a ; no interrupts + out0 (z180_stat0),a ; set stat0 + xor a ; signal success + ret ; done +; +asci_cinit1: + or $FF ; signal error + ret ; done +; +; +; +asci_cin: + call asci_cist ; check for char ready + jr z,asci_cin ; if not, loop + in0 a,(z180_rdr0) ; get char + ret ; done +; +; +; +asci_cout: + push af ; save incoming +asci_cout1: + call asci_cost ; ready for char? + jr z,asci_cout1 ; loop if not + pop af ; restore incoming + out0 (z180_tdr0),a ; write byte + ret ; and done +; +; +; +asci_cist: + in0 a,(z180_stat0) ; get status + push af ; save status + and $70 ; line error? + jr z,asci_cist1 ; continue if no errors +; + ; clear line error(s) or nothing further can be received!!! + in0 a,(z180_cntla0) ; read cntla + res 3,a ; clear efr (error flag reset) + out0 (z180_cntla0),a ; update cntla +; +asci_cist1: + pop af ; recover original status + and $80 ; data ready? + ret +; +; +; +asci_cost: + in0 a,(z180_stat0) ; get status + and $02 ; isolate bit 5 + ret ; a != 0 if char ready, else 0 diff --git a/Source/HDIAG/hdiag.asm b/Source/HDIAG/hdiag.asm new file mode 100644 index 00000000..9d37a523 --- /dev/null +++ b/Source/HDIAG/hdiag.asm @@ -0,0 +1,588 @@ +; +; +;======================================================================= +; HDIAG Diagmostic ROM +;======================================================================= +; +; HDIAG is a framework for a diagnotic environment intended to be +; suitable for all systems supported by RomWBW. RomWBW expects hardware +; to be fully functional making it difficult to use it to initially +; check out a system. HDIAG is explicitly constructed to be as simple +; as possible. +; +; There is only a single variant of HDIAG that is built. HDIAG is +; designed to detect the environment it is operating under at startup +; and dynamically adapt to it. +; +; HDIAG can be assembled to boot in one of 2 modes (rom or application) +; 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. +; +; - APPBOOT: Boot as 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. +; +#include "z180.inc" +; +;======================================================================= +; Page Zero Definition +;======================================================================= +; +; Generic page zero setup. Only applies to ROMBOOT startup mode. +; +#ifdef ROMBOOT +; + .org $0000 +; + jp hd_start ; rst $00: jump to boot code + .fill ($08-$) + ret ; rst $08 + .fill ($10-$) + ret ; rst $10 + .fill ($18-$) + ret ; rst $18 + .fill ($20-$) + ret ; rst $20 + .fill ($28-$) + ret ; rst $28 + .fill ($30-$) + ret ; rst $30 + .fill ($38-$) + reti ; h/w int return + .fill ($66-$) + retn ; h/w nmi return + .fill ($100-$) ; pad remainder of page zero +; +#else + .org $0100 +; +#endif +; +;======================================================================= +; Startup +;======================================================================= +; +; Before transitioning to RAM, we need to determine the memory +; manager to use because some platforms will not have any RAM mapped +; to the upper 32K of CPU address space until the memory manager +; is initialized. +; +hd_start: +; +; Discover CPU Type and Memory Manager +; +; Some of this code is derived from UNA by John Coffman +; +; CPU Type: +; 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 +; +; Memory Manager: +; 0: SBC/MBC/Zeta 1 +; 1: Zeta 2/RC2014 +; 2: Z180 +; 3: N8? +; 4: Z280 +; +; + di ; no interrupts allowed +; + ld a,$80 + out ($0D),a +; + ; Use H for memory manager, and L for CPU Type + ld hl,0 ; assume Z80 and SBC +; + ; Test for 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,hd_tryZ280 ; if != 30, not a Z180, try Z280 + inc l ; Z80180 or better +; +#ifdef APPBOOT +; + ; Reset Z180 internal register base to zero + xor a + out0 ($7F),a + out0 ($BF),a + out0 ($FF),a +; +#endif +; + ; Test for older S-class (rev K) + in0 a,(z180_ccr) ; supposedly only on s-class + inc a ; FF -> 0 + jr z,hd_z180res ; if zero, pre-S, HD61480 or equiv + inc l ; 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 always 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,hd_z180res ; if zero, rev-K + inc l ; otherwise Z8S180 rev N w/ asci brg + jr hd_z180res ; go to Z180 reset +; +hd_tryZ280: + ; 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,hd_z80res ; if not Z280, we are Z80 + ld l,4 ; we are Z280 + jr hd_z280res ; handle Z280 initialization +; +hd_z80res: + ld a,$01 + out (0),a + ; Reset Z80 here (is there anything?) + jr hd_cpu1 +; +hd_z180res: +; + ; Reset z180 registers here + ; Set CPU speed to oscillator X 1 + xor a + out0 (z180_cmr),a + ld a,$80 + out0 (z180_ccr),a + ; Set default wait states + ld a,$%00000100 ; mem wait=0, i/o wait=+1 + out0 (z180_dcntl),a +; +#ifdef ROMBOOT + ; Setup Z180 MMU + ; Keep ROM page zero in lower 32K!!! + ld a,$80 ; Common Base @ 32K, Bank Base @ 0K + out0 (z180_cbar),a + xor a ; Physical address zero + out0 (z180_cbr),a ; ... for Common Base + out0 (z180_bbr),a ; ... and Bank Base +#else + xor a ; Physical address zero + out0 (z180_cbr),a ; ... for Common Base +#endif +; + jr hd_cpu1 +; +hd_z280res: + ; Reset Z280 registers here + ; Make sure memmgr is reset to defaults! + jr hd_cpu1 +; +hd_cpu1: + ld a,$02 + out ($0D),a +; + ; Reset Zeta 2 memory manager (in case it exists) +#ifdef ROMBOOT + xor a ; disable value + out ($7C),a ; write it + xor a ; 16K ROM page 0 + out ($78),a + inc a ; 16K ROM page 1 + out ($79),a +#endif + ld a,2 ; 16K ROM page 2 + out ($7A),a + inc a ; 16K ROM page 3 + out ($7B),a +; + ; Reset N8 supplemental memory manager + ; *** Need to implement this *** +; + ld a,$03 + out ($0D),a +; + ; If SBC memmgr, RAM is already in himem, otherwise ROM + ld ix,$FFFF ; point to himem + ld a,$A5 ; an unlikely bit pattern + ld (ix),a ; write the value + cp (ix+0) ; check value written + jr z,hd_cpu2 ; SBC memory manager, we are done! +; + ld a,$04 + out ($0D),a +; + ; Now test for Zeta 2 memory manager + ; Start by initializing and enabling the page registers + inc h ; assume Zeta 2 memory manager +#ifdef ROMBOOT + xor a ; ROM page 0 + out ($78),a + inc a ; ROM page 1 + out ($79),a +#endif + ld a,$20 ; first RAM page + out ($7A),a + inc a ; second RAM page + out ($7B),a + ld a,1 ; enable paging + out ($7C),a +; + ld a,$05 + out ($0D),a +; + ; Test himem RAM again + ld ix,$FFFF ; point to himem + ld a,$A5 ; an unlikely bit pattern + ld (ix),a ; write the value + cp (ix+0) ; check value written + jr z,hd_cpu2 ; Zeta 2 memory manager, we are done! +; + ld a,$06 + out ($0D),a +; + ; If neither SBC nor Zeta 2, then we assume the memory + ; manager is the native memory manager onboard the CPU + ld a,l ; get cpu type + cp 4 ; Z280? + jr z,hd_z280init ; handle it + or a ; Z80? + jr nz,hd_z180init ; if no, do handle Z180 +; + ; If we get here, we are stuck. We believe we are a Z80 + ; but both of the Z80 memory manager tests failed. +hd_halt: + + + ld a,$07 + out ($0D),a + + + ld hl,str_halt + call prtstr + halt ; give up +; +hd_z180init: + ; Initialize Z180 memory manager + ; Put first RAM page into himem (commmon) + ld a,$80 + out0 (z180_cbr),a +; + ld h,2 + jr hd_cpu2 + +hd_N8init: + ; Initialize N8 memory manager + ld h,3 + jr hd_cpu2 + +hd_z280init: + ; Initialize Z280 memory manager + ld h,4 + jr hd_cpu2 +; +hd_cpu2: + ld a,$08 + out ($0D),a +; + ld ($8000),hl ; stash cpu/memmgr at $8000 +; +; Transition to upper memory (omit page zero) +; + ld hl,$0000+$100 + ld de,$8000+$100 + ld bc,$8000-$100 + ldir + jp hd_start2 +; + .org $ + $8000 +; +; +;======================================================================= +; Post-relocation Startup +;======================================================================= +; +hd_start2: +; + ld a,$09 + out ($0D),a +; + ld sp,$FF00 ; Stack just below FF page +; +; Copy FF page image to real location. Use a decrementing copy +; just in case page image is within $100 bytes of $FF00. Very +; unlikely, but just to be safe. +; + ld hl,ffpgimg+$FF ; Start at end of image + ld de,$FFFF ; To top of RAM + ld bc,$100 ; Copy 1 page + lddr ; Execute +; +; Recover cpu/memmgr codes stashed at $8000 and +; save them in FFpg +; + ld hl,($8000) + ld (hd_cpu),hl +; +; Probe and initialize serial port console driver. We just go +; through the options stopping at the first one that works. The +; order of polling below is intended to find the most reasonable +; console port. +; +; + ld a,$0A + out ($0D),a +; + ; Z280 UART + ld ix,z2u_jptbl + call jpix + jr z,hd_start3 + ; ASCI + ld ix,asci_jptbl + call jpix + jr z,hd_start3 + ; UART + ld ix,uart_jptbl + call jpix + jr z,hd_start3 + ; ACIA + ld ix,acia_jptbl + call jpix + jr z,hd_start3 + ; SIO + ld ix,sio_jptbl + call jpix + jr z,hd_start3 +; + ; Ugh, nothing worked + ld a,$0C + out ($0D),a + halt +; +; +; +hd_start3: +; + ld a,$0D + out ($0D),a +; +; Copy selected console serial driver vector table into place +; + push ix + pop hl + ld de,hd_serjptbl + ld bc,5*3 + ldir +; +; +; + ; Map a RAM page to lower 32K +; + ; Setup zero page in lower 32K +; +; +; +hd_start4: +; + ld hl,str_banner + call prtstr +; + ld hl,str_cputag + call prtstr + ld a,($8000) ; cpu type + ;call prthex8 + rlca + ld hl,str_cpu + call addhla + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + call prtstr +; +; + ld hl,str_mmtag + call prtstr + ld a,($8001) ; memory manager + ;call prthex8 + rlca + ld hl,str_mm + call addhla + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + call prtstr +; + call cin + jp hd_start4 +; +; +; + jp hd_halt +; +;======================================================================= +; Helper functions +;======================================================================= +; +; +;======================================================================= +; Include various utility code modules +;======================================================================= +; +#include "util.asm" +; +;======================================================================= +; Console I/O +;======================================================================= +; +; Internal serial driver routing jump table. The console serial +; port is detected at startup and the following table is populated +; dynamically at that time. +; +hd_serjptbl: + jp 0 ; Console port initialization + jp 0 ; Console read byte + jp 0 ; Console write byte + jp 0 ; Console input status + jp 0 ; Console output status +; +; Wrapper functions for console I/O handles routing abstraction and +; ensures that no registers are modified other than AF for input +; functions. +; +hd_cinit: + push af + push bc + push de + push hl + call hd_serjptbl + 0 + pop hl + pop de + pop bc + pop af + ret +; +hd_cin: + push bc + push de + push hl + call hd_serjptbl + 3 + pop hl + pop de + pop bc + ret +; +hd_cout: + push af + push bc + push de + push hl + call hd_serjptbl + 6 + pop hl + pop de + pop bc + pop af + ret +; +hd_cist: + push bc + push de + push hl + call hd_serjptbl + 9 + pop hl + pop de + pop bc + ret +; +hd_cost: + push af + push bc + push de + push hl + call hd_serjptbl + 12 + pop hl + pop de + pop bc + pop af + ret +; +; Include all serial drivers +; +#include "uart.asm" +#include "asci.asm" +#include "acia.asm" +#include "sio.asm" +#include "z2u.asm" +; +;======================================================================= +; Working literals and internal variables +;======================================================================= +; +str_banner .db "\r\n\r\nHDIAG v0.90",0 +str_cputag .db "\r\nCPU Model: ",0 +str_mmtag .db "\r\nMemory Manager: ",0 +str_halt .db "\r\n\r\n*** System HALTed ***",0 +; +str_cpu: + .dw str_cpuz80 + .dw str_cpuz180 + .dw str_cpuz180K + .dw str_cpuz180N + .dw str_cpuz280 +; +str_cpuz80 .db "Z80",0 +str_cpuz180 .db "Z80180",0 +str_cpuz180K .db "Z8S180-K",0 +str_cpuz180N .db "Z8S180-N",0 +str_cpuz280 .db "Z80280",0 +; +str_mm: + .dw str_mmsbc + .dw str_mmz2 + .dw str_mmz180 + .dw str_mmn8 + .dw str_mmz280 +; +str_mmsbc .db "SBC/MBC",0 +str_mmz2 .db "Zeta2/RC2014",0 +str_mmz180 .db "Z180 Native",0 +str_mmn8 .db "Z180 Native (N8)",0 +str_mmz280 .db "Z280 Native",0 +; +;======================================================================= +; Top page of CPU RAM, global variables and function jump table +;======================================================================= +; +; This area is defined here, but copied to the top page of RAM at +; initialization! +; +; The top page (256 bytes) of CPU address space is used to maintain +; a jump table of functions available to all diagnostic modules. +; It also contains some global variables at fixed locations for use +; by diagnostic modules. +; +ffpgimg .equ $ + .org $FF00 ; Set code org +; +hd_jptbl: +cinit jp hd_cinit ; Console port initialization +cin jp hd_cin ; Console read byte +cout jp hd_cout ; Console write byte +cist jp hd_cist ; Console input status +cost jp hd_cost ; Console output status +; + .fill $FF80-$ +hd_cpu .db 0 ; CPU type +hd_mmgr .db 0 ; Memory manager type + .end + + diff --git a/Source/HDIAG/hdiag_old.asm b/Source/HDIAG/hdiag_old.asm new file mode 100644 index 00000000..46456513 --- /dev/null +++ b/Source/HDIAG/hdiag_old.asm @@ -0,0 +1,2543 @@ +; +;================================================================================================== +; HDIAG +;================================================================================================== +; +; THIS FILE CONTAINS A FRAMEWORK FOR A DIAGNOTIC ENVIRONMENT. IT IS ESSENTIALLY A STRIPPED DOWN +; VERSION OF HBIOS. IT DOES NO BANK SWITCHING, BUT THE INTERRUPT MANAGEMENT FRAMEWORK IS +; RETAINED. UPON STARTUP, IT RELOCATES TO UPPER (COMMON) RAM AS QUICKLY AS POSSIBLE. +; +; THERE IS NO HBIOS API. MINIMAL SERIAL PORT ACCESS IS PROVIDED BY INCLUDING THE PLATFORM +; APPROPRIATE MIN_XXX.ASM SERIAL DRIVER. SERIAL PORT SPEEDS ARE FIXED AND THERE IS NO +; FLOW CONTROL. NONE OF THE TYPICAL DRIVER MODULES (CHARACTER, DISK, VIDEO, ETC.) ARE INCLUDED +; AND THERE IS NO DISPATCHING MECHANISM. +; +; IN ORDER TO BUILD PLATFORM APPROPRIATE VERSIONS, THE FULL HBIOS INCLUDE FILE STRUCTURE +; IS USED SO THAT ALL OF THE HBIOS CONFIG SETTINGS CAN BE USED. +; +; THIS FILE CAN BE COMPILED TO BOOT IN ONE OF 2 MODES (ROM OR APPLICATION) 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. +; +; - 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. +; +; INCLUDE FILE NESTING: +; +; hdiag.asm +; - std.asm +; - ver.inc +; - hbios.inc +; - build.inc +; - config/_.asm +; - cfg_.asm +; - util.asm +; - min_[uart|asci|sio|acia].asm +; - dsky.asm ??? +; - diagnostic modules... +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +#DEFINE HDIAG +; +; MAKE SURE EXACTLY ONE OF ROMBOOT, APPBOOT IS DEFINED. +; +MODCNT .EQU 0 +#IFDEF ROMBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IFDEF APPBOOT +MODCNT .SET MODCNT + 1 +#ENDIF +#IF (MODCNT != 1) + .ECHO "*** ERROR: PLEASE DEFINE ONE AND ONLY ONE OF ROMBOOT, APPBOOT!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +; +; +#IF (DIAGENABLE) +#DEFINE DIAG(N) PUSH AF + #DEFCONT \ LD A,N + #DEFCONT \ OUT (DIAGPORT),A + #DEFCONT \ POP AF +#ELSE +#DEFINE DIAG(N) \; +#ENDIF +; +#IF (LEDENABLE) + #IF (LEDMODE == LEDMODE_STD) +#DEFINE LED(N) PUSH AF + #DEFCONT \ LD A,~N + #DEFCONT \ OUT (LEDPORT),A + #DEFCONT \ POP AF + #ENDIF + #IF (LEDMODE == LEDMODE_RTC) +#DEFINE LED(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 +#ELSE +#DEFINE LED(N) \; +#ENDIF +; +; +; +#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 .DB $ED,$7F,$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 +; +#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 +; +; +; +#IF (CTCENABLE) +CTCA .EQU CTCBASE + 0 ; CTC: CHANNEL A REGISTER ADR +CTCB .EQU CTCBASE + 1 ; CTC: CHANNEL B REGISTER ADR +CTCC .EQU CTCBASE + 2 ; CTC: CHANNEL C REGISTER ADR +CTCD .EQU CTCBASE + 3 ; CTC: CHANNEL D REGISTER ADR +#ENDIF +; +; THIS EQUATE IS UPDATED BY DRIVER INCLUDES THAT SHARE THE RTC LATCH. +; AS DRIVER IS INCLUDED, IT WILL USE .SET TO SET ANY BITS THEY OWN +; AND WANT TO SET AS DEFAULT. +; +RTCDEF .EQU 0 ; ALLOWS DRIVERS TO SET BITS +; +#IF (PLATFORM == PLT_SCZ180) +RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT +#ENDIF +; +; +; +#IFNDEF APPBOOT +; + .ORG 0 +; +;================================================================================================== +; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE, LEAVE INTERRUPTS DISABLED +;================================================================================================== +; + .FILL (000H - $),0FFH ; RST 0 + JP HB_START + .DW ROM_SIG + .FILL (008H - $),0FFH ; RST 8 + RET + .FILL (010H - $),0FFH ; RST 10 + RET + .FILL (018H - $),0FFH ; RST 18 + RET + .FILL (020H - $),0FFH ; RST 20 + RET + .FILL (028H - $),0FFH ; RST 28 + RET + .FILL (030H - $),0FFH ; RST 30 + RET + .FILL (038H - $),0FFH ; RST 38 / IM1 INT + #IF (INTMODE == 1) + JP INT_IM1 ; JP TO INTERRUPT HANDLER IN HI MEM + #ELSE + 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, ", ", TIMESTAMP, 0 +AUTH .DB "WBW",0 +DESC .DB "ROMWBW v", BIOSVER, ", Copyright (C) 2020, Wayne Warthen, GNU GPL v3", 0 +; + .FILL ($100 - $),$FF ; PAD REMAINDER OF PAGE ZERO +; +#ENDIF +; +; +; + .ORG $100 + JP HB_START +; +;================================================================================================== +; HBIOS UPPER MEMORY PROXY (RELOCATED TO RUN IN TOP 2 PAGES OF CPU RAM) +;================================================================================================== +; +; THE FOLLOWING CODE IS RELOCATED TO THE TOP OF MEMORY TO HANDLE INVOCATION DISPATCHING +; + ;.FILL (HBX_IMG - $) ; FILL TO START OF PROXY IMAGE START +HBX_IMG .SET $ + .ORG HBX_LOC ; ADJUST FOR RELOCATION +; +; MEMORY LAYOUT: +; +; HBIOS PROXY CODE $FE00 (256 BYTES) +; INTERRUPT VECTORS $FF00 (32 BYTES, 16 ENTRIES) +; INTERRUPT HANDLER STUBS $FF20 (128 BYTES) +; HBIOS PROXY COPY BUFFER $FF80 (64 BYTES) +; HBIOS PROXY MGMT BLOCK $FFE0 (32 BYTES) +; +; DEFINITIONS +; +HBX_BUFSIZ .EQU $40 ; INTERBANK COPY 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 (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 +;;;; +;;; .DB $ED,$71 ; SC +;;; .DW HB_DISPATCH ; SC PARAMETER +;;;; +;;; 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. +;; Preserve all Registers including Flags. +;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; +HBX_BNKSEL: + ; IF AN INTERRUPT OCCURS DURING THE BANK SWITCH CODE, + ; THE BANK WILL BE SET TO (CURBNK) AS THE INTERRUPT + ; RETURNS. SO, IT IS IMPORTANT THAT (HB_CURBNK) BE + ; SET AS THE FIRST STEP TO AVOID ISSUES IF AN INTERRUPT + ; OCCURS DURING PROCESSING. + LD (HB_CURBNK),A ; RECORD NEW CURRENT BANK +; +HBX_BNKSEL_INT: +; +#IF (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. + ;BIT 7,A ; [8] TEST RAM BIT + ;JR Z,HBX_ROM ; [12/7] IF NOT SET, JUST DO ROM + OR A ; [4] SET FLAGS + JP P,HBX_ROM ; [10] BIT 7 INDICATES RAM + #ENDIF + OUT (MPCL_RAM),A ; SET RAM PAGE SELECTOR +HBX_ROM: + OUT (MPCL_ROM),A ; SET ROM PAGE SELECTOR + RET ; DONE +#ENDIF +; +#IF (MEMMGR == MM_Z2) + BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE + JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE + RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT + ADD A,16 ; ADD 16 x 32K - RAM STARTS FROM 512K +; +HBX_ROM: + RLCA ; TIMES 2 - GET 16K PAGE INSTEAD OF 32K + OUT (MPGSEL_0),A ; BANK_0: 0K - 16K + INC A ; + OUT (MPGSEL_1),A ; BANK_1: 16K - 32K + #IF (CPUFAM == CPU_Z280) + PCACHE + #ENDIF + RET ; DONE +#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: + RES 7,A ; CLEAR BIT 7 FROM ABOVE + RLCA ; SCALE SELECTOR TO + RLCA ; ... GO FROM Z180 4K PAGE SIZE + RLCA ; ... TO DESIRED 32K PAGE SIZE + OUT0 (Z180_BBR),A ; WRITE TO BANK BASE + LD A,N8_DEFACR | 80H ; SELECT RAM BY SETTING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +; +HBX_ROM: + OUT0 (N8_RMAP),A ; BANK INDEX TO N8 RMAP REGISTER + XOR A ; ZERO ACCUM + OUT0 (Z180_BBR),A ; ZERO BANK BASE + LD A,N8_DEFACR ; SELECT ROM BY CLEARING BIT 7 + OUT0 (N8_ACR),A ; ... IN N8 ACR REGISTER + RET ; DONE +#ENDIF +; +#IF (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: + 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 + .DB $ED,$71 ; SC + .DW Z280_BNKSEL ; SC PARAMETER + 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,$10 ; ADD 16 x 32K - RAM STARTS FROM 512K +; +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 + +#IF (RAMSIZE == 256) + XOR %00000100 ; TOP 32K IS ALWAYS IN FIRST CHIP +#ENDIF + +#IF (RAMSIZE == 1024) + XOR %00010000 ; TOP 32K IS ALWAYS IN FIRST CHIP +#ENDIF + + 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 +; +;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +; 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) + .DB $ED,$71 ; SC + .DW Z280_BNKCPY ; SC PARAMETER + RET +#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 + .DB $ED,$71 ; SC + .DW HBX_BNKCALL2 ; CALL HERE IN SYSTEM MODE + 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 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 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 +; +; SPECIAL ROUTINE IN HIGH MEMORY TO PERFORM A COLD START ON Z280 +; THIS REQUIRES US TO REMAP LOW MEMORY, THEN JUMP TO ZERO +; +#IF (MEMMGR == MM_Z280) +; +Z280_RESTART: + DI ; KILL INTERRUPTS + LD SP,HBX_LOC ; STACK IN HIGH MEMORY +; + ; COPY Z280 BANK SELECT ROUTINE TO HIGH MEMORY + LD HL,Z280_BNKSEL + LD DE,$8000 + LD BC,Z280_BNKSEL_LEN + LDIR +; + ; MAKE ROM BOOT BANK ACTIVE IN LOW SYS MEM + LD A,BID_BOOT + LD B,$10 ; FIRST SYS PDR + CALL $8000 ; DO IT +; + ; NOW JUST JUMP TO START OF ROM BOOT CODE + JP 0 +#ENDIF +; +; PRIVATE STACK AT END OF HBIOS CODE +; OCCUPIES SPACE BEFORE IVT +; +HBX_INTSTKSIZ .EQU $FF00 - $ + .ECHO "HBIOS INT STACK space: " + .ECHO HBX_INTSTKSIZ + .ECHO " bytes.\n" + .FILL HBX_INTSTKSIZ,$FF +HBX_INTSTK .EQU $ +; +;#IF (HBX_INTSTKSIZ < 24) +#IF (HBX_INTSTKSIZ < 22) + .ECHO "*** ERROR: INTERRUPT STACK IS TOO SMALL!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; +#IF ((INTMODE == 2) | (INTMODE == 3)) +; +; HBIOS INTERRUPT SLOT ASSIGNMENTS +; +; # Z80 Z180 +; --- -------------- -------------- +; 0 CTC0A INT1 -+ +; 1 CTC0B INT2 | +; 2 CTC0C TIM0 | +; 3 CTC0D TIM1 | +; 4 UART0 DMA0 +- Z180 INTERNAL +; 5 UART1 DMA1 | +; 6 CSIO | +; 7 SIO0 SER0 | +; 8 SIO1 SER1 -+ +; 9 PIO0A PIO0A +; 10 PIO0B PIO0B +; 11 PIO1A PIO1A +; 12 PIO1B PIO1B +; 13 SIO0 +; 14 SIO1 +; 15 +; +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 +; +#ENDIF +; +INT_IM1: +#IF (INTMODE == 1) + CALL HBX_INT + .DB $00 +#ELSE + RETI ; UNEXPECTED INT, RET W/ INTS LEFT DISABLED +#ENDIF +; +#IF (INTMODE > 0) +; +HBX_INT: ; COMMON INTERRUPT ROUTING CODE +; + #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 +; + ; 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 +; + HB_EI ; ENABLE INTERRUPTS + RETI ; AND RETURN +; + #ENDIF + +#ENDIF +; +; SMALL TEMPORARY STACK FOR USE BY HBX_BNKCPY +; +HBX_TMPSTKSIZ .EQU (HBX_XFC - HBX_BUFSIZ - $) + .ECHO "HBIOS TEMP STACK space: " + .ECHO HBX_TMPSTKSIZ + .ECHO " 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) +; +#IFDEF ROMBOOT + .DB BID_BOOT ; HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID +#ELSE + .DB BID_USR ; HB_CURBNK: CURRENTLY ACTIVE LOW MEMORY BANK ID +#ENDIF + .DB $FF ; HB_INVBNK: BANK ACTIVE AT TIME OF HBIOS CALL INVOCATION + .DW 0 ; HB_SRCADR: BNKCPY SOURCE ADDRESS + .DB BID_USR ; HB_SRCBNK: BNKCPY SOURCE BANK ID + .DW 0 ; HB_DSTADR: BNKCPY DESTINATION ADDRESS + .DB BID_USR ; HB_DSTBNK: BNKCPY DESTINATION BANK ID + .DW 0 ; HB_CPYLEN: BNKCPY LENGTH + .FILL 4,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE + .DB RTCDEF ; SHADOW VALUE FOR RTC LATCH PORT + .DB $FE ; HB_LOCK: HBIOS MUTEX LOCK + JP 0 ; HB_INVOKE: FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) + JP HBX_BNKSEL ; HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL + JP HBX_BNKCPY ; HB_BNKCPY: FIXED ADR ENTRY FOR HBX_BNKCPY + JP HBX_BNKCALL ; HB_BNKCALL: FIXED ADR ENTRY FOR HBX_BNKCALL + .DW HBX_IDENT ; ADDRESS OF HBIOS PROXY START (DEPRECATED) + .DW HBX_IDENT ; HB_IDENT: ADDRESS OF HBIOS IDENT INFO DATA BLOCK +; + .FILL MEMTOP - $ ; FILL TO END OF MEMORY (AS NEEDED) + .ORG HBX_IMG + HBX_SIZ ; RESET ORG +; +;================================================================================================== +; HDIAG CORE +;================================================================================================== +; +;================================================================================================== +; SYSTEM INITIALIZATION +;================================================================================================== +; +HB_START: +#IFDEF APPBOOT + #IF (MEMMGR == MM_Z280) + LD A,%00000001 + OUT (DIAGPORT),A + LD DE,Z280_BOOTERR + LD C,9 + LD A,%00000010 + OUT (DIAGPORT),A + CALL $0005 + LD A,%00001000 + OUT (DIAGPORT),A + RET +; +Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 native memory management!!!\r\n\r\n$" + #ENDIF +#ENDIF + + DI ; NO INTERRUPTS + IM 1 ; INTERRUPT MODE 1 +; +#IF (DIAGENABLE) + LD A,%00000001 + OUT (DIAGPORT),A +#ENDIF +#IF (LEDENABLE) + #IF (LEDMODE == LEDMODE_STD) + XOR A ; LED IS INVERTED, TURN IT ON + #ENDIF + #IF (LEDMODE == LEDMODE_RTC) + LD A,%00000001 ; LED 0 + LD (HB_RTCVAL),A ; SAVE TO SHADOW REGISTER + #ENDIF + OUT (LEDPORT),A +#ENDIF +; + LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY +; +#IF (CPUFAM == CPU_Z280) + ; 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 +; + ; START BY SELECTING I/O PAGE $FF + 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 +; + #IF (MEMMGR == MM_Z280) +; + ; INITIALIZE ALL OF THE SYSTEM PAGE DESCRIPTORS WITH BLOCK MOVE + XOR A ; FIRST USER PDR + 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,16 ; PROGRAM 16 PDRS + .DB $ED,$93 ; OTIRW +; + ; INITIALIZE ALL OF THE USER PAGE DESCRIPTORS WITH BLOCK MOVE + LD A,$10 ; FIRST SYSTEM PDR + 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,16 ; PROGRAM 16 PDRS + .DB $ED,$93 ; OTIRW +; + ; ENABLE MMU (SYSTEM AND USER TRANSLATION) + LD C,Z280_MMUMCR ; MMU MASTER CONTROL REGISTER + LD HL,$BBFF ; ENABLE USER & SYSTEM TRANSLATE + OUTW (C),HL +; + ; DISABLE MEMORY REFRESH CYCLES + LD A,$08 ; DISABLED + OUT (Z280_RRR),A ; SET REFRESH RATE REGISTER +; + ; CONFIGURE Z280 INT/TRAP VECTOR TABLE POINTER REGISTER + ; WILL POINT TO ROM COPY FOR NOW, UPDATED TO RAM LATER ON + LD C,Z280_VPR + LD HL,Z280_IVT >> 8 ; TOP 16 BITS OF PHYSICAL ADR OF IVT + LDCTL (C),HL +; + JR Z280_INITZ ; JUMP TO CODE CONTINUATION +; + #IF (($ % 2) == 1) + ; WORD ALIGN THE TABLE + .DB 0 + #ENDIF +; +Z280_BOOTPDRTBL: + ; LOWER 32 K (BANKED) + .DW ($000 << 4) | $A + .DW ($001 << 4) | $A + .DW ($002 << 4) | $A + .DW ($003 << 4) | $A + .DW ($004 << 4) | $A + .DW ($005 << 4) | $A + .DW ($006 << 4) | $A + .DW ($007 << 4) | $A + ; UPPER 32 K (COMMON) + .DW (((((BID_COM & $7F) * 8) + 0) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 1) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 2) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 3) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 4) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 5) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 6) + (1 << (RAMLOC - 12))) << 4) | $A + .DW (((((BID_COM & $7F) * 8) + 7) + (1 << (RAMLOC - 12))) << 4) | $A +; +Z280_INITZ: +; + #ENDIF +; + ; RESTORE I/O PAGE TO $00 + 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 +; +#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 + + DIAG(%00000010) + + ; 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) + ; + ; IT HAS BEEN REPORTED THAT CMR NEEDS TO BE SET PRIOR TO CCR + ; WHEN USING AN INPUT FREQUENCY THAT IS XTAL / 2. + ; I NEVER EXPERIENCED A PROBLEM RELATED TO ORDER, BUT JUST + ; FOR GOOD MEASURE, CMR IS SET PRIOR TO CCR BELOW. + ; https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=316&#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)) + ; 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 +; +#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 +; +#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 +; +#IF (MEMMGR == MM_Z2) + ; SET PAGING REGISTERS + #IFDEF ROMBOOT + XOR A + OUT (MPGSEL_0),A + INC A + OUT (MPGSEL_1),A + #ENDIF + LD A,62 + OUT (MPGSEL_2),A + INC A + OUT (MPGSEL_3),A + ; ENABLE PAGING + LD A,1 + OUT (MPGENA),A +#ENDIF +; + DIAG(%00000011) +; +; CHECK BATTERY BACKUP STATUS BEFORE WE COPY PROXY TO 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. +; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM. +; + DEC SP ; RESERVE A STACK BYTE + XOR A ; ZERO MEANS LOW BAT + LD (HBX_LOC - 1),A ; WRITE IT (SHOULD ALWAYS WORK) + INC A ; 1 MEANS BAT OK + LD (HBX_LOC - 1),A ; OVERWRITE IF NVC ALLOWS IT +; +; IF APPBOOT, SAVE CURRENT BANKID +; +; THIS IS NOT GOING TO WORK IF THE APP BOOT IMAGE IS LOADED +; USING THE UNA FAT32 LOADER. SHOULD PROBABLY CHECK THAT THERE +; IS A VALID ROMWBW PROXY IN MEMORY BEFORE DOING THIS. HOWEVER, +; THIS USE CASE IS PROBABLY NON-EXISTENT. THE IMG BOOT IMAGE +; SHOULD WORK FINE WITH THE UNA FAT32 LOADER. +; +#IFDEF APPBOOT + LD A,(HB_CURBNK) + DEC SP ; RESERVE A STACK BYTE + LD (HBX_LOC - 2),A ; SAVE BANK + PUSH AF ; ALSO ON STACK +#ENDIF +; +; INSTALL PROXY IN UPPER MEMORY +; + LD DE,HBX_LOC ; AS PER ABOVE + LD HL,HBX_IMG + LD BC,HBX_SIZ + LDIR +; +; IF APPBOOT, RESTORE CURRENT BANK ID +; +#IFDEF APPBOOT + POP AF + LD (HB_CURBNK),A +#ENDIF +; +; TRANSITION TO UPPER (COMMON) RAM +; + LD HL,0 ; FROM START OF CURRENT BANK + LD DE,$8000 ; TO START OF COMMON RAM + LD BC,$8000-$200-1 ; EVERYTHING BUT THE PROXY AND BATCOND + LDIR + JP HB_START1 +; +; EXECUTION RESUMES HERE AFTER SWITCH TO RAM BANK +; + .ORG $8000 + $ +; +HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK +; + DIAG(%00000111) + LED(%00000010) +; + LD A,(HBX_LOC - 1) ; RECALL BATTERY STATE AND SAVE + LD (HB_BATCOND),A ; FOR FUTURE REFERENCE +; + LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN +; +#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 + ((((BID_BIOS & $7F) * 8) + (1 << (RAMLOC - 12))) << 4) + (Z280_IVT >> 8) + LDCTL (C),HL +#ENDIF +; +; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO +; +#IFDEF APPBOOT +; + ; GET AND SAVE APP BOOT BANK ID + LD A,(HBX_LOC - 2) + LD (HB_APPBNK),A +;;;; +;;; ; MAKE SURE RST 08 VECTOR IS RIGHT +;;; LD A,$C3 +;;; LD ($0008),A +;;; LD HL,HB_INVOKE +;;; LD ($0009),HL +; + ; MAKE SURE IM1 INT VECTOR IS RIGHT + #IF (INTMODE == 1) + ; JP INT_IM1 IF INTERRUPT MODE ACTIVE + LD A,$C3 + LD ($0038),A + LD HL,INT_IM1 + LD ($0039),HL + #ELSE + ; RETI ($ED, $4D) IF NON-INTERRUPT MODE + LD HL,$0038 + LD (HL),$ED + INC HL + LD (HL),$4D + #ENDIF +; +#ENDIF +; + DIAG(%00001111) +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + PRTS("DEBUG-IVT$") + LD DE,HB_IVT + CALL DUMP_BUFFER + CALL NEWLINE +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +; DISCOVER CPU TYPE +; +; 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 +; + 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 +; +#IF (SKZENABLE) +; + ; 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 +; +#IF (CPUFAM == CPU_Z180) +; + ; AT BOOT, Z180 PHI IS OSC / 2 + LD C,(CPUOSC / 2) / 1000000 + LD DE,(CPUOSC / 2) / 1000 +; + #IF (Z180_CLKDIV >= 1) + LD A,(HB_CPUTYPE) ; GET CPU TYPE + CP 2 ; Z8S180 REV K OR BETTER? + JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! + ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED + LD A,$80 + OUT0 (Z180_CCR),A + ; REFLECT SPEED CHANGE + LD C,CPUOSC / 1000000 + LD DE,CPUOSC / 1000 + #ENDIF + + #IF (Z180_CLKDIV >= 2) + LD A,(HB_CPUTYPE) ; GET CPU TYPE + CP 3 ; Z8S180 REV N OR BETTER? + JR C,HB_CPU2 ; 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 + ; REFLECT SPEED CHANGE + LD C,(CPUOSC * 2) / 1000000 + LD DE,(CPUOSC * 2) / 1000 + #ENDIF +; +HB_CPU2: + ; SAVE CPU SPEED + LD A,C + LD (CB_CPUMHZ),A + LD (CB_CPUKHZ),DE +; +#ENDIF +; + DIAG(%00011111) +; + LD A,(CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +; +#IF (CPUFAM == CPU_Z180) +; + ; SET FINAL DESIRED WAIT STATES + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (Z180_DCNTL),A +; +#ENDIF +; +#IF (CPUFAM == CPU_Z280) +; + 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 +; + 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 +; +#ENDIF +; +#IF (INTMODE == 2) + ; SETUP Z80 IVT AND INT MODE 2 + LD A,HBX_IVT >> 8 ; SETUP HI BYTE OF IVT ADDRESS + LD I,A ; ... AND PLACE IT IN I REGISTER + + #IF (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 + + IM 2 ; SWITCH TO INT MODE 2 +#ENDIF +; +#IF (INTMODE == 3) +; + ; SETUP Z280 INT A FOR VECTORED INTERRUPTS + LD HL,%0010000000000000 + LD C,Z280_ISR + LDCTL (C),HL +; + IM 3 +; +#ENDIF +; +#IF (CPUFAM == CPU_Z180) +; + #IF (INTMODE == 2) +; + ; MASK ALL EXTERNAL INTERRUPTS FOR NOW + LD A,$01 ; INT0 ENABLED, INT1-2 DISABLED + OUT0 (Z180_ITC),A ; WRITE TO INT/TRAP CONTROL REGISTER +; + #ENDIF +; +#ENDIF +; + DIAG(%00111111) +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE + CALL REGDMP +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +#IF (DSKYENABLE) + CALL DSKY_PREINIT +; + 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 + CALL DSKY_SHOW +#ENDIF +; + ; INITIALIZE SERIAL PORT + CALL CINIT +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE + CALL REGDMP +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; + DIAG(%01111111) + LED(%00000011) +; +#IF FALSE +; +; TEST DEBUG *************************************************************************************** +; + CALL NEWLINE2 + PRTS("DEBUG+IVT$") + LD DE,HB_IVT + CALL DUMP_BUFFER +; +; TEST DEBUG *************************************************************************************** +; +#ENDIF +; +; ANNOUNCE HBIOS +; + CALL NEWLINE2 + PRTX(STR_BANNER) +; + DIAG(%11111111) +; +; 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 +; + 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 +; +; DISPLAY CPU CONFIG +; + CALL NEWLINE + +#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 + 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 +#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 + CALL PRTSTRD + .TEXT " MMU$" +; +; DISPLAY MEMORY CONFIG +; + CALL NEWLINE + LD HL,ROMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB ROM, $" + LD HL,RAMSIZE + CALL PRTDEC + CALL PRTSTRD + .TEXT "KB RAM$" +; +#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("BTCR=$") + LD C,Z280_BTCR ; BUS TIMING AND CONTROL REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("BTIR=$") + LD C,Z280_BTIR ; BUS TIMING AND CONTROL REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL + CALL PC_SPACE + PRTS("CCR=$") + LD C,Z280_CCR ; CACHE CONTROL REGISTER + LDCTL HL,(C) + CALL PRTHEXWORDHL +#ENDIF +; +#IFDEF ROMBOOT +; +; ROM CHECKSUM VERIFICATION +; THE FIRST ROM BANK HAS A CHECKSUM INJECTED SUCH THAT +; A COMPUTED CHECKSUM ACROSS THE ENTIRE BANK SHOLD ALWAYS BE ZERO +; +HB_ROMCK: + CALL NEWLINE + PRTS("ROM VERIFY:$") +; + ; TEST FIRST 4 BANKS OF ROM + LD B,1 ; 1 BANK + LD C,0 ; STARTING AT BANK 0 +HB_ROMCK1: + PUSH BC ; SAVE LOOP CONTROL + CALL HB_CKBNK ; 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 HL,$7FFF ; START AT BANK END + LD BC,1 ; DECREMENT VALUE + XOR A ; ZERO ACCUM +HB_CKBNK1: + ADD A,(HL) ; ADD NEXT BYTE + OR A ; CLEAR CARRY + SBC HL,BC ; DECREMENT + JR NC,HB_CKBNK1 ; LOOP TILL DONE + HB_EI ; ALLOW INTERRUPTS AGAIN + RET ; AND DONE +; +HB_CKBNKSIZ .EQU $-HB_CKBNK ; SIZE OF ROUTINE +; +HB_ROMCKZ: +; +#ENDIF +; +; LOW BATTERY DIAGNOSTIC MESSAGE +; +#IF (BATCOND) + LD A,(HB_BATCOND) + OR A + LD DE,STR_LOWBAT + CALL Z,WRITESTR +#ENDIF +; + LD DE,STR_SYSHALT + CALL WRITESTR + JR $ + DI + HALT +; +;================================================================================================== +; INTERRUPT VECTOR TABLE (MUST START AT PAGE BOUNDARY!!!) +;================================================================================================== +; + .FILL $100 - ($ & $FF) +; +; +; 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. +; +#IF (INTMODE < 2) +; +HB_IVT: + 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 +; +#ENDIF +; +; 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. +; +#IF ((INTMODE == 2) | (INTMODE == 3)) +; +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 +; +#ENDIF +; +#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 +; +HB_IM1CNT .DB 0 ; NUMBER OF ENTRIES IN CALL LIST +HB_IM1MAX .DB 8 ; MAX ENTRIES IN CALL LIST +HB_IM1PTR .DW HB_IVT ; POINTER FOR NEXT IM1 ENTRY +; +#ENDIF +; +; 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 CONTINUE + OR $FF ; SIGNAL INTERRUPT HANDLED + RET +; +; Z280 BAD INT HANDLER +; +#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 +; + .DB $ED,$55 ; RETIL +; +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 + PUSH DE +; + .DB $ED,$96 ; LDUP A,(HL) +; + ; HANDLE DI + CP $F3 ; DI? + JR NZ,Z280_PRIVINST2 + HB_DI ; DO THE DI + INC HL ; BUMP PAST IT + JR Z280_PRIVINSTX +; +Z280_PRIVINST2: + ; HANDLE EI + CP $FB ; EI? + JR NZ,Z280_PRIVINST3 + HB_EI ; DO THE EI + 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: + .DB $ED,$96 ; LDUP A,(HL) + CALL PRTHEXBYTE + INC HL + DJNZ Z280_PRIVINST4 + CALL PC_RBKT +; + ; GO NO FURTHER + DI + HALT +; +Z280_PRIVINSTX: + ; RESTORE REGISTERS + POP DE + POP BC + 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 + .DB $ED,$55 ; RETIL +; +HB_MSRSAV .DW 0 ; SAVED MSR +HB_RCSAV .DW 0 ; SAVED REASON CODE +; +Z280_PRIVSTR .TEXT "\r\n\r\n*** Privileged Instruction @$" +; +#ENDIF +; +;================================================================================================== +; Z280 INTERRUPT VECTOR TABLE +;================================================================================================== +; +#IF (MEMMGR == MM_Z280) +; + ; 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. +; + .FILL $1000 - ($ & $FFF) ; MUST BE 4K ALIGNED! +; +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 +; +; Z280 BANK SELECTION (CALLED FROM PROXY) +; +#IF (MEMMGR == MM_Z280) +; +; REG A HAS BANK ID, REG B HAS INITIAL PDR TO PROGRAM +; REGISTERS AF, BC, HL DESTROYED +; +; THIS ROUTINE MAY BE RELOCATED TO RUN IN HIGH MEMORY IN CERTAIN CASES +; LIKE A SYSTEM RESTART. IT MUST BE KEPT ENTIRELY RELOCATABLE. +; +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 +; + ; 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 (RC2014) + ; 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, MOVE RAM BIT + SET RAMLOC-16,H ; HL=0000 RBBB B000 0000 +; +Z280_BNKSEL2: +; + ; SET LOW NIBBLE + LD A,$0A ; VALUE FOR LOW NIBBLE + .DB $ED,$6D ; 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 BANK COPY (CALLED FROM PROXY) +; +#IF (MEMMGR == MM_Z280) +; +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 (IOPRVAL),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: + .DB $ED,$B7 ; INW HL,(C) + 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,(IOPRVAL) ; 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. + ; RC2014 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 + JR Z,Z2DMAADR2 + RES 6,H + SET RAMLOC-16,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 +; +; 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 + .DB $ED,$55 ; RETIL +#ENDIF +; +#DEFINE USEDELAY +#INCLUDE "util.asm" +; +#IF (DSKYENABLE) +#DEFINE DSKY_KBD + #IF (DSKYMODE == DSKYMODE_V1) +#INCLUDE "dsky.asm" + #ENDIF + #IF (DSKYMODE == DSKYMODE_NG) +#INCLUDE "dskyng.asm" + #ENDIF +#ENDIF +; +; 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 +; +; +; +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 +; +; +; +SYSHALT: + LD DE,STR_HALT + CALL WRITESTR + DI + HALT +; +; 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 +; +HB_CPU_STR: .TEXT " Z80$" + .TEXT " Z80180$" + .TEXT " Z8S180-K$" + .TEXT " Z8S180-N$" + .TEXT " Z80280$" +; +;================================================================================================== +; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) +;================================================================================================== +; +#IF (MINIO == MINIO_UART) + #INCLUDE "min_uart.asm" +#ENDIF +; +#IF (MINIO == MINIO_ASCI) + #INCLUDE "min_asci.asm" +#ENDIF +; +#IF (MINIO == MINIO_ACIA) + #INCLUDE "min_acia.asm" +#ENDIF +; +#IF (MINIO == MINIO_SIO) + #INCLUDE "min_sio.asm" +#ENDIF +; +#IF (MINIO == MINIO_Z2U) + #INCLUDE "min_z2u.asm" +#ENDIF +; +;================================================================================================== +; MISCELLANEOUS UTILITY FUNCTIONS +;================================================================================================== +; +; SET HL TO IY+A, A IS TRASHED +; +LDHLIYA: + PUSH IY ; COPY INSTANCE DATA PTR + POP HL ; ... TO HL + ;JP ADDHLA ; APPLY OFFSET TO HL AND RETURN + ADD A,L ; ADD OFFSET TO LSB + LD L,A ; ... PUT BACK IN L + RET NC ; DONE IF CF NOT SET + INC H ; IF CF SET, BUMP MSB + RET ; ... AND RETURN +; +;================================================================================================== +; HBIOS GLOBAL DATA +;================================================================================================== +; +HB_CPUTYPE .DB 0 ; 0=Z80, 1=80180, 2=SL1960, 3=ASCI BRG +; +CB_CPUMHZ .DB CPUMHZ +CB_CPUKHZ .DW CPUKHZ +; +IOPRVAL .DW 0 ; TEMP STORAGE FOR IOPR +; +HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK) +; +STR_BANNER .DB "RomWBW HDIAG v", BIOSVER, ", ", TIMESTAMP, "$" +STR_PLATFORM .DB PLATFORM_NAME, "$" +STR_SWITCH .DB "*** Activating CRT Console ***$" +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)? $" +STR_SYSHALT .TEXT "\r\n\r\n*** SYSTEM HALTED ***$" +; +#IF (DSKYENABLE) ; 'H','B','I','O',' ',' ',' ',' ' + #IF (DSKYMODE == DSKYMODE_V1) +MSG_HBVER .DB $3E,$7F,$0A,$7B,$00,$00,$00,$00 ; "HBIO " + #ENDIF + #IF (DSKYMODE == DSKYMODE_NG) +MSG_HBVER .DB $76,$7F,$30,$3F,$00,$00,$00,$00 ; "HBIO " + #ENDIF +#ENDIF +; +HB_APPBNK .DB 0 ; START BANK WHEN RUN IN APP MODE +; +HB_BCDTMP .FILL 5,0 ; BCD NUMBER STORAGE (TEMP) +; +HB_END .EQU $ +; +SLACK .EQU HBX_LOC - $ + .ECHO "HDIAG space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +#IFDEF ROMBOOT + .FILL SLACK +#ENDIF +; + .END diff --git a/Source/HDIAG/sio.asm b/Source/HDIAG/sio.asm new file mode 100644 index 00000000..b38a4abe --- /dev/null +++ b/Source/HDIAG/sio.asm @@ -0,0 +1,108 @@ +; +;======================================================================= +; HDIAG SIO Driver +;======================================================================= +; +; Assumes the UART port conventions for RC2014. Command/status port +; at $80 and read/write data port at $81. +; Assuming a UART clock frequency of 1.8432 MHz, the baud rate +; will be 38400. +; +sio_cmd .equ $80 ; SIO command/status port +sio_dat .equ $81 ; SIO read/write port +; +sio_jptbl: + jp sio_cinit ; Initialize serial port + jp sio_cin ; Read byte + jp sio_cout ; Write byte + jp sio_cist ; Input status + jp sio_cost ; Output Status +; +; +; +sio_cinit: + ; Detect SIO here... + ; Zero the int vector register + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + xor a ; zero accum + out (sio_cmd+2),a ; write to WR2 + ; Read the int vector register and check for zero + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + in a,(sio_cmd+2) ; get int vector value + and $F0 ; only top nibble + ret nz ; abort if not zero + ; Set test value in int vector register + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + ld a,$FF ; test value + out (sio_cmd+2),a ; write to WR2 + ; Read the int vector register to confirm value written + ld a,2 ; select WR2 (int vector) + out (sio_cmd+2),a ; do it + in a,(sio_cmd+2) ; get int vector value + and $F0 ; only top nibble + cp $F0 ; compare + ret nz ; abort if miscompare +; + ; Program the SIO, just channel A + ld c,sio_cmd ; command port + ld hl,sio_initregs ; point to init values + ld b,sio_initlen ; count of bytes to write + otir ; write all values +; + xor a ; signal success + ret ; done +; +; +; +sio_cin: + call sio_cist ; check for char ready + jr z,sio_cin ; if not, loop + in a,(sio_dat) ; read byte + ret ; done +; +; +; +sio_cout: + push af ; save incoming +sio_cout1: + call sio_cost ; ready for char? + jr z,sio_cout1 ; loop if not + pop af ; restore incoming + out (sio_dat),a ; write byte + ret ; and done +; +; +; +sio_cist: + xor a ; select WR0 + out (sio_cmd),a ; do it + in a,(sio_cmd) ; get status + and $01 ; isolate rx ready + ret ; a != 0 if rx ready, else 0 +; +; +; +sio_cost: + xor a ; select WR0 + out (sio_cmd),a ; do it + in a,(sio_cmd) ; get status + and $04 ; isolate tx ready (empty) + ret ; a != 0 if tx ready, else 0 +; +; Table for chip register initialization. Simple setup for clock +; divided by 64. Assuming a system clock of 7.3728 MHz, this will +; result in a baud rate of 115200 which is standard for RC2014. +; +sio_initregs: + .db $00, $18 ; wr0: channel reset cmd + .db $04, $C4 ; wr4: clk baud parity stop bit + .db $01, $00 ; wr1: no interrupts + .db $02, $00 ; wr2: im2 vec offset + .db $03, $E1 ; wr3: 8 bit rcv, cts/dcd auto, rx enable + .db $05, $EA ; wr5: dtr, 8 bits send, tx enable, rts 1 11 0 1 0 1 0 (1=dtr,11=8bits,0=sendbreak,1=txenable,0=sdlc,1=rts,0=txcrc) +; +sio_initlen .equ $-sio_initregs + diff --git a/Source/HDIAG/uart.asm b/Source/HDIAG/uart.asm new file mode 100644 index 00000000..36a030c3 --- /dev/null +++ b/Source/HDIAG/uart.asm @@ -0,0 +1,106 @@ +; +;======================================================================= +; HDIAG UART Driver +;======================================================================= +; +; Assumes the UART conventions for SBC/MBC/Zeta, base port at $68. +; Assuming a UART clock frequency of 1.8432 MHz, the baud rate +; will be 38400. +; +uart_iob .equ $68 +uart_osc .equ 1843200 +uart_baudrate .equ 38400 +uart_divisor .equ uart_osc / uart_baudrate / 16 +; +uart_rbr .equ uart_iob + 0 ; dlab=0: rcvr buffer reg (read only) +uart_thr .equ uart_iob + 0 ; dlab=0: xmit holding reg (write only) +uart_ier .equ uart_iob + 1 ; dlab=0: int enable reg +uart_iir .equ uart_iob + 2 ; int ident register (read only) +uart_fcr .equ uart_iob + 2 ; fifo control reg (write only) +uart_lcr .equ uart_iob + 3 ; line control reg +uart_mcr .equ uart_iob + 4 ; modem control reg +uart_lsr .equ uart_iob + 5 ; line status reg +uart_msr .equ uart_iob + 6 ; modem status reg +uart_scr .equ uart_iob + 7 ; scratch register +uart_dll .equ uart_iob + 0 ; dlab=1: divisor latch (ls) +uart_dlm .equ uart_iob + 1 ; dlab=1: divisor latch (ms) +; +; +; +uart_jptbl: + jp uart_cinit ; Initialize serial port + jp uart_cin ; Read byte + jp uart_cout ; Write byte + jp uart_cist ; Input status + jp uart_cost ; Output Status +; +; +; +uart_cinit: + ; Test for existence + xor a ; zero accum + out (uart_ier),a ; ier := 0 + ld a,$80 ; dlab bit on + out (uart_lcr),a ; output to lcr (dlab regs now active) + ld a,$5A ; load test value + out (uart_dlm),a ; output to dlm + in a,(uart_dlm) ; read it back + cp $5A ; check for test value + ret nz ; nope, unknown uart or not present + xor a ; dlab bit off + out (uart_lcr),a ; output to lcr (dlab regs now inactive) + in a,(uart_ier) ; read ier + cp $5A ; check for test value + jr nz,uart_cinit1 ; if *not* $5A, good to go + or $FF ; signal error + ret ; done +; +uart_cinit1: + ld a,$80 ; lcr := dlab on + out (uart_lcr),a ; set lcr + ld a,uart_divisor & $ff ; low byte of divisor + out (uart_dll),a ; set divisor (lsb) + ld a,uart_divisor / $100 ; high byte of divisor + out (uart_dlm),a ; set divisor (msb) + xor a ; zero accum + out (uart_ier),a ; init ier (no ints) + ld a,$03 ; value for lcr and mcr + out (uart_lcr),a ; lcr := 3, dlab off, 8 data, 1 stop, no parity + out (uart_mcr),a ; mcr := 3, dtr on, rts on + ld a,$07 ; enable & reset fifo's + out (uart_fcr),a ; do it + xor a ; signal success + ret +; +; +; +uart_cin: + call uart_cist ; received char ready? + jr z,uart_cin ; loop if not + in a,(uart_rbr) ; read byte + ret ; and done +; +; +; +uart_cout: + push af ; save incoming +uart_cout1: + call uart_cost ; ready for char? + jr z,uart_cout1 ; loop if not + pop af ; restore incoming + out (uart_thr),a ; write byte + ret ; and done +; +; +; +uart_cist: + in a,(uart_lsr) ; get status + and $01 ; isolate bit 0 (receive data ready) + ret ; a != 0 if char ready, else 0 +; +; +; +uart_cost: + in a,(uart_lsr) ; get status + and $20 ; isolate bit 5 + ret ; a != 0 if char ready, else 0 diff --git a/Source/HDIAG/util.asm b/Source/HDIAG/util.asm new file mode 100644 index 00000000..b2a1cfb4 --- /dev/null +++ b/Source/HDIAG/util.asm @@ -0,0 +1,106 @@ +; +;======================================================================= +; HDIAG Utility Functions +;======================================================================= +; +; Print string at HL on console, null terminated. +; HL and AF are trashed. +; +prtstr: + ld a,(hl) ; get next character + or a ; set flags + inc hl ; bump pointer regardless + ret z ; done if null + call cout ; display character + jr prtstr ; loop till done +; +; Print the hex byte value in A +; +prthex8: + push af + push de + call hexascii + ld a,d + call cout + ld a,e + call cout + pop de + pop af + ret +; +; Print the hex word value in BC +; +prthex16: + push af + ld a,b + call prthex8 + ld a,c + call prthex8 + pop af + ret +; +; Print the hex dword value in DE:HL +; +prthex32: + push bc + push de + pop bc + call prthex16 + push hl + pop bc + call prthex16 + pop bc + ret +; +; Convert binary value in A to ASCII hex characters in DE +; +hexascii: + ld d,a + call hexconv + ld e,a + ld a,d + rlca + rlca + rlca + rlca + call hexconv + ld d,a + ret +; +; Convert low nibble of A to ASCII hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret + +; +; Jump to address in HL/IX/IY +; +; No registers affected +; Typically used as "call jphl" to call a routine +; at address in HL register. +; +jphl: + jp (hl) +; +jpix: + jp (ix) +; +jpiy: + jp (iy) +; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret + diff --git a/Source/HDIAG/z180.inc b/Source/HDIAG/z180.inc new file mode 100644 index 00000000..3e0ff0f8 --- /dev/null +++ b/Source/HDIAG/z180.inc @@ -0,0 +1,71 @@ +; +;======================================================================= +; Z180 Internal I/O Ports +;======================================================================= +; +; These are offsets from the Z180 I/O base address. +; +z180_cntla0 .equ $00 ; asci0 control a +z180_cntla1 .equ $01 ; asci1 control a +z180_cntlb0 .equ $02 ; asci0 control b +z180_cntlb1 .equ $03 ; asci1 control b +z180_stat0 .equ $04 ; asci0 status +z180_stat1 .equ $05 ; asci1 status +z180_tdr0 .equ $06 ; asci0 transmit +z180_tdr1 .equ $07 ; asci1 transmit +z180_rdr0 .equ $08 ; asci0 receive +z180_rdr1 .equ $09 ; asci1 receive +z180_cntr .equ $0a ; csi/o control +z180_trdr .equ $0b ; csi/o transmit/receive +z180_tmdr0l .equ $0c ; timer 0 data lo +z180_tmdr0h .equ $0d ; timer 0 data hi +z180_rldr0l .equ $0e ; timer 0 reload lo +z180_rldr0h .equ $0f ; timer 0 reload hi +z180_tcr .equ $10 ; timer control +; +z180_asext0 .equ $12 ; asci0 extension control (z8s180) +z180_asext1 .equ $13 ; asci1 extension control (z8s180) +; +z180_tmdr1l .equ $14 ; timer 1 data lo +z180_tmdr1h .equ $15 ; timer 1 data hi +z180_rldr1l .equ $16 ; timer 1 reload lo +z180_rldr1h .equ $17 ; timer 1 reload hi +z180_frc .equ $18 ; free running counter +; +z180_astc0l .equ $1a ; asci0 time constant lo (z8s180) +z180_astc0h .equ $1b ; asci0 time constant hi (z8s180) +z180_astc1l .equ $1c ; asci1 time constant lo (z8s180) +z180_astc1h .equ $1d ; asci1 time constant hi (z8s180) +z180_cmr .equ $1e ; clock multiplier (latest z8s180) +z180_ccr .equ $1f ; cpu control (z8s180) +; +z180_sar0l .equ $20 ; dma0 source addr lo +z180_sar0h .equ $21 ; dma0 source addr hi +z180_sar0b .equ $22 ; dma0 source addr bank +z180_dar0l .equ $23 ; dma0 dest addr lo +z180_dar0h .equ $24 ; dma0 dest addr hi +z180_dar0b .equ $25 ; dma0 dest addr bank +z180_bcr0l .equ $26 ; dma0 byte count lo +z180_bcr0h .equ $27 ; dma0 byte count hi +z180_mar1l .equ $28 ; dma1 memory addr lo +z180_mar1h .equ $29 ; dma1 memory addr hi +z180_mar1b .equ $2a ; dma1 memory addr bank +z180_iar1l .equ $2b ; dma1 i/o addr lo +z180_iar1h .equ $2c ; dma1 i/o addr hi +z180_iar1b .equ $2d ; dma1 i/o addr bank (z8s180) +z180_bcr1l .equ $2e ; dma1 byte count lo +z180_bcr1h .equ $2f ; dma1 byte count hi +z180_dstat .equ $30 ; dma status +z180_dmode .equ $31 ; dma mode +z180_dcntl .equ $32 ; dma/wait control +z180_il .equ $33 ; interrupt vector load +z180_itc .equ $34 ; int/trap control +; +z180_rcr .equ $36 ; refresh control +; +z180_cbr .equ $38 ; mmu common base register +z180_bbr .equ $39 ; mmu bank base register +z180_cbar .equ $3a ; mmu common/bank area register +; +z180_omcr .equ $3e ; operation mode control +z180_icr .equ $3f ; i/o control register diff --git a/Source/HDIAG/z2u.asm b/Source/HDIAG/z2u.asm new file mode 100644 index 00000000..5e3dc109 --- /dev/null +++ b/Source/HDIAG/z2u.asm @@ -0,0 +1,49 @@ +; +;======================================================================= +; HDIAG Z180 UART Driver +;======================================================================= +; +z2u_jptbl: + jp z2u_cinit ; Initialize serial port + jp z2u_cin ; Read byte + jp z2u_cout ; Write byte + jp z2u_cist ; Input status + jp z2u_cost ; Output Status +; +; +; +z2u_cinit: + ; initialize port here + or $FF ; signal failure for now + ret +; +; +; +z2u_cin: + call z2u_cist ; check for char ready + jr z,z2u_cin ; if not, loop + ; read byte here + ret ; done +; +; +; +z2u_cout: + push af ; save incoming +z2u_cout1: + call z2u_cost ; ready for char? + jr z,z2u_cout1 ; loop if not + pop af ; restore incoming + ; write byte here + ret ; and done +; +; +; +z2u_cist: + ; check input status here + ret +; +; +; +z2u_cost: + ; check output status here + ret ; a != 0 if char ready, else 0 diff --git a/Source/Makefile b/Source/Makefile index cb096c4a..3887f8ae 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -1,7 +1,8 @@ # # order is actually important, because of build dependencies # -SUBDIRS = Prop +SUBDIRS = HDIAG +SUBDIRS += Prop SUBDIRS += Apps SUBDIRS += CBIOS SUBDIRS += Forth diff --git a/Source/ver.inc b/Source/ver.inc index 8874a42f..2311d3d0 100644 --- a/Source/ver.inc +++ b/Source/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 1 #DEFINE RUP 1 #DEFINE RTP 0 -#DEFINE BIOSVER "3.1.1-pre.116" +#DEFINE BIOSVER "3.1.1-pre.117" diff --git a/Source/ver.lib b/Source/ver.lib index dca1306a..3fef82fa 100644 --- a/Source/ver.lib +++ b/Source/ver.lib @@ -3,5 +3,5 @@ rmn equ 1 rup equ 1 rtp equ 0 biosver macro - db "3.1.1-pre.116" + db "3.1.1-pre.117" endm diff --git a/Tools/Makefile.inc b/Tools/Makefile.inc index b5a8bf44..70820679 100644 --- a/Tools/Makefile.inc +++ b/Tools/Makefile.inc @@ -69,6 +69,9 @@ CPM=$(TOOLS)/cpm/bin rm -f $$($(CASEFN) $*.hex) ; \ fi +%.rom: %.asm + $(TASM) $(TASMFLAGS) $< $@ $*.lst + %.hex: %.asm $(ZXCC) $(CPM)/MAC -$< -$$PO