diff --git a/Source/Apps/Survey/survey.mac b/Source/Apps/Survey/survey.mac index b341e485..e26a9f77 100644 --- a/Source/Apps/Survey/survey.mac +++ b/Source/Apps/Survey/survey.mac @@ -607,9 +607,20 @@ PDLY: JNZ PDLY ; .Z80 - ; RECORD THE ACTIVE BANK - LD A,(0FFE0H) ; GET CURRENT HBIOS BANK ID - LD (BANK),A ; AND SAVE IT + ; record the active bank + ld a,(0ffe0h) ; get current hbios bank id + ld (BANK),a ; and save it + ; Check for Z180 CPU + xor a ; assume Z80 + ld (IS180),a ; save it + ld de,0506H ; 5 x 6 + db 0EDH,05CH ; MLT DE: de = 30 if z180 + ld a,e ; result to A + cp 30 ; check if multiply happened + jr nz,z80 ; if invalid, then Z80 + or 0ffH ; flag value for Z180 + ld (IS180),a ; save it +z80: .8080 ; LXI H,0 ; Init active port counter @@ -623,28 +634,57 @@ PORTLP: JZ ISPORT ; Print mask port ENDIF ; - mov c,a ; port number to reg c - mvi b,0 ; for 16 bit port addressing .Z80 + di ; interrupts off + ld a,(IS180) ; Z180? + or a + jr nz,rd180 +; + ; Z80 port read + ld a,d + ld c,a + ld (pnum),a ; dynamic update in a,(c) - .8080 + push af + ld b,0 + in a,(0FFH) +pnum equ $-1 + push af + jr rdz ; - .Z80 - ; MAKE SURE CORRECT BANK IS STILL SELECTED! +rd180: + ; Z180 port read + ld a,d + ld c,a + ld (pnum1),a ; dynamic update + in a,(c) + push af + ld b,0 + db 0EDH,038H,0FFH ; IN0 +pnum1 equ $-1 + push af +; +rdz: + ; Make sure correct bank is still selected! push af ld a,(BANK) call 0FFF3H pop af - .8080 ; -; inactive port could return 0xFF or 0x78 or the port address + ei ; interrupts back on now ; - cmp c - jz nextpt - cpi 0FFh - jz nextpt - cpi 078h - jz nextpt +; port is considered inactive if values read from different port +; read mechanisms differ or if the value $FF is read consistently +; + pop af + ld c,a + pop af + cp c + jr nz,NEXTPT + cp 0FFH + jr z,NEXTPT +; + .8080 ISPORT: mov a,d ; got a live one, probably ani 0f0h ; is port in same group as last ? @@ -760,6 +800,7 @@ EMPF: DS 1 ; Empty so far flag BLKSHF: DS 1 ; block shift factor MAXALL: DS 2 ; maximum block number BANK: DS 1 ; saved HBIOS bank id +IS180: DS 1 ; non-zero for Z180 CPU FINIS EQU $ ; End of program ; .DEPHASE diff --git a/Source/Apps/Test/Build.cmd b/Source/Apps/Test/Build.cmd index cc5679b0..dea44672 100644 --- a/Source/Apps/Test/Build.cmd +++ b/Source/Apps/Test/Build.cmd @@ -23,6 +23,7 @@ pushd ps2info && call Build || exit /b & popd pushd 2piotst && call Build || exit /b & popd pushd piomon && call Build || exit /b & popd pushd banktest && call Build || exit /b & popd +pushd portswp && call Build || exit /b & popd goto :eof diff --git a/Source/Apps/Test/Clean.cmd b/Source/Apps/Test/Clean.cmd index 540d8888..f611848e 100644 --- a/Source/Apps/Test/Clean.cmd +++ b/Source/Apps/Test/Clean.cmd @@ -20,3 +20,4 @@ pushd ps2info && call Clean || exit /b 1 & popd pushd 2piotst && call Clean || exit /b 1 & popd pushd piomon && call Clean || exit /b 1 & popd pushd banktest && call Clean || exit /b 1 & popd +pushd portswp && call Clean || exit /b 1 & popd diff --git a/Source/Apps/Test/Makefile b/Source/Apps/Test/Makefile index 7f511966..e1f78754 100644 --- a/Source/Apps/Test/Makefile +++ b/Source/Apps/Test/Makefile @@ -1,5 +1,5 @@ OBJECTS = -SUBDIRS = DMAmon I2C inttest ppidetst ramtest tstdskng rzsz vdctest kbdtest ps2info 2piotst piomon banktest +SUBDIRS = DMAmon I2C inttest ppidetst ramtest tstdskng rzsz vdctest kbdtest ps2info 2piotst piomon banktest portswp DEST = ../../../Binary/Apps/Test TOOLS =../../../Tools diff --git a/Source/Apps/Test/portswp/Build.cmd b/Source/Apps/Test/portswp/Build.cmd new file mode 100644 index 00000000..763cf712 --- /dev/null +++ b/Source/Apps/Test/portswp/Build.cmd @@ -0,0 +1,11 @@ +@echo off +setlocal + +set TOOLS=../../../../Tools +set PATH=%TOOLS%\tasm32;%PATH% +set TASMTABS=%TOOLS%\tasm32 + +tasm -t180 -g3 -fFF portswp.asm portswp.com portswp.lst || exit /b + +copy /Y portswp.com ..\..\..\..\Binary\Apps\Test\ || exit /b + diff --git a/Source/Apps/Test/portswp/Clean.cmd b/Source/Apps/Test/portswp/Clean.cmd new file mode 100644 index 00000000..9ecb428f --- /dev/null +++ b/Source/Apps/Test/portswp/Clean.cmd @@ -0,0 +1,6 @@ +@echo off +setlocal + +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.bin del *.bin diff --git a/Source/Apps/Test/portswp/Makefile b/Source/Apps/Test/portswp/Makefile new file mode 100644 index 00000000..81d334fc --- /dev/null +++ b/Source/Apps/Test/portswp/Makefile @@ -0,0 +1,9 @@ +OBJECTS = portswp.com +DEST = ../../../../Binary/Apps/Test +TOOLS =../../../../Tools + +USETASM=1 + +include $(TOOLS)/Makefile.inc + +TASM=$(BINDIR)/uz80as -t hd64180 diff --git a/Source/Apps/Test/portswp/portswp.asm b/Source/Apps/Test/portswp/portswp.asm new file mode 100644 index 00000000..dd6d49c2 --- /dev/null +++ b/Source/Apps/Test/portswp/portswp.asm @@ -0,0 +1,595 @@ +;=============================================================================== +; PORTSWP - Sweep Ports +; +;=============================================================================== +; +; Author: Wayne Warthen (wwarthen@gmail.com) +;_______________________________________________________________________________ +; +; Usage: +; PORTSWP +; +; Operation: +; Reads all ports (multiple ways) and displays values read +;_______________________________________________________________________________ +; +; Change Log: +; 2023-02-14 [WBW] Initial release +;_______________________________________________________________________________ +; +; ToDo: +;_______________________________________________________________________________ +; +;=============================================================================== +; Definitions +;=============================================================================== +; +runloc .equ $C000 ; Running location (upper memory required) +stksiz .equ $40 ; Working stack size +; +rmj .equ 3 ; intended HBIOS version - major +rmn .equ 1 ; intended HBIOS version - minor +; +restart .equ $0000 ; CP/M restart vector +; +#include "../../../HBIOS/hbios.inc" +; +;=============================================================================== +; Code Section +;=============================================================================== +; + .org $100 +; + ; relocate worker code to upper memory + ld hl,begin ; start of working code image + ld de,runloc ; running location + ld bc,size ; size of working code image + ldir ; copy to upper RAM + jp runloc ; and go +; +; Start of working code +; +begin .equ $ ; image loaded here +; + .org runloc ; now generate running location adresses +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +; + ; process + call process ; do main processing + jr nz,exit ; abort on error +; +exit: ; clean up and return to command processor + call crlf ; formatting + ld sp,(stksav) ; restore stack + ;jp restart ; return to CP/M via restart + ret ; return to CP/M w/o restart +; +; Initialization +; +init: + call crlf2 ; formatting + ld de,msgban ; point to version message part 1 + call prtstr ; print it +; + call idbio ; identify active BIOS + cp 1 ; check for HBIOS + jp nz,errbio ; handle BIOS error +; + ld a,rmj << 4 | rmn ; expected HBIOS ver + cp d ; compare with result above + jp nz,errbio ; handle BIOS error +; +initx + ; initialization complete + xor a ; signal success + ret ; return +; +; Process +; +process: + call crlf + ld a,($FFE0) ; get current hbios bank id + ld (orgbnk),a ; and save it + ld a,0 ; start with port 0 + ld (curport),a ; save it for use below + ; Test for z180 using mlt + ld de,$0506 ; 5 x 6 + mlt de ; de = 30 if z180 + ld a,e ; result to A + cp 30 ; check if multiply happened + jr nz,loop ; if invalid, then Z80 + or $FF ; flag value for Z180 + ld (is180),a ; save it +; +loop: + call crlf + ld a,(curport) + call prthex + ld a,':' + call prtchr +; + di ; interrupts off +; + ld hl,vallist ; init value list pointer + call portread ; read the port + call portread ; do it again +; + ; restore possibly corrupted bank registers + ld a,(orgbnk) ; get proper bank id + call $FFF3 ; restore it +; + ei ; interrupts safe now +; + ld hl,vallist ; re-init value list pointer + ld b,4 ; print 4 values +prtloop: + ld a,' ' + call prtchr + ld a,(hl) + call prthex + inc hl + djnz prtloop +; + ; update port and loop as needed + ld a,(curport) ; get current port + inc a ; move to next + ld (curport),a ; save it + jr z,done ; done on wraparound + jr loop ; loop until done +; +done: +; + call crlf2 + ld de,msgdone ; message to print + call prtstr ; do it +; + ret ; all done +; +; +; +portread: + ld a,(is180) + or a + jr nz,portread_z180 +; +portread_z80: ; user traditional "IN" + ; read port using IN + ld a,(curport) ; get current port + ld (port),a ; modify IN instruction + in a,($FF) ; read the port +port .equ $-1 + ld (hl),a ; save it + inc hl ; bump value list pointer +; + ; read port using IN (C) + ld a,(curport) ; get current port + ld b,0 ; in case 16 bits decoded + ld c,a ; move to reg C + in a,(c) ; read the port + ld (hl),a ; save it + inc hl ; bump value list pointer + ret +; +portread_z180: ; use "IN0" + ; read port using IN + ld a,(curport) ; get current port + ld (port1),a ; modify IN instruction + in0 a,($FF) ; read the port +port1 .equ $-1 + ld (hl),a ; save it + inc hl ; bump value list pointer +; + ; read port using IN (C) + ld a,(curport) ; get current port + ld b,0 ; in case 16 bits decoded + ld c,a ; move to reg C + in a,(c) ; read the port + ld (hl),a ; save it + inc hl ; bump value list pointer + ret +; +; Identify active BIOS. RomWBW HBIOS=1, UNA UBIOS=2, else 0 +; +idbio: +; + ; Check for UNA (UBIOS) + ld a,($FFFD) ; fixed location of UNA API vector + cp $C3 ; jp instruction? + jr nz,idbio1 ; if not, not UNA + ld hl,($FFFE) ; get jp address + ld a,(hl) ; get byte at target address + cp $FD ; first byte of UNA push ix instruction + jr nz,idbio1 ; if not, not UNA + inc hl ; point to next byte + ld a,(hl) ; get next byte + cp $E5 ; second byte of UNA push ix instruction + jr nz,idbio1 ; if not, not UNA, check others +; + ld bc,$04FA ; UNA: get BIOS date and version + rst 08 ; DE := ver, HL := date +; + ld a,2 ; UNA BIOS id = 2 + ret ; and done +; +idbio1: + ; Check for RomWBW (HBIOS) + ld hl,(HB_IDENT) ; HL := HBIOS ident location + ld a,'W' ; First byte of ident + cp (hl) ; Compare + jr nz,idbio2 ; Not HBIOS + inc hl ; Next byte of ident + ld a,~'W' ; Second byte of ident + cp (hl) ; Compare + jr nz,idbio2 ; Not HBIOS +; + ld b,BF_SYSVER ; HBIOS: VER function + ld c,0 ; required reserved value + rst 08 ; DE := version, L := platform id +; + ld a,1 ; HBIOS BIOS id = 1 + ret ; and done +; +idbio2: + ; No idea what this is + xor a ; Setup return value of 0 + ret ; and done +; +; Print character in A without destroying any registers +; +prtchr: + push bc ; save registers + push de + push hl + ld e,a ; character to print in E + ld b,BF_CIOOUT ; HBIOS function to output a character + ld c,CIO_CONSOLE ; write to current console unit + call HB_INVOKE ; invoke HBIOS via call + pop hl ; restore registers + pop de + pop bc + ret +; +prtdot: +; + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +prtspace: +; + ; shortcut to print a space preserving all regs + push af ; save af + ld a,' ' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +prtcr: +; + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,13 ; load CR value + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print a zero terminated string at (DE) without destroying any registers +; +prtstr: + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + ret +; +; Print a block of memory nicely formatted +; de=buffer address +; +dump_buffer: + call crlf + + push de + pop hl + inc d + inc d + +db_blkrd: + push bc + push hl + pop bc + call prthexword ; print start location + pop bc + call prtspace ; + ld c,16 ; set for 16 locs + push hl ; save starting hl +db_nxtone: + ld a,(hl) ; get byte + call prthex ; print it + call prtspace ; +db_updh: + inc hl ; point next + dec c ; dec. loc count + jr nz,db_nxtone ; if line not done + ; now print 'decoded' data to right of dump +db_pcrlf: + call prtspace ; space it + ld c,16 ; set for 16 chars + pop hl ; get back start +db_pcrlf0: + ld a,(hl) ; get byte + and 060h ; see if a 'dot' + ld a,(hl) ; o.k. to get + jr nz,db_pdot ; +db_dot: + ld a,2eh ; load a dot +db_pdot: + call prtchr ; print it + inc hl ; + ld a,d ; + cp h ; + jr nz,db_updh1 ; + ld a,e ; + cp l ; + jp z,db_end ; +db_updh1: +; if block not dumped, do next character or line + dec c ; dec. char count + jr nz,db_pcrlf0 ; do next +db_contd: + call crlf ; + jp db_blkrd ; + +db_end: + ret +; +; Print the value in A in hex without destroying any registers +; +prthex: + push af ; save AF + push de ; save DE + call hexascii ; convert value in A to hex chars in DE + ld a,d ; get the high order hex char + call prtchr ; print it + ld a,e ; get the low order hex char + call prtchr ; print it + pop de ; restore DE + pop af ; restore AF + ret ; done +; +; print the hex word value in bc +; +prthexword: + push af + ld a,b + call prthex + ld a,c + call prthex + pop af + ret +; +; print the hex dword value in de:hl +; +prthex32: + push bc + push de + pop bc + call prthexword + push hl + pop bc + call prthexword + pop bc + ret +; +; Convert binary value in A to ascii hex characters in DE +; +hexascii: + ld d,a ; save A in D + call hexconv ; convert low nibble of A to hex + ld e,a ; save it in E + ld a,d ; get original value back + rlca ; rotate high order nibble to low bits + rlca + rlca + rlca + call hexconv ; convert nibble + ld d,a ; save it in D + ret ; done +; +; Convert low nibble of A to ascii hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Get the next non-blank character from (HL). +; +nonblank: + ld a,(hl) ; load next character + or a ; string ends with a null + ret z ; if null, return pointing to null + cp ' ' ; check for blank + ret nz ; return if not blank + inc hl ; if blank, increment character pointer + jr nonblank ; and loop +; +; Convert character in A to uppercase +; +ucase: + cp 'a' ; if below 'a' + ret c ; ... do nothing and return + cp 'z' + 1 ; if above 'z' + ret nc ; ... do nothing and return + res 5,a ; clear bit 5 to make lower case -> upper case + ret ; and return +; +; Add the value in A to HL (HL := HL + A) +; +addhl: + add a,l ; A := A + L + ld l,a ; Put result back in L + ret nc ; if no carry, we are done + inc h ; if carry, increment H + ret ; and return +; +; Jump indirect to address in HL +; +jphl: + jp (hl) +; +; Short delay functions. No clock speed compensation, so they +; will run longer on slower systems. The number indicates the +; number of call/ret invocations. a single call/ret is +; 27 t-states on a z80, 25 t-states on a z180 +; +; ; Z80 Z180 +; ; ---- ---- +dly64: call dly32 ; 1728 1600 +dly32: call dly16 ; 864 800 +dly16: call dly8 ; 432 400 +dly8: call dly4 ; 216 200 +dly4: call dly2 ; 108 100 +dly2: call dly1 ; 54 50 +dly1: ret ; 27 25 + +; +; Errors +; +erruse: ; command usage error (syntax) + ld de,msguse + jr err +; +errprm: ; command parameter error (syntax) + ld de,msgprm + jr err +; +errbio: ; invalid BIOS or version + ld de,msgbio + jr err +; +err: ; print error string and return error signal + call crlf2 ; print newline +; +err1: ; without the leading crlf + call prtstr ; print error string +; +err2: ; without the string +; call crlf ; print newline + or $FF ; signal error + ret ; done +; +;=============================================================================== +; Storage Section +;=============================================================================== +; +is180 .db 0 ; non-zero for z180 +orgbnk .db 0 ; original bank id +curport .db 0 ; current port being processed +vallist .fill 8,0 ; port values read +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +; Messages +; +msgban .db "PORTSWP v1.0, 14-Feb-2023",13,10 + .db "Copyright (C) 2023, Wayne Warthen, GNU GPL v3",0 +msguse .db "Usage: PORTSWP",13,10 +msgprm .db "Parameter error (PORTSWP /? for usage)",0 +msgbio .db "Incompatible BIOS or version, " + .db "HBIOS v", '0' + rmj, ".", '0' + rmn, " required",0 +str_sep .db ": ",0 +; +;msgcur .db "Initial Bank ID = 0x",0 +;msg80 .db "Hello from bank 0x80!",0 +;msgxcal .db "Inter-bank procedure call test...",0 +msgdone .db "End of Port Sweep",0 +; +; +; +size .equ $ - runloc +; + .end