mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
Preliminary Support for Interrupt Management API
This commit is contained in:
519
Source/Apps/IntTest.asm
Normal file
519
Source/Apps/IntTest.asm
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user