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

ALIGN   32, 4
.VIDC20_abort				;decode instruction and translate to
					;GPU
 ADR     R12, VARS
 ADR     R6, DAV_r0			;R6 = register stack

 LDR     R0, DAV_abort			;the faulting address
 LDR     R0, [R0, #0]			;load the faulting instruction in R0
                 ;%100PUSWL		;STM instruction
 AND     R1, R0, #%11100001 << 20
 TEQ     R1,     #%10000000 << 20	;STMxx Rx, {Rn...Rn} ?
 BNE     _not_STM			;NO

					;R0 bits 15...0 contain registers
					;..written
 MOV     R5, R0, LSL #17		;reduce R5 to registers being written
 MOVS    R5, R5, LSR #18		;stripping off PC and leaving R0 in CS
 ._STM_loop
   LDRCS   R0, [R6]			;C set if register used
   BLCS    translate_VIDC20_to_GPU	;|+   perform the translation
   ADD     R6, R6, #4			;go to next register
   MOVS    R5, R5, LSR #1		;are there any more registers?
 BNE     _STM_loop			;loop until we've handled all registers
 BCS     _STM_loop			;catch the last register in C

B       AbortI_skip			;exit back to user code


 ._not_STM
                 ;%01IPUBWL		;STR instruction
 AND     R1, R0, #%11000001 << 20
 TEQ     R1,     #%01000000 << 20	;STR Rd, [Rn ...] ?
 BNE     AbortI_skip			;NO

					;R0 contains instruction to decode
 AND     R1, R0, #%1111 << 12		;R0 = R2 << 12

 LDR     R0, [R6, R1, LSR #12 - 2]	;R0 = value written to VIDC
 ADR     R14, AbortI_skip		;return address
;B       translate_VIDC20_to_GPU	;perform the translation
					;fall-thru to translate_VIDC20_to_GPU



;translate_VIDC20_to_GPU
;-------------------------
;translate a write to VIDC20 to the equivalant GPU change
;
;Entry:
; R0 = value being written to VIDC
; R12 = pointer to VARS
;
; The following registers are free to use: R0-R4, R8-R12
					;DO NOT ALIGN, fall-thru code above
.translate_VIDC20_to_GPU
 LDR     R1, [R12, #emulate_RISCOS - VARS]	;what are we emulating
 CMP     R1, #&350 << 8			;RO3.11 or lower
 BLO     translate_VIDC1_to_VIDC20	;YES

#if compile_IOMD == 1
 LDR     R1, [R12, #VIDC20_addr - VARS]	;proxy write on IOMD
 STR     R0, [R1]
MOV     PC, R14
#endif

#if compile_GPU == 1
 MOV     R1, R0, LSR #24		;R1 = VIDC command
 BIC     R0, R0, #&FF << 24		;R0 = VIDC value

 TST     R1, #&F0			;palette entry?
 BEQ     _VIDC20_palette		;YES

 CMP     R1, #VIDC20_VPAR		;is it palette address register?
 STREQB  R0, _current_VIDC20_VPAR	;YES
 MOVEQ   PC, R14

 CMP     R1, #VIDC20_BCR		;is it border colour?
 BEQ     _VIDC20_border_palette		;YES
 MOVLO   PC, R14			;ignore reserved and LCD

 CMP     R1, #VIDC20_HCR		;is it cursor palette?
 BLO     _VIDC20_cursor_palette		;YES

 CMP     R1, #VIDC20_HIR		;is it a horizontal command?
 BLS     _VIDC20_horizontal		;YES

 CMP     R1, #VIDC20_VCR		;ignore test registers
 MOVLO   PC, R14

 CMP     R1, #VIDC20_VCER		;is it a vertical command?
 BLS     _VIDC20_vertical		;YES

MOV     PC, R14				;unknown command, exit



;translate palette commands
;--------------------------
;VIDC20-17

._current_VIDC20_VPAR  DCD 0


._VIDC20_palette
 LDRB    R1, _current_VIDC20_VPAR
 ADR     R8, GPU_palette
 STR     R0, [R8, R1, LSL #2]		;store the palette entry

 ADD     R1, R1, #1			;increase pointer
 STRB    R1, _current_VIDC20_VPAR
MOV     PC, R14




;translate border and cursor colour commands
;-------------------------------------------
;VIDC20-19

._VIDC20_cursor_palette
 AND     R1, R1, #%11 << 4		;mask logical colour and check for 1+

 ADR     R8, Cursor_palette
 STR     R0, [R8, R1, LSR #2]		;store palette entry

._VIDC20_border_palette
MOV     PC, R14




;translate horizontal commands
;-----------------------------
;VIDC20-19

._VIDC20_horizontal
 ADD     R2, R12, #(vidc20_regs - (VIDC20_HCR << 2)) - VARS

 TEQ     R1, #VIDC20_HCSR
 BICNE   R0, R0, #%1			;bit 0 is always zero
 TEQ     R1, #VIDC20_HCR
 BICEQ   R0, R0, #%11			;bits 0/1 are always zero

 LDR     R3, [R2, R1, LSL #2]
 TEQ     R0, R3				;did the value change?
 MOVEQ   PC, R14			;NO, exit
 STR     R0, [R2, R1, LSL #2]		;store a copy of the VIDC20 register

 #if compile_GPU == 1 AND use_overlay == 1
   TEMP    R4
   CMP     R1, #VIDC20_HSWR
   CMPNE   R1, #VIDC20_HCSR
   STRLO   R13, HAL_vidc_list_dirty	;update GPU on next VSync
   LOCK    R4
 #endif

 TEQ     R1, #VIDC20_HDSR
 TEQNE   R1, #VIDC20_HDER
 MOVNE   PC, R14

 LDR     R3, [R2, #VIDC20_HDSR << 2]	;HDSR
 LDR     R4, [R2, #VIDC20_HDER << 2]	;HDER
 SUBS    R1, R4, R3
 MOVMI   PC, R14			;exit if negative

 LDR     R2, [R12, #VIDC20_width - VARS]
 TEQ     R1, R2				;has the value changed?
 STRNE   R1, [R12, #VIDC20_width - VARS]	;YES, update
 TEMP    R0
 STRNE   R1, HAL_vidc_list_dirty	; |+ and update GPU on next VSync
 LOCK    R0
MOV     PC, R14




;translate vertical commands
;---------------------------
;VIDC20-22

._VIDC20_vertical
 #if compile_IOMD == 1
   MOV     R3, R0
   CMP     R1, #VIDC20_VBSR		;VBSR or above?
   LDRHSB  R2, [R12, #TV_offset - VARS]	;YES, adjust for *TV
   SUBHSS  R0, R0, R2			; |
   MOVMI   R0, R3			; |+ went negative, use original value
 #endif

; ADD    R0, R0, #2			;correct value (N+2)
					;NOTE VIDC20 TRM is wrong stating (N-1)

 ADD     R2, R12, #(vidc20_regs - (VIDC20_HCR << 2)) - VARS
 LDR     R3, [R2, R1, LSL #2]
 TEQ     R0, R3				;did the value change?
 MOVEQ   PC, R14			;NO, exit
 STR     R0, [R2, R1, LSL #2]		;store a copy of the VIDC20 register

 #if compile_GPU == 1 AND use_overlay == 1
   TEMP    R4
   CMP     R1, #VIDC20_VSWR
   CMPNE   R1, #VIDC20_VCSR
   STRLO   R13, HAL_vidc_list_dirty	;update GPU on next VSync
   LOCK    R4
 #endif

 #if compile_GPU == 1
   TEQ     R1, #VIDC20_VCSR		;VCSR?
   TEQNE   R1, #VIDC20_VCER		;or VCER?
   BNE     _skip_GPU_cursor
   LDR     R0, [R2, #VIDC20_VCSR << 2]
   LDR     R1, [R2, #VIDC20_VCER << 2]
   SUBS    R1, R1, R0			;is there a cursor?
   MOVGT   R1, #1			;YES
   MOVLE   R1, #0			;NO
   STR     R1, [R12, #Cursor_state - VARS]
   ._skip_GPU_cursor
 #endif

 TEQ     R1, #VIDC20_VDSR
 TEQNE   R1, #VIDC20_VDER
 MOVNE   PC, R14

 LDR     R0, [R2, #VIDC20_VDSR << 2]
 LDR     R1, [R2, #VIDC20_VDER << 2]
 SUBS    R1, R1, R0			;R1 = display height
 MOVMI   PC, R14

 LDR     R2, [R12, #VIDC20_height - VARS]
 TEQ     R1, R2				;has the value changed?
 STRNE   R1, [R12, #VIDC20_height - VARS]	;YES, update
 TEMP    R0
 STRNE   R1, HAL_vidc_list_dirty	; |+ and update GPU on next VSync
 LOCK    R0
MOV   PC, R14
#endif
