;MEMC_abort
;---------
;An attempt was made to write to the MEMC memory space
;
;Entry:
; DAV_r0 - memory block, containing R0, R1 ... R14, PC
; R1 - aborting address
;
;Exit:
; R0-R12 corrupt

#set IOC_Vinit  = 0			;MEMC registers
#set IOC_Vstart = 1
#set IOC_Vend   = 2
#set IOC_Cinit  = 3
#set IOC_Sstart = 4
#set IOC_SendN  = 5
#set IOC_Sptr   = 6
#set MEMC_CR    = 7
#set IOC_SendC  = 8

#set IOC_physical_screen = &2000000

					;IOMD registers
					;--------------
					;ref ARM7500 datasheet 13.3.51
#set IOMD_SDCURA   = &180		;Sound DMA Current A
#set IOMD_SDENDA   = &184		;Sound DMA End A
#set IOMD_SDCURB   = &188		;Sound DMA Current B
#set IOMD_SDENDB   = &18C		;Sound DMA End B
#set IOMD_SDCR     = &190		;Sound DMA Control (8 bit value)
#set IOMD_SDST     = &194		;Sound DMA Status  (8 bit value)

#set IOMD_CURSCUR  = &1C0		;Cursor DMA current
#set IOMD_CURSINIT = &1C4		;Cursor DMA init

#set IOMD_VIDEND   = &1D4		;Video DMA end
#set IOMD_VIDSTART = &1D8		;Video DMA start
#set IOMD_VIDINITA = &1DC		;Video DMA init
#set IOMD_VIDCR    = &1E0		;Video cursor DMA control
					;--------------
;ZZZ
;#set SAMLength     = 2048		;DMA length for dual bank VRAM
#set IOMD_DMA_S_Bit= 1 << 31		;Stop DMA transfer when end hit
#set IOMD_DMA_L_Bit= 1 << 30		;Only set if DMA buffer length is
					;1 DMA read.  ie 16 bytes long
#set IOMD_DMA_O_Bit= 1 << 2		;overrun bit
#set IOMD_DMA_I_Bit= 1 << 1		;interrupt occurred
#set IOMD_DMA_W_Bit= 1			;A/B buffer indication


;update_MEMC
;-----------
;updates MEMC CR
;
;Entry:
; R0 - MEMC value
; R2 - IOMD address if applicable
; R3 - MEMC_CR (7)
; R7 - MEMC_registers ptr
;
;Exit:
; R0 - corrupt

.update_MEMC
; #if compile_IOMD == 1			;disabled as Rockfall/Rotor/No Excuses
;   STMFD   R13!, {R14}			;turn off DMA - we emulate DMA
;   LDR     R14, [R7, R3, LSL #2]
;   EOR     R14, R14, R0
;   TST     R14, #1 << 11		;sound DMA enable
; #endif
 STR     R0, [R7, R3, LSL #2]		;store value
; #if compile_IOMD == 1
;   ANDNE   R0, R0, #1 << 11		;sound DMA state changed
;   MOVNE   R0, R0, LSR #11 - 5		;shift to IOMD bit
;   STRNEB  R0, [R2, #IOMD_SDCR]		;ARM7500 13-26
;   LDMFD   R13!, {PC}
; #endif
MOV     PC, R14




.MEMC_abort
 SUB     R1, R1, #&3600000
 MOV     R3, R1, LSR #17		;R3 = MEMC register

 ADR     R7, MEMC_registers		;R7 = our MEMC register copy

 MOV     R0, R1, LSL #(32 - 17)
 MOV     R0, R0, LSR #(32 - 17) - 2	;R0 = corrected value (was /16)
 BIC     R0, R0, #%1111			;clear ignored bits


 ;References RO source for the following:
 ;/Sources/Video/HWSupport/VIDC20Video/s/GVect  GV_SetDMAAddress
 ;RiscPCTRM1-10 / 1-15

#if compile_IOMD == 1
 LDR     R2, IOMD_addr			;R2 = IOMD chip address
#endif
 ADD     PC, PC, R3, LSL #2		;jump to relevent code
 NOP
 B       _video
 B       _video
 B       _video
 B       _cinit
 B       _sstart
 B       _sendn
 B       _sptr				;a write to sptr copies sstart to sptr
					;sptr is the current Sound DMA pointer
					;used by Rockfall at 15F20
 ADR     R14, AbortI_skip
 MOV     R0, R0, LSR #2			;not an address, so correct register
 B       update_MEMC

#if compile_GPU == 1
._video					;GPU
 LDR     R2, DA2_address		;non-IOMD - track change
 ADD     R0, R2, R0			;convert to logical address
 B       _P1
#endif
._cinit					;Mouse pointer DMA
#if compile_IOMD == 1
 STR     R0, [R2, #IOMD_CURSINIT]
 B       _P1
#endif

._sendn					;Next Sound Buffer End (set 1st)
._sstart				;Next Sound Buffer Start (set 2nd)
 AND     R6, R0, #&7F000		;physical address page
 AND     R0, R0, #&00FF0		;R0=offset in page of start
 CMP     R6, #&78000			;1F00000 to 1F08000?
 SUBHS   R6, R6, #&78000		;YES
 ADDHS   R6, R6, #&1F00000
 BHS     _P0

 LDR     R1, DA2_size			;work out the logical address
 CMP     R6, R1				;is it in screen memory?
 ADDLS   R6, R6, #IOC_physical_screen	;YES, add current screen address
 MOVHI   R12, #11			;NO
 BHI     report_unimplemented		;report ADFF500B

 ._P0
 ORR     R0, R0, R6

 ._P1
 STR     R0, [R7, R3, LSL #2]		;store value
B       AbortI_skip

; No Excuses	Fire	3B710 > 3C980 (1280)
;               Walk	3B3C0 > 3B700 (350)
;			3B070 > 3B3B0 (350)
; Rockfall	Silence	14000 > 14400 (410)
;		Collect 18430 > 18E50 (A30)
;		Drop	16390 > 169F0 (670)
; Zelanites     ?

._sptr					;force a sound buffer swap
 LDR     R0, [R7, #IOC_Sstart << 2]	;get start
 LDR     R1, [R7, #IOC_SendN << 2]	;get end
 STR     R0, [R7, #IOC_Sptr << 2]
 STR     R1, [R7, #IOC_SendC << 2]
 B       AbortI_skip			;exit back to user code




#if compile_IOMD == 1
._video					;VIDC20
;ZZZ
 MOV     R10, #15			;DMA alignment
; LDR     R8, vram_available
; MOV     R9, #16			;DRAM, DMA length
; CMP     R8, #1024*1024
; MOVEQ   R9, #SAMLength >> 1		;1MB VRAM
; MOVHI   R9, #SAMLength			;2MB VRAM
					;R9 = DMA length
 LDR     R9, DA2_address
 LDR     R1, hwd_framestore
 ADD     R9, R9, R0			;R9=logical address
 ADD     R0, R0, R1			;R0=physical addrss
 STR     R9, [R7, R3, LSL #2]		;store value

;ZZZ
; SUB     R10, R9, #1			;alignment for Vstart and Vend
 BIC     R1, R1, R10			;align
 ADD     PC, PC, R3, LSL #2
 NOP
 B       _vinit
 B       _vstart
._vend
;ZZZ
; TEQ     R9, #16			;DRAM mode?
; BEQ     _skip_VRAM_restrictions	;YES
;
; LDR     R1, [R7, #IOC_Vstart << 2]
; BIC     R1, R1, R10			;align to half-SAM length
; SUB     R3, R0, R1			;R1=size of buffer
; BIC     R3, R3, R10, LSL #1		;align to SAM length
; ADD     R0, R1, R3			;new buffer length
; SUB     R0, R0, R9			;reduce end by half-SAM length
;
; ._skip_VRAM_restrictions
 LDR     R1, [R7, #IOC_Vinit << 2]
 TEQ     R1, R9				;Vinit = Vend?
 LDR     R1, [R2, #IOMD_VIDINITA]
 BIC     R1, R1, #%101 << 29
 MOV     R3, R1
 ORREQ   R1, R1, #IOMD_DMA_L_Bit	;YES, set L bit
 BICNE   R1, R1, #IOMD_DMA_L_Bit	;NO, clear L bit
 TEQ     R1, R3				;did Vinit change?
 STRNE   R1, [R2, #IOMD_VIDINITA]	;YES

 STR     R0, [R2, #IOMD_VIDEND]
B       AbortI_skip			;exit back to user code

._vstart
 BL      flush_screen			;flush the screen cache
 STR     R0, [R2, #IOMD_VIDSTART]
 B       AbortI_skip			;exit back to user code

._vinit
 LDR     R1, [R7, #IOC_Vend << 2]
 TEQ     R1, R9				;Vinit = Vend?
 ORREQ   R0, R0, #IOMD_DMA_L_Bit	;YES, set L bit
 BICNE   R0, R0, #IOMD_DMA_L_Bit	;NO, clear L bit
 STR     R0, [R2, #IOMD_VIDINITA]
B       AbortI_skip			;exit back to user code
#endif
