
/*****************************************************************/
/*     Offset in SCPUState structure				 */
/*****************************************************************/
#define Flags_ofs		0    
#define BranchSkip_ofs		4
#define NMIActive_ofs		5
#define IRQActive_ofs		6
#define WaitingForInterrupt_ofs	7
#define InDMA_ofs		8
#define WhichEvent		9
#define SRAMModified_ofs	10
#define BRKTriggered_ofs	11
#define PC_ofs			12
#define PCBase_ofs		16

#define PCAtOpcodeStart_ofs	20

#define WaitAddress_ofs		24

#define WaitCounter_ofs		28
#define Cycles_ofs		32
#define NextEvent_ofs		36
#define V_Counter_ofs		40
#define MemSpeed_ofs		44
#define MemSpeedx2_ofs		48
#define FastROMSpeed_ofs	52
#define AutoSaveTimer_ofs	56
#define NMITriggerPoint_ofs	60
#define NMICycleCount_ofs	64
#define IRQCycleCount_ofs	68

#define	RPB_ofs		72
#define	RDB_ofs		73
#define	RP_ofs		74
#define	RA_ofs		76
#define RAH_ofs		RA_ofs+1
#define	RD_ofs		78
#define	RS_ofs		80
#define	RX_ofs		82
#define	RY_ofs		84
#define	RPC_ofs		86
   

#define	asm_OPTABLE_ofs		88
#define TriedInterleavedMode2_ofs	92



#define Map_ofs		96
#define WriteMap_ofs	100
#define MemorySpeed_ofs 104
#define BlockIsRAM_ofs  108
#define SRAM 		112
#define BWRAM 		116
#define SRAMMask 	120

#define	APUExecuting_ofs 122

#define	PALMOS_R9_ofs 	124
#define	PALMOS_R10_ofs 	128
/*****************************************************************/


#ifdef __PALMOS__
/* prepare */
.macro		PREPARE_C_CALL
	STMFD	R13!,{R9,R10,R12,R14}
	LDR	R9,[regCPUvar,#PALMOS_R9_ofs]
	LDR	R10,[regCPUvar,#PALMOS_R10_ofs]
.endm
.macro		PREPARE_C_CALL_R0
	STMFD	R13!,{R0,R9,R10,R12,R14}
	LDR	R9,[regCPUvar,#PALMOS_R9_ofs]
	LDR	R10,[regCPUvar,#PALMOS_R10_ofs]
.endm
.macro		PREPARE_C_CALL_R0R1
	STMFD	R13!,{R0,R1,R9,R10,R12,R14}
	LDR	R9,[regCPUvar,#PALMOS_R9_ofs]
	LDR	R10,[regCPUvar,#PALMOS_R10_ofs]
.endm
.macro		PREPARE_C_CALL_LIGHT
	STMFD	R13!,{R14}
	LDR	R9,[regCPUvar,#PALMOS_R9_ofs]
	LDR	R10,[regCPUvar,#PALMOS_R10_ofs]
.endm
.macro		PREPARE_C_CALL_LIGHTR12
	STMFD	R13!,{R9,R10,R12,R14}
	LDR	R9,[regCPUvar,#PALMOS_R9_ofs]
	LDR	R10,[regCPUvar,#PALMOS_R10_ofs]
.endm
/* restore */
.macro		RESTORE_C_CALL
	LDMFD	R13!,{R9,R10,R12,R14}	

.endm
.macro		RESTORE_C_CALL_R0
	LDMFD	R13!,{R0,R9,R10,R12,R14}	
.endm
.macro		RESTORE_C_CALL_R1
	LDMFD	R13!,{R1,R9,R10,R12,R14}	
.endm
.macro		RESTORE_C_CALL_LIGHT
	LDMFD	R13!,{R14}
.endm
.macro		RESTORE_C_CALL_LIGHTR12
	LDMFD	R13!,{R9,R10,R12,R14}
.endm
#else
/* prepare */
.macro		PREPARE_C_CALL
	STMFD	R13!,{R12,R14}	
.endm
.macro		PREPARE_C_CALL_R0
	STMFD	R13!,{R0,R12,R14}	
.endm
.macro		PREPARE_C_CALL_R0R1
	STMFD	R13!,{R0,R1,R12,R14}		
.endm
.macro		PREPARE_C_CALL_LIGHT
	STMFD	R13!,{R14}
.endm
.macro		PREPARE_C_CALL_LIGHTR12
	STMFD	R13!,{R12,R14}
.endm
/* restore */
.macro		RESTORE_C_CALL
	LDMFD	R13!,{R12,R14}
.endm
.macro		RESTORE_C_CALL_R0
	LDMFD	R13!,{R0,R12,R14}
.endm
.macro		RESTORE_C_CALL_R1
	LDMFD	R13!,{R1,R12,R14}
.endm
.macro		RESTORE_C_CALL_LIGHT
	LDMFD	R13!,{R14}
.endm
.macro		RESTORE_C_CALL_LIGHTR12
	LDMFD	R13!,{R12,R14}
.endm
#endif

//--------------
.macro		LOAD_REGS	
	//regD & regPBank share the same register
	LDRB		regPBank,[regCPUvar,#RPB_ofs]
	LDRH		rscratch,[regCPUvar,#RD_ofs]
	ORR		regD,regD,rscratch, LSL #16	
	//rstatus & regDBank share the same register
	LDRB		regDBank,[regCPUvar,#RDB_ofs]
	LDRH		rscratch,[regCPUvar,#RP_ofs]	
	ORRS		rstatus, rstatus, rscratch,LSL #STATUS_SHIFTER  	
	//if Carry set, then EMULATION bit was set
	ORRCS		rstatus,rstatus,#MASK_EMUL	
	//
	LDRH		regA,[regCPUvar,#RA_ofs]		
	LDRH		regX,[regCPUvar,#RX_ofs]
	LDRH		regY,[regCPUvar,#RY_ofs]
	LDRH		regS,[regCPUvar,#RS_ofs]
	//Shift X,Y & A according to the current mode (INDEX, MEMORY bits)
	TST		rstatus,#MASK_INDEX
	MOVNE		regX,regX,LSL #24
	MOVNE		regY,regY,LSL #24
	MOVEQ		regX,regX,LSL #16
	MOVEQ		regY,regY,LSL #16
	TST		rstatus,#MASK_MEM
	MOVNE		regA,regA,LSL #24
	MOVEQ		regA,regA,LSL #16
	
	LDR		regpcbase,[regCPUvar,#PCBase_ofs]
	LDR		rpc,[regCPUvar,#PC_ofs]	
	LDR		regCycles,[regCPUvar,#Cycles_ofs]
.endm


.macro		SAVE_REGS
	//regD & regPBank is same register
	STRB		regPBank,[regCPUvar,#RPB_ofs]
	MOV		rscratch,regD, LSR #16
	STRH		rscratch,[regCPUvar,#RD_ofs]
	//rstatus & regDBank is same register
	STRB		regDBank,[regCPUvar,#RDB_ofs]
	MOVS		rscratch, rstatus, LSR #STATUS_SHIFTER  
	ORRCS		rscratch,rscratch,#0x100 //EMULATION bit
	STRH		rscratch,[regCPUvar,#RP_ofs]
	//
	//Shift X,Y & A according to the current mode (INDEX, MEMORY bits)
	TST		rstatus,#MASK_INDEX
	MOVNE		rscratch,regX,LSR #24
	MOVNE		rscratch2,regY,LSR #24
	MOVEQ		rscratch,regX,LSR #16
	MOVEQ		rscratch2,regY,LSR #16
	STRH		rscratch,[regCPUvar,#RX_ofs]
	STRH		rscratch2,[regCPUvar,#RY_ofs]
	TST		rstatus,#MASK_MEM
	LDRNEH		rscratch,[regCPUvar,#RA_ofs]
	BICNE		rscratch,rscratch,#0xFF
	ORRNE		rscratch,rscratch,regA,LSR #24	
	MOVEQ		rscratch,regA,LSR #16
	STRH		rscratch,[regCPUvar,#RA_ofs]
	
	STRH		regS,[regCPUvar,#RS_ofs]	
	STR		regpcbase,[regCPUvar,#PCBase_ofs]
	STR		rpc,[regCPUvar,#PC_ofs]
	
	STR		regCycles,[regCPUvar,#Cycles_ofs]
.endm

/*****************************************************************/
.macro		ADD1CYCLE		
		add	regCycles,regCycles, #ONE_CYCLE		
.endm
.macro		ADD1CYCLENE
		addne	regCycles,regCycles, #ONE_CYCLE		
.endm		
.macro		ADD1CYCLEEQ
		addeq	regCycles,regCycles, #ONE_CYCLE		
.endm		

.macro		ADD2CYCLE
		add	regCycles,regCycles, #(ONE_CYCLE*2)
.endm
.macro		ADD2CYCLENE
		addne	regCycles,regCycles, #(ONE_CYCLE*2)
.endm
.macro		ADD2CYCLE2MEM		
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]
		add	regCycles,regCycles, #(ONE_CYCLE*2)
		add	regCycles, regCycles, rscratch, LSL #1		
.endm
.macro		ADD2CYCLE1MEM
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]
		add	regCycles,regCycles, #(ONE_CYCLE*2)
		add	regCycles, regCycles, rscratch
.endm

.macro		ADD3CYCLE
		add	regCycles,regCycles, #(ONE_CYCLE*3)
.endm

.macro		ADD1CYCLE1MEM
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]
		add	regCycles,regCycles, #ONE_CYCLE
		add	regCycles, regCycles, rscratch
.endm

.macro		ADD1CYCLE2MEM
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]
		add	regCycles,regCycles, #ONE_CYCLE
		add	regCycles, regCycles, rscratch, lsl #1
.endm

.macro		ADD1MEM
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]		
		add	regCycles, regCycles, rscratch
.endm
			
.macro		ADD2MEM
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]		
		add	regCycles, regCycles, rscratch, lsl #1
.endm
			
.macro		ADD3MEM
		ldr	rscratch,[regCPUvar,#MemSpeed_ofs]		
		add	regCycles, rscratch, regCycles
		add	regCycles, regCycles, rscratch, lsl #1
.endm

/**************/
.macro		ClearDecimal
		BIC	rstatus,rstatus,#MASK_DECIMAL	
.endm			
.macro		SetDecimal
		ORR	rstatus,rstatus,#MASK_DECIMAL	
.endm
.macro		SetIRQ
		ORR	rstatus,rstatus,#MASK_IRQ
.endm						
.macro		ClearIRQ
		BIC	rstatus,rstatus,#MASK_IRQ
.endm

.macro		CPUShutdown
//if (Settings.Shutdown && CPU.PC == CPU.WaitAddress)
		LDR		rscratch,[regCPUvar,#WaitAddress_ofs]
		CMP		rpc,rscratch
		BNE		5431f
//if (CPU.WaitCounter == 0 && !(CPU.Flags & (IRQ_PENDING_FLAG | NMI_FLAG)))		
		LDR		rscratch,[regCPUvar,#Flags_ofs]
		LDR		rscratch2,[regCPUvar,#WaitCounter_ofs]
		TST		rscratch,#(IRQ_PENDING_FLAG|NMI_FLAG)
		BNE		5432f		
		MOVS		rscratch2,rscratch2
		BNE		5432f
//CPU.WaitAddress = NULL;		
		MOV		rscratch,#0
		STR		rscratch,[regCPUvar,#WaitAddress_ofs]
//if (Settings.SA1)
//		S9xSA1ExecuteDuringSleep ();		: TODO
		
//	    CPU.Cycles = CPU.NextEvent;
		LDR		regCycles,[regCPUvar,#NextEvent_ofs]
		LDRB		r0,[regCPUvar,#APUExecuting_ofs]
		MOVS		r0,r0
		BEQ		5431f
//	    if (IAPU.APUExecuting)
/*	    {
		ICPU.CPUExecuting = FALSE;
		do
		{
		    APU_EXECUTE1();
		} while (APU.Cycles < CPU.NextEvent);
		ICPU.CPUExecuting = TRUE;
	    }
	*/					
		asmAPU_EXECUTE2
		B		5431f
.pool		
5432:
/*	else
	if (CPU.WaitCounter >= 2)
	    CPU.WaitCounter = 1;
	else
	    CPU.WaitCounter--;
*/
		CMP		rscratch2,#1
		MOVHI		rscratch2,#1
		//SUBLS		rscratch2,rscratch2,#1
		MOVLS		rscratch2,#0
		STR		rscratch2,[regCPUvar,#WaitCounter_ofs]
5431:		

.endm						
.macro		BranchCheck0	
		/*in rsctach : OpAddress
		/*destroy rscratch2*/
		LDRB	rscratch2,[regCPUvar,#BranchSkip_ofs]
		MOVS	rscratch2,rscratch2	
		BEQ	1110f
		MOV	rscratch2,#0		
		STRB	rscratch2,[regCPUvar,#BranchSkip_ofs]
		SUB	rscratch2,rpc,regpcbase
		//if( CPU.PC - CPU.PCBase > OpAddress) return;
		CMP	rscratch2,rscratch
		BHI	1111f
1110:		
.endm									
.macro		BranchCheck1		
		/*in rsctach : OpAddress
		/*destroy rscratch2*/
		LDRB	rscratch2,[regCPUvar,#BranchSkip_ofs]
		MOVS	rscratch2,rscratch2	
		BEQ	1110f
		MOV	rscratch2,#0		
		STRB	rscratch2,[regCPUvar,#BranchSkip_ofs]
		SUB	rscratch2,rpc,regpcbase
		//if( CPU.PC - CPU.PCBase > OpAddress) return;
		CMP	rscratch2,rscratch
		BHI	1111f
1110:
.endm												
.macro		BranchCheck2
		/*in rsctach : OpAddress
		/*destroy rscratch2*/
		LDRB	rscratch2,[regCPUvar,#BranchSkip_ofs]
		MOVS	rscratch2,rscratch2	
		BEQ	1110f
		MOV	rscratch2,#0		
		STRB	rscratch2,[regCPUvar,#BranchSkip_ofs]
		SUB	rscratch2,rpc,regpcbase
		//if( CPU.PC - CPU.PCBase > OpAddress) return;
		CMP	rscratch2,rscratch
		BHI	1111f
1110:		
.endm
			
.macro		S9xSetPCBase
		// in  : rscratch (0x00hhmmll)				
		PREPARE_C_CALL			
		BL	asm_S9xSetPCBase		
		RESTORE_C_CALL
		LDR	rpc,[regCPUvar,#PC_ofs]
		LDR	regpcbase,[regCPUvar,#PCBase_ofs]
.endm		

.macro		S9xFixCycles
#ifdef	__PALMOS__
		LDR		rscratch2,[regCPUvar,#PALMOS_R10_ofs]
#endif		
		TST		rstatus,#MASK_EMUL
		LDRNE		rscratch, = jumptable1	   //Mode 0 : M=1,X=1
		BNE		991111f
		//EMULATION=0
		TST		rstatus,#MASK_MEM
		BEQ		991112f
		//MEMORY=1
		TST		rstatus,#MASK_INDEX
		//INDEX=1  //Mode 0 : M=1,X=1
		LDRNE		rscratch, = jumptable1		
		//INDEX=0  //Mode 1 : M=1,X=0
		LDREQ		rscratch, = jumptable2
		B		991111f
991112:		//MEMORY=0		
		TST		rstatus,#MASK_INDEX
		//INDEX=1   //Mode 3 : M=0,X=1
		LDRNE		rscratch, = jumptable4
		//INDEX=0   //Mode 2 : M=0,X=0
		LDREQ		rscratch, = jumptable3		
991111:
#ifdef	__PALMOS__
		ADD		rscratch,rscratch,rscratch2
#endif		
		STR		rscratch,[regCPUvar,#asm_OPTABLE_ofs]
.endm		
.macro		S9xOpcode_NMI
		SAVE_REGS
		PREPARE_C_CALL_LIGHT
		BL	asm_S9xOpcode_NMI
		RESTORE_C_CALL_LIGHT
		LOAD_REGS		
.endm
.macro		S9xOpcode_IRQ
		SAVE_REGS
		PREPARE_C_CALL_LIGHT
		BL	asm_S9xOpcode_IRQ
		RESTORE_C_CALL_LIGHT
		LOAD_REGS		
.endm
.macro		S9xDoHBlankProcessing
		SAVE_REGS
		PREPARE_C_CALL_LIGHT
		BL	asm_S9xDoHBlankProcessing
		RESTORE_C_CALL_LIGHT
		LOAD_REGS		
.endm

/********************************/
.macro		EXEC_OP					
		LDR		R1,[regCPUvar,#asm_OPTABLE_ofs]
		STR		rpc,[regCPUvar,#PCAtOpcodeStart_ofs]
		ADD1MEM
		LDRB		R0, [rpc], #1		
		
#ifdef	__PALMOS__		
		LDR		R2,[regCPUvar,#PALMOS_R10_ofs]
		LDR		R3,[R1,R0,LSL #2]
		ADD		PC,R2,R3	
#else
		LDR		PC, [R1,R0, LSL #2]
#endif		
.endm
.macro		NEXTOPCODE
#ifdef	__TESTING__
		B	endmainLoop
#endif		
		LDR			rscratch,[regCPUvar,#NextEvent_ofs]
		CMP			regCycles,rscratch
		BLT			mainLoop
  		S9xDoHBlankProcessing
		B			mainLoop
.endm

.macro		asmAPU_EXECUTE
		LDRB		R0,[regCPUvar,#APUExecuting_ofs]
		MOVS		R0,R0
		BEQ		43210f
		//SAVE_REGS
		STR		regCycles,[regCPUvar,#Cycles_ofs]
		PREPARE_C_CALL_LIGHTR12
		BL		asm_APU_EXECUTE
		RESTORE_C_CALL_LIGHTR12
		LDR		regCycles,[regCPUvar,#Cycles_ofs]
		//LOAD_REGS
		//S9xFixCycles
43210:
.endm

.macro		asmAPU_EXECUTE2
		//SAVE_REGS		
		STR		regCycles,[regCPUvar,#Cycles_ofs]
		PREPARE_C_CALL_LIGHTR12
		BL		asm_APU_EXECUTE2
		RESTORE_C_CALL_LIGHTR12
		LDR		regCycles,[regCPUvar,#Cycles_ofs]		
		//LOAD_REGS
.endm


//void asmMainLoop(asm_cpu_var_t *asmcpuPtr);
asmMainLoop:
	//save registers
	STMFD		R13!,{R4-R11,LR}
	//init pointer to CPUvar structure
	MOV		regCPUvar,R0
	//init registers
	LOAD_REGS
	//get cpu mode from flag and init jump table
	S9xFixCycles
mainLoop:
	//APU Execute
	asmAPU_EXECUTE
	
	//Test Flags
	LDR		rscratch,[regCPUvar,#Flags_ofs]
	MOVS		rscratch,rscratch
	BNE		CPUFlags_set	//If flags => check for irq/nmi/scan_keys...	
	
	EXEC_OP						//Execute next opcode
	
CPUFlags_set:	//Check flags (!=0)
		TST	rscratch,#NMI_FLAG		//Check NMI
		BEQ	CPUFlagsNMI_FLAG_cleared	
		LDR	rscratch2,[regCPUvar,#NMICycleCount_ofs]
		SUBS	rscratch2,rscratch2,#1
		STR	rscratch2,[regCPUvar,#NMICycleCount_ofs]		
		BNE	CPUFlagsNMI_FLAG_cleared	
		BIC	rscratch,rscratch,#NMI_FLAG
		STR	rscratch,[regCPUvar,#Flags_ofs]		
		LDRB	rscratch2,[regCPUvar,#WaitingForInterrupt_ofs]
		MOVS	rscratch2,rscratch2
		BEQ	NotCPUaitingForInterruptNMI
		MOV	rscratch2,#0
		ADD	rpc,rpc,#1
		STRB	rscratch2,[regCPUvar,#WaitingForInterrupt_ofs]		
NotCPUaitingForInterruptNMI:
		S9xOpcode_NMI
		LDR	rscratch,[regCPUvar,#Flags_ofs]	
CPUFlagsNMI_FLAG_cleared:
		TST	rscratch,#IRQ_PENDING_FLAG   //Check IRQ_PENDING_FLAG
		BEQ	CPUFlagsIRQ_PENDING_FLAG_cleared		
		LDR	rscratch2,[regCPUvar,#IRQCycleCount_ofs]
		MOVS	rscratch2,rscratch2
		BNE	CPUIRQCycleCount_NotZero		
	 	LDRB	rscratch2,[regCPUvar,#WaitingForInterrupt_ofs]
		MOVS	rscratch2,rscratch2
		BEQ	NotCPUaitingForInterruptIRQ
	        MOV	rscratch2,#0
		ADD	rpc,rpc,#1
		STRB	rscratch2,[regCPUvar,#WaitingForInterrupt_ofs]
NotCPUaitingForInterruptIRQ:
		LDRB	rscratch2,[regCPUvar,#IRQActive_ofs]
		MOVS	rscratch2,rscratch2
		BEQ	CPUIRQActive_cleared
		TST	rstatus,#MASK_IRQ
		BNE	CPUFlagsIRQ_PENDING_FLAG_cleared
		S9xOpcode_IRQ
		LDR	rscratch,[regCPUvar,#Flags_ofs]	
		B	CPUFlagsIRQ_PENDING_FLAG_cleared
CPUIRQActive_cleared:		
		BIC	rscratch,rscratch,#IRQ_PENDING_FLAG
		STR	rscratch,[regCPUvar,#Flags_ofs]	
		B	CPUFlagsIRQ_PENDING_FLAG_cleared
CPUIRQCycleCount_NotZero:
		SUB	rscratch2,rscratch2,#1
		STR	rscratch2,[regCPUvar,#IRQCycleCount_ofs]
CPUFlagsIRQ_PENDING_FLAG_cleared:

		TST	rscratch,#SCAN_KEYS_FLAG   //Check SCAN_KEYS_FLAG
		BNE	endmainLoop		

	EXEC_OP	//Execute next opcode

endmainLoop:
    /*Registers.PC = CPU.PC - CPU.PCBase;
    S9xPackStatus ();
    APURegisters.PC = IAPU.PC - IAPU.RAM;
    S9xAPUPackStatus ();
    
    if (CPU.Flags & SCAN_KEYS_FLAG)
    {
	    S9xSyncSpeed ();
	CPU.Flags &= ~SCAN_KEYS_FLAG;
    }	*/
/********end*/
	SAVE_REGS
	LDMFD		R13!,{R4-R11,LR}
	MOV		PC,LR


.pool

//void test_opcode(struct asm_cpu_var *asm_var);
test_opcode:
	//save registers
	STMFD		R13!,{R4-R11,LR}
	//init pointer to CPUvar structure
	MOV		regCPUvar,R0
	//init registers
	LOAD_REGS
	//get cpu mode from flag and init jump table
	S9xFixCycles
	
	EXEC_OP
.pool
