;	WinSTon

;	MOVEM regs,-(An)
;	MOVEM regs,<ea>
;	MOVEM (An)+,regs
;	MOVEM <ea>,regs

;	XNZVC
;	-----

PUBLIC _movem_reg_an_dec_word
PUBLIC _movem_reg_an_dec_long
PUBLIC _movem_reg_ea_word
PUBLIC _movem_reg_ea_long
PUBLIC _movem_an_inc_reg_word
PUBLIC _movem_an_inc_reg_long
PUBLIC _movem_ea_reg_word
PUBLIC _movem_ea_reg_long

;-----------------------------------------------------------------------
;Write word 'bx' to 'ebp', check intercepts and leave 'ecx' alone
WriteWord_EBP PROC NEAR
	push	ecx
	INTERCEPT_CHECK_ADDR_WRITEWORD					;Write 'bx' to 'ebp', corrupts 'ecx'
	pop		ecx
	ret
WriteWord_EBP ENDP

;-----------------------------------------------------------------------
;Write long 'ebx' to 'ebp', check intercepts and leave 'ecx' alone
WriteLong_EBP PROC NEAR
	push	ecx
	INTERCEPT_CHECK_ADDR_WRITELONG					;Write 'ebx' to 'ebp', corrupts 'ecx'
	pop		ecx
	ret
WriteLong_EBP ENDP

;-----------------------------------------------------------------------
;MOVEM.W regs,-(An)
_movem_reg_an_dec_word PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	mov		edx,DECODE_1[ecx]						;Get address Ay, keep 'edx' for later
	mov		ebp,[edx]								;Load (An)
	mov		[PostIncRegister],ebp					;Store An as may be over written during register moves
	mov		DWORD PTR [MovemPtr],ebp				;Store as ST address

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
	push	edx										;May get corrupted by Write_EBP
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store register to memory
	mov		ebx,15									;Immediate is in order D0(bit15) to A7(bit0)
	sub		ebx,ecx
	mov		bx,WORD PTR _Regs[ebx*4]				;Read register
		
	sub		DWORD PTR [MovemPtr],SIZE_WORD			;Pre-decrement
	mov		ebp,[MovemPtr]
	call	WriteWord_EBP							;Write to memory (wrong endian)

	ADD_CYCLES	4									;4 cycles, 4n (WORD)
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop
	pop		edx

	;Decrement (An) register
	mov		ebx,[NumRegsStored]
	shl		ebx,1
	mov		ecx,[PostIncRegister]					;- An before instruction
	sub		ecx,ebx
	mov		[edx],ecx

	FRET
_movem_reg_an_dec_word ENDP

;MOVEM.L regs,-(An)
_movem_reg_an_dec_long PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	mov		edx,DECODE_1[ecx]						;Get address Ay, keep 'edx' for later
	mov		ebp,[edx]								;Load (An)
	mov		[PostIncRegister],ebp					;Store An as may be over written during register moves
	mov		DWORD PTR [MovemPtr],ebp				;Store as ST address

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
	push	edx										;May get corrupted by Write_EBP
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store register to memory
	mov		ebx,15									;Immediate is in order D0(bit15) to A7(bit0)
	sub		ebx,ecx
	mov		ebx,_Regs[ebx*4]						;Read register

	sub		DWORD PTR [MovemPtr],SIZE_LONG			;Pre-decrement
	mov		ebp,[MovemPtr]
	call	WriteLong_EBP							;Write to memory (wrong endian)
		
	ADD_CYCLES	8									;8 cycles, 8n (LONG)
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop
	pop		edx

	;Decrement (An) register
	mov		ebx,[NumRegsStored]
	shl		ebx,2
	mov		ecx,[PostIncRegister]					;- An before instruction
	sub		ecx,ebx
	mov		[edx],ecx

	FRET
_movem_reg_an_dec_long ENDP

;-----------------------------------------------------------------------
;MOVEM.W regs,<ea>
_movem_reg_ea_word PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	LEFFADDR_LONG									;Load <ea>
	mov		DWORD PTR [MovemPtr],ebx				;Store as ST address

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store register to memory
	mov		bx,WORD PTR _Regs[ecx*4]				;Read register

	mov		ebp,[MovemPtr]
	add		DWORD PTR [MovemPtr],SIZE_WORD			;Increment
	call	WriteWord_EBP							;Write to memory (wrong endian)

	ADD_CYCLES	4									;4 cycles, 4n (WORD)
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop
	FRET
_movem_reg_ea_word ENDP

;MOVEM.L regs,<ea>
_movem_reg_ea_long PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	LEFFADDR_LONG									;Load <ea>
	mov		DWORD PTR [MovemPtr],ebx				;Store as ST address

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store register to memory
	mov		ebx,_Regs[ecx*4]						;Read register

	mov		ebp,[MovemPtr]
	add		DWORD PTR [MovemPtr],SIZE_LONG			;Increment
	call	WriteLong_EBP							;Write to memory (wrong endian)

	ADD_CYCLES	8									;8 cycles, 8n (WORD)
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop
	FRET
_movem_reg_ea_long ENDP

;-----------------------------------------------------------------------
;MOVEM.W (An)+,regs
_movem_an_inc_reg_word PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	mov		edx,DECODE_1[ecx]						;Get address Ay, keep 'edx' for later
	mov		ebp,[edx]								;Load (An)
	mov		[PostIncRegister],ebp					;Store An as may be over written during register moves
	MASK_24BIT_ADDR(ebp)							;as 24-bit address in PC memory

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store memory to register
	mov		bx,WORD PTR _STRam[ebp]					;Read from memory (wrong endian)
	SWAP_ENDIAN_WORD_BX
	movsx	ebx,bx									;Sign extend to 32-bits
	mov		_Regs[ecx*4],ebx						;Save to register
	add		ebp,SIZE_WORD
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop

	;Increment (An) register
	mov		ebx,[NumRegsStored]
	shl		ebx,1									;4n (WORD)
	ADD_CYCLES_EBX
	ADD_CYCLES_EBX									;NOTE Keep 'ebx' for this add:-
	add		ebx,[PostIncRegister]					;+ An before instruction
	mov		[edx],ebx

	FRET
_movem_an_inc_reg_word ENDP

;MOVEM.L (An)+,regs
_movem_an_inc_reg_long PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	mov		edx,DECODE_1[ecx]						;Get address Ay, keep 'edx' for later
	mov		ebp,[edx]								;Load (An)
	mov		[PostIncRegister],ebp					;Store An as may be over written during register moves
	MASK_24BIT_ADDR(ebp)							;as 24-bit address in PC memory

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store memory to register
	mov		ebx,DWORD PTR _STRam[ebp]				;Read from memory (wrong endian)
	SWAP_ENDIAN_LONG_EBX
	mov		_Regs[ecx*4],ebx						;Save to register
	add		ebp,SIZE_LONG
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop

	;Increment (An) register
	mov		ebx,[NumRegsStored]
	shl		ebx,2									;8n (LONG)
	ADD_CYCLES_EBX
	ADD_CYCLES_EBX									;NOTE Keep 'ebx' for this add:-
	add		ebx,[PostIncRegister]					;+ An before instruction
	mov		[edx],ebx

	FRET
_movem_an_inc_reg_long ENDP

;-----------------------------------------------------------------------
;MOVEM.W <ea>,regs
_movem_ea_reg_word PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	LEFFADDR_LONG									;Load <ea>
	mov		ebp,ebx
	MASK_24BIT_ADDR(ebp)							;as 24-bit address in PC memory

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store memory to register
	mov		bx,WORD PTR _STRam[ebp]					;Read from memory (wrong endian)
	SWAP_ENDIAN_WORD_BX
	movsx	ebx,bx									;Sign extend to 32-bits
	mov		_Regs[ecx*4],ebx						;Save to register
	add		ebp,SIZE_WORD
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop

	mov		ebx,[NumRegsStored]
	shl		ebx,2									;4n (WORD)
	ADD_CYCLES_EBX

	FRET
_movem_ea_reg_word ENDP

;MOVEM.L <ea>,regs
_movem_ea_reg_long PROC NEAR
	mov		bx,IMM_WORD[esi]						;Immediate data (wrong endian)
	add		esi,SIZE_WORD							;Increase program counter
	SWAP_ENDIAN_WORD_BX
	mov		[MovemWord],ebx							;Store for tests

	LEFFADDR_LONG									;Load <ea>
	mov		ebp,ebx
	MASK_24BIT_ADDR(ebp)							;as 24-bit address in PC memory

	mov		[NumRegsStored],0						;Count number of registers stored
	xor		ecx,ecx									;Check all 16 registers
reg_loop:
	;Do need to store this register?
	bt		[MovemWord],ecx
	jnc		no_reg_store							;No

	;Store memory to register
	mov		ebx,DWORD PTR _STRam[ebp]				;Read from memory (wrong endian)
	SWAP_ENDIAN_LONG_EBX
	mov		_Regs[ecx*4],ebx						;Save to register
	add		ebp,SIZE_LONG
	inc		[NumRegsStored]							;Increase count

no_reg_store:
	inc		ecx										;Next register
	cmp		ecx,16
	jl		reg_loop

	mov		ebx,[NumRegsStored]
	shl		ebx,3									;8n (LONG)
	ADD_CYCLES_EBX

	FRET
_movem_ea_reg_long ENDP
