diff --git a/Source/Apps/Test/Build.cmd b/Source/Apps/Test/Build.cmd index e0fca5e1..e68dee33 100644 --- a/Source/Apps/Test/Build.cmd +++ b/Source/Apps/Test/Build.cmd @@ -21,6 +21,7 @@ pushd vdctest && call Build || exit /b & popd pushd kbdtest && call Build || exit /b & popd pushd ps2info && call Build || exit /b & popd pushd 2piotst && call Build || exit /b & popd +pushd piomon && call Build || exit /b & popd goto :eof diff --git a/Source/Apps/Test/Clean.cmd b/Source/Apps/Test/Clean.cmd index ee9e01eb..243c2a5c 100644 --- a/Source/Apps/Test/Clean.cmd +++ b/Source/Apps/Test/Clean.cmd @@ -18,3 +18,4 @@ pushd vdctest && call Clean || exit /b 1 & popd pushd kbdtest && call Clean || exit /b 1 & popd pushd ps2info && call Clean || exit /b 1 & popd pushd 2piotst && call Clean || exit /b 1 & popd +pushd piomon && call Clean || exit /b 1 & popd diff --git a/Source/Apps/Test/Makefile b/Source/Apps/Test/Makefile index 56f2b77a..8f14cfa7 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 +SUBDIRS = DMAmon I2C inttest ppidetst ramtest tstdskng rzsz vdctest kbdtest ps2info 2piotst piomon DEST = ../../../Binary/Apps/Test TOOLS =../../../Tools diff --git a/Source/Apps/Test/piomon/Build.cmd b/Source/Apps/Test/piomon/Build.cmd new file mode 100644 index 00000000..f0e405e1 --- /dev/null +++ b/Source/Apps/Test/piomon/Build.cmd @@ -0,0 +1,10 @@ +@echo off +setlocal + +set TOOLS=../../../../Tools +set PATH=%TOOLS%\tasm32;%PATH% +set TASMTABS=%TOOLS%\tasm32 + +tasm -t180 -g3 -fFF piomon.asm piomon.com piomon.lst || exit /b + +copy /Y piomon.com ..\..\..\..\Binary\Apps\Test\ || exit /b diff --git a/Source/Apps/Test/piomon/Clean.cmd b/Source/Apps/Test/piomon/Clean.cmd new file mode 100644 index 00000000..9ecb428f --- /dev/null +++ b/Source/Apps/Test/piomon/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/piomon/Makefile b/Source/Apps/Test/piomon/Makefile new file mode 100644 index 00000000..d3054352 --- /dev/null +++ b/Source/Apps/Test/piomon/Makefile @@ -0,0 +1,7 @@ +OBJECTS = piomon.com +DEST = ../../../../Binary/Apps/Test +TOOLS =../../../../Tools + +USETASM=1 + +include $(TOOLS)/Makefile.inc \ No newline at end of file diff --git a/Source/Apps/Test/piomon/Readme.txt b/Source/Apps/Test/piomon/Readme.txt new file mode 100644 index 00000000..ddf13f7a --- /dev/null +++ b/Source/Apps/Test/piomon/Readme.txt @@ -0,0 +1,36 @@ +PIOMON is a program to verify operation of the Z80 MBC DUALPIO board + +Most testing requires the use of loopback hardware constructed as: + +Channel A RDY STB D0 D1 D2 D3 D4 D5 D6 D7 + \ / | | | | | | | | + \ / | | | | | | | | + X | | | | | | | | + / \ | | | | | | | | + / \ | | | | | | | | +Channel B RDY STB D0 D1 D2 D3 D4 D5 D6 D7 + +The DUALPIO has, well, 2 PIO chips. Only one chip +is tested at a time. At startup, PIOMON will ask +you for the port of the chip to test. It defaults +to the standard port number for the primary PIO chip +on an MBC DUALPIO board. + +The port number specified is the base I/O port. Each +chip has two channels which are addressed in the +menu by specifying A or B. + +MBC DUALPIO Primary PIO = 0xB8 +MBC DUALPIO Secondary PIO = 0xBC + +If you try to use PIOMON without the RDY and STB +cross connected, you may have interrupt issues +because STB will be floating. + +N.B., V1 and V2 of the DUALPIO lack a hardware reset. The +PIO chips will reset at power-on, but they do not reset +when the reset button is pushed. + +Happy St. Patrick's Day!!! + +--WBW 7:42 PM 3/17/2022 \ No newline at end of file diff --git a/Source/Apps/Test/piomon/piomon.asm b/Source/Apps/Test/piomon/piomon.asm new file mode 100644 index 00000000..d7cdb71f --- /dev/null +++ b/Source/Apps/Test/piomon/piomon.asm @@ -0,0 +1,1361 @@ +; +;======================================================================= +; Zilog PIO Monitor & Hardware Testing Application +;======================================================================= +; +iodef .equ $B8 ; Default base I/O port address +; +; +; +; Port address offsets from base address +iodata .equ 0 ; Channel A Data +iodatb .equ 1 ; Channel B Data +ioctla .equ 2 ; Channel A Control +ioctlb .equ 3 ; Channel B Control +; +intveca .equ 0 ; Channel A interrupt vector +intvecb .equ 1 ; Channel B interrupt vector +; +iocmd .equ $E3 ; PS/2 controller command port address +iodat .equ $E2 ; PS/2 controller data port address +; +cpumhz .equ 8 ; for time delay calculations (not critical) +; +; General operational equates (should not requre adjustment) +; +stksiz .equ $40 ; Working stack size +buflen .equ $80 ; Command buffer length +; +ltimout .equ 0 ; 256*10ms = 2.56s +stimout .equ 10 ; 10*10ms = 100ms +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +bf_sysint .equ $FC ; INT function +; +bf_sysintinfo .equ $00 ; INT INFO subfunction +bf_sysintget .equ $10 ; INT GET subfunction +bf_sysintset .equ $20 ; INT SET subfunction +; +bel .equ 7 ; ASCII bell +bs .equ 8 ; ASCII backspace +lf .equ 10 ; ASCII linefeed +cr .equ 13 ; ASCII carriage return +; +;======================================================================= +; + .org $100 ; standard CP/M executable +; +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + call nl + ld hl,str_banner ; banner + call pstr +; +getport1: + ld hl,str_port1 + call pstr + ld a,(iobase) + call prthexbyte + ld hl,str_port2 + call pstr + call rdln + ld ix,cmdbuf + call skipws + or a + jr z,getport2 + call ishex + jr nz,getport1 + call gethex ; get port value + jp c,getport1 ; handle overflow + ld (iobase),a ; save value +; +getport2: + call init +; + call main ; do the real work +; +exit: + call deinit +; + call nl2 + ld hl,str_exit + call pstr +; + ; clean up and return to command processor + call nl ; formatting + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart +; +;======================================================================= +; Initialize +;======================================================================= +; +init: + ; Install interrupt handler in upper mem + ld hl,reladr + ld de,$A000 + ld bc,hsiz + ldir +; + ; Install interrupt vectors (RomWBW specific!!!) + ld hl,inta ; pointer to my interrupt handler + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intveca ; vector idx + di + rst 08 ; do it + ld (orgveca),hl ; save the original vector + ei ; interrupts back on + ld hl,intb ; pointer to my interrupt handler + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intvecb ; vector idx + di + rst 08 ; do it + ld (orgvecb),hl ; save the original vector + ei ; interrupts back on +; + ; Load the interrupt vectors + ld a,(iobase) + add a,ioctla + ld c,a + ld a,intveca * 2 + out (c),a + ld a,(iobase) + add a,ioctlb + ld c,a + ld a,intvecb * 2 + out (c),a +; + ; Set the interrupt control words + ld a,(iobase) + add a,ioctla + ld c,a + ld a,%10000111 + out (c),a ; int enab, no mask follows + ;ld a,%11111111 + ;out (ioctla),a ; no ints in control mode + ld a,(iobase) + add a,ioctlb + ld c,a + ld a,%10000111 + out (c),a ; int enab, no mask follows + ;ld a,%11111111 + ;out (ioctlb),a ; no ints in control mode +; + ret +; +deinit: + call reset +; + ld a,(iobase) + add a,ioctla + ld c,a + ld a,%00010111 ; clear interrupt ctl word + out (c),a + ld a,%11111111 ; clear mask + out (c),a + ld a,%00000000 ; clear interrupt vector + out (c),a +; + ld a,(iobase) + add a,ioctlb + ld c,a + ld a,%00010111 ; clear interrupt ctl word + out (c),a + ld a,%11111111 ; clear mask + out (c),a + ld a,%00000000 ; clear interrupt vector + out (c),a +; + ; Deinstall interrupt vectors + ld hl,(orgveca) ; original vector + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intveca ; vector idx + di + rst 08 ; do it + ei ; interrupts back on + ld hl,(orgvecb) ; original vector + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intvecb ; vector idx + di + rst 08 ; do it + ei ; interrupts back on + ret +; +;======================================================================= +; Main Program +;======================================================================= +; +main: + ; Prompt + call nl2 + ld hl,str_pre + call pstr + ld a,(iobase) + call prthexbyte +; + ld hl,str_int1 + call pstr + ld hl,(intcnta) + call prtdec + ld hl,str_int2 + call pstr + ld hl,(intcntb) + call prtdec +; + ld hl,str_pre2 + call pstr +; + ; Read command line + call rdln + ld ix,cmdbuf +; +main1: + ;;;; Upper case the entire command line + ;;;ld a,(ix) + ;;;or a + ;;;jr z,main2 + ;;;call upcase + ;;;ld (ix),a + ;;;inc ix + ;;;jr main1 +; +main2: + ld ix,cmdbuf + call skipws + or a ; check for eol + call nz,runcmd ; run command if not eol + jr main ; loop +; +; Run the command line pointed to by IX +; +runcmd: + ld ix,cmdbuf ; point to cmd line + call skipws + or a ; check for eol + ret z ; return if nothing there +; + ld a,(ix) ; get character +; + ; Dispatch + cp '?' ; Help + jp z,help + cp 'H' ; Help + jp z,help + cp 'X' ; Exit + jp z,exit + cp 'P' ; PIO Base Port + jp z,setport + cp 'Z' ; Reset Chip + jp z,reschip + cp 'W' ; Watch pins + jp z,watch + cp 'I' ; Input pins on channel + jp z,input + cp 'O' ; Output pins on channel + jp z,output + cp 'S' ; Send strobed byte to channel + jp z,send + cp 'R' ; Read strobed byte from channel + jp z,receive + cp 'T' ; Test + jp z,test + jp err_invcmd ; Invalid command +; +help: + ld hl,str_usage + call pstr + ret +; +setport: + call findws ; skip command + call skipws ; skip white space + call ishex ; do we have a number + jp nz,err_invcmd ; handle invalid command + call gethex + jp c,err_invcmd ; handle overflow error + push af + call deinit + pop af + ld (iobase),a ; set new port value + call init + ret ; and done +; +reschip: + ld hl,str_reschip1 + call pstr + call reset + ld hl,str_reschip2 + call pstr + ret +; +watch: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_watch1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_watch2 + call pstr + call nl2 ; formatting + call ctlport ; set c to ctl port of channel + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%11111111 ; set all pins to input + out (c),a ; do it + call dataport ; set c to data port + ld a,0 + ld b,0 + jr watch2 +watch1: + call keychk ; key pressed? + ret nz ; return if so + in a,(c) ; read data port + cp b ; same as before + jr z,watch1 ; loop +watch2: + ld b,a ; save in B + ld hl,str_watchtag + call pstr + ld a,b ; restore value read + call prthexbyte ; print new value + jr watch1 +; +input: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_input1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_input2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%11111111 ; set all pins to input + out (c),a ; do it + call dataport ; set c to data port + in a,(c) + call prthexbyte + ret +; +output: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + call findws ; skip command + call skipws ; skip white space + call ishex ; do we have a number + jp nz,err_invcmd ; handle invalid command + call gethex + jp c,err_invcmd ; handle overflow error + push af +; + ld hl,str_output1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_output2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%00000000 ; set all pins to output + out (c),a ; do it + call dataport ; set c to data port + pop af + out (c),a + call prthexbyte + ret +; +send: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + call findws ; skip command + call skipws ; skip white space + call ishex ; do we have a number + jp nz,err_invcmd ; handle invalid command + call gethex + jp c,err_invcmd ; handle overflow error + push af +; + ld hl,str_send1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_send2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%00001111 ; strobed output mode + out (c),a ; do it + call dataport ; set c to data port + pop af + out (c),a + call prthexbyte + ret +; +receive: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_receive1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_receive2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%01001111 ; strobed input mode + out (c),a ; do it + call dataport ; set c to data port + in a,(c) + call prthexbyte + ret +; +test: + inc ix ; skip command byte + ld a,(ix) ; get character +; + ; Dispatch + cp 'R' + jp z,test_rdbk ; Readback Test + cp 'L' + jp z,test_lpbk ; Loopback Test + cp 'S' + jp z,test_stlp ; Strobed Loopback Test + jp err_invcmd + ret +; +test_rdbk: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_rdbk + call pstr + ld a,(channel) + add a,'A' + call cout + call nl ; formatting + call ctlport ; set c to ctl port of channel + ld a,%00001111 ; mode 0 (output mode) + out (c),a ; do it + call dataport ; set c to data port +; + ld hl,vallist + ld b,vallen +test_rdbk0: + push hl + push bc + ld a,(hl) + call test_rdbk1 + pop bc + pop hl + jp nz,err_fail + inc hl + djnz test_rdbk0 + ret +; +test_rdbk1: + ld b,a + call nl + ld a,b + call prthexbyte + out (c),a + ld hl,str_arrow + call pstr + in a,(c) + call prthexbyte + cp b + ret +; +test_lpbk: + ld hl,str_lpbkAB + call pstr + ld a,(iobase) ; Test from A + add a,ioctla + ld d,a + ld a,(iobase) ; ... to B + add a,ioctlb + ld e,a + push de + call reset + call test_lpbk1 ; avoid output on both channels + pop de + jp nz,err_fail + ld hl,str_lpbkBA + call pstr + ld a,d ; switch direction + ld d,e + ld e,a + call reset ; avoid output on both channels + call test_lpbk1 + jp nz,err_fail + ret +; +test_lpbk1: + ; Setup output channel + ld c,d + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%00000000 ; set all pins to output + out (c),a ; do it +; + ; Setup input channel + ld c,e + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%11111111 ; set all pins to input + out (c),a ; do it +; + ; Loop through test values + dec d ; point to data port (output) + dec d + dec e ; point to data port (input) + dec e + ld hl,vallist + ld b,vallen +; +test_lpbk2: + call test_lpbk3 + ret nz + inc hl + djnz test_lpbk2 + ret +; +test_lpbk3: + call nl + ld c,d + ld a,(hl) + call prthexbyte + out (c),a + push hl + ld hl,str_arrow + call pstr + pop hl + ld c,e + in a,(c) + call prthexbyte + cp (hl) + ret +; +test_stlp: + ld hl,str_stlpAB + call pstr + ld a,(iobase) ; Test from A + add a,ioctla + ld d,a + ld a,(iobase) ; ... to B + add a,ioctlb + ld e,a + push de + call reset + call test_stlp1 ; avoid output on both channels + pop de + jp nz,err_fail + ld hl,str_stlpBA + call pstr + ld a,d ; switch direction + ld d,e + ld e,a + call reset ; avoid output on both channels + call test_stlp1 + jp nz,err_fail + ret +; +test_stlp1: + ; Setup output channel + ld c,d + ld a,%00001111 ; strobed output mode + out (c),a ; do it +; + ; Setup input channel + ld c,e + ld a,%01001111 ; strobed input mode + out (c),a ; do it +; + ; Loop through test values + dec d ; point to data port (output) + dec d + dec e ; point to data port (input) + dec e + ld hl,vallist + ld b,vallen +; +test_stlp2: + call test_stlp3 + ret nz + inc hl + djnz test_stlp2 + ret +; +test_stlp3: + call nl + ld c,d + ld a,(hl) + call prthexbyte + out (c),a + push hl + ld hl,str_arrow + call pstr + pop hl + ld c,e + in a,(c) + call prthexbyte + cp (hl) + ret +; +; +; +getchan: + ld a,(ix) ; get byte + sub 'A' ; convert to binary + cp 2 ; check for max value + ret nc ; return with NZ if too high + ld (channel),a ; save new value + cp a ; set ZF + ret ; done +; +; +; +reset: + ld a,(iobase) + add a,ioctla + ld c,a + call reset1 + ld a,(iobase) + add a,ioctlb + ld c,a + jr reset1 +; +reset1: + ld a,%01001111 ; set mode 1 (input) + out (c),a + ;ld a,%00010111 ; clear interrupt ctl word + ;out (c),a + ;ld a,%11111111 ; clear mask + ;out (c),a + ;ld a,%00000000 ; clear interrupt vector + ;out (c),a + ret +; +; +; +ctlport: + ld a,(iobase) ; base port + add a,ioctla ; offset to control ports + ld c,a ; put in c + ld a,(channel) ; get channel + add a,c ; combine + ld c,a + ret +; +; +; +dataport: + ld a,(iobase) ; base port + add a,iodata ; offset to data ports + ld c,a ; put in c + ld a,(channel) ; get channel + add a,c ; combine + ld c,a + ret +; +; Error Handlers +; +err_abort: + ld hl,str_err_abort + jr err_ret +err_invcmd: + ld hl,str_err_invcmd + jr err_ret +err_fail: + ld hl,str_err_fail + jr err_ret +; +err_ret: + push hl + ld hl,str_err_prefix + call pstr + pop hl + jp pstr +; +str_err_prefix .db bel,"\r\n\r\n*** ",0 +str_err_abort .db "User Aborted",0 +str_err_invcmd .db "Invalid command, press '?' for help",0 +str_err_fail .db "Test failed!",0 +; +;======================================================================= +; Utility functions +;======================================================================= +; +; Print string at HL on console, null terminated +; +pstr: + push af + push hl +pstr1: + ld a,(hl) ; get next character + or a ; set flags + inc hl ; bump pointer regardless + jr z,pstr2 ; done if null + call cout ; display character + jr pstr1 ; loop till done +pstr2: + pop hl + pop af + ret +; +; Print volume label string at HL, '$' terminated, 16 chars max +; +pvol: + ld b,16 ; init max char downcounter +pvol1: + ld a,(hl) ; get next character + cp '$' ; set flags + inc hl ; bump pointer regardless + ret z ; done if null + call cout ; display character + djnz pvol1 ; loop till done + ret ; hit max of 16 chars +; +; Start a newline on console (cr/lf) +; +nl2: + call nl ; double newline +nl: + ld a,cr ; cr + call cout ; send it + ld a,lf ; lf + jp cout ; send it and return +; +; Print a dot on console +; +pdot: + push af + ld a,'.' + call cout + pop af + ret +; +; +; +keychk: + call cst + or a + ret z + call cin + or $FF + ret +; +; Read a string on the console to cmdbuf +; +; Input is zero terminated +; +rdln: + ld de,cmdbuf ; init buffer address ptr +rdln_nxt: + call cin ; get a character + cp bs ; backspace? + jr z,rdln_bs ; handle it if so + cp cr ; return? + jr z,rdln_cr ; handle it if so +; + ; check for non-printing characters + cp ' ' ; first printable is space char + jr c,rdln_bel ; too low, beep and loop + cp '~'+1 ; last printable char + jr nc,rdln_bel ; too high, beep and loop +; + ; need to check for buffer overflow here!!! + ld hl,cmdbuf+buflen ; max cmd length + or a ; clear carry + sbc hl,de ; test for max + jr z,rdln_bel ; at max, beep and loop +; + ; good to go, echo and store character + call upcase + call cout ; echo character input + ld (de),a ; save in buffer + inc de ; inc buffer ptr + jr rdln_nxt ; loop till done +; +rdln_bs: + ld hl,cmdbuf ; start of buffer + or a ; clear carry + sbc hl,de ; subtract from cur buf ptr + jr z,rdln_bel ; at buf start, just beep + ld hl,str_bs ; backspace sequence + call pstr ; send it + dec de ; backup buffer pointer + jr rdln_nxt ; and loop +; +rdln_bel: + ld a,bel ; Bell characters + call cout ; send it + jr rdln_nxt ; and loop +; +rdln_cr: + xor a ; null to A + ld (de),a ; store terminator + ret ; and return +; +; Find next whitespace character at buffer adr in DE, returns with first +; whitespace character in A. +; +findws: + ld a,(ix) ; get next char + or a ; check for eol + ret z ; done if so + cp ' ' ; blank? + ret z ; nope, done + inc ix ; bump buffer pointer + jr findws ; and loop +; +; Skip whitespace at buffer adr in DE, returns with first +; non-whitespace character in A. +; +skipws: + ld a,(ix) ; get next char + or a ; check for eol + ret z ; done if so + cp ' ' ; blank? + ret nz ; nope, done + inc ix ; bump buffer pointer + jr skipws ; and loop +; +; Uppercase character in A +; +upcase: + cp 'a' ; below 'a'? + ret c ; if so, nothing to do + cp 'z'+1 ; above 'z'? + ret nc ; if so, nothing to do + and ~$20 ; convert character to lower + ret ; done +; +; Get numeric chars at IX and convert to number returned in A +; Carry flag set on overflow +; +getnum: + ld c,0 ; C is working register +getnum1: + ld a,(ix) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getnum2 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getnum2 ; abort if above +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 10 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + add a,c ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(ix) ; get new digit + sub '0' ; make binary + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc ix ; bump to next char + jr getnum1 ; loop +; +getnum2: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Get hex chars at IX and convert to binary number returned in A +; Carry flag set on overflow +; +gethex: + ld c,0 ; C is working register +gethex1: + ld a,(ix) ; get the active char + call ishex ; is it a hex char? + jr nz,gethex9 ; abort if not +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 16 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(ix) ; get new hex digit + call isnum ; regular number? + jr z,gethex2 ; if so, handle it, else hex char + sub 'A'-10 ; convert to binary + jr gethex3 ; and continue +gethex2: + sub '0' ; convert to binary +gethex3: + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc ix ; bump to next char + jr gethex1 ; loop +; +gethex9: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Is character in A numberic? NZ if not +; +isnum: + cp '0' ; compare to ascii '0' + jr c,isnum1 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,isnum1 ; abort if above + cp a ; set Z + ret +isnum1: + cp '0' ; set NZ w/o changing value + ret ; and done +; +; Is character in A hex? NZ if not +; +ishex: + call isnum ; is it a numeric? + ret z ; if so, all done + cp 'A' ; first hex char + jr c,ishex1 ; abort if below + cp 'F' + 1 ; last hex char + jr nc,ishex1 ; abort if above + cp a ; set Z + ret ; done +ishex1: + cp '0' ; set NZ w/o changing value + ret ; done +; +; Delay 16us (cpu speed compensated) incuding call/ret invocation +; Register A and flags destroyed +; No compensation for z180 memory wait states +; There is an overhead of 3ts per invocation +; Impact of overhead diminishes as cpu speed increases +; +; cpu scaler (cpuscl) = (cpuhmz - 2) for 16us + 3ts delay +; note: cpuscl must be >= 1! +; +; example: 8mhz cpu (delay goal is 16us) +; loop = ((6 * 16) - 5) = 91ts +; total cost = (91 + 40) = 131ts +; actual delay = (131 / 8) = 16.375us +; + ; --- total cost = (loop cost + 40) ts -----------------+ +delay: ; 17ts (from invoking call) | + ld a,(cpuscl) ; 13ts | +; | +delay1: ; | + ; --- loop = ((cpuscl * 16) - 5) ts ------------+ | + dec a ; 4ts | | + jr nz,delay1 ; 12ts (nz) / 7ts (z) | | + ; ----------------------------------------------+ | +; | + ret ; 10ts (return) | + ;-------------------------------------------------------+ +; +; Delay 16us * DE (cpu speed compensated) +; Register DE, A, and flags destroyed +; No compensation for z180 memory wait states +; There is a 27ts overhead for call/ret per invocation +; Impact of overhead diminishes as DE and/or cpu speed increases +; +; cpu scaler (cpuscl) = (cpuhmz - 2) for 16us outer loop cost +; note: cpuscl must be > 0! +; +; Example: 8MHz cpu, DE=6250 (delay goal is .1 sec or 100,000us) +; inner loop = ((16 * 6) - 5) = 91ts +; outer loop = ((91 + 37) * 6250) = 800,000ts +; actual delay = ((800,000 + 27) / 8) = 100,003us +; + ; --- total cost = (outer loop + 27) ts ------------------------+ +vdelay: ; 17ts (from invoking call) | +; | + ; --- outer loop = ((inner loop + 37) * de) ts ---------+ | + ld a,(cpuscl) ; 13ts | | +; | | +vdelay1: ; | | + ; --- inner loop = ((cpuscl * 16) - 5) ts ------+ | | + dec a ; 4ts | | | + jr nz,vdelay1 ; 12ts (nz) / 7ts (z) | | | + ; ----------------------------------------------+ | | +; | | + dec de ; 6ts | | + ld a,d ; 4ts | | + or e ; 4ts | | + jp nz,vdelay ; 10ts | | + ;-------------------------------------------------------+ | +; | + ret ; 10ts (final return) | + ;---------------------------------------------------------------+ +; +; Delay about 0.5 seconds +; 500000us / 16us = 31250 +; +ldelay: + push af + push de + ld de,31250 + call vdelay + pop de + pop af + ret +; +#if (cpumhz < 3) +cpuscl .db 1 ; cpu scaler must be > 0 +#else +cpuscl .db cpumhz - 2 ; otherwise 2 less than phi mhz +#endif +; +; Print value of a in decimal with leading zero suppression +; +prtdecb: + push hl + push af + ld l,a + ld h,0 + call prtdec + pop af + pop hl + ret +; +; Print value of HL in decimal with leading zero suppression +; +prtdec: + push bc + push de + push hl + 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 + call prtdec1 + pop hl + pop de + pop bc + ret +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + jr z,prtdec3 + ld e,0 + call cout +prtdec3: + ret +; +; 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 +; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret +; +; +; +prtdot: + push af + ld a,'.' + call cout + pop af + ret +; +; Print the hex byte value in A +; +prthexbyte: + 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 +; +prthexword: + push af + ld a,b + call prthexbyte + ld a,c + call prthexbyte + 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 + 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 0Fh ; low nibble only + add a,90h + daa + adc a,40h + daa + ret +; +; Output character from A +; +cout: + ; Save all incoming registers + push af + push bc + push de + push hl +; + ; Output character to console via BDOS + ld e,a ; output char to E + ld c,6 ; BDOS direct console I/O + call bdos ; output character +; + ; Restore all registers + pop hl + pop de + pop bc + pop af + ret +; +; Input character to A +; +cin: + ; Save incoming registers (AF is output) + push bc + push de + push hl +; + ; Input character from console via BDOS +cin1: + ld e,$FF ; input request + ld c,6 ; BDOS direct console I/O + call bdos ; input character to A + or a ; test for zero (no input) + jr z,cin1 ; loop till we have a char +; + ; Restore registers (AF is output) + pop hl + pop de + pop bc + ret +; +; Return input status in A (0 = no char, != 0 char waiting) +; +cst: + ; Save incoming registers (AF is output) + push bc + push de + push hl +; + ; Get console input status via BDOS + ld e,$FE ; status + ld c,6 ; BDOS direct console I/O + call bdos ; input status to A +; + ; Restore registers (AF is output) + pop hl + pop de + pop bc + ret +; +; +; +;======================================================================= +; Constants +;======================================================================= +; +str_banner .db "Zilog PIO Monitor v0.1, 14-Mar-2022\r\n" + .db "Press ? for help$" +str_bs .db bs,' ',bs,0 +str_port1 .db "\r\n\r\nEnter PIO port in hex [",0 +str_port2 .db "]:",0 +str_pre .db "Zilog PIO @ Port 0x",0 +str_pre2 .db "\r\n\r\n>",0 +str_exit .db "Done, Thank you for using Zilog PIO Monitor!",0 +str_reschip1 .db "\r\n\r\nFull Reset of PIO Chip... ",0 +str_reschip2 .db "Done",0 +str_int1 .db "\r\nChannel A Interrupts=",0 +str_int2 .db ", Channel B Interrupts=",0 +str_watch1 .db "\r\n\r\nWatching Channel ",0 +str_watch2 .db ", press any to end...",0 +str_watchtag .db "\rPort Value=0x",0 +str_input1 .db "\r\n\r\nValue of Pins on Channel ",0 +str_input2 .db " = 0x",0 +str_output1 .db "\r\n\r\nSetting Value of Pins on Channel ",0 +str_output2 .db " = 0x",0 +str_receive1 .db "\r\n\r\nReceived from Channel ",0 +str_receive2 .db " = 0x",0 +str_send1 .db "\r\n\r\nSent to Channel ",0 +str_send2 .db " = 0x",0 +str_rdbk .db "\r\n\r\nReadback Test on Channel ",0 +str_arrow .db " --> ",0 +str_lpbkAB .db "\r\n\r\nLoopback Test in Bit Control Mode A->B...\r\n",0 +str_lpbkBA .db "\r\n\r\nLoopback Test in Bit Control Mode B->A...\r\n",0 +str_stlpAB .db "\r\n\r\nLoopback Test in Strobed Mode A->B...\r\n",0 +str_stlpBA .db "\r\n\r\nLoopback Test in Strobed Mode B->A...\r\n",0 +str_usage .db "\r\n" + .db "\r\n P n - Set Current PIO Base Port" + .db "\r\n Z - Reset PIO (both channels)" + .db "\r\n Wc - Watch Channel c Pin Values (bit control)" + .db "\r\n Oc n - Output Channel c Pin Values (bit control)" + .db "\r\n Ic - Input Channel c Pin Values (bit control)" + .db "\r\n Sc n - Send Value to Channel c (strobed)" + .db "\r\n Rc - Receive Value from Channel c (strobed)" + .db "\r\n TRc - Test Readback on Channel c (bit control)" + .db "\r\n TL - Test Loopback (bit control)" + .db "\r\n TS - Test Loopback (strobed)" + .db "\r\n H,? - Help" + .db "\r\n X - Exit" + .db "\r\n " + .db "\r\n Loopback tests require hardware loopback (see readme.txt)" + .db 0 +; +;======================================================================= +; Working data +;======================================================================= +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +iobase .db iodef ; current I/O base address +channel .db 0 ; current channel +wrkval .db 0 +; +cmdbuf .fill buflen+1,0 +; +vallist: + .db $00,$FF,$AA,$55,$A5,$5A,$FF,$00 +vallen .equ $ - vallist +; +orgveca .dw 0 ; saved int vector, channel A +orgvecb .dw 0 ; saved int vector, channel B +; +;=============================================================================== +; Interrupt Handler +;=============================================================================== +; +reladr .equ $ ; relocation start adr +; + .org $A000 ; code will run here +; +inta: +; + ld hl,(intcnta) + inc hl + ld (intcnta),hl +; + or $ff ; signal int handled + ret +; +intb: +; + ld hl,(intcntb) + inc hl + ld (intcntb),hl +; + or $ff ; signal int handled + ret +; +intcnta .dw 0 +intcntb .dw 0 +; +hsiz .equ $ - $A000 ; size of handler to relocate +; + .org reladr + hsiz +; + .end + \ No newline at end of file diff --git a/desktop.ini b/desktop.ini deleted file mode 100644 index bb9f3d69..00000000 --- a/desktop.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ViewState] -Mode= -Vid= -FolderType=Generic