;page_zero_abort
;---------------
;An attempt was made to read/write to <&8000
;
;Entry:
; DAV_r0 - memory block, containing R0, R1 ... R14, PC
; R1 - aborting address

.page_zero_abort
 #if High_Vectors == 0 AND JIT_debug == 1
   ADR     R7, jit_page_zero_aborts
   LDR     R0, [R7, #0]
   ADD     R0, R0, #1
   STR     R0, [R7, #0]
 #endif

 LDR     R0, DAV_abort			;the faulting address

 MOV     R7, R1				;R7=aborting address
 LDR     R0, [R0, #0]			;R0=faulting instruction
 ADR     R6, DAV_r0			;R6=register stack
                 ;%100PUSWL		;STM/LDM instruction
 AND     R1, R0, #%11100001 << 20
 #if High_Vectors == 0 AND ZeroPain == 0
   TEQ     R1,   #%10000001 << 20	;LDMxx Rx, {<reglist>} ?
   BEQ     _pass_to_ZeroPain		;YES
 #endif
 #if High_Vectors == 0 AND ZeroPain == 1
   TEQ     R1,   #%10000001 << 20	;LDMxx Rx, {<reglist>} ?
   BEQ     AbortI_skip			;YES, fail silently
 #endif
 TEQ     R1,     #%10000000 << 20	;STMxx Rx, {<reglist>} ?
 BNE     _not_STM			;YES

._STM
 BIC     R7, R7, #%11			;word align
 BIC     R0, R0, #1 << 22		;force words in translate_page_zero_write
					;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   R2, [R6]			;C set if register used
   BLCS    translate_page_zero_write	;|+   perform the translation
   ADD     R6, R6, #4			;go to next register
   ADD     R7, R7, #4			;go to next zero page location
   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


#if High_Vectors == 0 AND ZeroPain == 0
._pass_to_ZeroPain
 LDR     R7, [R6, #4 * 7]		;restore R7
 LDR     R6, [R6, #4 * 6]		;restore R6
 B       pass_Abort_to_OS - 4		;pass to ZeroPain
#endif


._not_STM
                 ;%01IPUBWL		;STR/LDR instruction
 AND     R1, R0, #%11000001 << 20
 TEQ     R1,   #%01000001 << 20		;LDR Rd, [Rn ...] ?
 #if High_Vectors == 0 AND ZeroPain == 0
   BEQ     _pass_to_ZeroPain		;YES
 #endif
 #if High_Vectors == 0 AND ZeroPain == 1
   BEQ     AbortI_skip			;YES, fail silently
 #endif
 TEQ     R1,     #%01000000 << 20	;STR Rd, [Rn ...] ?
 MOVNE   R12, #&15			;ADFF5015
 BNE     report_unimplemented		;either SWP or ADFFS bug

 ADR     R14, AbortI_skip		;exit back to user code
._STR					;R0 contains instruction to decode
 AND     R1, R0, #%1111 << 12		;R1=Rd << 12
 LDR     R2, [R6, R1, LSR #12 - 2]	;R0=value to write

 #if High_Vectors == 0 AND Unaligned_Support == 1
   TST     R0, #1 << 22			;word or byte?
   BICEQ   R7, R7, #%11			;word align
 #endif
 B       translate_page_zero_write	;perform the translation




;translate_page_zero_read
;------------------------
;translates reads in page zero to suitable values
;called from the JIT, so needs to exit back via i_instruction_handled

;Entry:
; R0 - original instruction
; R1 - Rd                   (if Unaligned_Support == 0)
; R3 - register dump        (if Unaligned_Support == 0)
; R7 - address being read
;
; R1, R2, R6, R8-R12 free to use (if Unaligned_Support == 0)
; R1, R2, R8-R12 free to use (if Unaligned_Support == 1)
;
;Exit: (if Unaligned_Support == 1)
; R2 - value

ALIGN   32, 4
.translate_page_zero_read
 LDR     R2, page_zero_EnvString
 SUB     R2, R7, R2
 CMP     R2, #&100			;EnvString?
 BLO     i_copy_instruction		;YES

 LDR     R2, page_zero_EnvTime
 SUB     R2, R7, R2
 CMP     R2, #&5			;EnvTime?
 BLS     i_copy_instruction		;YES

 TEMP    R4
 BIC     R6, R7, #%11			;word align

 TEQ     R6, #&18			;IRQ hardware vector?
 LDREQ   R2, jit_managed_IRQ_entry
 BEQ     _read_handled

 TEQ     R6, #&100			;IRQ1V?
 #if High_Vectors == 0 AND compile_RO == 400
   BEQ     i_copy_instruction
 #endif
 #if High_Vectors == 0 AND compile_RO > 400
   LDREQ   R2, jit_managed_ldr_pc_r13_2
   BEQ     _read_handled
 #endif

 TEQ     R6, #&10C0			;VDU screen start address (VDU var 148)
 BEQ     _VDU_screenstart

 TEQ     R6, #&1584			;VIDCControlCopy
 LDREQ   R2, VIDC1_CR
 BEQ     _read_handled

 TEQ     R6, #&1588			;VertAdjust
 LDREQ   R2, page_zero_VertAdjust
 BEQ     _read_handled

 TEQ     R6, #&1474			;HSWRSoftCopy
 LDREQ   R2, page_zero_HSWRSoftCopy
 BEQ     _read_handled

 TEQ     R6, #&10D4			;CursorFudgeFactor
 LDREQ   R2, page_zero_CursorFudgeFactor
 BEQ     _read_handled

 #if High_Vectors == 0 AND Private_CLib == 1
   EORS    R4, R6, #&FEC
   LDREQ   R2, private_RISCOSLibWord
   LDREQ   R2, [R2, #0]
   BEQ     _read_handled

   TEQ     R6, #&FF0
   LDREQ   R2, private_CLibWord
   LDREQ   R2, [R2, #0]
   BEQ     _read_handled
 #endif

 LOCK    R4

 #if High_Vectors == 0 AND ZeroPain == 0
   LDR     R12, [R3, #15 * 4]
   SUB     R12, R12, #8			;correct PC prefetch
   STR     R12, [R3, #15 * 4]
   MOV     R12, #&11			;ADFF5011
 B       report_unimplemented		;report unknown address
 #endif
 #if High_Vectors == 0 AND ZeroPain == 1
   MOV     R2, #0			;silently fail
; B       _read_handled			;fall-thru
 #endif



 ;Entry:
 ; R0 - original instruction
 ; R1 - Rd
 ; R2 - value to return
 ; R7 - address being read
 ; R13 - stacked R0-R7
 ; have to switch CPU mode to alter R8-R14

._read_handled
 MOV     R5, R14			;preserve R14
 BL      abort_update_register		;update Rd
 MOV     R14, R5			;preserve R14

					;update any post index before skip
 TST     R0, #1 << 21			;LDR Rd, [Rn, xx]! ?
 BNE     _write_back			;YES

 TST     R0, #1 << 24			;LDR Rd, [Rn], xx ?
 BNE     _exit				;NO, pre-indexed
					;YES, post-indexed
 AND     R1, R0, #%1111 << 16		;R1 = Rn
 MOV     R1, R1, LSR #8
					; ***** decode Operand 2 ******
 TST     R0, #1 << 25			;LDR Rd, [Rn, #{+/-}<immed_12>] ?
 BNE     _xTR_shift			;NO, LDR Rd, [Rn, {+/-}Rm{,<shift>}]

				;:LDR Rd, [Rn], #{+/-}<immed_12>
				;:LDR Rd, [Rn, #{+/-}<immed_12>]!
 MOV     R4, R0, LSL #31 - 11		;R4 = offset in bits 31..20
 TST     R0, #1 << 23			;U (Up / Down)
 SUBEQ   R7, R7, R4, LSR #31 - 11	;LDR Rd, [Rn, #-<immed_12>]
 ADDNE   R7, R7, R4, LSR #31 - 11	;LDR Rd, [Rn, #+<immed_12>]
 B       _write_back
				;Reference: ARM710VE-25
				;NOTE: STR Rd, [Rn, {+/-}Rm, <shift_type> Rx]!
				;      is not a valid instruction
				;:LDR Rd, [Rn], {+/-}Rm {, <shift> #<immed_5>}
 ._xTR_shift			;:LDR Rd, [Rn, {+/-}Rm {, <shift> #<immed_5>}]!
 ADR     R3, DAV_r0			;register dump
 AND     R5, R0, #%1111			;R5 = Rm
 LDR     R2, [R3, R5, LSL #2]		;R2 = value of Rm
 AND     R6, R0, #%11111 << 7
 MOV     R6, R6, LSR #7			;R6 = #<immed_5>

 ANDS    R5, R0, #%11 << 5		;R5 = shift type
 MOVEQ   R4, R2, LSL R6			;R4=Rm, LSL #<immed_5>
 BEQ     _xTR_shift_decoded
 CMP     R5, #%10 << 5
 MOVLT   R4, R2, LSR R6			;R4=Rm, LSR #<immed_5>
 MOVEQ   R4, R2, ASR R6			;R4=Rm, ASR #<immed_5>
 BLS     _xTR_shift_decoded
				;Reference: ARM710VE-25
				;:LDR Rd, [Rn, {+/-}Rm, ROR #<immed_5>/RRX]!
 TST     R0, #%11111 << 7		;is it RRX?
 MOVNE   R4, R2, ROR R6			;NO, Rm, ROR #n
 BNE     _xTR_shift_decoded
				;:LDR Rd, [Rn, {+/-}Rm, RRX]!
 MRS     R4, SPSR			;get CPSR
 MOVS    R4, R4, LSL #3			; |  shift carry into C
 MOV     R4, R2, RRX			; |+ Rm, RRX

 ._xTR_shift_decoded
 TST     R0, #1 << 23			;U (Up / Down)
 ADDNE   R7, R7, R4			;Rm, <shift> #<immed_5>
 SUBEQ   R7, R7, R4			;-Rm, <shift> #<immed_5>
					;fall-thru to _write_back

 ._write_back				;need to set Rn=R7
 AND     R1, R0, #%1111 << 16		;R1 = Rn

 MOV     R5, R14			;preserve R14
 MOV     R1, R1, LSR #8
 MOV     R2, R7				;R2 = value
 MOV     R7, #0				;R7 = no rotation
 BL      abort_update_register
 MOV     R14, R5			;preserve R14

 ._exit
 SUB     R2, R14, #4			;skip instruction
 STR     R2, [R13, #UND_exit_PC]	;update exit PC
B       i_instruction_handled_no_codelet




._VDU_screenstart
   STMFD   R13!, {R0-R1, R3, R12, R14}
   MVN     R0, #0
   STR     R0, [R13, #-4]!
   MOV     R0, #148
   STR     R0, [R13, #-4]!
   MOV     R0, R13
   MOV     R1, R13
   MRS     R3, CPSR_all
   BIC     R12, R3, #%1111
   ORR     R12, R12, #%11		;switch to SVC
   MSR     CPSR_all, R12
   NOP
   ADR     R12, _SPSR
   BL      hv_pre_SWI_veneer		;pass next SWI to our vector handler
   SWI     XOS_ReadVduVariables
   BL      dontexit_SWI_veneer
   MSR     CPSR_all, R3			;switch back to ABT
   #if High_Vectors == 0 AND compile_IOMD == 1
     NOP
   #endif
   LDR     R2, [R13], #8
   LDMFD   R13!, {R0-R1, R3, R12, R14}
   B       _read_handled

 ._SPSR	DBD 4




;abort_update_register
;---------------------
;Updates a register value

;Entry:
; R1 - register
; R2 - value to write
; R7 - rotational offset in lower two bits
;
;Exit:
; R1, R2, R3, R4 - corrupted

.abort_update_register
 ANDS    R3, R7, #%11			;get rotation offset
 MOVNE   R3, R3, LSL #3			; |    *8
 MOVNE   R2, R2, ROR R3			; |    shift value to bottom 8 bits

 TST     R0, #1 << 22			;word or byte?
 ANDNE   R2, R2, #&FF			;word, mask down to byte

 CMP     R1, #8				;is it a register we have stacked?
 STRLO   R2, [R13, R1, LSL #2]		;YES
 MOVLO   PC, R14			; +- and exit

 SUB     R1, R1, #8			;change R8 thru R14

 MRS     R3, SPSR			;get original CPU state
 TST     R3, #%1111			;is abort in User mode?
 BNE     _not_User			;NO

 STR     R2, _tmp			;YES, change user register
 ADR     R3, _tmp
 #if compile_IOMD == 1
   ADD     PC, PC, R1, LSL #4
 #endif
 #if compile_IOMD == 0
   ADD     PC, PC, R1, LSL #3
 #endif
 NOP
 MOV     R8, R2				;LDR R8, ...
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
   NOP
 #endif
 MOV     R9, R2				;LDR R9, ...
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
   NOP
 #endif
 MOV     R10, R2			;LDR R10, ...
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
   NOP
 #endif
 MOV     R11, R2			;LDR R11, ...
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
   NOP
 #endif
 MOV     R12, R2			;LDR R12, ...
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
   NOP
 #endif
 LDMIA   R3, {R13}^			;LDR R13, ...
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
 #endif
 LDMIA   R3, {R14}^			;LDR R14, ...
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 MOV     PC, R14
 #if compile_IOMD == 1
   NOP
 #endif
 B       _report			;LDR PC, ... unsupported

 ._tmp DCD 0

 ._not_User
 MRS     R4, CPSR
 ORR     R3, R3, #%11 << 6		;disable IRQ/FIQ
 MSR     CPSR_all, R3			;switch to faulting mode
 #if High_Vectors == 0 AND compile_IOMD == 1
   NOP
 #endif
 ADD     PC, PC, R1, LSL #3		;change non-USER register
 NOP
 MOV     R8, R2				;LDR R8, ...
 B       _P2
 MOV     R9, R2				;LDR R9, ...
 B       _P2
 MOV     R10, R2			;LDR R10, ...
 B       _P2
 MOV     R11, R2			;LDR R11, ...
 B       _P2
 MOV     R12, R2			;LDR R12, ...
 B       _P2
 MOV     R13, R2			;LDR R13, ...
 B       _P2
 MOV     R14, R2			;LDR R14, ...
 B       _P2
 B       _report			;LDR PC, ... unsupported

 ._P2
 MSR     CPSR_all, R4			;switch back to UND32
 #if High_Vectors == 0 AND compile_IOMD == 1
   NOP
 #endif
MOV     PC, R14

 ._report
 MOV     R12, #9			;report unimplemented
B       report_unimplemented_PC_plus_8	;ADFF5009




;translate_page_zero_write
;Entry:
; R0 - instruction
; R2 - value to write
; R7 - aborting address (word aligned if STM or STR)
;
;Exit:
; R5, R6 - must be preserved
; R7-R14 - preserved

ALIGN   32, 4
.translate_page_zero_write

 #if High_Vectors == 0 AND compile_RO == 400
   LDR     R1, DAV_abort		;the faulting address
   CMP     R1, #jit_slotsize		;is it RISCOS?
   BHS     _proxy_write			;YES, proxy the write
 #endif

 TEMP    R1
 TEQ     R7, #&18			;IRQ vector
 BEQ     _IRQ
 CMP     R7, #&100			;IRQ1V
 BEQ     _IRQ1V
 MOVLO   PC, R14			;FIQ routine?  ignore it

 LDR     R3, page_zero_EnvString	;could be HIGH, so must come before
 SUB     R3, R7, R3			;scratch space check
 CMP     R3, #&100			;EnvString?
 BLO     _proxy_write			;YES

 #if compile_RO > 400
   LDR     R3, page_zero_module_cmdline	;will be HIGH, so must come before
   CMP     R3, #0			;..scratch space check.  is it set?
   SUBNE   R3, R7, R3			;YES,
   CMPNE   R3, #&100			; |   Module commandline?
   BLO     _proxy_write			; |+  YES
 #endif

 CMP     R7, #&4000			;scratch space
 BHS     _proxy_write

 CMP     R7, #&1C			;hardware vector?
 MOVLO   R12, #&16
 BLO     report_unimplemented		;YES, report it ADFF5016

 TEQ     R7, #&9B2			;VULAcopy (Oh No, More Lemmings!)
 MOVEQ   PC, R14			;ignore it

 #if High_Vectors == 0 AND Private_CLib == 1
   EORS    R1, R7, #&FEC
   LDREQ   R7, private_RISCOSLibWord
   STREQ   R2, [R7, #0]
   MOVEQ   PC, R14

   TEQ     R7, #&FF0
   LDREQ   R7, private_CLibWord
   STREQ   R2, [R7, #0]
   MOVEQ   PC, R14
 #endif
 LOCK    R1

#if High_Vectors == 0 AND ZeroPain == 0
 MOV     R12, #&15			;ADFF5015
B       report_unimplemented		;report unknown address
#endif
#if High_Vectors == 0 AND ZeroPain == 1
MOV   PC, R14				;fail silently
#endif


 ._proxy_write
 TST     R0, #1 << 22			;word or byte?
 STRNEB  R2, [R7, #0]			;byte, proxy the write
 STREQ   R2, [R7, #0]			;word, proxy the write

 CMP     R7, #jit_code_start		;in JIT space?
 LDRLO   R2, branch_to_jit		;YES, Hypervisor entry instruction
 ADDLO   R1, R7, #jit_code_start	; |
 BICLO   R1, R1, #%11			; | align write
 STRLO   R2, [R1, #0]			; |+ reset JIT space
MOV   PC, R14


 ._IRQ
 AND     R1, R2, #%1111 << 24
 TEQ     R1,     #%1010 << 24		;is it a B instruction?
 MOVNE   R12, #1
 BNE     report_unimplemented		;NO, report it ADFF5001

 TEMP    R1
 LDR     R3, jit_managed_IRQ_entry
 TEQ     R2, R3				;are we releasing the IRQ?
 MOVEQ   R0, #0				;YES
 STREQ   R0, hypervised_IRQv
 MOVEQ   PC, R14

 MOV     R2, R2, LSL #8			;correct address
 MOV     R2, R2, ASR #6			;sign extend
 ADD     R2, R2, #&18 + 8		;correct for offset
 CMP     R2, #jit_appspace_end
 MOVHS   R12, #1
 BHS     report_unimplemented		;report it ADFF5001

 ADD     R2, R2, #jit_code_start
 STR     R2, hypervised_IRQv
MOV     PC, R14


 ._IRQ1V
 #if High_Vectors == 0 AND compile_RO == 400
   STR     R2, [R7]			;proxy the write
 #endif
 #if High_Vectors == 0 AND compile_RO > 400
   LDR     R3, jit_managed_ldr_pc_r13_2	;jit_managed_mov_pc_r14
   TEQ     R2, R3			;are we releasing the IRQ?
   MOVEQ   R0, #0			;YES
   STREQ   R0, hypervised_IRQ1V
   MOVEQ   PC, R14

   CMP     R2, #jit_appspace_end
   ADDLO   R2, R2, #jit_code_start	;correct address
   STR     R2, hypervised_IRQ1V		;our hypervisor will handle it
 #endif
MOV     PC, R14
 LOCK    R1
