;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 == 1 AND JIT_debug == 1
   ADR     R8, jit_page_zero_aborts
   LDR     R0, [R8, #0]
   ADD     R0, R0, #1
   STR     R0, [R8, #0]
 #endif

 LDR     R14, DAV_abort			;the faulting address
 CMP     R14, #&4000			;branch into Page Zero?
 MOVLO   R12, #&10			;ADFF5010
 BLO     report_unimplemented		;report it

 ADR     R8, DAV_r0			;R8=register stack
 MOV     R10, R1			;R10=aborting address
 LDR     R0, [R14], #4			;R0=faulting instruction
 STR     R14, [R8, #15 * 4]		;update PC

 ANDS    R1, R0, #%111 << 25		;SWP or LDREX/STREX on ARMv5+?
 BEQ     JIT_PZ_SWP			;YES
 CMP     R1,     #%100 << 25		;is it STM?
 BHI     JIT_PZ_STF			;NO, %110 : STF
 BNE     JIT_PZ_STR			;NO, %010 / %011 : STR/LDR

._STM
 AND     R4, R0, #%1111 << 16		;R4 = register
 LDR     R1, Early_Abort_Mode		;R1 = instruction Early Abort Mode
 LDR     R7, [R8, R4, LSR #16 - 2]	;R7 = Rd value (ie address)
 MOV     R12, R7			;R12 = unaligned Abort address
 BIC     R7, R7, #%11			;word align

 TST     R0, #1 << 20			;LDM?
 BNE     JIT_PZ_LDM			;YES

 TST     R1, #%01			;is LDM/STM in Late Abort mode?
 TSTNE   R0, #1 << 21			;YES, write-back?
 BEQ     _STM_early_abort_mode		;NO

; MOV     R2, #0				;need to fixup Rn
; MOVS    R1, R0, LSL #17
; ._STM_L1
;   ADC     R2, R2, R1, LSR #31
;   MOVS    R1, R1, LSL #2
; BNE     _STM_L1
; ADC     R2, R2, R1, LSR #31
 MOV     R1, #&33			;11 instructions
 ORR     R1, R1, R1, LSL #8		;assumes R0-PC can't exist
 EOR     R2, R1, R1, LSL #1
 AND     R2, R2, R0, LSR #1
 SUB     R5, R0, R2
 AND     R2, R1, R5, LSR #2
 AND     R5, R5, R1
 ADD     R5, R5, R2
 ADD     R5, R5, R5, LSR #4
 ADD     R5, R5, R5, LSR #8
 AND     R2, R5, #%1111			;R2=<reglist> bit count

 TST     R0, #1 << 23			;Ix or Dx
 ADDEQ   R7, R7, R2, LSL #2		;Dx
 SUBNE   R7, R7, R2, LSL #2		;Ix
 ._STM_early_abort_mode
					;now need to perform:
					;STM/LDM<mode> R7,{<reglist>}
 TST     R0, #1 << 23			;Ix or Dx
 BNE     _STM_Ix

._STM_Dx
 TST     R0, #1 << 24			;DB or DA
 SUBNE   R7, R7, #4			;DB

 MOV     R6, #15 * 4
 MOVS    R1, R0, LSL #16
 BPL     _STM_Dx_L1_P1			;skip to 1st register
 ._STM_Dx_L1_P2
   LDR     R2, [R8, R6]			;load register value
   BL      translate_page_zero_write
   SUB     R7, R7, #4			;go to next address

   ._STM_Dx_L1_P1
     SUB     R6, R6, #4			;go to next register
     MOVS    R1, R1, LSL #1		;is it in reglist?
   BGT     _STM_Dx_L1_P1		;NO
 BMI     _STM_Dx_L1_P2			;YES

 TST     R0, #1 << 24			;DB or DA
 ADDNE   R7, R7, #4			;DB
 TST     R0, #1 << 21			;write-back?
 ANDNE   R12, R12, #%11			; |   get misalignment
 ORRNE   R7, R7, R12			; |   put back into Rd
 STRNE   R7, [R8, R4, LSR #16 - 2]	;YES
B       JIT_AbortI_decoded




._STM_Ix
 TST     R0, #1 << 24			;IB or IA
 ADDNE   R7, R7, #4			;IB

 MOV     R6, #0
 MOV     R1, R0, LSL #16
 MOVS    R1, R1, LSR #17
 ._STM_Ix_L1
   BCC     _STM_Ix_L1_P1
   ._STM_Ix_L1_P2
   LDR     R2, [R8, R6]			;load register value
   BL      translate_page_zero_write
   ADD     R7, R7, #4			;go to next address

   ._STM_Ix_L1_P1
   ADD     R6, R6, #4			;go to next register
   MOVS    R1, R1, LSR #1
 BNE     _STM_Ix_L1
 BCS     _STM_Ix_L1_P2

 TST     R0, #1 << 24			;IB or IA
 SUBNE   R7, R7, #4			;IB
 TST     R0, #1 << 21			;write-back?
 ANDNE   R12, R12, #%11			; |   get misalignment
 ORRNE   R7, R7, R12			; |   put back into Rd
 STRNE   R7, [R8, R4, LSR #16 - 2]	;YES
B       JIT_AbortI_decoded




.JIT_PZ_LDM
 TST     R1, #%01			;is LDM/STM in Late Abort mode?
 TSTNE   R0, #1 << 21			;YES, write-back?
 BEQ     _LDM_decoded			;NO

; MOV     R2, #0				;need to fixup Rn
; MOVS    R1, R0, LSL #17
; ._LDM_L1
;   ADC     R2, R2, R1, LSR #31
;   MOVS    R1, R1, LSL #2
; BNE     _LDM_L1
; ADC     R2, R2, R1, LSR #31
 MOV     R1, #&33			;11 instructions
 ORR     R1, R1, R1, LSL #8		;assumes R0-PC can't exist
 EOR     R2, R1, R1, LSL #1
 AND     R2, R2, R0, LSR #1
 SUB     R5, R0, R2
 AND     R2, R1, R5, LSR #2
 AND     R5, R5, R1
 ADD     R5, R5, R2
 ADD     R5, R5, R5, LSR #4
 ADD     R5, R5, R5, LSR #8
 AND     R2, R5, #%1111			;R2=<reglist> bit count

 TST     R0, #1 << 23			;Ix or Dx
 ADDEQ   R7, R7, R2, LSL #2		;Dx
 SUBNE   R7, R7, R2, LSL #2		;Ix

._LDM_decoded
					;now need to perform:
					;LDM<mode> R7,{<reglist>}
 TST     R0, #1 << 23			;Ix or Dx
 BNE     _LDM_Ix

._LDM_Dx
 TST     R0, #1 << 24			;DB or DA
 SUBNE   R7, R7, #4			;DB

 MOV     R6, #15 * 4
 MOVS    R1, R0, LSL #16
 ._LDM_Dx_L1
   BPL     _skip_Dx
   BL      translate_page_zero_read
   STR     R2, [R8, R6]			;store result
   SUB     R7, R7, #4			;go to next address
   ._skip_Dx
   SUB     R6, R6, #4			;go to next register
   MOVS    R1, R1, LSL #1
 BNE     _LDM_Dx_L1

 TST     R0, #1 << 24			;DB or DA
 ADDNE   R7, R7, #4			;DB
 TST     R0, #1 << 21			;write-back?
 ANDNE   R12, R12, #%11			;YES, get misalignment
 ORRNE   R7, R7, R12			; |   put back into Rd
 STRNE   R7, [R8, R4, LSR #16 - 2]	; |+  update register
B       JIT_AbortI_decoded


._LDM_Ix
 TST     R0, #1 << 24			;IB or IA
 ADDNE   R7, R7, #4			;IB

 MOV     R6, #0
 MOV     R1, R0, LSL #16
 MOVS    R1, R1, LSR #17
 ._LDM_Ix_L1
   BCC     _skip_Ix
   BL      translate_page_zero_read
   STR     R2, [R8, R6]			;store result
   ADD     R7, R7, #4			;go to next address
   ._skip_Ix
   ADD     R6, R6, #4			;go to next register
   MOVS    R1, R1, LSR #1
 BNE     _LDM_Ix_L1
 BCS     _LDM_Ix_L1

 TST     R0, #1 << 24			;IB or IA
 SUBNE   R7, R7, #4			;IB
 TST     R0, #1 << 21			;write-back?
 ANDNE   R12, R12, #%11			;YES, get misalignment
 ORRNE   R7, R7, R12			; |   put back into Rd
 STRNE   R7, [R8, R4, LSR #16 - 2]	; |+  update register
B       JIT_AbortI_decoded




.JIT_PZ_STR			;ARM710VE-36
 LDR     R7, abort_address
 AND     R1, R0, #%1111 << 12		;R1 = Rd
 TST     R0, #1 << 20			;LDR?
 BNE     JIT_PZ_LDR			;YES

 TST     R0, #1 << 22			;word or byte?
 LDREQ   R2, [R8, R1, LSR #12 - 2]	;word, load value being written
 LDRNEB  R2, [R8, R1, LSR #12 - 2]	;bytes, load value being written
 BL      translate_page_zero_write
.JIT_PZ_STR_memory_unchanged
					;--------- Now correct Rn ----------
                 ;%IPUBW
 AND     R1, R0, #%01001 << 21
 TEQ     R1,     #%01001 << 21		;STR/LDR Rd, [Rn, xx]! ?
 TEQNE   R1,     #%00000 << 21		;STR/LDR Rd, [Rn], xx?
 BNE     JIT_AbortI_decoded		;NO

 LDR     R1, Early_Abort_Mode		;R1 = instruction Early Abort Mode
 TST     R1, #%10			;is LDR/STR in Late Abort mode?
 BNE     JIT_AbortI_decoded		;NO

				;Reference: ARM710VE-36
 AND     R1, R0, #%1111 << 16		;R1 = Rn
 LDR     R12, [R8, R1, LSR #16 - 2]	;R12 = value of Rn

 TST     R0, #1 << 25			;STR Rd, [Rn, #{+/-}<immed_12>] ?
 BNE     _xTR_shift			;NO, STR Rd, [Rn, {+/-}Rm{,<shift>}]!

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

 ANDS    R7, R0, #%11 << 5		;R7 = shift type
 MOVEQ   R4, R2, LSL R6			;R4=Rm, LSL #<immed_5>
 BEQ     _xTR_shift_decoded
 CMP     R7, #%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
				;:STR 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
				;:STR 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   R12, R12, R4			;Rm, <shift> #<immed_5>
 SUBEQ   R12, R12, R4			;-Rm, <shift> #<immed_5>
 STR     R12, [R8, R1, LSR #16 - 2]	;store it back
B       JIT_AbortI_decoded





.JIT_PZ_LDR				;R7=address R1=Rd
 BL      translate_page_zero_read
 STR     R2, [R8, R1, LSR #12 - 2]	;store in register
B       JIT_PZ_STR_memory_unchanged




.JIT_PZ_SWP				;SWP Rd, Rm, [Rn] or LDR/STREX
#if High_Vectors == 1 AND compile_RO == 500
.JIT_PZ_LDREX				;fall-thru to report
#endif
.JIT_PZ_STF				;fall-thru to report
B       JIT_Abort_report




;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
; R7 - address being read
; R8 - register dump
;
; R3, R5, R9-R11 free to use
;
;Exit:
;
; R2 - value
; R3, R5 - corrupted

ALIGN   32, 4
.translate_page_zero_read
 BIC     R5, R7, #%11			;word align

 TEMP    R3
 TEQ     R5, #&18			;IRQ hardware vector?
 LDREQ   R2, jit_managed_IRQ_entry
 MOVEQ   PC, R14

 TEQ     R5, #&100			;IRQ1V?
 LDREQ   R2, jit_managed_ldr_pc_r13_2
 MOVEQ   PC, R14

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

 TEQ     R5, #&1584			;VIDCControlCopy
 LDREQ   R2, VIDC1_CR
 MOVEQ   PC, R14

 TEQ     R5, #&1588			;VertAdjust
 LDREQ   R2, page_zero_VertAdjust
 MOVEQ   PC, R14

 TEQ     R5, #&1474			;HSWRSoftCopy
 LDREQ   R2, page_zero_HSWRSoftCopy
 MOVEQ   PC, R14

 TEQ     R5, #&10D4			;CursorFudgeFactor
 LDREQ   R2, page_zero_CursorFudgeFactor
 MOVEQ   PC, R14

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

   TEQ     R5, #&FF0
   LDREQ   R2, private_CLibWord
   LDREQ   R2, [R2, #0]
   MOVEQ   PC, R14
 #endif
 LOCK    R3

 #if High_Vectors == 1 AND ZeroPain == 0
   LDR     R12, [R8, #15 * 4]
   SUB     R12, R12, #4			;correct PC
   STR     R12, [R8, #15 * 4]
   MOV     R12, #&11			;ADFF5011
 B       report_unimplemented		;report unknown address
 #endif
 #if High_Vectors == 1 AND ZeroPain == 1
   MOV     R2, #0			;silently fail
 MOV     PC, R14
 #endif


._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_c, R12
 ADR     R12, _SPSR
 BL      hv_pre_SWI_veneer		;pass next SWI to our vector handler
 SWI     XOS_ReadVduVariables
 BL      dontexit_SWI_veneer
 MSR     CPSR_c, R3			;switch back to ABT
 LDR     R2, [R13], #8
 LDMFD   R13!, {R0-R1, R3, R12, PC}

 ._SPSR	DBD 4




;translate_page_zero_write
;Entry:
; R0 - instruction
; R2 - value to write
; R7 - aborting address (word aligned if STM or STR)
; R8 - register dump
;
; R3, R5, R9-R11 free to use
;
;Exit:
; R2, R3, R5 - corrupted

ALIGN   32, 4
.translate_page_zero_write
 TEMP    R5
 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

 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

 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 == 1 AND Private_CLib == 1
   EORS    R5, 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    R5

 #if High_Vectors == 1 AND ZeroPain == 0
   LDR     R12, [R8, #15 * 4]
   SUB     R12, R12, #4			;correct PC
   STR     R12, [R8, #15 * 4]
   MOV     R12, #&15			;ADFF5015
 B       report_unimplemented		;report unknown address
 #endif
 #if High_Vectors == 1 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
 BICEQ   R3, R7, #%11
 STREQ   R2, [R3, #0]			;word, proxy the write

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


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

 TEMP    R5
 LDR     R3, jit_managed_IRQ_entry
 TEQ     R2, R3				;are we releasing the IRQ?
 MOVEQ   R2, #0				;YES
 STREQ   R2, 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
 LDR     R3, jit_managed_ldr_pc_r13_2	;jit_managed_mov_pc_r14
 TEQ     R2, R3				;are we releasing the IRQ?
 MOVEQ   R2, #0				;YES
 STREQ   R2, 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
MOV     PC, R14
 LOCK    R5
