/*
	WinSTon
*/

//-----------------------------------------------------------------------
#define STRAM_OFFSET		edi
#define STRAM_ADDR(Var)		( (unsigned long)STRam+((unsigned long)Var&0x00ffffff) )	// Offset ST address to PC pointer
#define RET					__asm	jmp	InstructionLoop

//-----------------------------------------------------------------------
// We need to save our emulation condition codes and program counter when calling 'C'
// NOTE we need to preserve the top byte in the program counter as this is lost when converted into PC address space
#define	SAVE_ASSEM_REGS		__asm	mov		[EmuCCode],eax \
							__asm	sub		esi,STRAM_OFFSET \
							__asm	and		[PC],0xff000000 \
							__asm	or		[PC],esi

#define	RESTORE_ASSEM_REGS	__asm	mov		edi,OFFSET [STRam] \
							__asm	mov		esi,[PC] \
							__asm	and		esi,0x00ffffff \
							__asm	add		esi,STRAM_OFFSET \
							__asm	mov		eax,[EmuCCode]

//-----------------------------------------------------------------------
// Push/Pop all registers when going between assembler and 'C' functions
#define PUSH_ALL			__asm	push	eax \
							__asm	push	ebx \
							__asm	push	ecx \
							__asm	push	edx \
							__asm	push	esi \
							__asm	push	edi \
							__asm	push	ebp

#define POP_ALL				__asm	pop		ebp \
							__asm	pop		edi \
							__asm	pop		esi \
							__asm	pop		edx \
							__asm	pop		ecx \
							__asm	pop		ebx \
							__asm	pop		eax

//-----------------------------------------------------------------------
// Swap upper and lower bytes of 16-bit word
#define SWAP_ENDIAN_WORD_AX		__asm	ror	ax,8
#define SWAP_ENDIAN_WORD_BX		__asm	ror	bx,8
#define SWAP_ENDIAN_WORD_CX		__asm	ror	cx,8
#define SWAP_ENDIAN_WORD_DX		__asm	ror	dx,8

// Swap upper and lower words of 32-bit word
#define SWAP_ENDIAN_LONG_EAX	__asm	bswap	eax
#define SWAP_ENDIAN_LONG_EBX	__asm	bswap	ebx
#define SWAP_ENDIAN_LONG_ECX	__asm	bswap	ecx
#define SWAP_ENDIAN_LONG_EDX	__asm	bswap	edx

//-----------------------------------------------------------------------
// Offsets from memory space program counter to immediate data(in wrong endian)
#define IMM_BYTE	SIZE_BYTE							// Byte offset 
#define IMM_WORD
#define IMM_LONG

//-----------------------------------------------------------------------
// Set clock times for each instruction, see '68000 timing' pages for details
// NOTE All times are rounded up to nearest 4 cycles
#define	ROUND_CYCLES_TO4(var)	(((int)(var)+3)&0xfffffffc)

#define	ADD_CYCLES(op,r,w)		  __asm	sub	[PendingInterruptCount],(op+3)&0xfffffffc \
								  __asm add [SoundCycles],(op+3)&0xfffffffc

//-----------------------------------------------------------------------
// Decode table structure offsets, see 'DecodeTable[]' MUST match 'decode.inc'
#define DECODE_CYCLES		0							// Cycles for this instruction, includes <ea> etc...
#define DECODE_FUNCTION		4							// Decode function to call
#define DECODE_EA			8							// <ea> Decode function
#define DECODE_1			12							// src/dest parameters
#define DECODE_2			16
#define DECODE_DISASS		20							// Disassembly function
#define SIZEOF_DECODE		8

//-----------------------------------------------------------------------
#define PENDING_INTERRUPT_FLAG_MFP			0x0001		// 'PendingInterruptFlag' masks, MUST match 'decode.inc'
#define PENDING_INTERRUPT_FLAG_TRACE		0x0002
#define	CLEAR_PENDING_INTERRUPT_FLAG_MFP	0xfffe
#define	CLEAR_PENDING_INTERRUPT_FLAG_TRACE	0xfffd

//-----------------------------------------------------------------------
#define INSTRUCTION_HISTORY_SIZE	8192				// MUST be ^2, and MUST match 'decode.inc'
#define INSTRUCTION_HISTORY_MASK	(INSTRUCTION_HISTORY_SIZE-1)

//-----------------------------------------------------------------------
#define	NUM_BREAKPOINTS		8							// MUST match 'decode.inc'

//-----------------------------------------------------------------------
// 68000 instruction emulation functions
extern "C" void abcd_dn_dn(void);
extern "C" void abcd_an_an(void);

extern "C" void add_ea_dn_byte(void);
extern "C" void add_ea_dn_word(void);
extern "C" void add_ea_dn_long(void);
extern "C" void add_dn_ea_byte(void);
extern "C" void add_dn_ea_word(void);
extern "C" void add_dn_ea_long(void);

extern "C" void adda_ea_an_word(void);
extern "C" void adda_ea_an_long(void);

extern "C" void addi_imm_dn_byte(void);
extern "C" void addi_imm_dn_word(void);
extern "C" void addi_imm_dn_long(void);
extern "C" void addi_imm_ea_byte(void);
extern "C" void addi_imm_ea_word(void);
extern "C" void addi_imm_ea_long(void);

extern "C" void addq_imm_dn_byte(void);
extern "C" void addq_imm_dn_word(void);
extern "C" void addq_imm_dn_long(void);
extern "C" void addq_imm_an_word(void);
extern "C" void addq_imm_an_long(void);
extern "C" void addq_imm_ea_byte(void);
extern "C" void addq_imm_ea_word(void);
extern "C" void addq_imm_ea_long(void);

extern "C" void addx_dn_dn_byte(void);
extern "C" void addx_dn_dn_word(void);
extern "C" void addx_dn_dn_long(void);
extern "C" void addx_an_an_byte(void);
extern "C" void addx_an_an_word(void);
extern "C" void addx_an_an_long(void);

extern "C" void and_ea_dn_byte(void);
extern "C" void and_ea_dn_word(void);
extern "C" void and_ea_dn_long(void);
extern "C" void and_dn_ea_byte(void);
extern "C" void and_dn_ea_word(void);
extern "C" void and_dn_ea_long(void);

extern "C" void andi_imm_dn_byte(void);
extern "C" void andi_imm_dn_word(void);
extern "C" void andi_imm_dn_long(void);
extern "C" void andi_imm_ea_byte(void);
extern "C" void andi_imm_ea_word(void);
extern "C" void andi_imm_ea_long(void);
extern "C" void andi_imm_ccr_byte(void);
extern "C" void andi_imm_sr_word(void);

extern "C" void asl_dn_dn_byte(void);
extern "C" void asl_dn_dn_word(void);
extern "C" void asl_dn_dn_long(void);
extern "C" void asl_imm_dn_byte(void);
extern "C" void asl_imm_dn_word(void);
extern "C" void asl_imm_dn_long(void);
extern "C" void asl_ea_word(void);

extern "C" void asr_dn_dn_byte(void);
extern "C" void asr_dn_dn_word(void);
extern "C" void asr_dn_dn_long(void);
extern "C" void asr_imm_dn_byte(void);
extern "C" void asr_imm_dn_word(void);
extern "C" void asr_imm_dn_long(void);
extern "C" void asr_ea_word(void);

extern "C" void bcc_s(void);
extern "C" void bcc_w(void);
extern "C" void bcs_s(void);
extern "C" void bcs_w(void);
extern "C" void beq_s(void);
extern "C" void beq_w(void);
extern "C" void bge_s(void);
extern "C" void bge_w(void);
extern "C" void bgt_s(void);
extern "C" void bgt_w(void);
extern "C" void bhi_s(void);
extern "C" void bhi_w(void);
extern "C" void ble_s(void);
extern "C" void ble_w(void);
extern "C" void bls_s(void);
extern "C" void bls_w(void);
extern "C" void blt_s(void);
extern "C" void blt_w(void);
extern "C" void bmi_s(void);
extern "C" void bmi_w(void);
extern "C" void bne_s(void);
extern "C" void bne_w(void);
extern "C" void bpl_s(void);
extern "C" void bpl_w(void);
extern "C" void bvc_s(void);
extern "C" void bvc_w(void);
extern "C" void bvs_s(void);
extern "C" void bvs_w(void);

extern "C" void bchg_dn_dn_long(void);
extern "C" void bchg_dn_ea_byte(void);
extern "C" void bchg_imm_dn_long(void);
extern "C" void bchg_imm_ea_byte(void);

extern "C" void bclr_dn_dn_long(void);
extern "C" void bclr_dn_ea_byte(void);
extern "C" void bclr_imm_dn_long(void);
extern "C" void bclr_imm_ea_byte(void);

extern "C" void bra_s(void);
extern "C" void bra_w(void);

extern "C" void bset_dn_dn_long(void);
extern "C" void bset_dn_ea_byte(void);
extern "C" void bset_imm_dn_long(void);
extern "C" void bset_imm_ea_byte(void);

extern "C" void bsr_s(void);
extern "C" void bsr_w(void);

extern "C" void btst_dn_dn_long(void);
extern "C" void btst_dn_ea_byte(void);
extern "C" void btst_imm_dn_long(void);
extern "C" void btst_imm_ea_byte(void);

extern "C" void chk_ea_dn_word(void);

extern "C" void clr_dn_byte(void);
extern "C" void clr_dn_word(void);
extern "C" void clr_dn_long(void);
extern "C" void clr_ea_byte(void);
extern "C" void clr_ea_word(void);
extern "C" void clr_ea_long(void);

extern "C" void cmp_ea_dn_byte(void);
extern "C" void cmp_ea_dn_word(void);
extern "C" void cmp_ea_dn_long(void);

extern "C" void cmpa_ea_an_word(void);
extern "C" void cmpa_ea_an_long(void);

extern "C" void cmpi_imm_dn_byte(void);
extern "C" void cmpi_imm_dn_word(void);
extern "C" void cmpi_imm_dn_long(void);
extern "C" void cmpi_imm_ea_byte(void);
extern "C" void cmpi_imm_ea_word(void);
extern "C" void cmpi_imm_ea_long(void);

extern "C" void cmp_an_an_byte(void);
extern "C" void cmp_an_an_word(void);
extern "C" void cmp_an_an_long(void);

extern "C" void dbcc(void);
extern "C" void dbcs(void);
extern "C" void dbeq(void);
extern "C" void dbf(void);
extern "C" void dbge(void);
extern "C" void dbgt(void);
extern "C" void dbhi(void);
extern "C" void dble(void);
extern "C" void dbls(void);
extern "C" void dblt(void);
extern "C" void dbmi(void);
extern "C" void dbne(void);
extern "C" void dbpl(void);
extern "C" void dbt(void);
extern "C" void dbvc(void);
extern "C" void dbvs(void);

extern "C" void divs_ea_dn_word(void);

extern "C" void divu_ea_dn_word(void);

extern "C" void eor_dn_dn_byte(void);
extern "C" void eor_dn_dn_word(void);
extern "C" void eor_dn_dn_long(void);
extern "C" void eor_dn_ea_byte(void);
extern "C" void eor_dn_ea_word(void);
extern "C" void eor_dn_ea_long(void);

extern "C" void eori_imm_dn_byte(void);
extern "C" void eori_imm_dn_word(void);
extern "C" void eori_imm_dn_long(void);
extern "C" void eori_imm_ea_byte(void);
extern "C" void eori_imm_ea_word(void);
extern "C" void eori_imm_ea_long(void);
extern "C" void eori_imm_ccr_byte(void);
extern "C" void eori_imm_sr_word(void);

extern "C" void exg_dn_dn_long(void);
extern "C" void exg_an_an_long(void);
extern "C" void exg_dn_an_long(void);

extern "C" void ext_dn_word(void);
extern "C" void ext_dn_long(void);

extern "C" void illegal(void);

extern "C" void jmp_ea(void);

extern "C" void jsr_ea(void);

extern "C" void lea_ea_an_long(void);

extern "C" void link(void);

extern "C" void lsl_dn_dn_byte(void);
extern "C" void lsl_dn_dn_word(void);
extern "C" void lsl_dn_dn_long(void);
extern "C" void lsl_imm_dn_byte(void);
extern "C" void lsl_imm_dn_word(void);
extern "C" void lsl_imm_dn_long(void);
extern "C" void lsl_ea_word(void);

extern "C" void lsr_dn_dn_byte(void);
extern "C" void lsr_dn_dn_word(void);
extern "C" void lsr_dn_dn_long(void);
extern "C" void lsr_imm_dn_byte(void);
extern "C" void lsr_imm_dn_word(void);
extern "C" void lsr_imm_dn_long(void);
extern "C" void lsr_ea_word(void);

extern "C" void move_ea_000_byte(void);
extern "C" void move_ea_000_word(void);
extern "C" void move_ea_000_long(void);
extern "C" void move_ea_010_byte(void);
extern "C" void move_ea_010_word(void);
extern "C" void move_ea_010_long(void);
extern "C" void move_ea_011_byte(void);
extern "C" void move_ea_011_byte_A7(void);
extern "C" void move_ea_011_word(void);
extern "C" void move_ea_011_long(void);
extern "C" void move_ea_100_byte(void);
extern "C" void move_ea_100_byte_A7(void);
extern "C" void move_ea_100_word(void);
extern "C" void move_ea_100_long(void);
extern "C" void move_ea_101_byte(void);
extern "C" void move_ea_101_word(void);
extern "C" void move_ea_101_long(void);
extern "C" void move_ea_110_byte(void);
extern "C" void move_ea_110_word(void);
extern "C" void move_ea_110_long(void);
extern "C" void move_ea_111_000_byte(void);
extern "C" void move_ea_111_000_word(void);
extern "C" void move_ea_111_000_long(void);
extern "C" void move_ea_111_001_byte(void);
extern "C" void move_ea_111_001_word(void);
extern "C" void move_ea_111_001_long(void);
extern "C" void move_usp_an_long(void);
extern "C" void move_an_usp_long(void);
extern "C" void move_ea_ccr_word(void);
extern "C" void move_sr_dn_word(void);
extern "C" void move_sr_ea_word(void);
extern "C" void move_ea_sr_word(void);

extern "C" void movea_ea_an_word(void);
extern "C" void movea_ea_an_long(void);

extern "C" void movem_reg_an_dec_word(void);
extern "C" void movem_reg_an_dec_long(void);
extern "C" void movem_reg_ea_word(void);
extern "C" void movem_reg_ea_long(void);
extern "C" void movem_an_inc_reg_word(void);
extern "C" void movem_an_inc_reg_long(void);
extern "C" void movem_ea_reg_word(void);
extern "C" void movem_ea_reg_long(void);

extern "C" void movep_dn_an_word(void);
extern "C" void movep_dn_an_long(void);
extern "C" void movep_an_dn_word(void);
extern "C" void movep_an_dn_long(void);

extern "C" void moveq_imm_dn_long(void);

extern "C" void muls_ea_dn_word(void);

extern "C" void mulu_ea_dn_word(void);

extern "C" void nbcd_dn_byte(void);
extern "C" void nbcd_ea_byte(void);

extern "C" void neg_dn_byte(void);
extern "C" void neg_dn_word(void);
extern "C" void neg_dn_long(void);
extern "C" void neg_ea_byte(void);
extern "C" void neg_ea_word(void);
extern "C" void neg_ea_long(void);

extern "C" void negx_dn_byte(void);
extern "C" void negx_dn_word(void);
extern "C" void negx_dn_long(void);
extern "C" void negx_ea_byte(void);
extern "C" void negx_ea_word(void);
extern "C" void negx_ea_long(void);

extern "C" void nop(void);

extern "C" void not_dn_byte(void);
extern "C" void not_dn_word(void);
extern "C" void not_dn_long(void);
extern "C" void not_ea_byte(void);
extern "C" void not_ea_word(void);
extern "C" void not_ea_long(void);

extern "C" void or_ea_dn_byte(void);
extern "C" void or_ea_dn_word(void);
extern "C" void or_ea_dn_long(void);
extern "C" void or_dn_ea_byte(void);
extern "C" void or_dn_ea_word(void);
extern "C" void or_dn_ea_long(void);

extern "C" void ori_imm_dn_byte(void);
extern "C" void ori_imm_dn_word(void);
extern "C" void ori_imm_dn_long(void);
extern "C" void ori_imm_ea_byte(void);
extern "C" void ori_imm_ea_word(void);
extern "C" void ori_imm_ea_long(void);
extern "C" void ori_imm_ccr_byte(void);
extern "C" void ori_imm_sr_word(void);

extern "C" void pea_ea_long(void);

extern "C" void reset(void);

extern "C" void rol_dn_dn_byte(void);
extern "C" void rol_dn_dn_word(void);
extern "C" void rol_dn_dn_long(void);
extern "C" void rol_imm_dn_byte(void);
extern "C" void rol_imm_dn_word(void);
extern "C" void rol_imm_dn_long(void);
extern "C" void rol_ea_word(void);

extern "C" void ror_dn_dn_byte(void);
extern "C" void ror_dn_dn_word(void);
extern "C" void ror_dn_dn_long(void);
extern "C" void ror_imm_dn_byte(void);
extern "C" void ror_imm_dn_word(void);
extern "C" void ror_imm_dn_long(void);
extern "C" void ror_ea_word(void);

extern "C" void roxl_dn_dn_byte(void);
extern "C" void roxl_dn_dn_word(void);
extern "C" void roxl_dn_dn_long(void);
extern "C" void roxl_imm_dn_byte(void);
extern "C" void roxl_imm_dn_word(void);
extern "C" void roxl_imm_dn_long(void);
extern "C" void roxl_ea_word(void);

extern "C" void roxr_dn_dn_byte(void);
extern "C" void roxr_dn_dn_word(void);
extern "C" void roxr_dn_dn_long(void);
extern "C" void roxr_imm_dn_byte(void);
extern "C" void roxr_imm_dn_word(void);
extern "C" void roxr_imm_dn_long(void);
extern "C" void roxr_ea_word(void);

extern "C" void rte(void);

extern "C" void rtr(void);

extern "C" void rts(void);

extern "C" void sbcd_dn_dn(void);
extern "C" void sbcd_an_an(void);

extern "C" void scc_dn(void);
extern "C" void scc(void);
extern "C" void scs_dn(void);
extern "C" void scs(void);
extern "C" void seq_dn(void);
extern "C" void seq(void);
extern "C" void sf_dn(void);
extern "C" void sf(void);
extern "C" void sge_dn(void);
extern "C" void sge(void);
extern "C" void sgt_dn(void);
extern "C" void sgt(void);
extern "C" void shi_dn(void);
extern "C" void shi(void);
extern "C" void sle_dn(void);
extern "C" void sle(void);
extern "C" void sls_dn(void);
extern "C" void sls(void);
extern "C" void slt_dn(void);
extern "C" void slt(void);
extern "C" void smi_dn(void);
extern "C" void smi(void);
extern "C" void sne_dn(void);
extern "C" void sne(void);
extern "C" void spl_dn(void);
extern "C" void spl(void);
extern "C" void st_dn(void);
extern "C" void st(void);
extern "C" void svc_dn(void);
extern "C" void svc(void);
extern "C" void svs_dn(void);
extern "C" void svs(void);

extern "C" void stop(void);

extern "C" void sub_ea_dn_byte(void);
extern "C" void sub_ea_dn_word(void);
extern "C" void sub_ea_dn_long(void);
extern "C" void sub_dn_ea_byte(void);
extern "C" void sub_dn_ea_word(void);
extern "C" void sub_dn_ea_long(void);

extern "C" void suba_ea_an_word(void);
extern "C" void suba_ea_an_long(void);

extern "C" void subi_imm_dn_byte(void);
extern "C" void subi_imm_dn_word(void);
extern "C" void subi_imm_dn_long(void);
extern "C" void subi_imm_ea_byte(void);
extern "C" void subi_imm_ea_word(void);
extern "C" void subi_imm_ea_long(void);

extern "C" void subq_imm_dn_byte(void);
extern "C" void subq_imm_dn_word(void);
extern "C" void subq_imm_dn_long(void);
extern "C" void subq_imm_an_word(void);
extern "C" void subq_imm_an_long(void);
extern "C" void subq_imm_ea_byte(void);
extern "C" void subq_imm_ea_word(void);
extern "C" void subq_imm_ea_long(void);

extern "C" void subx_dn_dn_byte(void);
extern "C" void subx_dn_dn_word(void);
extern "C" void subx_dn_dn_long(void);
extern "C" void subx_an_an_byte(void);
extern "C" void subx_an_an_word(void);
extern "C" void subx_an_an_long(void);

extern "C" void swap_dn_word(void);

extern "C" void tas_dn_byte(void);
extern "C" void tas_ea_byte(void);

extern "C" void trap(void);

extern "C" void trapv(void);

extern "C" void tst_dn_byte(void);
extern "C" void tst_dn_word(void);
extern "C" void tst_dn_long(void);
extern "C" void tst_ea_byte(void);
extern "C" void tst_ea_word(void);
extern "C" void tst_ea_long(void);

extern "C" void unlk_an(void);


extern "C" unsigned char PCCodeTable_NZVC[4096];
extern "C" unsigned char PCCodeTable_NZV_CX_SAME[4096];
extern "C" unsigned long ShiftCycleTable_ByteWord[64];
extern "C" unsigned long ShiftCycleTable_Long[64];
extern "C" unsigned long Regs[16+1];
extern "C" unsigned long STRamEnd;
extern "C" unsigned long STRamEnd_BusErr;
extern "C" short int PendingInterruptCount;
extern "C" short int PendingInterruptFlag;
extern "C" void *PendingInterruptFunction;
extern "C" int InsPC;
extern "C" int SoundCycles;
extern "C" unsigned long PC;
extern "C" unsigned short int SR,SR_Before;
extern "C" BOOL bInSuperMode;
extern "C" unsigned long *Reg_SuperSP,*Reg_UserSP;
extern "C" unsigned long EmuCCode;
extern "C" unsigned long StackSave;
extern "C" unsigned long ExceptionVector;
extern "C" unsigned long BusAddressLocation;
extern "C" unsigned char STRam[16*1024*1024];
extern "C" unsigned long DecodeTable[65536*SIZEOF_DECODE];
extern "C" unsigned long InstructionHistory[INSTRUCTION_HISTORY_SIZE];
extern "C" int InstructionHistoryIndex;
extern "C" unsigned long BreakPointInstruction;
extern "C" unsigned long AddressBreakpoints[NUM_BREAKPOINTS];
extern "C" unsigned long BreakOnAddress;
extern "C" unsigned long CPUStopped;

extern "C" void RunIntructions(void);
extern "C" void InstructionLoop(void);
