;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_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
					;--------------

#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
 STR     R0, [R7, R3, LSL #2]		;store value

 #if compile_IOMD == 1
   AND     R0, R0, #1 << 11		;sound DMA enable
   MOV     R0, R0, LSR #11 - 5		;shift to IOMD bit
   STRB    R0, [R2, #IOMD_SDCR]		;ARM7500 13-26
 #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


; 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)

._sendn
; MOV     R1, #0
; STR     R1, [R7, #IOC_Sstart << 2]	;clear start

._sstart				;SendN is written before Sstart
 BL      _physical_to_logical		;convert address
 STR     R0, [R7, R3, LSL #2]		;store value

._sptr
 LDR     R0, [R7, #IOC_Sstart << 2]	;get start
 TEQ     R0, #0
 LDRNE   R4, [R7, #IOC_SendN << 2]	;get end
 TEQNE   R4, #0
 BEQ     AbortI_skip			;NO

 STR     R0, [R7, #IOC_Sptr << 2]	;set Sptr
 MOV     R0, #0
 STR     R0, [R7, #IOC_Sstart << 2]	;clear Sstart
B       AbortI_skip			;exit back to user code


._physical_to_logical
 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
MOV     PC, R14

#if compile_GPU == 1
._cinit					;GPU Mouse pointer
 BL      _physical_to_logical		;convert address
 STR     R0, [R7, R3, LSL #2]		;store value
B       AbortI_skip			;exit back to user code


._video					;GPU
 LDR     R2, DA2_address		;non-IOMD - track change
 ADD     R0, R2, R0			;convert to logical address

 STR     R0, [R7, R3, LSL #2]		;store value
B       AbortI_skip			;exit back to user code
#endif


#if compile_IOMD == 1
._cinit					;VIDC20 Mouse pointer
 STR     R0, [R7, R3, LSL #2]		;store value
 STR     R0, [R2, #IOMD_CURSINIT]
B       AbortI_skip			;exit back to user code


._video					;VIDC20
 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     R1, hwd_framestore
 ADD     R0, R0, R1			;add on our screen address
 STR     R0, [R7, R3, LSL #2]		;store value

 TEQ     R3, #IOC_Vinit
 BEQ     _vinit

 SUB     R10, R9, #1			;alignment for Vstart and Vend

 TEQ     R3, #IOC_Vend			;Vend?
 BEQ     _vend				;NO

 TEQ     R3, #IOC_Vstart		;Vstart?
 BICEQ   R0, R0, R10			;align to half-SAM length
 STREQ   R0, [R2, #IOMD_VIDSTART]
 #if JIT_debug == 1 AND compile_IOMD == 1
   TEMP    R3
   STREQ   R0, MEMC_Vinit
   LOCK    R3
 #endif
 BEQ     AbortI_skip			;exit back to user code

B       report_abort			;report all others

 ._vinit
 LDR     R1, [R7, #IOC_Vend << 2]
 BIC     R1, R1, R10			;align to half-SAM length
 TEQ     R0, R1				;Vinit = Vend?
 ORREQ   R0, R0, #IOMD_DMA_L_Bit	;YES, set L bit
 STR     R0, [R2, #IOMD_VIDINITA]
B       AbortI_skip			;exit back to user code


 ._vend
; 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]
 MOV     R3, R1
 TEQ     R1, R0				;Vinit = Vend?
 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
#endif

