/*
 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
 *
 * (c) Copyright 1996, 1997, 1998 Gary Henderson (gary@daniver.demon.co.uk) and
 *                                Jerremy Koot (jkoot@snes9x.com)
 *
 * Super FX C emulator code 
 * (c) Copyright 1997, 1998 Ivar (Ivar@snes9x.com) and
 *                          Gary Henderson.
 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
 *
 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
 * DOS port code contains the works of other authors. See headers in
 * individual files.
 *
 * Snes9x homepage: www.snes9x.com
 *
 * Permission to use, copy, modify and distribute Snes9x in both binary and
 * source form, for non-commercial purposes, is hereby granted without fee,
 * providing that this license information and copyright notice appear with
 * all copies and any derived work.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event shall the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Snes9x is freeware for PERSONAL USE only. Commercial users should
 * seek permission of the copyright holders first. Commercial use includes
 * charging money for Snes9x or software derived from Snes9x.
 *
 * The copyright holders request that bug fixes and improvements to the code
 * should be forwarded to them so everyone can benefit from the modifications
 * in future versions.
 *
 * Super NES and Super Nintendo Entertainment System are trademarks of
 * Nintendo Co., Limited and its subsidiary companies.
 */

.macro Adc8 K
	testb $Decimal, FLAGS
	jnz .ADC8Decimal\K
	GetCarry
	adcb AL, %al
	SetZNCV
	movb %al, AL
	jmp MainAsmLoop

.ADC8Decimal\K:
	GetCarry
	adcb AL, %al
	daa
	movb %al, AL
	SetZNCV
	jmp MainAsmLoop
.endm

.macro Adc16 K
	testb $Decimal, FLAGS
	jnz .ADC16Decimal\K
	GetCarry
	adcw AA, %ax
	movw %ax, AA
	setc _Carry
	seto _Overflow
	setnz _Zero
	movb %ah, _Negative
	jmp MainAsmLoop

.ADC16Decimal\K:
	GetCarry
	adcb AL, %al
	daa
	movb %al, AL
	movb %ah, %al
	adcb AH, %al
	daa
	movb %al, AH
	setc _Carry
	seto _Overflow
	movw AA, %ax
	movb %ah, _Negative
	orb %ah, %al
	movb %al, _Zero
	jmp MainAsmLoop
.endm

.macro Sbc8 K
	testb $Decimal, FLAGS
	jnz .SBC8Decimal\K
	GetNotCarry
	sbbb %al, AL
	movb AL, %al
	setnc _Carry
	SetZNV
	jmp MainAsmLoop

.SBC8Decimal\K:
	GetNotCarry
	movb %al, %dl
	movb AL, %al
	sbbb %dl, %al
	das
	movb %al, AL
	setnc _Carry
	SetZNV
	jmp MainAsmLoop
.endm

.macro Sbc16 K
	testb $Decimal, FLAGS
	jnz .SBC16Decimal\K
	GetNotCarry
	sbbw %ax, AA
	setnc _Carry
	setnz _Zero
	seto _Overflow
	movb AH, %al
	movb %al, _Negative
	jmp MainAsmLoop

.SBC16Decimal\K:
	movl %eax, %edx
	movw AA, %ax
	GetNotCarry
	sbbb %dl, %al
	das
	movb %al, AL
	movb %ah, %al
	sbbb %dh, %al
	das
	movb %al, AH
	setnc _Carry
	seto _Overflow
	movw AA, %ax
	movb %ah, _Negative
	orb %ah, %al
	movb %al, _Zero
	jmp MainAsmLoop
.endm

.macro Ora8 K
	orb AL, %al
	movb %al, AL
	SetZN
	jmp MainAsmLoop
.endm

.macro Ora16 K
	orw AA, %ax
	movw %ax, AA
	Set16ZN
	jmp MainAsmLoop
.endm

.macro Eor8 K
	xorb AL, %al
	movb %al, AL
	SetZN
	jmp MainAsmLoop
.endm

.macro Eor16 K
	xorw AA, %ax
	movw %ax, AA
	Set16ZN
	jmp MainAsmLoop
.endm

.macro And8 K
	andb AL, %al
	movb %al, AL
	SetZN
	jmp MainAsmLoop
.endm

.macro And16 K
	andw AA, %ax
	movw %ax, AA
	Set16ZN
	jmp MainAsmLoop
.endm

.macro Lda8 K
	movb %al, AL
	SetZN
	jmp MainAsmLoop
.endm

.macro Lda16 K
	movw %ax, AA
	testw %ax, %ax
	Set16ZN
	jmp MainAsmLoop
.endm

.macro Ldx8 K
	movb %al, XL
	SetZN
	jmp MainAsmLoop
.endm

.macro Ldx16 K
	movw %ax, XX
	testw %ax, %ax
	Set16ZN
	jmp MainAsmLoop
.endm

.macro Ldy8 K
	movb %al, YL
	SetZN
	jmp MainAsmLoop
.endm

.macro Ldy16 K
	movw %ax, YY
	testw %ax, %ax
	Set16ZN
	jmp MainAsmLoop
.endm

.macro Cmp8 K
	movb AL, %ah
	subb %al, %ah
	setnc _Carry
	movb %ah, _Negative
	movb %ah, _Zero
	jmp MainAsmLoop
.endm

.macro Cmp16 K
	movw AA, %dx
	subw %ax, %dx
	setnc _Carry
	setnz _Zero
	movb %dh, _Negative
	jmp MainAsmLoop
.endm

.macro Cpx8 K
	movb XL, %ah
	subb %al, %ah
	setnc _Carry
	movb %ah, _Negative
	movb %ah, _Zero
	jmp MainAsmLoop
.endm

.macro Cpx16 K
	movw XX, %dx
	subw %ax, %dx
	setnc _Carry
	setnz _Zero
	movb %dh, _Negative
	jmp MainAsmLoop
.endm

.macro Cpy8 K
	movb YL, %ah
	subb %al, %ah
	setnc _Carry
	movb %ah, _Negative
	movb %ah, _Zero
	jmp MainAsmLoop
.endm

.macro Cpy16 K
	movw YY, %dx
	subw %ax, %dx
	setnc _Carry
	setnz _Zero
	movb %dh, _Negative
	jmp MainAsmLoop
.endm

.macro Asl8 K
	pushl %edx
	call S9xGetByte
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	salb %al
	SetZNC
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Asl16 K
	pushl %edx
	call S9xGetWord
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	salw %ax
	Set16ZNC
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Lsr8 K
	pushl %edx
	call S9xGetByte
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	shrb %al
	SetZNC
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Lsr16 K
	pushl %edx
	call S9xGetWord
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	shrw %ax
	Set16ZNC
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Rol8 K
	pushl %edx
	call S9xGetByte
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	GetCarry
	rclb %al
	SetZNC
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Rol16 K
	pushl %edx
	call S9xGetWord
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	GetCarry
	rclw %ax
	setc _Carry
	movb %ah, _Negative
	testw %ax, %ax
	setnz _Zero
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Ror8 K
	pushl %edx
	call S9xGetByte
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	GetCarry
	rcrb %al
	SetZNC
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Ror16 K
	pushl %edx
	call S9xGetWord
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	GetCarry
	rcrw %ax
	setc _Carry
	movb %ah, _Negative
	testw %ax, %ax
	setnz _Zero
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Bit8 K
	call S9xGetByte
	movb %al, _Negative
	testb $0x40, %al
	setnz _Overflow
	andb AL, %al
	movb %al, _Zero
	jmp MainAsmLoop
.endm

.macro Bit16 K
	call S9xGetWord
	movb %ah, _Negative
	testb $0x40, %ah
	setnz _Overflow
	andw AA, %ax
	setnz _Zero
	jmp MainAsmLoop
.endm

.macro Dec8 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetByte
	decb %al
	SetZN
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Dec16 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetWord
	decw %ax
	Set16ZN
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Inc8 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetByte
	incb %al
	SetZN
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Inc16 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetWord
	incw %ax
	Set16ZN
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Sta8 K
	movb AL, %al
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Sta16 K
	movw AA, %ax
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Stx8 K
	movb XL, %al
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Stx16 K
	movw XX, %ax
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Sty8 K
	movb YL, %al
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Sty16 K
	movw YY, %ax
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Stz8 K
	xorb %al, %al
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Stz16 K
	xorl %eax, %eax
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Trb8 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetByte
	movb AL, %dl
	testb %al, %dl
	setnz _Zero
	xorb $0xff, %dl
	andb %dl, %al
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Trb16 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetWord
	movw AA, %dx
	testw %ax, %dx
	setnz _Zero
	xorl $0xffffffff, %edx
	andl %edx, %eax
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro Tsb8 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	call S9xGetByte
	movb AL, %dl
	testb %al, %dl
	setnz _Zero
	orb %dl, %al
	popl %edx
	call S9xSetByte
	jmp MainAsmLoop
.endm

.macro Tsb16 K
	pushl %edx
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif	
	call S9xGetWord
	movw AA, %dx
	testw %ax, %dx
	setnz _Zero
	orw %dx, %ax
	popl %edx
	call S9xSetWord
	jmp MainAsmLoop
.endm

.macro CheckForIrq K
	testb $0xff, IRQActive
	jz .CheckForIrqS9xExit\K
	testb $IRQ, FLAGS
	jnz .CheckForIrqS9xExit\K
	testb $0xff, DisableIRQ
	jnz .CheckForIrqS9xExit\K
	call S9xOpcode_IRQ
.CheckForIrqS9xExit\K:
.endm

.macro S9xFixCycles K
	testw $Emulation, FLAGS16
	jz .S9xFixCyclesNoEmulation\K
#ifndef VAR_CYCLES
	movl $S9xE1M1X1, CPUSpeed
#endif
	movl $S9xOpcodesM1X1, CPUOpcodes
	jmp .S9xFixCyclesS9xExit\K

.S9xFixCyclesNoEmulation\K:	
	testb $MemoryFlag, FLAGS
	jz .S9xFixCyclesNoMemory\K
	testb $IndexFlag, FLAGS
	jz .S9xFixCyclesNoIndex\K
#ifndef VAR_CYCLES
	movl $S9xE0M1X1, CPUSpeed
#endif
	movl $S9xOpcodesM1X1, CPUOpcodes
	jmp .S9xFixCyclesS9xExit\K
.S9xFixCyclesNoIndex\K:
#ifndef VAR_CYCLES
	movl $S9xE0M1X0, CPUSpeed
#endif
	movl $S9xOpcodesM1X0, CPUOpcodes
	jmp .S9xFixCyclesS9xExit\K

.S9xFixCyclesNoMemory\K:
	testb $IndexFlag, FLAGS
	jz .S9xFixCyclesNoIndex2\K
#ifndef VAR_CYCLES
	movl $S9xE0M0X1, CPUSpeed
#endif
	movl $S9xOpcodesM0X1, CPUOpcodes
	jmp .S9xFixCyclesS9xExit\K
.S9xFixCyclesNoIndex2\K:
#ifndef VAR_CYCLES
	movl $S9xE0M0X0, CPUSpeed
#endif
	movl $S9xOpcodesM0X0, CPUOpcodes
.S9xFixCyclesS9xExit\K:
.endm

.macro S9xUnpackStatus K
	movb FLAGS, %al
	movb %al, _Negative
	testb $Zero, %al
	setz _Zero
	testb $Carry, FLAGS
	setnz _Carry
	testb $Overflow, FLAGS
	setnz _Overflow
.endm

.macro S9xPackStatus K
	movb _Carry, %al
	andb $~(Zero | Negative | Carry | Overflow), FLAGS
	orb %al, FLAGS
	movb _Negative, %al
	andb $0x80, %al
	orb %al, FLAGS
	movb _Overflow, %al
	salb $6, %al
	orb %al, FLAGS
	testb $0xff, _Zero
	setz %al
	salb %al
	orb %al, FLAGS
.endm

.macro CPUShutdown K
#ifdef CPU_SHUTDOWN
	testb $0xff, BranchSkip
	jnz .NoCPUShutdown\K
	testb $0xff, Shutdown
	jz .NoCPUShutdown\K
	movl PCBase, %eax
	addl %edx, %eax
	cmpl %eax, WaitAddress
	jne .NoCPUShutdown\K
	movl WaitCounter, %eax
	testl %eax, %eax
	jnz .CPUShutdownNotYet\K
	xorl %eax, %eax
	movl %eax, WaitAddress
	movl NextEvent, CYCLES
	testb $0xff, APUExecuting
	jz .NoCPUShutdown\K

	pushl %edx
	movb $0, CPUExecuting
.CPUShutdownAPUExecLoop\K:
#ifdef DEBUGGER
	testb $2,APUFlags
	je .CPUShutdownNoAPUS9xTrace\K
	STORE_REGISTERS
	ccall S9xTraceAPU
	LOAD_REGISTERS
.CPUShutdownNoAPUS9xTrace\K:
#endif
	xorl %eax,%eax
#ifdef SPC700_C
	movl APUPC,%edx
	SAVE_CYCLES
	movb (%edx),%al
#else
	movb (APUPC),%al
#endif
	movl S9xApuCycles(,%eax,4), %edx
	movl S9xApuOpcodes(,%eax,4),%eax
	addl %edx, APUCycles
	call *%eax
#ifdef SPC700_C
	LOAD_CYCLES
#endif
	movl NextEvent, %eax
	cmpl %eax, APUCycles
	jl .CPUShutdownAPUExecLoop\K
	
	popl %edx
	movb $1, CPUExecuting
	jmp .NoCPUShutdown\K

.CPUShutdownNotYet\K:
	cmpl $2, %eax
	jb .CPUShutdownDecCounter\K
	movl $1, %eax
	movl %eax, WaitCounter
	jmp .NoCPUShutdown\K
.CPUShutdownDecCounter\K:
	decl WaitCounter
.NoCPUShutdown\K:	
#endif
.endm
