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

;i_STM
;-----
;STM Rn{!}, {<reg_list>, PC}{^}

;@@@ needs to handle STM Rn{!}, {<reg_list>, [PC]}^ by checking if CPU
;    is in USR and removing the ^ if necessary

ALIGN   32, 4
.i_STM
 CODELET 14
 BIC     R0, R0, #PC_reglist		;original instruction less PC
; BIC     R0, R0, #1 << 22		;remove {^} (fixes Fire & Ice
;					;..on ARMv7)
 STR     R7, [R13, #-4]!		;preserve R7

 LDRB    R1, JIT_ARM4
 TEQ     R1, #0				;ARMv3?
 ADDEQ   R7, R7, #4			;YES, correct R7 for pre-fetch PC+12
					;NO, StrongARM is PC+8
 STR     R7, [R6, #-4]			;store PC in tmp1

 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}
 STMIA   R6!, {R1-R4}


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


 LDMIA   R5!, {R1, R3}

 MOVS    R2, R0, LSL #17		;STMxx Rn{!}, {PC}{^}?
 BNE     _reglist			;NO

 BIC     R0, R0, #1 << 22		;ARMv7 fix - remove {^} (fixes Sensible Soccer)
 LDR     R3, [R5], #4			;drop 1 instruction
 ORR     R2, R0, R7			;STMxx Rn{!}, {Rx}
 STMIA   R6!, {R1-R3}

 ADD     R5, R5, #4			;skip 1 instruction
 B       _P1

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

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

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

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

 ._P6
 STMIA   R6!, {R1, R3}

 LDMIA   R5!, {R1, R4}
					;-------- 2nd instruction --------
 MOV     R2, R0
					;-------- 4th instruction --------
 TST     R0, #1 << 23			;STMDx?
 BNE     _stmix
 TST     R0, #1 << 21			;STMDx Rn!?
 BEQ     _P3				;NO, need the ADD Rn, Rn, #4
 STMIA   R6!, {R1-R2}			;YES, drop the ADD Rn, Rn, #4
 B       _P1

 ._stmix
 TST     R0, #1 << 21			;STMIx Rn!?
 STMEQIA R6!, {R1-R2}			;YES, drop the ADD Rn, Rn, #4
 BEQ     _P1

 ._P3
 AND     R3, R0, #%1111 << 16		;R3=Rn
 ORR     R4, R4, R3
 ORR     R4, R4, R3, LSR #4		;ADD Rn, Rn, #4
 STMIA   R6!, {R1-R2, R4}

 ._P1
 LDR     R3, [R5]
 SUB     R2, R14, R6			;correct for offset and prefetch
 SUB     R2, R2, #8 + 4
 BIC     R2, R2, #%111111 << 26
 ORR     R3, R3, R2, LSR #2		;B <original address + 4>

 MOVS    R0, R0, LSL #17		;STMxx Rn{!}, {PC}?

 STRNE   R3, [R6]
 STMEQIA R6!, {R3-R5}			;STMxx Rn{!}, {PC} needs two NOPs

 LDR     R7, [R13], #4			;preserve R7
B       i_instruction_handled


 ._codelet_R0
 STR     R0, _codelet_R0-8		;R1 tmp2
 STR     R1, _codelet_R0-12		;R2 tmp3
 #if compile_RO > 400
   MRS     R0, CPSR			;R3
   AND     R1, R0, #&F0000003		;R4 flags / CPU mode
   AND     R0, R0, #%11 << 6		;R1 - IRQ / FIQ
   ORR     R1, R1, R0, LSL #20		;R2
 #endif
 #if compile_RO == 400
   MOV     R1, PC			;R3
   AND     R1, R1, #&FC000003		;R4 flags / CPU mode
   NOP					;R1
   NOP					;R2
 #endif
 LDR     R0, _codelet_R0-4		;R3 tmp1
 ORR     R0, R0, R1			;R4
 LDR     R1, _codelet_R0-12		;R1 tmp3
 STR     R0, [R0], #0			;R3 (optional) STR R0, [Rn, #reglist-4]
 LDR     R0, _codelet_R0-8		;R1 tmp2
 ;DCD     %10000000 << 20		;R2 STM... (less PC)
 ADD     R0, R0, #4			;R4 (optional) ADD Rn, Rn, #4
					;   if Rn not in reglist
 DCD     B_blank			;R3 B <original address + 4>
			;instructions:
			; Rn, {<reglist>, PC} - 14 (IB, IA, DB, DA)
			; Rn, {PC}            - 11 (IB, IA, DB, DA)

 ._codelet_R1
 STR     R0, _codelet_R1-8		;R1 tmp2
 STR     R1, _codelet_R1-12		;R2 tmp3
 #if compile_RO > 400
   MRS     R0, CPSR			;R3
   AND     R1, R0, #&F0000003		;R4 flags / CPU mode
   AND     R0, R0, #%11 << 6		;R1 - IRQ / FIQ
   ORR     R1, R1, R0, LSL #20		;R2
 #endif
 #if compile_RO == 400
   MOV     R1, PC			;R3
   AND     R1, R1, #&FC000003		;R4 flags / CPU mode
   NOP					;R1
   NOP					;R2
 #endif
 LDR     R0, _codelet_R1-4		;R3 tmp1 R0=original PC
 ORR     R1, R0, R1			;R4
 LDR     R0, _codelet_R1-8		;R1 tmp2
 STR     R1, [R0], #0			;R3 (optional) STR R1, [Rn, #reglist-4]
 LDR     R1, _codelet_R1-12		;R1 tmp3
 ;DCD     %10000000 << 20		;R2 STM... (less PC)
 ADD     R0, R0, #4			;R4 (optional) ADD Rn, Rn, #4
					;   if Rn not in reglist
 DCD     B_blank			;R2 B <original address + 4>




;STM PC, {<reg_list>}{^}
;STM PC, {<reg_list>, PC}{^} - currently uncoded (reported in core)
.i_STM_PC_in_Rn
 CODELET 5
 ADR     R5, _codelet

 LDMIA   R5!, {R1-R2}

 MOVS    R3, R0, LSR #1			;find first unused register
 MOV     R4, #0				;R4=Rx
 ._L1
   ADDCS   R4, R4, #1
   MOVCSS  R3, R3, LSR #1
 BCS     _L1
					;-------- 1st instruction --------
 ORR     R1, R1, R4, LSL #12		;add in Rx
					;-------- 2nd instruction --------
 ORR     R2, R2, R4, LSL #12		;add in Rx
					;-------- 3rd instruction --------
 BIC     R3, R0, #%1111 << 16		;clear Rn
 ORR     R3, R3, R4, LSL #16		;add in Rx

 STMIA   R6!, {R1-R3}


 LDMIA   R5!, {R1-R2}
					;-------- 1st instruction --------
 ORR     R1, R1, R4, LSL #12		;add in Rx
					;-------- 2nd instruction --------
 SUB     R5, R14, R6
 SUB     R5, R5, #8 + (2 * 4)		;correct for offset and prefetch
 BIC     R5, R5, #%111111 << 26
 ORR     R2, R2, R5, LSR #2		;B <original address + 4>

 STMIA   R6, {R1-R2}
B       i_instruction_handled


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



#if ARMv7_support == 1
;: STMxx R0!,{R0-R2}
;NOTE: STMxx R13!,{R0-R2,R13}^ in SVC will put updated R13 back into USER R13

.i_STM_Rn_in_reglist
 TST     R0, #1<<22			;is PSR & force user-bit set?
 MOVNE   R1, #&19			;YES
 BNE     JIT_report_unimplemented	;ADFF5019

 CODELET 3

 AND     R1, R0, #%1111 << 16		;R1=Rn
 BIC     R0, R0, #1 << 21		;clear writeback

 TST     R0, #1 << 23			;increment or decrement?
 ADREQ   R5, _codelet_D
 ADRNE   R5, _codelet_I

 AND     R4, R0, #1			;R0  R4=count of registers
 MOVS    R2, R0, LSL #18
 ADC     R4, R4, R2, LSR #31		;R13/R14
 MOVS    R2, R2, LSL #2
 ADC     R4, R4, R2, LSR #31		;R11/R12
 MOVS    R2, R2, LSL #2
 ADC     R4, R4, R2, LSR #31		;R9/R10
 MOVS    R2, R2, LSL #2
 ADC     R4, R4, R2, LSR #31		;R4/R8
 MOVS    R2, R2, LSL #2
 ADC     R4, R4, R2, LSR #31		;R5/R6
 MOVS    R2, R2, LSL #2
 ADC     R4, R4, R2, LSR #31		;R3/R4
 MOVS    R2, R2, LSL #2
 ADC     R4, R4, R2, LSR #31		;R1/R2

 LDMIA   R5, {R2-R3}
 ORR     R2, R2, R1, LSR #4		;ADD/SUB Rn, __, #__
 ORR     R2, R2, R1			;ADD/SUB Rn, Rn, #__
 ORR     R2, R2, R4, LSL #2		;ADD/SUB Rn, Rn, #<regcount>

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


 ._codelet_I
; DCD     0				;STM Rn,{<reglist>}
 ADD     R0, R0, #0			;ADD Rn,Rn,#<reg count>
 DCD     B_blank			;B <original address + 4>

 ._codelet_D
; DCD     0				;STM Rn,{<reglist>}
 SUB     R0, R0, #0			;SUB Rn,Rn,#<reg count>
 DCD     B_blank			;B <original address + 4>
					;3 instructions
#endif
