mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
cp/m fails to boot with the dma driver included but no dma hardware installed. This is because the default "dma_fail_flag" indicates that the dma is good to go. But in safe mode the dma initialization never takes place to find no dma and set this flag, so the memory driver hangs. This change is to make the default status of the flag the failed state so the memory driver will fallback to software in recovery mode.
340 lines
10 KiB
NASM
340 lines
10 KiB
NASM
;==================================================================================================
|
|
; Z80 DMA DRIVER
|
|
;==================================================================================================
|
|
;
|
|
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_FBACK .equ TRUE ; ALLOW FALLBACK TO SOFTWARE
|
|
DMA_RDY .EQU %00001000
|
|
DMA_FORCE .EQU 0
|
|
;
|
|
;==================================================================================================
|
|
; DMA CLOCK SPEED CONTROL - OPTION TO SWITCH TO HALF CLOCK SPEED. MOST SYSTEMS NEED THIS.
|
|
;==================================================================================================
|
|
;
|
|
DMA_USEHALF .equ TRUE ; USE CLOCK DIVIDER
|
|
;
|
|
#IF (DMA_USEHALF & (DMAMODE=DMAMODE_MBC))
|
|
#DEFINE DMAIOHALF LD A,(HB_RTCVAL) \ AND ~%00001000 \ OUT (RTCIO),A
|
|
#DEFINE DMAIOFULL PUSH AF \ LD A,(HB_RTCVAL) \ OUT (RTCIO),A \ POP AF
|
|
#ENDIF
|
|
;
|
|
#IF (DMA_USEHALF & (DMAMODE=DMAMODE_ECB))
|
|
#DEFINE DMAIOHALF LD A,(HB_RTCVAL) \ OR %00001000 \ OUT (RTCIO),A
|
|
#DEFINE DMAIOFULL PUSH AF \ LD A,(HB_RTCVAL) \ OUT (RTCIO),A \ POP AF
|
|
#ENDIF
|
|
;
|
|
#IF (!DMA_USEHALF)
|
|
#DEFINE DMAIOHALF \;
|
|
#DEFINE DMAIOFULL \;
|
|
#ENDIF
|
|
;
|
|
;==================================================================================================
|
|
; DMA INITIALIZATION CODE
|
|
;==================================================================================================
|
|
;
|
|
DMA_INIT:
|
|
CALL NEWLINE
|
|
PRTS("DMA: IO=0x$") ; announce
|
|
LD A, DMABASE
|
|
CALL PRTHEXBYTE
|
|
;
|
|
LD A,DMA_FORCE
|
|
out (DMABASE+1),a ; force ready off
|
|
;
|
|
DMAIOHALF
|
|
;
|
|
call DMAProbe ; do we have a dma?
|
|
jr nz,DMA_NOTFOUND
|
|
;
|
|
ld hl,DMACode ; program the
|
|
ld b,DMACode_Len ; dma command
|
|
ld c,DMABASE ; block
|
|
;
|
|
di
|
|
otir ; load dma
|
|
ei
|
|
|
|
xor a ; set status
|
|
ld (DMA_FAIL_FLAG),a ; ok to use dma
|
|
;
|
|
DMA_EXIT:
|
|
DMAIOFULL
|
|
|
|
ret
|
|
;
|
|
DMA_NOTFOUND:
|
|
push af
|
|
call PRTSTRD
|
|
.db " NOT PRESENT$"
|
|
|
|
#IF (DMA_FBACK)
|
|
call PRTSTRD
|
|
.db ". USING SOFTWARE$"
|
|
LD A,ERR_NOHW
|
|
LD (DMA_FAIL_FLAG),A
|
|
#ENDIF
|
|
pop af
|
|
jr DMA_EXIT
|
|
;
|
|
DMA_FAIL_FLAG:
|
|
.db DMA_FAIL_FLAG
|
|
;
|
|
;==================================================================================================
|
|
; DMA PROBE - WRITE TO ADDRESS REGISTER AND READ BACK
|
|
;==================================================================================================
|
|
;
|
|
DMAProbe:
|
|
ld a,DMA_RESET
|
|
out (DMABASE),a
|
|
ld a,%01111101 ; R0-Transfer mode, A -> B, start address follows
|
|
out (DMABASE),a
|
|
ld a,$cc
|
|
out (DMABASE),a
|
|
ld a,$dd
|
|
out (DMABASE),a
|
|
ld a,$e5
|
|
out (DMABASE),a
|
|
ld a,$1a
|
|
out (DMABASE),a
|
|
ld a,DMA_LOAD
|
|
out (DMABASE),a
|
|
;
|
|
ld a,DMA_READ_MASK_FOLLOWS ; set up
|
|
out (DMABASE),a ; for
|
|
ld a,%00011000 ; register
|
|
out (DMABASE),a ; read
|
|
ld a,DMA_START_READ_SEQUENCE
|
|
out (DMABASE),a
|
|
;
|
|
in a,(DMABASE) ; read in
|
|
ld c,a ; address
|
|
in a,(DMABASE)
|
|
ld b,a
|
|
;
|
|
xor a ; is it
|
|
ld hl,$ddcc ; a match
|
|
sbc hl,bc ; 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 c,DMABASE ; block
|
|
;
|
|
DMAIOHALF
|
|
;
|
|
di
|
|
otir ; load and execute dma
|
|
ei
|
|
;
|
|
ld a,DMA_READ_STATUS_BYTE ; check status
|
|
out (DMABASE),a ; of transfer
|
|
in a,(DMABASE) ; set non-zero
|
|
and %00111011 ; if failed
|
|
sub %00011011
|
|
|
|
DMAIOFULL
|
|
|
|
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 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 c,DMABASE ; block
|
|
;
|
|
DMAIOHALF
|
|
|
|
di
|
|
otir ; load and execute dma
|
|
ei
|
|
;
|
|
ld a,DMA_READ_STATUS_BYTE ; check status
|
|
out (DMABASE),a ; of transfer
|
|
in a,(DMABASE) ; set non-zero
|
|
and %00111011 ; if failed
|
|
sub %00011011
|
|
;
|
|
DMAIOFULL
|
|
|
|
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 c,DMABASE ; block
|
|
;
|
|
DMAIOHALF
|
|
;
|
|
di
|
|
otir ; load and execute dma
|
|
ei
|
|
;
|
|
ld a,DMA_READ_STATUS_BYTE ; check status
|
|
out (DMABASE),a ; of transfer
|
|
in a,(DMABASE) ; set non-zero
|
|
and %00111011 ; if failed
|
|
sub %00011011
|
|
;
|
|
DMAIOFULL
|
|
;
|
|
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
|
|
;==================================================================================================
|
|
;
|
|
#IF (0)
|
|
;
|
|
DMARegDump:
|
|
ld a,DMA_READ_MASK_FOLLOWS
|
|
out (DMABASE),a
|
|
ld a,%01111110
|
|
out (DMABASE),a
|
|
ld a,DMA_START_READ_SEQUENCE
|
|
out (DMABASE),a
|
|
;
|
|
in a,(DMABASE)
|
|
ld c,a
|
|
in a,(DMABASE)
|
|
ld b,a
|
|
call PRTHEXWORD
|
|
ld a,':'
|
|
call COUT
|
|
;
|
|
in a,(DMABASE)
|
|
ld c,a
|
|
in a,(DMABASE)
|
|
ld b,a
|
|
call PRTHEXWORD
|
|
ld a,':'
|
|
call COUT
|
|
;
|
|
in a,(DMABASE)
|
|
ld c,a
|
|
in a,(DMABASE)
|
|
ld b,a
|
|
call PRTHEXWORD
|
|
;
|
|
call NEWLINE
|
|
ret
|
|
#ENDIF
|