You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1064 lines
26 KiB

;==================================================================================================
; Z80 DMA TEST UTILITY - ROMWBW SPECIFIC
;==================================================================================================
;
;==================================================================================================
; PLATFORM CONFIGURATION
;==================================================================================================
;
DMAMODE_NONE .EQU 0
DMAMODE_ECB .EQU 1 ; ECB-DMA WOLFGANG KABATZKE'S Z80 DMA ECB BOARD
DMAMODE_Z180 .EQU 2 ; Z180 INTEGRATED DMA
DMAMODE_Z280 .EQU 3 ; Z280 INTEGRATED DMA
DMAMODE_RC .EQU 4 ; RCBUS Z80 DMA
DMAMODE_MBC .EQU 5 ; MBC
DMAMODE_VDG .EQU 6 ; VELESOFT DATAGEAR
;
DMABASE .EQU $0b ; DMA: DMA BASE ADDRESS
DMAMODE .EQU DMAMODE_VDG ; SELECT DMA DEVICE FOR TESTING
DMAIOTST .EQU $68 ; AN OUTPUT PORT FOR TESTING - 16C450 SERIAL OUT
;
;==================================================================================================
; HELPER MACROS AND EQUATES
;==================================================================================================
;
FALSE .EQU 0
TRUE .EQU ~FALSE
;
#DEFINE PRTC(C) CALL PRTCH \ .DB C ; PRINT CHARACTER C TO CONSOLE - PRTC('X')
#DEFINE PRTS(S) CALL PRTSTRD \ .TEXT S ; PRINT STRING S TO CONSOLE - PRTD("HELLO")
#DEFINE PRTX(X) CALL PRTSTRI \ .DW X ; PRINT STRING AT ADDRESS X TO CONSOLE - PRTI(STR_HELLO)
;
;==================================================================================================
; INTERRUPT TESTING CONFIGURATION
; ASSUMES SYSTEM IS ALREADY CONFIGURED FOR IM2 OPERATION
; INTIDX MUST BE SET TO AN UNUSED INTERRUPT SLOT
;==================================================================================================
;
INTENABLE .EQU TRUE ; ENABLE INT TESTING
INTIDX .EQU 1 ; INT VECTOR INDEX
;
;==================================================================================================
; DMA MODE BYTES
;==================================================================================================
;
DMA_CONTINUOUS .equ %10111101 ; + Pulse
DMA_BYTE .equ %10011101 ; + Pulse
DMA_BURST .equ %11011101 ; + Pulse
DMA_LOAD .equ $cf ; %11001111
DMA_ENABLE .equ $87 ; %10000111
DMA_FORCE_READY .equ $b3
DMA_DISABLE .equ $83
DMA_START_READ_SEQUENCE .equ $a7
DMA_READ_STATUS_BYTE .equ $bf
DMA_READ_MASK_FOLLOWS .equ $bb
DMA_RESET .equ $c3
;DMA_RESET_PORT_A_TIMING .equ $c7
;DMA_RESET_PORT_B_TIMING .equ $cb
;DMA_CONTINUE .equ $d3
;DMA_DISABLE_INTERUPTS .equ $af
DMA_ENABLE_INTERUPTS .equ $ab
;DMA_RESET_DISABLE_INTERUPTS .equ $a3
;DMA_ENABLE_AFTER_RETI .equ $b7
DMA_REINIT_STATUS_BYTE .equ $8b
;
DMA_RDY .EQU %00001000
DMA_FORCE .EQU 0
;
;==================================================================================================
; ROMWBW HBIOS DEFINITIONS
;==================================================================================================
;
bf_sysint .equ $FC ; INT function
bf_sysget .equ $F8 ; GET function
;
bf_sysintinfo .equ $00 ; INT INFO subfunction
bf_sysintget .equ $10 ; INT GET subfunction
bf_sysintset .equ $20 ; INT SET subfunction
bf_sysgetcpuspd .equ $F3 ; GET CPUSPD subfunction
;
;==================================================================================================
; MAIN DMA MONITOR ROUTINE
;==================================================================================================
;
.ORG $0100
;
MAIN:
LD (SAVSTK),SP ; SETUP LOCAL
LD SP,STACK ; STACK
;
call PRTSTRD ; WELCOME
.db "\n\rDMA Monitor V3\n\r$"
;
#IF (INTENABLE)
;
; Install interrupt handler in upper mem
ld hl,reladr
ld de,$A000
ld bc,hsiz
ldir
;
; Install interrupt vector (RomWBW specific!!!)
ld hl,int ; pointer to my interrupt handler
ld b,bf_sysint
ld c,bf_sysintset ; set new vector
ld e,INTIDX ; vector idx
di
rst 08 ; do it
ld (orgvec),hl ; save the original vector
ei ; interrupts back on
;
#ENDIF
;
MENULP: CALL DISPM ; DISPLAY MENU
CALL CINU ; GET SELECTION
CALL COUT
;
MENULP1:
CALL NEWLINE
CP 'D'
JP Z,DMATST_D ; DUMP REGISTERS
CP 'I'
JP Z,DMATST_I ; INITIALIZE
#IF (INTENABLE)
CP 'T'
JP Z,DMATST_T ; TOGGLE INT USAGE
#ENDIF
CP 'M'
JP Z,DMATST_M ; MEMORY COPY
CP 'N'
JP Z,DMATST_N ; MEMORY COPY ITER
CP '0'
JP Z,DMATST_01
CP 'O'
JP Z,DMATST_O
#IF !(DMAMODE==DMAMODE_VDG)
CP '1'
JP Z,DMATST_01
CP 'R'
JP Z,DMATST_R ; TOGGLE RESET
CP 'Y'
JP Z,DMATST_Y ; TOGGLE READY
#ENDIF
cp 'S'
call z,DMACFG_S ; SET PORT
CP 'X'
JP Z,DMABYE ; EXIT
;
JR MENULP
;
DMACFG_S:
call PRTSTRD
.db "\n\rSet port address\n\rPort:$"
call HEXIN
ld hl,dmaport
ld (hl),a
inc hl
inc a
ld (hl),a
jp MENULP
;
DMABYE:
#IF (INTENABLE)
; Deinstall interrupt vector
ld hl,(orgvec) ; original vector
ld b,bf_sysint
ld c,bf_sysintset ; set new vector
ld e,INTIDX ; vector idx
di
rst 08 ; do it
ei ; interrupts back on
#ENDIF
;
LD SP,(SAVSTK) ; RESTORE CP/M STACK
RET
;
DMATST_I:
call PRTSTRD
.db "\n\rStart Initialization\n\r$"
CALL DMA_INIT
JP MENULP
;
#IF (INTENABLE)
;
DMATST_T:
LD A,(USEINT)
XOR $FF
LD (USEINT),A
JP MENULP
;
#ENDIF
;
DMATST_M:
call PRTSTRD
.db "\n\rPerforming Memory-Memory Copy Test\n\r$"
CALL DMAMemTest
JP MENULP
;
DMATST_N:
call PRTSTRD
.db "\n\rPerforming Iterative Memory-Memory Copy Test\n\r$"
CALL DMAMemTestIter
JP MENULP
;
DMATST_01:
call PRTSTRD
.db "\n\rPerforming Port Selection Test\n\r$"
CALL DMA_Port01
JP MENULP
;
DMATST_O:
call PRTSTRD
.db "\n\rTest output to I\O device\n\r$"
CALL DMA_ReadyO
JP MENULP
;
DMATST_D:
call PRTSTRD
.db "\n\rRegister dump:\n\r$"
CALL DMARegDump
JP MENULP
;
DMATST_Y:
call PRTSTRD
.db "\n\rPerforming Ready Bit Test\n\r$"
CALL DMA_ReadyT
JP MENULP
;
DMATST_R:
call PRTSTRD
.db "\n\rPerforming Reset\n\r$"
; CALL
JP MENULP
;
;==================================================================================================
; DISPLAY MENU
;==================================================================================================
;
DISPM: call PRTSTRD
.db "\n\rDMA Device: $"
LD C,DMAMODE ; DISPLAY
LD A,00000111B ; TARGET
LD DE,DMA_DEV_STR ; DEVICE
CALL PRTIDXMSK
;
call PRTSTRD
.db ", Port=0x$"
LD A,(dmaport) ; DISPLAY
CALL PRTHEXBYTE ; DMA PORT
;
#IF (INTENABLE)
;
call PRTSTRD
.db "\n\rInterrupts=$"
LD A,(USEINT)
OR A
LD A,'Y'
JR NZ,DISPM_INT
LD A,'N'
JR DISPM_INT
;
DISPM_INT:
CALL COUT
;
call PRTSTRD
.db ", Interrupt Count=$"
ld hl,(counter)
call PRTDEC
;
#ENDIF
;
#IF (DMAMODE==DMAMODE_VDG)
call PRTSTRD
.db "\n\rReset\\Ready Latch unsupported.$"
#ENDIF
call PRTSTRD ; DISPLAY SPEED
.db "\n\rCPU at $"
LD B,bf_sysget
LD C,bf_sysgetcpuspd ; GET CURRENT
RST 08 ; SPEED SETTING
OR A
LD A,L
JR Z,SPDDISP
LD A,3
;
SPDDISP:LD DE,DMA_SPD_STR
CALL PRTIDXDEA
CALL NEWLINE
;
LD HL,MENU_OPT ; DISPLAY
CALL PRTSTR ; MENU OPTIONS
RET
;
#INCLUDE "util.asm"
;
;==================================================================================================
; DMA INITIALIZATION CODE
;==================================================================================================
;
DMA_INIT:
CALL NEWLINE
PRTS("DMA: IO=0x$") ; announce
LD A,(dmaport)
CALL PRTHEXBYTE
;
#IF !(DMAMODE==DMAMODE_VDG)
ld a,(dmautil)
ld c,a
LD A,DMA_FORCE
out (c),a ; force ready off
#ENDIF
;
;
call DMAProbe ; do we have a dma?
jr nz,DMA_NOTFOUND
;
call PRTSTRD
.db " DMA Found\n\r$"
;
ld hl,DMACode ; program the
ld b,DMACode_Len ; dma command
ld c,DMABASE ; block
;
di
otir ; load dma
ei
xor a ; set status
;
DMA_EXIT:
ret
;
DMA_NOTFOUND:
push af
call PRTSTRD
.db " NOT Present$"
pop af
jr DMA_EXIT
;
DMA_FAIL_FLAG:
.db 0
;
DMA_DEV_STR:
.TEXT "NONE$"
.TEXT "ECB$"
.TEXT "Z180$"
.TEXT "Z280$"
.TEXT "RCBUS$"
.TEXT "MBC$"
.TEXT "DATAGEAR$"
;
DMA_SPD_STR:
.TEXT "half speed.$"
.TEXT "full speed.$"
.TEXT "double speed.$"
.TEXT "unknown speed.$"
;
MENU_OPT:
.TEXT "\n\r"
.TEXT "D) Dump DMA registers\n\r"
.TEXT "I) Initialize DMA\n\r"
.TEXT "T) Toggle Interrupt Usage\n\r"
.TEXT "M) Test Memory-Memory Copy\n\r"
.TEXT "N) Test Memory-Memory Copy Iteratively\n\r"
.TEXT "O) Memory to I/O Test\n\r"
.TEXT "0) Test DMA Port Selection\n\r"
#IF !(DMAMODE==DMAMODE_VDG)
.TEXT "1) Test DMA Latch Port Selection\n\r"
.TEXT "Y) Test Ready Bit\n\r"
#ENDIF
.TEXT "S) Set DMA port\n\r"
.TEXT "X) Exit\n\r"
.TEXT ">$"
;
;==================================================================================================
; OUTPUT A BUFFER OF TEXT TO AN IOPORT
;==================================================================================================
;
DMABUF .TEXT "0123456789abcdef"
;
DMA_ReadyO:
call PRTSTRD
.db "\r\nOutputing string to port 0x$"
ld a,DMAIOTST
call PRTHEXBYTE
call NEWLINE
;
ld b,16
IOLoop: push bc
call NEWLINE
ld hl,DMABUF
ld a,DMAIOTST
ld bc,16
;
call DMAOTIR
;
call PRTSTRD
.db " Return Status: $"
call PRTHEXBYTE
;
pop bc
djnz IOLoop
call NEWLINE
ret
;
;==================================================================================================
; PULSE PORT (COMMON ROUTINE WITH A CONTAINING ASCII PORT OFFSET)
;==================================================================================================
;
DMA_Port01:
call PRTSTRD
.db "\r\nPulsing port 0x$"
sub '0' ; Calculate
ld c,a
ld a,(dmaport) ; Port to
add a,c
call PRTHEXBYTE
call NEWLINE
ld c,a ; toggle
ld b,$20 ; loop counter
portlp: push bc
call PC_PERIOD
push bc
ld b,0
ld a,0
portlp1:out (c),a
djnz portlp1
pop bc
call delay
pop bc
djnz portlp
call NEWLINE
JP MENULP
;
delay: push bc
ld bc,0
dlylp: dec bc
ld a,b
or c
jr nz,dlylp
pop bc
ret
;
;==================================================================================================
; TOGGLE READY BIT
;==================================================================================================
;
DMA_ReadyT:
call NEWLINE
#IF !(DMAMODE==DMAMODE_VDG)
#ENDIF
ld a,(dmautil)
ld c,a ; toggle
ld b,$20 ; loop counter
portlp2:push bc
ld a,b
call PRTDECB
call PRTSTRD
.db ": ON$"
call delay
ld a,$FF
; ld c,DMABASE+1
out (c),a
call PRTSTRD
.db " -> OFF$"
call delay
call PRTSTRD
.db "\r \r$"
; ld c,DMABASE+1
ld a,0
out (c),a
pop bc
djnz portlp2
ret
;
;==================================================================================================
; DMA MEMORY MOVE
;==================================================================================================
;
DMAMemMove:
;
LD HL,$8000 ; PREFILL DESTINATION WITH $55
LD A,$55
LD (HL),A
LD DE,$8001
LD BC,4096-1
LDIR
;
LD HL,PROEND ; FILL SOURCE WITH $AA
LD A,$AA
LD (HL),A
LD DE,PROEND+1
LD BC,4096-1
LDIR
;
LD HL,PROEND ; DMA COPY
LD DE,$8000
LD BC,4096-1
LD A,(USEINT) ; USE INTS?
OR A ; TEST VALUE
JR NZ,DMAMemMove1 ; IF SO, DO SO
CALL DMALDIR ; ELSE NORMAL DMA
JR DMAMemMove2
;
DMAMemMove1:
CALL DMALDIRINT ; DMA W/ INTERRUPTS
;
DMAMemMove2:
;
; LD HL,$8400 ; PLANT
; LD A,$00 ; BAD
; LD (HL),A ; SEED
;
call PRTSTRD
.db "Return Status: $"
call PRTHEXBYTE
LD A,$AA ; CHECK COPY SUCCESSFULL
LD HL,$8000
LD BC,4096
NXTCMP: CPI
JP PO,CMPOK
JR Z,NXTCMP
RET ; RET W/ ZF CLEAR
;
CMPOK:
RET ; RET W/ ZF SET
;
;==================================================================================================
; DMA MEMORY TEST
;==================================================================================================
;
DMAMemTest:
call DMAMemMove ; do a single memory copy
jr z,DMAMemTestOK
jr DMAMemTestFail
;
DMAMemTestOK:
call PRTSTRD
.db "\n\rMemory-Memory Test Passed\n\r$"
ret
;
DMAMemTestFail:
call PRTSTRD
.db "\n\rMemory-Memory Test Failed\n\r$"
ret
;
;==================================================================================================
; DMA MEMORY MOVE ITERATIVE
;==================================================================================================
;
DMAMemTestIter:
ld b,$20 ; loop counter
ld a,b
call PRTDECB
call PRTSTRD
.db " iterations:\n\r$"
DMAMemTestIterLoop:
push bc ; save loop control
call DMAMemMove ; do an iteration
jr z,DMAMemTestIterOK
call PRTSTRD
.db " Mismatch\n\r$"
jr DMAMemTestIterCont ; continue
;
DMAMemTestIterOK:
call PRTSTRD
.db " Match\n\r$"
;
DMAMemTestIterCont:
pop bc
djnz DMAMemTestIterLoop
call NEWLINE
ret
;
;==================================================================================================
; DMA PROBE - WRITE TO ADDRESS REGISTER AND READ BACK
;==================================================================================================
;
DMAProbe:
ld a,(dmaport)
ld c,a
ld a,DMA_RESET
out (c),a
ld a,%01111101 ; R0-Transfer mode, A -> B, start address follows
out (c),a
ld a,$cc
out (c),a
ld a,$dd
out (c),a
ld a,$e5
out (c),a
ld a,$1a
out (c),a
ld a,DMA_LOAD
out (c),a
;
ld a,DMA_READ_MASK_FOLLOWS ; set up
out (c),a ; for
ld a,%00011000 ; register
out (c),a ; read
ld a,DMA_START_READ_SEQUENCE
out (c),a
;
in a,(c) ; read in
ld e,a ; address
in a,(c)
ld d,a
;
xor a ; is it
ld hl,$ddcc ; a match
sbc hl,de ; return with
ret z ; status
cpl
ret
;
DMACode ;.db DMA_DISABLE ; R6-Command Disable DMA
.db %01111101 ; R0-Transfer mode, A -> B, start address, block length follow
.dw 0 ; R0-Port A, Start address
.dw 0 ; R0-Block length
.db %00010100 ; R1-No timing bytes follow, address increments, is memory
.db %00010000 ; R2-No timing bytes follow, address increments, is memory
.db %10000000 ; R3-DMA, interrupt, stop on match disabled
.db DMA_CONTINUOUS ; R4-Continuous mode, destination address, interrupt and control byte follow
.dw 0 ; R4-Port B, Destination address
.db %00001100 ; R4-Pulse byte follows, Pulse generated
.db 0 ; R4-Pulse offset
.db %10010010+DMA_RDY; R5-Stop on end of block, ce/wait multiplexed, READY active config
.db DMA_LOAD ; R6-Command Load
; .db DMA_FORCE_READY ; R6-Command Force ready
; .db DMA_ENABLE ; R6-Command Enable DMA
DMACode_Len .equ $-DMACode
;
;==================================================================================================
; DMA COPY BLOCK CODE - ASSUMES DMA PREINITIALIZED
;==================================================================================================
;
DMALDIR:
ld (DMASource),hl ; populate the dma
ld (DMADest),de ; register template
ld (DMALength),bc
;
ld hl,DMACopy ; program the
ld b,DMACopy_Len ; dma command
ld a,(dmaport) ; block
ld c,a
;
di
otir ; load and execute dma
ei
;
ld a,DMA_READ_STATUS_BYTE ; check status
out (c),a ; of transfer
in a,(c) ; set non-zero
; and %00111011 ; if failed
; sub %00011011
ret
;
DMACopy ;.db DMA_DISABLE ; R6-Command Disable DMA
.db %01111101 ; R0-Transfer mode, A -> B, start address, block length follow
DMASource .dw 0 ; R0-Port A, Start address
DMALength .dw 0 ; R0-Block length
.db %00010100 ; R1-No timing bytes follow, address increments, is memory
.db %00010000 ; R2-No timing bytes follow, address increments, is memory
.db %10000000 ; R3-DMA, interrupt, stop on match disabled
.db DMA_CONTINUOUS ; R4-Continuous mode, destination address, interrupt and control byte follow
DMADest .dw 0 ; R4-Port B, Destination address
.db %00001100 ; R4-Pulse byte follows, Pulse generated
.db 0 ; R4-Pulse offset
; .db %10010010+DMA_RDY;R5-Stop on end of block, ce/wait multiplexed, READY active config
.db DMA_LOAD ; R6-Command Load
.db DMA_FORCE_READY ; R6-Command Force ready
.db DMA_ENABLE ; R6-Command Enable DMA
DMACopy_Len .equ $-DMACopy
;
;==================================================================================================
; DMA COPY BLOCK CODE - ASSUMES DMA PREINITIALIZED
; INTERRUPT VERSION!
;==================================================================================================
;
DMALDIRINT:
;
#IF (INTENABLE)
;
ld (DMASourceInt),hl ; populate the dma
ld (DMADestInt),de ; register template
ld (DMALengthInt),bc
;
ld hl,DMACopyInt ; program the
ld b,DMACopyInt_Len ; dma command
ld a,(dmaport) ; block
ld c,a
;
di
otir ; load and execute dma
ei
;
ld a,DMA_READ_STATUS_BYTE ; check status
out (c),a ; of transfer
in a,(c)
call PRTSTRD
.db "Return Status: $"
call PRTHEXBYTE
; and %00111011 ; set non-zero
; sub %00011011 ; if failed
;
#ENDIF
;
ret
;
#IF (INTENABLE)
;
DMACopyInt ;.db DMA_DISABLE ; R6-Command Disable DMA
.db %01111101 ; R0-Transfer mode, A -> B, start address, block length follow
DMASourceInt .dw 0 ; R0-Port A, Start address
DMALengthInt .dw 0 ; R0-Block length
.db %00010100 ; R1-No timing bytes follow, address increments, is memory
.db %00010000 ; R2-No timing bytes follow, address increments, is memory
.db %10100000 ; R3-DMA, interrupt, stop on match disabled
.db DMA_CONTINUOUS ; R4-Continuous mode, destination address, interrupt and control byte follow
DMADestInt .dw 0 ; R4-Port B, Destination address
.db %00011110 ; R4-Interrupt control byte: Pulse byte follows, Pulse generated
.db 0 ; R4-Pulse control byte
.db INTIDX*2 ; R4-Interrupt vector
; .db %10010010+DMA_RDY;R5-Stop on end of block, ce/wait multiplexed, READY active config
.db %10011010
.db DMA_LOAD ; R6-Command Load
.db DMA_FORCE_READY ; R6-Command Force ready
.db DMA_ENABLE ; R6-Command Enable DMA
DMACopyInt_Len .equ $-DMACopyInt
;
#ENDIF
;
;==================================================================================================
; DMA I/O OUT BLOCK CODE - ADDRESS TO I/O PORT
;==================================================================================================
;
DMAOTIR:
ld (DMAOutSource),hl ; populate the dma
ld (DMAOutDest),a ; register template
ld (DMAOutLength),bc
;
ld hl,DMAOutCode ; program the
ld b,DMAOut_Len ; dma command
ld a,(dmaport) ; block
ld c,a
;
di
otir ; load and execute dma
ei
;
ld a,DMA_READ_STATUS_BYTE ; check status
out (c),a ; of transfer
in a,(c) ; set non-zero
; and %00111011 ; if failed
; sub %00011011
;
ret
;
DMAOutCode ;.db DMA_DISABLE ; R6-Command Disable DMA
.db %01111001 ; R0-Transfer mode, B -> A (temp), start address, block length follow
DMAOutSource .dw 0 ; R0-Port A, Start address
DMAOutLength .dw 0 ; R0-Block length
.db %00010100 ; R1-No timing bytes follow, fixed incrementing address, is memory
.db %00101000 ; R2-No timing bytes follow, address static, is i/o
.db %10000000 ; R3-DMA, interrupt, stop on match disabled
.db %10100101 ; R4-Continuous mode, destination port, interrupt and control byte follow
DMAOutDest .db 0 ; R4-Port B, Destination port
; .db %00001100 ; R4-Pulse byte follows, Pulse generated
; .db 0 ; R4-Pulse offset
.db %10010010+DMA_RDY;R5-Stop on end of block, ce/wait multiplexed, READY active config
.db DMA_LOAD ; R6-Command Load
.db %00000101 ; R0-Port A is Source
.db DMA_LOAD ; R6-Command Load
.db DMA_FORCE_READY ; R6-Command Force ready
.db DMA_ENABLE ; R6-Command Enable DMA
DMAOut_Len .equ $-DMAOutCode
;
;==================================================================================================
; DMA I/O INPUT BLOCK CODE - I/O PORT TO ADDRESS
;==================================================================================================
;
DMAINIR:
ld (DMAInDest),hl ; populate the dma
ld (DMAInSource),a ; register template
ld (DMAInLength),bc
;
ld hl,DMAInCode ; program the
ld b,DMAIn_Len ; dma command
ld a,(dmaport) ; block
ld c,a
;
di
otir ; load and execute dma
ei
;
ld a,DMA_READ_STATUS_BYTE ; check status
out (c),a ; of transfer
in a,(c) ; set non-zero
; and %00111011 ; if failed
; sub %00011011
;
ret
;
DMAInCode ;.db DMA_DISABLE ; R6-Command Disable DMA
.db %01111001 ; R0-Transfer mode, B -> A, start address, block length follow
DMAInDest .dw 0 ; R0-Port A, Start address
DMAInLength .dw 0 ; R0-Block length
.db %00010100 ; R1-No timing bytes follow, address increments, is memory
.db %00111000 ; R2-No timing bytes follow, address static, is i/o
.db %10000000 ; R3-DMA, interrupt, stop on match disabled
.db %10100101 ; R4-Continuous mode, destination port, no interrupt, control byte.
DMAInSource .db 0 ; R4-Port B, Destination port
; .db %00001100 ; R4-Pulse byte follows, Pulse generated
; .db 0 ; R4-Pulse offset
.db %10010010+DMA_RDY;R5-Stop on end of block, ce/wait multiplexed, READY active config
.db DMA_LOAD ; R6-Command Load
.db DMA_FORCE_READY ; R6-Command Force ready
.db DMA_ENABLE ; R6-Command Enable DMA
DMAIn_Len .equ $-DMAInCode
;
;==================================================================================================
; DEBUG - READ START, DESTINATION AND COUNT REGISTERS
;==================================================================================================
;
DMARegDump:
ld a,(dmaport)
ld c,a
ld a,DMA_READ_MASK_FOLLOWS
out (c),a
ld a,%01111110
out (c),a
ld a,DMA_START_READ_SEQUENCE
out (c),a
;
in a,(c)
ld l,a
in a,(c)
ld h,a
call PRTHEXWORDHL
ld a,':'
call COUT
;
in a,(c)
ld l,a
in a,(c)
ld h,a
call PRTHEXWORDHL
ld a,':'
call COUT
;
in a,(c)
ld l,a
in a,(c)
ld h,a
call PRTHEXWORDHL
;
call NEWLINE
ret
;
;==================================================================================================
; CONSOLE I/O ROUTINES
;==================================================================================================
;
CIO_CONSOLE .EQU $80 ; HBIOS DEFAULT CONSOLE
BF_CIOOUT .EQU $01 ; HBIOS FUNC: OUTPUT CHAR
BF_CIOIN .EQU $00 ; HBIOS FUNC: INPUT CHAR
BF_CIOIST .EQU $02 ; HBIOS FUNC: INPUT CHAR STATUS
;
;__CINU_______________________________________________________________________
;
; INPUT AN UPPERCASE CHARACTER
;_____________________________________________________________________________
;
CINU: CALL CIN
; Force upper case
CP 'a' ; < 'a'
RET C ; IF SO, JUST CONTINUE
CP 'z'+1 ; > 'z'
RET NC ; IS SO, JUST CONTINUE
SUB 'a'-'A' ; CONVERT TO UPPER
RET
;
;__HEXIN_______________________________________________________________________
;
; INPUT A HEX BYTE, RETURN VALUE IN A
;_____________________________________________________________________________
;
HEXIN: CALL CINU ; GET 1 CHAR INPUT
push af
CALL ISHEX ; CHECK FOR VALID CHARACTER
JR C,HEXIN
ADD A,A
ADD A,A
ADD A,A
ADD A,A
LD C,A ; Save top nibble
pop af ; Retreive letter
call COUT ; and display it
;
HEXIN1: CALL CINU ; GET 1 CHAR INPUT
push af
CALL ISHEX ; CHECK FOR VALID CHARACTER
JR C,HEXIN1
;
or c
ld c,a
pop af ; Retreive letter
call COUT ; and display it
;
ld a,c
CALL PRTHEXBYTE
RET
; CF SET MEANS CHARACTER 0-9,A-F
ISHEX: CP '0' ; < '0'?
JR C,ISHEX1 ; YES, NOT 0-9, CHECK A-F
CP '9' + 1 ; > '9'
jr nc,ISHEX1
sub '0' ; MUST BE 0-9, RETURN
ret
ISHEX1: CP 'A' ; < 'A'?
ret c ; YES, NOT A-F, FAIL
cp 'F' + 1 ; > 'F'
jr nc,ISHEX2
sub 'A' - 10
RET ; MUST BE A-F, RETURN
ISHEX2: SCF
RET
;
;__COUT_______________________________________________________________________
;
; OUTPUT CHARACTER FROM A
;_____________________________________________________________________________
;
COUT:
; SAVE ALL INCOMING REGISTERS
PUSH AF
PUSH BC
PUSH DE
PUSH HL
;
; OUTPUT CHARACTER TO CONSOLE VIA HBIOS
LD E,A ; OUTPUT CHAR TO E
LD C,CIO_CONSOLE ; CONSOLE UNIT TO C
LD B,BF_CIOOUT ; HBIOS FUNC: OUTPUT CHAR
CALL $FFF0 ; HBIOS OUTPUTS CHARACTER
;
; RESTORE ALL REGISTERS
POP HL
POP DE
POP BC
POP AF
RET
;
;__CIN________________________________________________________________________
;
; INPUT CHARACTER TO A
;_____________________________________________________________________________
;
CIN:
; SAVE INCOMING REGISTERS (AF IS OUTPUT)
PUSH BC
PUSH DE
PUSH HL
;
; INPUT CHARACTER FROM CONSOLE VIA HBIOS
LD C,CIO_CONSOLE ; CONSOLE UNIT TO C
LD B,BF_CIOIN ; HBIOS FUNC: INPUT CHAR
CALL $FFF0 ; HBIOS READS CHARACTER
LD A,E ; MOVE CHARACTER TO A FOR RETURN
;
; RESTORE REGISTERS (AF IS OUTPUT)
POP HL
POP DE
POP BC
RET
;
;__CST________________________________________________________________________
;
; 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 HBIOS
LD C,CIO_CONSOLE ; CONSOLE UNIT TO C
LD B,BF_CIOIST ; HBIOS FUNC: INPUT STATUS
CALL $FFF0 ; HBIOS RETURNS STATUS IN A
;
; RESTORE REGISTERS (AF IS OUTPUT)
POP HL
POP DE
POP BC
RET
;
USEINT .DB FALSE ; USE INTERRUPTS FLAG
;
SAVSTK: .DW 2
.FILL 64
STACK: .EQU $
;
orgvec .dw 0 ; saved interrupt vector
;
;===============================================================================
; Interrupt Handler
;===============================================================================
;
reladr .equ $ ; relocation start adr
;
.org $A000 ; code will run here
;
int:
; According to the DMA doc, you must issue
; a DMA_DISABLE command prior to a
; DMA_REINIT_STATUS_BYTE command to avoid a
; potential race condition.
ld a,(dmaport)
ld c,a
ld a,DMA_DISABLE
out (c),a
;
; The doc confuses me, but apparently it is
; necessary to reinitialize the status byte
; when an end-of-block interrupt occurs. Otherwise,
; the end-of-block condition remains set and
; causes the interrupt to fire continuously.
ld a,DMA_REINIT_STATUS_BYTE
out (c),a
;
ld hl,(counter)
inc hl
ld (counter),hl
;
or $ff ; signal int handled
ret
;
counter .dw 0
dmaport .db DMABASE
dmautil .db DMABASE+1
;
hsiz .equ $ - $A000 ; size of handler to relocate
;
.org reladr + hsiz
;
PROEND: .EQU $
;
.END