mirror of https://github.com/wwarthen/RomWBW.git
11 changed files with 793 additions and 25 deletions
@ -0,0 +1,519 @@ |
|||||
|
;=============================================================================== |
||||
|
; INTTEST - Test HBIOS interrupt API functions |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
; Author: Wayne Warthen (wwarthen@gmail.com) |
||||
|
;_______________________________________________________________________________ |
||||
|
; |
||||
|
; Usage: |
||||
|
; INTTEST |
||||
|
;_______________________________________________________________________________ |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Definitions |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
stksiz .equ $40 ; Working stack size |
||||
|
; |
||||
|
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 |
||||
|
; |
||||
|
z180_base .equ $40 ; i/o base address for internal z180 registers |
||||
|
z180_tcr .equ z180_base + $10 ; timer control |
||||
|
z180_tmdr0l .equ z180_base + $0C ; timer 0 data lo |
||||
|
|
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Code Section |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
.org $100 |
||||
|
; |
||||
|
; 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 crlf ; formatting |
||||
|
ld de,msgban ; point to version message part 1 |
||||
|
call prtstr ; print it |
||||
|
; |
||||
|
; relocate handler |
||||
|
ld hl,reladr |
||||
|
ld de,$8000 |
||||
|
ld bc,hsiz |
||||
|
ldir |
||||
|
; |
||||
|
initx |
||||
|
; initialization complete |
||||
|
xor a ; signal success |
||||
|
ret ; return |
||||
|
; |
||||
|
; Process |
||||
|
; |
||||
|
process: |
||||
|
; |
||||
|
; Get info |
||||
|
; |
||||
|
call crlf2 |
||||
|
ld de,msginfo ; message |
||||
|
call prtstr |
||||
|
; |
||||
|
ld b,bf_sysint ; INT function |
||||
|
ld c,bf_sysintinfo ; INFO subfunction |
||||
|
rst 08 |
||||
|
ld a,d |
||||
|
ld (intmod),a ; save int mode |
||||
|
ld a,e |
||||
|
ld (veccnt),a ; save vector count |
||||
|
; |
||||
|
push de |
||||
|
call crlf |
||||
|
ld de,msgmode ; mode |
||||
|
call prtstr |
||||
|
pop de |
||||
|
push de |
||||
|
ld a,d ; interrupt mode |
||||
|
call prtdecb |
||||
|
call crlf |
||||
|
ld de,msgcnt ; count of vectors |
||||
|
call prtstr |
||||
|
pop de |
||||
|
ld a,e |
||||
|
call prtdecb |
||||
|
; |
||||
|
; Done if int mode is 0 |
||||
|
; |
||||
|
ld a,(intmod) |
||||
|
or a |
||||
|
ret z |
||||
|
; |
||||
|
; List vectors |
||||
|
; |
||||
|
call crlf2 |
||||
|
ld de,msglst |
||||
|
call prtstr |
||||
|
ld a,(veccnt) ; get count of vectors |
||||
|
or a |
||||
|
jr z,estidx ; bypass if nothing to list |
||||
|
ld b,a ; make it the loop counter |
||||
|
ld c,0 ; vector entry index |
||||
|
; |
||||
|
lstlp: |
||||
|
push bc |
||||
|
call crlf |
||||
|
ld a,' ' |
||||
|
call prtchr |
||||
|
call prtchr |
||||
|
ld a,c |
||||
|
call prthex |
||||
|
ld a,':' |
||||
|
call prtchr |
||||
|
ld e,c |
||||
|
ld b,bf_sysint |
||||
|
ld c,bf_sysintget |
||||
|
rst 08 |
||||
|
push hl |
||||
|
pop bc |
||||
|
call prthexword |
||||
|
pop bc |
||||
|
inc c |
||||
|
djnz lstlp |
||||
|
; |
||||
|
; Establish interrupt vector index to hook |
||||
|
; |
||||
|
estidx: |
||||
|
ld a,(intmod) |
||||
|
ld c,0 |
||||
|
cp 1 |
||||
|
jr z,setidx |
||||
|
ld c,2 ; assume timer in entry 2 if im2 |
||||
|
cp 2 |
||||
|
jr z,setidx |
||||
|
ret ; neither im1 or im2, bail out |
||||
|
setidx: |
||||
|
ld a,c |
||||
|
ld (vecidx),a |
||||
|
; |
||||
|
; Hook vector |
||||
|
; |
||||
|
call crlf2 |
||||
|
ld de,msghook |
||||
|
call prtstr |
||||
|
call crlf2 |
||||
|
ld a,$ff |
||||
|
ld (count),a ; set counter to max value |
||||
|
; |
||||
|
ld a,(intmod) |
||||
|
cp 1 |
||||
|
jr z,hkim1 |
||||
|
cp 2 |
||||
|
jr z,hkim2 |
||||
|
ret |
||||
|
; |
||||
|
; IM1 specific code |
||||
|
; |
||||
|
hkim1: |
||||
|
ld hl,m1int ; pointer to my interrupt handler |
||||
|
ld b,bf_sysint |
||||
|
ld c,bf_sysintset ; set new vector |
||||
|
ld a,(vecidx) ; get vector idx |
||||
|
ld e,a ; put in E |
||||
|
di |
||||
|
rst 08 ; do it |
||||
|
ld (chain),hl ; save the chain address |
||||
|
ei ; interrupts back on |
||||
|
jr start |
||||
|
; |
||||
|
; IM2 specific code |
||||
|
; |
||||
|
hkim2: |
||||
|
ld hl,m2stub ; pointer to my interrupt stub |
||||
|
ld b,bf_sysint |
||||
|
ld c,bf_sysintset ; set new vector |
||||
|
ld a,(vecidx) ; get vector idx |
||||
|
ld e,a ; put in E |
||||
|
di |
||||
|
rst 08 ; do it |
||||
|
ld (chain),hl ; save the chain address |
||||
|
ld (engadr),de ; insert the int routing engine address |
||||
|
ei ; interrupts back on |
||||
|
jr start |
||||
|
; |
||||
|
; Wait for counter to countdown to zero |
||||
|
; |
||||
|
start: |
||||
|
ld a,(count) |
||||
|
ld e,a |
||||
|
call prthex ; print it |
||||
|
ld a,13 |
||||
|
call prtchr |
||||
|
loop: |
||||
|
ld a,(count) ; get current count value |
||||
|
cp e |
||||
|
jr z,loop |
||||
|
push af |
||||
|
call prthex ; print it |
||||
|
ld a,13 |
||||
|
call prtchr |
||||
|
pop af |
||||
|
or a ; set flags |
||||
|
jr z,loop1 ; done |
||||
|
jr loop ; and loop |
||||
|
loop1: |
||||
|
; |
||||
|
; Unhook |
||||
|
; |
||||
|
call crlf2 |
||||
|
ld de,msgunhk |
||||
|
call prtstr |
||||
|
ld hl,(chain) ; original vector |
||||
|
ld b,bf_sysint |
||||
|
ld c,bf_sysintset ; set new vector |
||||
|
ld a,(vecidx) ; get vector idx |
||||
|
ld e,a ; put in E |
||||
|
di |
||||
|
rst 08 ; do it |
||||
|
ei ; interrupts back on |
||||
|
; |
||||
|
xor a ; signal success |
||||
|
ret ; 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 c,$02 ; BDOS function to output a character |
||||
|
call bdos ; do it |
||||
|
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 |
||||
|
; |
||||
|
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 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 ; <CR> |
||||
|
call prtchr ; print it |
||||
|
ld a,10 ; <LF> |
||||
|
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) |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Storage Section |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
intmod .db 0 ; active interrupt mode |
||||
|
veccnt .db 0 ; count of ingterrupt vectors |
||||
|
vecidx .db 0 ; vector index to hook |
||||
|
; |
||||
|
stksav .dw 0 ; stack pointer saved at start |
||||
|
.fill stksiz,0 ; stack |
||||
|
stack .equ $ ; stack top |
||||
|
; |
||||
|
; Messages |
||||
|
; |
||||
|
msgban .db "INTTEST v1.0, 27-Aug-2018",13,10 |
||||
|
.db "Copyright (C) 2018, Wayne Warthen, GNU GPL v3",0 |
||||
|
msginfo .db "Interrupt information request...",0 |
||||
|
msgmode .db " Active interrupt mode: ",0 |
||||
|
msgcnt .db " Vector entries in use: ",0 |
||||
|
msglst .db "Interrupt vector address list:",0 |
||||
|
msghook .db "Hooking vector...",0 |
||||
|
msgunhk .db "Unhooking vector...",0 |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Interrupt Handler |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
reladr .equ $ ; relocation start adr |
||||
|
; |
||||
|
.org $8000 ; code will run here |
||||
|
; |
||||
|
m1int: |
||||
|
; count down to zero |
||||
|
ld a,(count) |
||||
|
or a |
||||
|
jr z,m1int1 |
||||
|
dec a |
||||
|
ld (count),a |
||||
|
m1int1: |
||||
|
; follow the chain... |
||||
|
ld hl,(chain) |
||||
|
jp (hl) |
||||
|
; |
||||
|
m2stub: |
||||
|
push hl |
||||
|
ld hl,m2int |
||||
|
jp $0000 |
||||
|
engadr .equ $ - 2 |
||||
|
; |
||||
|
m2int: |
||||
|
; count down to zero |
||||
|
ld a,(count) |
||||
|
or a |
||||
|
jr z,m2int1 |
||||
|
dec a |
||||
|
ld (count),a |
||||
|
m2int1: |
||||
|
; ack/reset z180 timer interrupt |
||||
|
in0 a,(z180_tcr) |
||||
|
in0 a,(z180_tmdr0l) |
||||
|
ret |
||||
|
; |
||||
|
chain .dw $0000 ; chain address |
||||
|
count .db 0 ; counter |
||||
|
|
||||
|
hsiz .equ $ - $8000 ; size of handler to relocate |
||||
|
.end |
||||
Loading…
Reference in new issue