/*
 * 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.
 */

.data
.BankSave:
	.long 0
.text

.globl S9xGetByte

S9xGetByte:
	movl %edx, %eax
	shrl $13, %eax
	and $0x7ff, %eax
#ifdef VAR_CYCLES
	movb MemorySpeed(%eax), %cl
#endif
#ifdef CPU_SHUTDOWN
	movb BlockIsRAM(%eax), %ch
#endif	
	movl Map(, %eax, 4), %eax
	cmpl $6, %eax
	jbe .GBSpecial
	andl $0xffff, %edx
#ifdef CPU_SHUTDOWN
	testb %ch, %ch
	jz .GBNotRAM
	pushl %eax
	movl PCAtOpcodeStart, %eax
	movl %eax, WaitAddress
	popl %eax
.GBNotRAM:
#endif	
#ifdef VAR_CYCLES
	andl $0xff, %ecx
	addl %ecx, CYCLES
#endif
	movb (%eax, %edx), %al
	ret

	.align 4
.GBSpecial:
	jmp *.GBJmpTable(, %eax, 4)
.data
	.align 4
.GBJmpTable:
	.long .GBPPU
	.long .GBCPU
	.long .GBDSP
	.long .GBLSRAM
	.long .GBHSRAM
	.long .GBNONE
	.long .GBDEBUG

.text
.GBPPU: /* MAP_PPU */
#ifdef VAR_CYCLES
	movb InDMA, %al
	testb %al, %al
	jne .GBPPU_NOADD
	addl $6, CYCLES
.GBPPU_NOADD:
#endif
	SAVE_CYCLES
	pushl %edx
	ccall S9xGetPPU
	popl %edx
	LOAD_CYCLES
	ret

.GBCPU: /* MAP_CPU */
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	SAVE_CYCLES
	pushl %edx
	ccall S9xGetCPU
	popl %edx
	LOAD_CYCLES
	ret

.GBDSP: /* MAP_DSP */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	SAVE_CYCLES
	pushl %edx
	ccall S9xGetDSP
	LOAD_CYCLES
	popl %edx
	ret

.GBLSRAM: /* MAP_LOROM_SRAM */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	andl $0xffff, %edx
	movl SRAM, %ecx
	andw SRAMMask, %dx
	movb (%ecx, %edx), %al
	ret

.GBHSRAM: /* MAP_HIROM_SRAM */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	movl %edx, %ecx
	andl $0xf0000, %ecx
	andl $0x7fff, %edx
	sarl $3, %ecx
	addl $-24576, %edx
	addl %ecx, %edx
	movl SRAM, %eax
	andw SRAMMask, %dx
	movb (%eax, %edx), %al
	ret

.GBNONE:
.GBDEBUG: /* MAP_DEBUG */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	xorl %eax, %eax
	ret

.globl S9xGetWord

S9xGetWord:
	movl %edx, %eax
	andl $0x1fff, %eax
	cmpl $0x1fff, %eax
	jne .GWNotAtBlockBoundary
	pushl %edx
	call S9xGetByte
	popl %edx
	incl %edx
	pushl %eax
	call S9xGetByte
	movb %al, %dl
	popl %eax
	movb %dl, %ah
	ret

.GWNotAtBlockBoundary:
	movl %edx, %eax
	shrl $13, %eax
	and $0x7ff, %eax
#ifdef VAR_CYCLES
	movb MemorySpeed(%eax), %cl
#endif
#ifdef CPU_SHUTDOWN
	movb BlockIsRAM(%eax), %ch
#endif	
	movl Map(, %eax, 4), %eax
	cmpl $6, %eax
	jbe .GWSpecial
	andl $0xffff, %edx
#ifdef CPU_SHUTDOWN
	testb %ch, %ch
	jz .GWNotRAM
	pushl %eax
	movl PCAtOpcodeStart, %eax
	movl %eax, WaitAddress
	popl %eax
.GWNotRAM:
#endif	
#ifdef VAR_CYCLES
	andl $0xff, %ecx
	addl %ecx, CYCLES
	addl %ecx, CYCLES
#endif
	movw (%eax, %edx), %ax
	ret

	.align 4
.GWSpecial:
	jmp *.GWJmpTable(, %eax, 4)

.data
	.align 4
.GWJmpTable:
	.long .GWPPU
	.long .GWCPU
	.long .GWDSP
	.long .GWLSRAM
	.long .GWHSRAM
	.long .GWNONE
	.long .GWDEBUG

.text
.GWPPU: /* MAP_PPU */
#ifdef VAR_CYCLES
	movb InDMA, %al
	testb %al, %al
	jne .GWPPU_NOADD
	addl $12, CYCLES
.GWPPU_NOADD:
#endif
	SAVE_CYCLES
	pushl %edx
	ccall S9xGetPPU
	popl %edx
	pushl %eax
	incl %edx
	pushl %edx
	ccall S9xGetPPU
	LOAD_CYCLES
	popl %edx
	popl %edx
	movb %al, %ah
	movb %dl, %al
	ret

.GWCPU: /* MAP_CPU */
#ifdef VAR_CYCLES
	addl $12, CYCLES
#endif
	SAVE_CYCLES
	pushl %edx
	ccall S9xGetCPU
	popl %edx
	pushl %eax
	incl %edx
	pushl %edx
	ccall S9xGetCPU
	LOAD_CYCLES
	popl %edx
	popl %edx
	movb %al, %ah
	movb %dl, %al
	ret

.GWDSP: /* MAP_DSP */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	SAVE_CYCLES
	pushl %edx
	ccall S9xGetDSP
	popl %edx
	pushl %eax
	incl %edx
	pushl %edx
	ccall S9xGetDSP
	LOAD_CYCLES
	popl %edx
	popl %edx
	movb %al, %ah
	movb %dl, %al
	ret

.GWLSRAM: /* MAP_LOROM_SRAM */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	andl $0xffff, %edx
	movl SRAM, %ecx
	andw SRAMMask, %dx
	movb (%ecx, %edx), %al
	incl %edx
	andw SRAMMask, %dx
	movb (%ecx, %edx), %ah
	ret

.GWHSRAM: /* MAP_HIROM_SRAM */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	movl %edx, %ecx
	andl $0xf0000, %ecx
	andl $0x7fff, %edx
	sarl $3, %ecx
	addl $-24576, %edx
	addl %ecx, %edx
	movl SRAM, %eax
	andw SRAMMask, %dx
	movw (%eax, %edx), %ax
	ret

.GWNONE:
.GWDEBUG: /* MAP_DEBUG */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	xorl %eax, %eax
	ret

.globl S9xSetByte
S9xSetByte:
	pushl %eax
#ifdef CPU_SHUTDOWN
	xorl %eax, %eax
	movl %eax, WaitAddress
#endif	
	movl %edx, %eax
	shrl $13, %eax
	and $0x7ff, %eax
#ifdef VAR_CYCLES
	movb MemorySpeed(%eax), %cl
#endif
	movl WriteMap(, %eax, 4), %eax
	cmpl $6, %eax
	jbe .SBSpecial
	andl $0xffff, %edx
#ifdef VAR_CYCLES
	andl $0xff, %ecx
	addl %ecx, CYCLES
#endif
	popl %ecx
	movb %cl, (%eax, %edx)
	ret

.SBSpecial:
	jmp *.SBJmpTable(, %eax, 4)
.data
	.align 4
.SBJmpTable:
	.long .SBPPU
	.long .SBCPU
	.long .SBDSP
	.long .SBLSRAM
	.long .SBHSRAM
	.long .SBNONE
	.long .SBDEBUG

.text
.SBPPU: /* MAP_PPU */
#ifdef VAR_CYCLES
	movb InDMA, %al
	testb %al, %al
	jne .SBPPU_NOADD
	addl $6, CYCLES
.SBPPU_NOADD:
#endif
	SAVE_CYCLES
	popl %eax
	pushl %edx
	pushl %eax
	ccall S9xSetPPU
	LOAD_CYCLES
	addl $8, %esp
	ret

.SBCPU: /* MAP_CPU */
#ifdef VAR_CYCLES
	addl $6, CYCLES
#endif
	STORE_REGISTERS
	popl %eax
	pushl %edx
	pushl %eax
	ccall S9xSetCPU
	LOAD_REGISTERS
	addl $8, %esp
	ret

.SBDSP: /* MAP_DSP */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	SAVE_CYCLES
	popl %eax
	pushl %edx
	pushl %eax
	ccall S9xSetDSP
	LOAD_CYCLES
	addl $8, %esp
	ret

.SBLSRAM: /* MAP_LOROM_SRAM */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	popl %eax
	movw SRAMMask, %cx
	orw %cx, %cx
	jz .SBLSRAM_SKIP
	andl $0xffff, %edx
	andw %cx, %dx
	movl SRAM, %ecx
	movb %al, (%ecx, %edx)
.SBLSRAM_SKIP:
	ret

.SBHSRAM: /* MAP_HIROM_SRAM */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	popl %eax
	movl %edx, %ecx
	andl $0xf0000, %ecx
	andl $0x7fff, %edx
	sarl $3, %ecx
	addl $-24576, %edx
	addl %ecx, %edx
	movw SRAMMask, %cx
	orw %cx, %cx
	jz .SBHSRAM_SKIP
	andw %cx, %dx
	movl SRAM, %ecx
	movb %al, (%ecx, %edx)
.SBHSRAM_SKIP:
	ret

.SBNONE:
.SBDEBUG: /* MAP_DEBUG */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	popl %eax
	ret

.globl S9xSetWord

S9xSetWord:
	pushl %eax
#ifdef CPU_SHUTDOWN
	xorl %eax, %eax
	movl %eax, WaitAddress
#endif	
	movl %edx, %eax
	shrl $13, %eax
	and $0x7ff, %eax
#ifdef VAR_CYCLES
	movb MemorySpeed(%eax), %cl
#endif
	movl WriteMap(, %eax, 4), %eax
	cmpl $6, %eax
	jbe .SWSpecial
	andl $0xffff, %edx
#ifdef VAR_CYCLES
	andl $0xff, %ecx
	addl %ecx, CYCLES
	addl %ecx, CYCLES
#endif
	popl %ecx
	movw %cx, (%eax, %edx)
	ret

.SWSpecial:
	jmp *.SWJmpTable(, %eax, 4)
.data
	.align 4
.SWJmpTable:
	.long .SWPPU
	.long .SWCPU
	.long .SWDSP
	.long .SWLSRAM
	.long .SWHSRAM
	.long .SWNONE
	.long .SWDEBUG

.text
.SWPPU: /* MAP_PPU */
#ifdef VAR_CYCLES
	movb InDMA, %al
	testb %al, %al
	jne .SWPPU_NOADD
	addl $12, CYCLES
.SWPPU_NOADD:
#endif
	SAVE_CYCLES
	popl %eax
	pushl %edx
	pushl %eax
	ccall S9xSetPPU
	popl %eax
	popl %edx
	movb %ah, %al
	incl %edx
	pushl %edx
	pushl %eax
	ccall S9xSetPPU
	LOAD_CYCLES
	addl $8, %esp
	ret

.SWCPU: /* MAP_CPU */
#ifdef VAR_CYCLES
	addl $12, CYCLES
#endif
	STORE_REGISTERS
	popl %eax
	pushl %edx
	pushl %eax
	ccall S9xSetCPU
	popl %eax
	popl %edx
	movb %ah, %al
	incl %edx
	pushl %edx
	pushl %eax
	ccall S9xSetCPU
	LOAD_REGISTERS
	addl $8, %esp
	ret

.SWDSP: /* MAP_DSP */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	SAVE_CYCLES
	popl %eax
	pushl %edx
	pushl %eax
	ccall S9xSetDSP
	popl %eax
	popl %edx
	movb %ah, %al
	incl %edx
	pushl %edx
	pushl %eax
	ccall S9xSetDSP
	LOAD_CYCLES
	addl $8, %esp
	ret

.SWLSRAM: /* MAP_LOROM_SRAM */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	popl %eax
	movw SRAMMask, %cx
	orw %cx, %cx
	jz .SWLSRAM_SKIP
	andl $0xffff, %edx
	andw %cx, %dx
	movl SRAM, %ecx
	movb %al, (%ecx, %edx)
	incl %edx
	andw SRAMMask, %dx
	movb %ah, (%ecx, %edx)
.SWLSRAM_SKIP:
	ret

.SWHSRAM: /* MAP_HIROM_SRAM */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	popl %eax
	movl %edx, %ecx
	andl $0xf0000, %ecx
	andl $0x7fff, %edx
	sarl $3, %ecx
	addl $-24576, %edx
	addl %ecx, %edx
	movw SRAMMask, %cx
	orw %cx, %cx
	jz .SWHSRAM_SKIP
	andw %cx, %dx
	movl SRAM, %ecx
	movw %ax, (%ecx, %edx)
.SWHSRAM_SKIP:
	ret

.SWNONE:
.SWDEBUG: /* MAP_DEBUG */
#ifdef VAR_CYCLES
	addl $16, CYCLES
#endif
	popl %eax
	ret

.globl S9xSetPCBase

S9xSetPCBase:
	movl %edx, %eax
	shrl $13, %eax
	and $0x7ff, %eax
#ifdef VAR_CYCLES
	movb MemorySpeed(%eax), %cl
#endif
	movl Map(, %eax, 4), %eax
	cmpl $6, %eax
	jbe .SPCSpecial
	andl $0xffff, %edx
#ifdef VAR_CYCLES
	andl $0xff, %ecx
	movl %ecx, MemSpeed
	addl %ecx, %ecx
	movl %ecx, MemSpeedx2
#endif
	movl %eax, PCBase
	addl %edx, %eax
	movl %eax, PC
	ret

	.align 4
.SPCSpecial:
	jmp *.SPCJmpTable(, %eax, 4)
.data
	.align 4
.SPCJmpTable:
	.long .SPCPPU
	.long .SPCCPU
	.long .SPCDSP
	.long .SPCLSRAM
	.long .SPCHSRAM
	.long .SPCNONE
	.long .SPCDEBUG

.text
.SPCPPU: /* MAP_PPU */
#ifdef VAR_CYCLES
	movl $6, MemSpeed
	movl $12, MemSpeedx2
#endif
	movl FillRAM, %ecx
	andl $0xffff, %edx
	movl %ecx, PCBase
	addl %edx, %ecx
	movl %ecx, PC
	ret

.SPCCPU: /* MAP_CPU */
#ifdef VAR_CYCLES
	movl $6, MemSpeed
	movl $12, MemSpeedx2
#endif
	movl FillRAM, %ecx
	andl $0xffff, %edx
	movl %ecx, PCBase
	addl %edx, %ecx
	movl %ecx, PC
	ret

.SPCDSP: /* MAP_DSP */
#ifdef VAR_CYCLES
	movl $8, MemSpeed
	movl $16, MemSpeedx2
#endif
	movl FillRAM, %ecx
	andl $0xffff, %edx
	movl %ecx, PCBase
	addl %edx, %ecx
	movl %ecx, PC
	ret

.SPCLSRAM: /* MAP_LOROM_SRAM */
#ifdef VAR_CYCLES
	movl $8, MemSpeed
	movl $16, MemSpeedx2
#endif
	movl SRAM, %ecx
	andl $0xffff, %edx
	movl %ecx, PCBase
	addl %edx, %ecx
	movl %ecx, PC
	ret

.SPCHSRAM: /* MAP_HIROM_SRAM */
#ifdef VAR_CYCLES
	addl $8, CYCLES
#endif
	movl SRAM, %eax
	andl $0xffff, %edx
	addl $-24576, %eax
	movl %eax, PCBase
	addl %eax, %edx
	movl %edx, PC
	ret

.SPCNONE:
.SPCDEBUG: /* MAP_DEBUG */
#ifdef VAR_CYCLES
	movl $8, MemSpeed
	movl $16, MemSpeedx2
#endif
	movl SRAM, %eax
	movl %eax, PCBase
	movl %eax, PC
	ret
