;Entry:
;R0  = instruction
;R7  = original instruction address + 8
;R14 = re-interpreted instruction address + 8

;i_LDM
;-----
;LDM Rn{!}, {<reg_list>, PC}{^}

ALIGN   32, 4
.i_LDM
 TST     R0, #1 << 22			;Update PSR?
 BNE     i_LDM_update_PSR		;YES

;LDM Rn{!}, {<reg_list>, PC}
 CODELET_REUSE 9
 BIC     R0, R0, #PC_reglist		;original instruction less PC

 STMFD   R13!, {R7, R14}

 TST     R0, #%1111 << 16		;is Rn R0?
 ADREQ   R5, _codelet_R1		;YES, use R1
 MOVEQ   R7, #%10			;R7=Rx
 ADRNE   R5, _codelet_R0		;NO,  use R0
 MOVNE   R7, #%1

 LDMIA   R5!, {R1, R4}

 MOVS    R14, R0, LSL #17		;LDMxx Rn{!}, {PC}?
 BNE     _reglist			;NO
					;-------- 4th instruction --------
 ORR     R4, R0, R7			;LDMxx Rn, {Rx}
 STMIA   R6!, {R1, R4}


 LDMIA   R5!, {R1-R3}
 STMIA   R6!, {R1-R3}

 LDMIA   R5, {R1, R4-R5}		;drop R2,R4 instructions
 SUB     R5, R5, #4 * 2			;correct 4th instruction
 STMIA   R6, {R1, R5}

 LDMFD   R13!, {R7, R14}
B       i_und_exit


 ._reglist
 TST     R0, #1 << 23			;LDMDx?
 BEQ     _P5				;YES
					;-------- 4th instruction --------
 AND     R7, R0, #1			;R0	R7=count of registers
 MOVS    R14, R0, LSL #18
 ADC     R7, R7, R14, LSR #31		;R13/R14
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R11/R12
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R9/R10
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R7/R8
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R5/R6
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R3/R7
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R1/R2

 ORR     R4, R4, #1 << 24		;needs to be pre-index
 ADD     R4, R4, R7, LSL #2		;LDR Rx, [Rn, #<offset>]
 AND     R7, R0, #%11 << 23		;PU bits
 TEQ     R7,     #%11 << 23		;LDMIB?
 ADDEQ   R4, R4, #4			;YES, increase offset by 1 word
 ._P5
 AND     R14, R0, #%1111 << 16		;R14=Rn
 ORR     R4, R4, R14			;LDR Rx, [Rn]

 TST     R0, #1 << 23			;LDMDx?
 BNE     _P6

 ADD     R4, R4, #4			;LDR Rx, [Rn], #4
 BIC     R4, R4, #%0100 << 21		;LDR Rx, [Rn], #-4
 TST     R0, #1 << 24			;LDMDB?
 ORRNE   R4, R4, #%1001 << 21		;YES, LDR Rx, [Rn, #4]!

 ._P6
 AND     R7, R1, #%1111 << 12		;R7=Rd from STR Rx, _codelet_Rx-4
 AND     R14, R0, #%1111 << 16		;R14=Rn
 TEQ     R14, R7, LSL #4		;Rx=Rn?
 MOVNE   R7, R7, LSR #12		;NO
 MOVNE   R14, #1
 MOVNE   R14, R14, LSL R7		;R14=bitmask for Rn
 TSTNE   R0, R14			;is Rx in the reglist?
					;NE if Rx is beng overwritten
 STMNEIA R6!, {R4}
 STMEQIA R6!, {R1, R4}


 LDMIA   R5!, {R1-R3}
 SUBNE   R3, R3, #4			;YES, correct STR Rx, _codelet_Rx-12
 STMIA   R6!, {R1-R3}


 LDMIA   R5, {R1, R4-R5}
 SUBNE   R5, R5, #8			;YES, correct LDR PC, _codelet_Rx-12
 STREQ   R1, [R6], #4
 STR     R0, [R6], #4
					;-------- 4th instruction --------
 AND     R1, R0, #%1111 << 16		;R1=Rn
 MOV     R3, R1, LSR #16
 MOV     R2, #1				;R2=bitmask for Rn

 TST     R0, #1 << 23			;LDMDx?
 BEQ     _P4				;YES
 TST     R0, #1 << 21			;LDMIx Rn!?
 BEQ     _P2				;NO, drop the ADD Rn, Rn, #4
 TST     R0, R2, LSL R3			;is Rn in <reglist>
 BEQ     _P3				;YES

 ._P2
 SUB     R5, R5, #4			;correct 5th instruction
 STR     R5, [R6]
B       _exit

 ._P4
 TST     R0, R2, LSL R3			;is Rn in <reglist>
 TSTEQ   R0, #1 << 21			;NO, LDMDx Rn!?
 BNE     _P2				;YES, drop the ADD Rn, Rn, #4

 ._P3
 ORR     R4, R4, R1			;NO
 ORR     R4, R4, R1, LSR #4		; |+ ADD Rn, Rn, #4
 STMIA   R6, {R4-R5}

 ._exit
 LDMFD   R13!, {R7, R14}
B       i_und_exit



 ._codelet_R0
 STR     R0, _codelet_R0-4		;R1 tmp1 (optional) R0<>Rn and R0 in reglist
 LDR     R0, [R0], #0			;R4 LDR R0, [Rn, #reglist-4]
 ADD     R0, R0, #jit_code_start	;R1 correct
 BIC     R0, R0, #&FC000003		;R2 clear status bits
 STR     R0, _codelet_R0-8		;R3 tmp2
 LDR     R0, _codelet_R0-4		;R1 tmp1 (optional) R0<>Rn and R0 in reglist
 ;DCD     %10000001 << 20		;R2 (optional) LDM... (less PC)
 ADD     R0, R0, #4			;R4 (optional) ADD Rn, Rn, #4
					;   LDM Rn only if Rn not in reglist
 LDR     PC, _codelet_R0-8 -4		;R5 tmp2
					;instructions:
			; Rn,  {<reglist>, PC}     - 8 (IB, IA) 9 (DB, DA)
			; Rn,  {<reglist>, Rn, PC} - 8 (IB, IA) 8 (DB, DA)
			; Rn,  {PC}                - 7
			; Rn!, {<reglist>, PC}     - 8 (IB, IA) 8 (DB, DA)
			; Rn!, {<reglist>, Rn, PC} - 8 (IB, IA) 8 (DB, DA)
			; Rn!, {PC}                - 7

 ._codelet_R1
 STR     R1, _codelet_R1-4		;R1 tmp1 (optional) Rn!=R1 and R1 in reglist
 LDR     R1, [R0], #0			;R4 LDR R1, [Rn, #reglist-4]
 ADD     R1, R1, #jit_code_start	;R1 correct
 BIC     R1, R1, #&FC000003		;R2 clear status bits
 STR     R1, _codelet_R1-8		;R3 tmp2
 LDR     R1, _codelet_R1-4		;R1 tmp1
 ;DCD     %10000001 << 20		;R2 (optional) LDM... (less PC)
 ADD     R0, R0, #4			;R4 (optional) ADD Rn, Rn, #4
					;   LDM Rn only if Rn not in reglist
 LDR     PC, _codelet_R1-8 -4		;R5 tmp2




;LDM Rn{!}, {<reg_list>, PC}^
.i_LDM_update_PSR
 #if compile_RO == 400
   CODELET_REUSE 15
 #endif
 #if compile_RO > 400 AND compile_IOMD == 0
   CODELET_REUSE 19
 #endif
 #if compile_RO > 400 AND compile_IOMD == 1
   CODELET_REUSE 20
 #endif
 BIC     R0, R0, #(1 << 22) + PC_reglist ;original instruction less PC and ^

 STMFD   R13!, {R7, R14}

 TST     R0, #%1111 << 16		;is Rn R0?
 ADREQ   R5, _codelet_R1		;YES, use R1
 MOVEQ   R7, #1 +1			;R8=Rx
 ADRNE   R5, _codelet_R0		;NO,  use R0
 MOVNE   R7, #0 +1

 LDMIA   R5!, {R1-R4}

 MOVS    R14, R0, LSL #17		;LDMxx Rn{!}, {PC}?
 BNE     _reglist			;NO

;LDMxx Rn{!}, {PC}^
					;-------- 2nd instruction --------
 ORR     R2, R0, R7			;LDMxx Rn, {Rx}
 STMIA   R6!, {R1-R4}


 LDMIA   R5!, {R2-R3}
 STMIA   R6!, {R2-R3}


 ADD     R5, R5, #3 * 4			;drop the next 4 instructions

 #if compile_RO == 400
   LDMIA   R5!, {R1-R3}
   SUB     R1, R1, #4 * 4		;correct 1st instruction
   STMIA   R6!, {R1-R3}
 #endif
 #if compile_RO > 400
   LDMIA   R5!, {R1-R4}
   SUB     R1, R1, #4 * 4		;correct 1st instruction
   STMIA   R6!, {R1-R4}

   #if compile_RO > 400 AND compile_IOMD == 0
     LDMIA   R5!, {R1-R3}
     STMIA   R6!, {R1-R3}
   #endif
   #if compile_RO > 400 AND compile_IOMD == 1
     LDMIA   R5!, {R1-R4}
     STMIA   R6!, {R1-R4}
   #endif
 #endif


 LDMIA   R5!, {R1-R2}
 SUB     R1, R1, #4 * 4			;correct 1st instruction
 SUB     R2, R2, #4 * 4			;correct 2nd instruction
 STMIA   R6!, {R1-R2}


 LDMFD   R13!, {R7, R14}
B       i_und_exit


;LDM Rn{!}, {<reg_list>, PC}^
 ._reglist
 TST     R0, #1 << 23			;LDMDx?
 BEQ     _P5				;YES
					;-------- 2nd instruction --------
 AND     R7, R0, #1			;R0  R7=count of registers
 MOVS    R14, R0, LSL #18
 ADC     R7, R7, R14, LSR #31		;R13/R14
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R11/R12
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R9/R10
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R7/R8
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R5/R6
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R3/R7
 MOVS    R14, R14, LSL #2
 ADC     R7, R7, R14, LSR #31		;R1/R2

 ORR     R2, R2, #1 << 24		;needs to be pre-index
 ADD     R2, R2, R7, LSL #2		;LDR Rx, [Rn, #<offset>]
 AND     R7, R0, #%11 << 23		;PU bits
 TEQ     R7,     #%11 << 23		;LDMIB?
 ADDEQ   R2, R2, #4			;YES, increase offset by 1 word
 ._P5
 AND     R14, R0, #%1111 << 16		;R14=Rn
 ORR     R2, R2, R14			;LDR Rx, [Rn]

 TST     R0, #1 << 23			;LDMDx?
 BNE     _P6

 ADD     R2, R2, #4			;LDR Rx, [Rn], #4
 BIC     R2, R2, #%0100 << 21		;LDR Rx, [Rn], #-4
 TST     R0, #1 << 24			;LDMDB?
 ORRNE   R2, R2, #%1001 << 21		;YES, LDR Rx, [Rn, #4]!

 ._P6
 STMIA   R6!, {R1-R4}


 LDMIA   R5!, {R2-R3}
 STMIA   R6!, {R2-R3}


 LDMIA   R5!, {R1, R3-R4}
 BIC     R2, R0, #%1111 << 28		;original instruction changed to...
 ORR     R2, R2, #%1110 << 28		;LDMAL
 STMIA   R6!, {R1-R3}
					;-------- 4th instruction --------
 AND     R1, R0, #%1111 << 16		;R1=Rn
 MOV     R3, R1, LSR #16
 MOV     R2, #1
 MOV     R2, R2, LSL R3			;R2=bitmask for Rn

 TST     R0, #1 << 23			;LDMDx?
 BEQ     _P4				;YES
 TST     R0, #1 << 21			;LDMIx Rn!?
 BEQ     _P2				;NO, drop the ADD Rn, Rn, #4
 TST     R0, R2				;is Rn in <reglist>
 BEQ     _P3				;YES
 B       _P2

 ._P4
 TST     R0, R2				;is Rn in <reglist>
 TSTEQ   R0, #1 << 21			;NO, LDMDx Rn!?
 BNE     _P2				;YES, drop the ADD Rn, Rn, #4

 ._P3
 ORR     R4, R4, R1			;NO
 ORR     R4, R4, R1, LSR #4		; |+ ADD Rn, Rn, #4
 STR     R4, [R6], #4

 #if compile_RO > 400
   LDMIA   R5!, {R1-R4}
   STMIA   R6!, {R1-R4}

   #if compile_RO > 400 AND compile_IOMD == 0
     LDMIA   R5!, {R1-R3}
     STMIA   R6!, {R1-R3}
   #endif
   #if compile_RO > 400 AND compile_IOMD == 1
     LDMIA   R5!, {R1-R4}
     STMIA   R6!, {R1-R4}
   #endif
 #endif
 #if compile_RO == 400
   LDMIA   R5!, {R1-R3}
   STMIA   R6!, {R1-R3}
 #endif

 LDMIA   R5!, {R1-R2}
 STMIA   R6!, {R1-R2}

 LDMFD   R13!, {R7, R14}
B       i_und_exit

 ._P2
 #if compile_RO > 400
   LDMIA   R5!, {R1-R4}
   SUB     R1, R1, #4			;correct 1st instruction
   STMIA   R6!, {R1-R4}

   #if compile_RO > 400 AND compile_IOMD == 0
     LDMIA   R5!, {R1-R3}
     STMIA   R6!, {R1-R3}
   #endif
   #if compile_RO > 400 AND compile_IOMD == 1
     LDMIA   R5!, {R1-R4}
     STMIA   R6!, {R1-R4}
   #endif
 #endif
 #if compile_RO == 400
   LDMIA   R5!, {R1-R3}
   SUB     R1, R1, #4			;correct 1st instruction
   STMIA   R6!, {R1-R3}
 #endif


 LDMIA   R5!, {R1-R2}
 SUB     R1, R1, #4			;correct 1st instruction
 SUB     R2, R2, #4			;correct 2nd instruction
 STMIA   R6!, {R1-R2}

 LDMFD   R13!, {R7, R14}
B       i_und_exit


 ._codelet_R0
 STR     R0, _codelet_R0-4		;R1 tmp1
 LDR     R0, [R0], #0			;R2 LDR R0, [Rn, #reglist-4]
 ADD     R0, R0, #jit_code_start	;R3 correct
 STR     R0, _codelet_R0-8		;R4 tmp2
 BIC     R0, R0, #&FC000003		;R2 clear status bits
 STR     R0, _codelet_R0-12		;R3 tmp3
 LDR     R0, _codelet_R0-4		;R1 tmp1 (optional)
 ;DCD     %10000001 << 20		;R2 (optional) LDM... (less PC)
 STR     R0, _codelet_R0-4  -4		;R3 tmp1 (optional)
 ADD     R0, R0, #4			;R4 (optional) ADD Rn, Rn, #4
					;   LDM Rn! only if Rn not in reglist
 LDR     R0, _codelet_R0-8  -4		;R1 tmp2
 #if compile_RO > 400
   AND     R0, R0, #&FC000003		;R2
   ORR     R0, R0, R0, LSR #20		;R3
   BIC     R0, R0, #%1111 << 8		;R4 clear unwanted bits
   BIC     R0, R0, #%11 << 26		;R1 clear FIQ/IRQ
   ORR     R0, R0, #c32bit		;R2 32bit
   MSR     CPSR_cf, R0			;R3
 #endif
 #if compile_RO == 400
   TEQP    R0, #0			;R2
 #endif
 #if compile_IOMD == 1
   NOP					;R3
 #endif
 LDR     R0, _codelet_R0-4  -4		;R1 tmp1
 LDR     PC, _codelet_R0-12 -4		;R2 tmp3
			;instructions:  -4 for all on 26bit
			; Rn, {<reglist>, PC}     - 18 (IB, IA) 19 (DB, DA)
			; Rn, {<reglist>, Rn, PC} - 17 (IB, IA) 18 (DB, DA)
			; Rn, {PC}                - 15 (IB, IA, DB, DA)
			; +1 on IOMD 32bit
 ._codelet_R1
 STR     R1, _codelet_R1-4		;R1 tmp1
 LDR     R1, [R0], #0			;R2 LDR R1, [Rn, #reglist-4]
 ADD     R1, R1, #jit_code_start	;R3 correct
 STR     R1, _codelet_R1-8		;R4 tmp2
 BIC     R1, R1, #&FC000003		;R2 clear status bits
 STR     R1, _codelet_R1-12		;R3 tmp3
 LDR     R1, _codelet_R1-4		;R1 tmp1 (optional)
 ;DCD     %10000001 << 20		;R2 (optional) LDM... (less PC)
 STR     R1, _codelet_R1-4  -4		;R3 tmp1 (optional)
 ADD     R0, R0, #4			;R4 (optional) ADD Rn, Rn, #4
					;   LDM Rn! only if Rn not in reglist
 LDR     R1, _codelet_R1-8  -4		;R1 tmp2
 #if compile_RO > 400
   AND     R1, R1, #&FC000003		;R2
   ORR     R1, R1, R1, LSR #20		;R3
   BIC     R1, R1, #%1111 << 8		;R1 clear unwanted bits
   BIC     R1, R1, #%11 << 26		;R2 clear FIQ/IRQ
   ORR     R1, R1, #c32bit		;R3 32bit
   MSR     CPSR_cf, R1			;R4
 #endif
 #if compile_RO == 400
   TEQP    R1, #0			;R2
 #endif
 #if compile_IOMD == 1
   NOP					;R3
 #endif
 LDR     R1, _codelet_R1-4  -4		;R1 tmp1
 LDR     PC, _codelet_R1-12 -4		;R2 tmp3




;BBB Won't load PC correctly
;LDM PC{!}, {<reg_list>}{^}
;LDM PC{!}, {<reg_list>, PC}{^} - currently uncoded (reported in core)
.i_LDM_PC_in_Rn
 TST     R0, #1 << 22			;changing PSR?
 MOVNE   R1, #9				;ADFF5009
 BNE     JIT_report_unimplemented	;YET TO BE CODED

 CODELET 3
 ADR     R5, _codelet

 LDMIA   R5, {R1, R3}

 MOVS    R2, R0, LSR #1			;find first used register
 MOV     R4, #0				;R4=Rx
 ._L1
   ADDCC   R4, R4, #1
   MOVCCS  R2, R2, LSR #1
 BCC     _L1
					;-------- 1st instruction --------
 ORR     R1, R1, R4, LSL #12		;add in Rx

					;-------- 2nd instruction --------
 BIC     R2, R0, #%1111 << 16		;clear Rn
 ORR     R2, R2, R4, LSL #16		;add in Rx

					;-------- 3rd instruction --------
 SUB     R5, R14, R6
 SUB     R5, R5, #8 + (3 * 4)		;correct for offset and prefetch
 BIC     R5, R5, #%111111 << 26
 ORR     R3, R3, R5, LSR #2		;B <original address + 4>

 STMIA   R6, {R1-R3}

B       i_instruction_handled


 ._codelet
 LDR     R0, _codelet-codelet_PC	;R1 LDR Rx, _PC
 ;DCD     %10000001 << 20		;R2 LDM Rx, {Rx, ...}
 DCD     B_blank			;R3 B <original address + 4>
					;3 instructions

