
	include	"SNES.i"

	include	"code/SNES_gui.i"

	incdir	"!includes:OS3.0"

	include	"exec/memory.i"
	include	"intuition/intuition.i"
	include	"libraries/gadtools.i"

	incdir	"!includes:"

	include	"LVO/exec_lib.i"
	include	"LVO/dos_lib.i"
	include	"LVO/intuition_lib.i"
	include	"LVO/graphics_lib.i"
	include "LVO/gadtools_lib.i"

	* memory-mapping ID's

MTYPE_ILLEGAL	=	0	;Illegal access
MTYPE_LRAM	=	1	;LowRAM
MTYPE_HRAM	=	2	;HighRAM
MTYPE_ERAM	=	3	;Expanded RAM
MTYPE_LROM	=	4	;LoROM rom-mapping
MTYPE_HROM	=	5	;HiROM rom-mapping
MTYPE_SRAM	=	6	;Save-RAM
MTYPE_HWARE	=	7	;Hardware

	section	code,code

	moveq.l	#-1,d0		;prevent execution
	rts

EMU_AllocateBuffers

	move.l	#-1,d7

	move.l	(4).w,a6

	* allocate pools

	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d0
	move.l	#131072,d1
	move.l	#131072,d2
	jsr	_LVOCreatePool(a6)
	move.l	d0,ptr_PublicPool
	tst.l	d0
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	prg_ROMSize,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_SNESRom
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#131072,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_SNESRam
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#65536+10,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_SNESVRam
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#SHW_SIZEOF,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_SNESHardware
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#PLANESIZE*8,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_RenderBufferBG1
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#PLANESIZE*8,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_RenderBufferBG2
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#PLANESIZE*8,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_RenderBufferBG3
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#PLANESIZE*8,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_RenderBufferBG4
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#(64*64)*2,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_SCBuffer
	beq	.Fail

	move.l	ptr_PublicPool,a0
	move.l	#PLANESIZE*4,d0
	jsr	_LVOAllocPooled(a6)
	move.l	d0,ptr_RenderMask
	beq	.Fail

	move.l	_GfxBase,a6
	move.l	#256,d0
	move.l	#240*8,d1
	jsr	_LVOAllocRaster(a6)
	move.l	d0,ptr_RenderBuffer
	beq	.Fail

	move.l	_GfxBase,a6
	move.l	#256,d0
	move.l	#240*8,d1
	jsr	_LVOAllocRaster(a6)
	move.l	d0,ptr_DisplayBuffer
	beq	.Fail

	* clear render buffers (AllocRaster() won't)

	move.l	ptr_RenderBuffer,a0
	move.l	ptr_DisplayBuffer,a1
	move.l	#(256*240)/16-1,d0
.ClearRender

	move.l	#0,(a0)+
	move.l	#0,(a1)+
	move.l	#0,(a0)+
	move.l	#0,(a1)+
	move.l	#0,(a0)+
	move.l	#0,(a1)+
	move.l	#0,(a0)+
	move.l	#0,(a1)+

	dbra	d0,.ClearRender

	move.l	#0,d7

.Fail
	move.l	d7,d0
	rts

EMU_FreeBuffers

	* free render buffers

	move.l	ptr_DisplayBuffer,a1
	tst.l	a1
	beq	.no_displaybuffer

	move.l	_GfxBase,a6
	move.l	ptr_DisplayBuffer,a0
	move.l	#256,d0
	move.l	#240*8,d1
	jsr	_LVOFreeRaster(a6)

	move.l	#0,ptr_DisplayBuffer
.no_displaybuffer

	move.l	ptr_RenderBuffer,a1
	tst.l	a1
	beq	.no_renderbuffer

	move.l	_GfxBase,a6
	move.l	ptr_RenderBuffer,a0
	move.l	#256,d0
	move.l	#240*8,d1
	jsr	_LVOFreeRaster(a6)

	move.l	#0,ptr_RenderBuffer
.no_renderbuffer

	* clear pointer allocated thru the pool

	move.l	#0,ptr_RenderBufferBG1
	move.l	#0,ptr_RenderBufferBG2
	move.l	#0,ptr_RenderBufferBG3
	move.l	#0,ptr_RenderBufferBG4

	move.l	#0,ptr_SNESHardware
	move.l	#0,ptr_SNESVRam
	move.l	#0,ptr_SNESRam
	move.l	#0,ptr_SNESRom

	* delete pools (and free all memory allocated)

	move.l	(4).w,a6

	tst.l	ptr_PublicPool
	beq	.no_PublicPool

	move.l	ptr_PublicPool,a0
	jsr	_LVODeletePool(a6)

	clr.l	ptr_PublicPool

.no_PublicPool

	rts

EMU_InitEmulation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Allocates memory, performs reset, prepares PC, etc.	*
*							*
* IN:	a0 - ptr to CPU structure.			*
*							*
* OUT:	d0 - Error.					*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	move.l	a0,a4

	move.l	#EXC_INVALIDHDR,d6

	move.l	#0,prg_EmulError

	lea.l	prg_ROMHeader,a1
	tst.l	RMH_HeaderValid(a1)
	beq	.Fail

	move.l	#EXC_OUTOFMEM,d6

	jsr	EMU_AllocateBuffers
	tst.l	d0
	bne	.Fail

	* load ROM image

	move.l	#EXC_ROMFAIL,d6

	lea.l	prg_FileNameBuffer,a0
	move.l	ptr_SNESRom,a1
	move.l	#4194304,d0
	jsr	ROM_LoadImage

	* initialize hardware

	move.l	#EXC_HARDINIT,d6

	move.l	ptr_SNESHardware,a2
	move.l	#%1111,SHW_BGMask(a2)
	move.l	#-1,SHW_ColourStore(a2)
	move.w  #-1,SHW_BG1HorizScrollStrobe(a2)
	move.w  #-1,SHW_BG1VertScrollStrobe(a2)
	move.w  #-1,SHW_BG2HorizScrollStrobe(a2)
	move.w  #-1,SHW_BG2VertScrollStrobe(a2)
	move.w  #-1,SHW_BG3HorizScrollStrobe(a2)
	move.w  #-1,SHW_BG3VertScrollStrobe(a2)
	move.w  #-1,SHW_BG4HorizScrollStrobe(a2)
	move.w  #-1,SHW_BG4VertScrollStrobe(a2)
	st.l	SHW_ScreenChange(a2)

	* initialize certain memory-addresses

	move.l	#EXC_MEMINIT,d6

	move.l	ptr_SNESRam,a0

	* set up fading table

	move.l	#EXC_FADEFAIL,d6

	jsr	GFX_BuildFade

	* reset emulating cpu to normal stats

	move.l	#EXC_RESETFAIL,d6

	move.l	a4,a0
	jsr	EMU_InitReset

	* open screen

	move.l	#EXC_SCREENFAIL,d6

	jsr	EMU_ScreenOpen
	tst.l	d0
	bne	.Fail

	clr.l	d0
	rts

.Fail
	move.l	d6,prg_EmulError
	st.l	d0
	rts

EMU_RunEmulation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*							*
* IN:	a0 - ptr to CPU structure.			*
*							*
* OUT:	d0 - Error.					*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	move.l	ptr_SNESHardware,a6

	* wait for frame update

	movem.l	a0/a6,-(sp)

	move.l	_GfxBase,a6
	jsr	_LVOWaitTOF(a6)

	movem.l	(sp)+,a0/a6

	tst.l	SHW_ScreenChange(a6)
	beq	.NoUpdateNeeded

	* update screen

	jsr	GFX_RenderScreen

	* double buffer

	jsr	EMU_SwapDisplay

.NoUpdateNeeded

	* update palette

	jsr	GFX_UpdatePalette

	* run VBL and init variables for next run

	move.l	#$ffff,SHW_NMIAccess(a6)

	lea.l	prg_ConfigBuffer,a2
	move.l	#53600,d0
	muls.l	CFG_Speed(a2),d0
	divs.l	#100,d0
	jsr	CPU_ExecuteInterrupt

	st.l	SHW_InterruptOccured(a6)
	or.l	#$80,SHW_ReadNMI(a6)
	move.l	#75,SHW_NMIAccess(a6)

	* emulate one frame code

	move.l	d1,d0
	jsr	CPU_EmulateCode

	movem.l	d0,-(sp)

	* clear joypad data

	clr.w	SHW_Joypad1Data(a6)
	clr.w	SHW_Joypad2Data(a6)
	clr.w	SHW_Joypad3Data(a6)
	clr.w	SHW_Joypad4Data(a6)

	* finally, poll the keystream and check for input

	* UGLY shit... Will use lowlevel.library instead.

.EmuMsgLoop

	move.l	(4).w,a6
	move.l	ptr_EmulationWindow,a0
	move.l	wd_UserPort(a0),a0
	jsr	_LVOGetMsg(a6)
	tst.l	d0
	beq	.NoEmuMsgLeft

	move.l	d0,a4

	move.l	im_Class(a4),d4

	cmp.l	#IDCMP_RAWKEY,d4
	bne	.no_IDCMP_RAWKEY

	move.w	im_Code(a4),d4

	cmp.w	#1,d4	;KEY_1
	bne	.not_KEY_1

	move.l	ptr_SNESHardware,a0
	move.l	SHW_BGMask(a0),d0
	bchg.l	#0,d0
	move.l	d0,SHW_BGMask(a0)
	st.l	SHW_ScreenChange(a0)

	clr.l	d4
.not_KEY_1

	cmp.w	#2,d4	;KEY_2
	bne	.not_KEY_2

	move.l	ptr_SNESHardware,a0
	move.l	SHW_BGMask(a0),d0
	bchg.l	#1,d0
	move.l	d0,SHW_BGMask(a0)
	st.l	SHW_ScreenChange(a0)

	clr.l	d4
.not_KEY_2

	cmp.w	#3,d4	;KEY_3
	bne	.not_KEY_3

	move.l	ptr_SNESHardware,a0
	move.l	SHW_BGMask(a0),d0
	bchg.l	#2,d0
	move.l	d0,SHW_BGMask(a0)
	st.l	SHW_ScreenChange(a0)

	clr.l	d4
.not_KEY_3

	cmp.w	#4,d4	;KEY_4
	bne	.not_KEY_4

	move.l	ptr_SNESHardware,a0
	move.l	SHW_BGMask(a0),d0
	bchg.l	#3,d0
	move.l	d0,SHW_BGMask(a0)
	st.l	SHW_ScreenChange(a0)

	clr.l	d4
.not_KEY_4

	cmp.w	#KEY_Break,d4
	bne	.not_KEY_Break

	move.l	#EXC_USERBREAK,prg_EmulError

.not_KEY_Break

	* poll joypad 1 (this code STINKS, will be rewritten)

	cmp.w	#KEY_JP1_A,d4
	bne	.not_KEY_JP1_A

	move.l	ptr_SNESHardware,a0
	bset.b	#7,SHW_Joypad1DataLow(a0)

	clr.l	d4

.not_KEY_JP1_A

	cmp.w	#KEY_JP1_X,d4
	bne	.not_KEY_JP1_X

	move.l	ptr_SNESHardware,a0
	bset.b	#6,SHW_Joypad1DataLow(a0)

	clr.l	d4

.not_KEY_JP1_X

	cmp.w	#KEY_JP1_TL,d4
	bne	.not_KEY_JP1_TL

	move.l	ptr_SNESHardware,a0
	bset.b	#5,SHW_Joypad1DataLow(a0)

	clr.l	d4

.not_KEY_JP1_TL

	cmp.w	#KEY_JP1_TR,d4
	bne	.not_KEY_JP1_TR

	move.l	ptr_SNESHardware,a0
	bset.b	#4,SHW_Joypad1DataLow(a0)

	clr.l	d4

.not_KEY_JP1_TR

	cmp.w	#KEY_JP1_B,d4
	bne	.not_KEY_JP1_B

	move.l	ptr_SNESHardware,a0
	bset.b	#7,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_B

	cmp.w	#KEY_JP1_Y,d4
	bne	.not_KEY_JP1_Y

	move.l	ptr_SNESHardware,a0
	bset.b	#6,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Y

	cmp.w	#KEY_JP1_Select,d4
	bne	.not_KEY_JP1_Select

	move.l	ptr_SNESHardware,a0
	bset.b	#5,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Select

	cmp.w	#KEY_JP1_Start,d4
	bne	.not_KEY_JP1_Start

	move.l	ptr_SNESHardware,a0
	bset.b	#4,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Start

	cmp.w	#KEY_JP1_Up,d4
	bne	.not_KEY_JP1_Up

	move.l	ptr_SNESHardware,a0
	bset.b	#3,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Up

	cmp.w	#KEY_JP1_Down,d4
	bne	.not_KEY_JP1_Down

	move.l	ptr_SNESHardware,a0
	bset.b	#2,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Down

	cmp.w	#KEY_JP1_Left,d4
	bne	.not_KEY_JP1_Left

	move.l	ptr_SNESHardware,a0
	bset.b	#1,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Left

	cmp.w	#KEY_JP1_Right,d4
	bne	.not_KEY_JP1_Right

	move.l	ptr_SNESHardware,a0
	bset.b	#0,SHW_Joypad1DataHigh(a0)

	clr.l	d4

.not_KEY_JP1_Right

	clr.l	d4

.no_IDCMP_RAWKEY

	move.l	(4).w,a6
	move.l	a4,a1
	jsr	_LVOReplyMsg(a6)

	bra	.EmuMsgLoop

.NoEmuMsgLeft

	movem.l	(sp)+,d0

	rts

EMU_FinishEmulation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*							*
* Does all deinit(frees all buffers etc.)		*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	jsr	EMU_FreeBuffers

	rts

EMU_ScreenOpen

	* setup bitmaps

	move.l	_GfxBase,a6
	lea.l	prg_DisplayBitMap,a0
	move.l	#8,d0
	move.l	#256,d1
	move.l	#240,d2
	jsr	_LVOInitBitMap(a6)

	move.l	ptr_DisplayBuffer,a0
	lea.l	prg_DisplayBitMap,a1
	lea.l	bm_Planes(a1),a1
	move.l	#8-1,d0
.SetPlanesDisplay

	move.l	a0,(a1)+
	lea.l	32*240(a0),a0

	dbra	d0,.SetPlanesDisplay

	move.l	#prg_DisplayBitMap,ptr_ScreenBitMapA

	move.l	_GfxBase,a6
	lea.l	prg_RenderBitMap,a0
	move.l	#8,d0
	move.l	#256,d1
	move.l	#240,d2
	jsr	_LVOInitBitMap(a6)

	move.l	ptr_RenderBuffer,a0
	lea.l	prg_RenderBitMap,a1
	lea.l	bm_Planes(a1),a1
	move.l	#8-1,d0
.SetPlanesRender

	move.l	a0,(a1)+
	lea.l	32*240(a0),a0

	dbra	d0,.SetPlanesRender

	move.l	#prg_RenderBitMap,ptr_ScreenBitMapB

	lea.l	prg_EmulationScreenTags,a0
	move.l	ptr_ScreenBitMapA,4(a0)

	lea.l	prg_ConfigBuffer,a4
	move.l	CFG_DisplayID(a4),12(a0)

	* open screen

	move.l	_IntuitionBase,a6
	sub.l	a0,a0
	lea.l	prg_EmulationScreenTags,a1
	jsr	_LVOOpenScreenTagList(a6)
	move.l	d0,ptr_EmulationScreen
	beq	.Fail

	* open screen window

	lea.l	prg_EmulationWindowTags,a0
	move.l	ptr_EmulationScreen,4(a0)

	move.l	_IntuitionBase,a6
	sub.l	a0,a0
	lea.l	prg_EmulationWindowTags,a1
	jsr	_LVOOpenWindowTagList(a6)
	move.l	d0,ptr_EmulationWindow
	beq	.Fail

	* set blank mouse-pointer for window
	* BUGGY!

	move.l	_IntuitionBase,a6
	move.l	ptr_EmulationWindow,a0
	lea.l	prg_BlankSprite,a1
	move.l	#0,d0
	move.l	#0,d1
	move.l	#0,d2
	move.l	#0,d3
	;jsr	_LVOSetPointer(a6)

	* allocate double-buffering structures

	move.l	_GfxBase,a6
	move.l	ptr_EmulationScreen,a0
	lea.l	sc_ViewPort(a0),a0
	jsr	_LVOAllocDBufInfo(a6)
	move.l	d0,ptr_ScreenDBuffer
	beq	.Fail

	* swap to fix display

	jsr	EMU_SwapDisplay

	clr.l	d0
	rts

.Fail
	st.l	d0
	rts


EMU_ScreenClose

	tst.l	ptr_ScreenDBuffer
	beq	.no_dbuffer

	move.l	_GfxBase,a6
	move.l	ptr_ScreenDBuffer,a1
	jsr	_LVOFreeDBufInfo(a6)

	move.l	#0,ptr_ScreenDBuffer

.no_dbuffer

	tst.l	ptr_EmulationWindow
	beq	.no_window

	move.l	_IntuitionBase,a6
	move.l	ptr_EmulationWindow,a0
	jsr	_LVOCloseWindow(a6)

	move.l	#0,ptr_EmulationWindow

.no_window

	tst.l	ptr_EmulationScreen
	beq	.no_screen

	move.l	_IntuitionBase,a6
	move.l	ptr_EmulationScreen,a0
	jsr	_LVOCloseScreen(a6)

	move.l	#0,ptr_EmulationScreen

.no_screen

	rts

EMU_SwapDisplay
*** Screen swapping function for flickerfree updating ***

	movem.l	d0-a6,-(sp)

	move.l	_GfxBase,a6
	move.l	ptr_EmulationScreen,a0
	lea.l	sc_ViewPort(a0),a0
	move.l	ptr_ScreenBitMapB,a1
	move.l	ptr_ScreenDBuffer,a2
	jsr	_LVOChangeVPBitMap(a6)

	move.l	ptr_EmulationScreen,a0
	lea.l	sc_RastPort(a0),a0
	move.l	ptr_ScreenBitMapA,rp_BitMap(a0)

	move.l	ptr_RenderBuffer,d0
	move.l	ptr_DisplayBuffer,ptr_RenderBuffer
	move.l	d0,ptr_DisplayBuffer

	move.l	ptr_ScreenBitMapA,d0
	move.l	ptr_ScreenBitMapB,ptr_ScreenBitMapA
	move.l	d0,ptr_ScreenBitMapB

	movem.l	(sp)+,d0-a6
	rts

EMU_InitReset
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Initializes registers and flags during a reset.	*
*							*
* IN:	a0 - ptr to CPU struct.				*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	;I give a damn about the 'real' reset
	;in the 65816, as I want everything working.

	move.w	#$0000,CPU_D(a0)
	move.b	#$00,CPU_DB(a0)
	move.b	#$00,CPU_PB(a0)
	move.w	#$0100,CPU_S(a0)
	move.w	#$0000,CPU_A(a0)
	move.w	#$0000,CPU_X(a0)
	move.w	#$0000,CPU_Y(a0)
	move.w	#$0134,CPU_P(a0)

	lea.l	prg_ROMHeader,a1
	move.w	RMH_RESET_Vector(a1),d0
	move.w	d0,CPU_PC(a0)

	lea.l	prg_ConfigBuffer,a2
	tst.l	CFG_ForceReset(a2)
	beq	.no_forcereset

	move.w	#$8000,CPU_PC(a0)

.no_forcereset

	rts

EMU_GetSNESAddress
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Converts an SNES address to a AMIGA address.		*
*							*
* IN:	a0 - ptr to CPU structure.			*
*	d0 - 24bit address.				*
*							*
* OUT:	d0 - absolute pointer in amiga-memory.		*
*							*
* If an memory error occurs, the emulation will be	*
* interrupted after the full execution of the calling	*
* instruction.						*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	move.l	d0,d1

	lea.l	prg_MemoryMap,a1

	and.l	#$00ffffff,d0
	lsr.l	#8,d0
	move.b	(a1,d0),d0
	and.l	#7,d0

	lea.l	.jumptable,a1
	move.l	(a1,d0*4),a1
	jmp	(a1)

.jumptable
	dc.l	.MTYPE_ILLEGAL
	dc.l	.MTYPE_LRAM
	dc.l	.MTYPE_HRAM
	dc.l	.MTYPE_ERAM
	dc.l	.MTYPE_LROM
	dc.l	.MTYPE_HROM
	dc.l	.MTYPE_SRAM
	dc.l	.MTYPE_HWARE

.MTYPE_ILLEGAL
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LRAM

	and.l	#$1fff,d1

	move.l	ptr_SNESRam,d0
	add.l	d1,d0

	rts

.MTYPE_HRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_ERAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LROM

	swap	d1
	and.w	#$7f,d1
	swap	d1
	sub.w	#$8000,d1
	lsl.w	#1,d1
	lsr.l	#1,d1

	move.l	ptr_SNESRom,d0
	add.l	d1,d0

	rts

.MTYPE_HROM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_SRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HWARE
	BREAKPOINT	EXC_ILLEGALMEM
	rts

EMU_GetByte
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fetches byte from SNES ROM,RAM or hardware.		*
*							*
* IN:	a0 - ptr to CPU structure.			*
*	d0 - 24bit offset.				*
*							*
* OUT:	d0 - Byte. (Exception may occur)		*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	move.l	d0,d1

	lea.l	prg_MemoryMap,a1

	and.l	#$00ffffff,d0
	lsr.l	#8,d0
	move.b	(a1,d0),d0
	and.l	#7,d0

	lea.l	.jumptable,a1
	move.l	(a1,d0*4),a1
	jmp	(a1)

.jumptable
	dc.l	.MTYPE_ILLEGAL
	dc.l	.MTYPE_LRAM
	dc.l	.MTYPE_HRAM
	dc.l	.MTYPE_ERAM
	dc.l	.MTYPE_LROM
	dc.l	.MTYPE_HROM
	dc.l	.MTYPE_SRAM
	dc.l	.MTYPE_HWARE

.MTYPE_ILLEGAL
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LRAM

	and.l	#$1fff,d1

	move.l	ptr_SNESRam,a1
	add.l	d1,a1

	move.b	(a1),d0
	and.l	#$ff,d0
	rts

.MTYPE_HRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_ERAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LROM

	swap	d1
	and.w	#$7f,d1
	swap	d1
	sub.w	#$8000,d1
	lsl.w	#1,d1
	lsr.l	#1,d1

	move.l	ptr_SNESRom,a1
	add.l	d1,a1

	move.b	(a1),d0
	and.l	#$ff,d0

	rts

.MTYPE_HROM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_SRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HWARE
	move.l	d1,d0
	jmp	HWR_GetByte

EMU_SetByte
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Sets a byte in SNES RAM or hardware.			*
*							*
* IN:	a0 - ptr to CPU structure.			*
*	d0 - 24bit offset.				*
*	d1 - Byte to write.				*
*							*
* If an memory error occurs, the emulation will be	*
* interrupted after the full execution of the calling	*
* instruction.						*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	move.l	d0,d2

	lea.l	prg_MemoryMap,a1

	and.l	#$00ffffff,d0
	lsr.l	#8,d0
	move.b	(a1,d0),d0
	and.l	#7,d0

	lea.l	.jumptable,a1
	move.l	(a1,d0*4),a1
	jmp	(a1)

.jumptable
	dc.l	.MTYPE_ILLEGAL
	dc.l	.MTYPE_LRAM
	dc.l	.MTYPE_HRAM
	dc.l	.MTYPE_ERAM
	dc.l	.MTYPE_LROM
	dc.l	.MTYPE_HROM
	dc.l	.MTYPE_SRAM
	dc.l	.MTYPE_HWARE

.MTYPE_ILLEGAL
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LRAM

	and.l	#$1fff,d2

	move.l	ptr_SNESRam,a1
	add.l	d2,a1

	move.b	d1,(a1)
	rts

.MTYPE_HRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_ERAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LROM
	;BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HROM
	;BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_SRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HWARE
	move.l	d2,d0
	jmp	HWR_SetByte

EMU_GetWord
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fetches word from SNES ROM,RAM or hardware.		*
*							*
* IN:	a0 - ptr to CPU structure.			*
*	d0 - 24bit offset.				*
*							*
* OUT:	d0 - Word.					*
*							*
* If an memory error occurs, the emulation will be	*
* interrupted after the full execution of the calling	*
* instruction.						*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	move.l	d0,d1

	lea.l	prg_MemoryMap,a1

	and.l	#$00ffffff,d0
	lsr.l	#8,d0
	move.b	(a1,d0),d0
	and.l	#7,d0

	lea.l	.jumptable,a1
	move.l	(a1,d0*4),a1
	jmp	(a1)

.jumptable
	dc.l	.MTYPE_ILLEGAL
	dc.l	.MTYPE_LRAM
	dc.l	.MTYPE_HRAM
	dc.l	.MTYPE_ERAM
	dc.l	.MTYPE_LROM
	dc.l	.MTYPE_HROM
	dc.l	.MTYPE_SRAM
	dc.l	.MTYPE_HWARE

.MTYPE_ILLEGAL
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LRAM

	and.l	#$1fff,d1

	move.l	ptr_SNESRam,a1
	add.l	d1,a1

	move.w	(a1),d0
	and.l	#$ffff,d0
	rol.w	#8,d0
	rts

.MTYPE_HRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_ERAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LROM

	swap	d1
	and.w	#$7f,d1
	swap	d1
	sub.w	#$8000,d1
	lsl.w	#1,d1
	lsr.l	#1,d1

	move.l	ptr_SNESRom,a1
	add.l	d1,a1

	move.w	(a1),d0
	and.l	#$ffff,d0
	rol.w	#8,d0

	rts

.MTYPE_HROM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_SRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HWARE
	move.l	d1,d0
	jmp	HWR_GetWord

EMU_SetWord
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Sets a byte in SNES RAM or hardware.			*
*							*
* IN:	a0 - ptr to CPU structure.			*
*	d0 - 24bit offset.				*
*	d1 - Word to write.				*
*							*
* If an memory error occurs, the emulation will be	*
* interrupted after the full execution of the calling	*
* instruction.						*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	ror.w	#8,d1
	move.l	d0,d2

	lea.l	prg_MemoryMap,a1

	and.l	#$00ffffff,d0
	lsr.l	#8,d0
	move.b	(a1,d0),d0
	and.l	#7,d0

	lea.l	.jumptable,a1
	move.l	(a1,d0*4),a1
	jmp	(a1)

.jumptable
	dc.l	.MTYPE_ILLEGAL
	dc.l	.MTYPE_LRAM
	dc.l	.MTYPE_HRAM
	dc.l	.MTYPE_ERAM
	dc.l	.MTYPE_LROM
	dc.l	.MTYPE_HROM
	dc.l	.MTYPE_SRAM
	dc.l	.MTYPE_HWARE

.MTYPE_ILLEGAL
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LRAM

	and.l	#$1fff,d2

	move.l	ptr_SNESRam,a1
	add.l	d2,a1

	move.w	d1,(a1)
	rts

.MTYPE_HRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_ERAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_LROM
	;BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HROM
	;BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_SRAM
	BREAKPOINT	EXC_ILLEGALMEM
	rts

.MTYPE_HWARE
	move.l	d2,d0
	jmp	HWR_SetWord

EMU_Debugger
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Main function for built in debugger.			*
*							*
* IN:	a0 - ptr to CPU structure.			*
*	a6 - hardware structure.			*
*							*
*							*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	movem.l	d0-a6,-(sp)

	move.l	a0,a4

	jsr	OpenDebugWindow
	tst.l	d0
	bne	.abort

	st.l	d5

.MainDebugger

	clr.l	d6

	* disassemble and update registers

	tst.l	d5
	beq	.no_update

	clr.l	d5

	move.l	_GadToolsBase,a6

	lea.l	.gadget_Table,a5

.ConvHexToString

	move.l	(a5)+,d4
	tst.l	d4
	bmi	.no_more_vals

	* hex2str conversion using table-lookup

	move.l	(a5)+,d0
	move.l	(a5)+,d1

	move.l	a4,a0
	add.l	d0,a0

	clr.l	d0
	move.b	(a0),d0

	cmp.l	#2,d1
	bne	.not_word

	move.w	(a0),d0

.not_word
	
	;move.w	(a0),d0

	lea.l	prg_TempText+4,a0
	lea.l	prg_HexTable,a1

	move.w	d0,d1
	and.l	#$f,d1
	move.b	(a1,d1),-(a0)
	lsr.w	#4,d0

	move.w	d0,d1
	and.l	#$f,d1
	move.b	(a1,d1),-(a0)
	lsr.w	#4,d0

	move.w	d0,d1
	and.l	#$f,d1
	move.b	(a1,d1),-(a0)
	lsr.w	#4,d0

	move.w	d0,d1
	and.l	#$f,d1
	move.b	(a1,d1),-(a0)
	lsr.w	#4,d0

	* set attributes

	lea.l	DebugGadgets,a0
	move.l	(a0,d4*4),a0
	move.l	DebugWnd,a1
	sub.l	a2,a2
	lea.l	prg_TempTag,a3
	jsr	_LVOGT_SetGadgetAttrsA(a6)

	bra	.ConvHexToString

.no_more_vals

.no_update

	move.l	a4,a5

	* wait for messages

	move.l	(4).w,a6		;put sysbase in a6
	move.l	DebugWnd,a0		;get ptr to memory-display window
	move.l	wd_UserPort(a0),a0	;get window userport
	jsr	_LVOWaitPort(a6)	;wait for messages

.msg_loop

	move.l	_GadToolsBase,a6	;put gadtoolsbase in a6
	move.l	DebugWnd,a0		;get ptr to memory-display window
	move.l	wd_UserPort(a0),a0	;get window userport
	jsr	_LVOGT_GetIMsg(a6)	;get any waiting message
	move.l	d0,ptr_DebugMessage	;store msg
	beq	.no_DebugMsgs		;if no message, continue looping

	move.l	ptr_DebugMessage,a4
	move.l	im_Class(a4),d4

	cmp.l	#IDCMP_CLOSEWINDOW,d4
	bne	.no_IDCMP_CLOSEWINDOW

	move.l	#2,d6
	clr.l	d4

.no_IDCMP_CLOSEWINDOW

	cmp.l	#IDCMP_GADGETUP,d4
	bne	.no_IDCMP_GADGETUP

	move.l	im_IAddress(a4),a3
	move.w	gg_GadgetID(a3),d4

	cmp.w	#GD_DBContEmulation,d4
	bne	.not_GD_DBContEmulation

	move.l	#1,d6
	clr.l	d4

.not_GD_DBContEmulation

	cmp.w	#GD_DBAbortEmulation,d4
	bne	.not_GD_DBAbortEmulation

	move.l	#2,d6
	clr.l	d4

.not_GD_DBAbortEmulation

	cmp.w	#GD_DBOneFrame,d4
	bne	.not_GD_DBOneFrame

	movem.l	d0-a6,-(sp)

	move.l	a5,a0
	jsr	EMU_RunEmulation

	movem.l	(sp)+,d0-a6

	clr.l	d4
	st.l	d5

.not_GD_DBOneFrame

	cmp.w	#GD_DBSingleStep,d4
	bne	.not_GD_DBSingleStep

	move.l	a5,a0
	move.l	ptr_SNESHardware,a6
	move.l	#0,d0
	jsr	CPU_EmulateCode	

	move.l	_GadToolsBase,a6

	clr.l	d4
	st.l	d5

.not_GD_DBSingleStep

	clr.l	d4

.no_IDCMP_GADGETUP

	move.l	_GadToolsBase,a6
	move.l	ptr_DebugMessage,a1
	jsr	_LVOGT_ReplyIMsg(a6)

.no_DebugMsgs

	move.l	a5,a4

	tst.l	d6
	beq	.MainDebugger

	cmp.l	#2,d6
	beq	.abort

.continue

	jsr	CloseDebugWindow

	movem.l	(sp)+,d0-a6
	move.l	#2,d0
	rts

.abort

	jsr	CloseDebugWindow

	movem.l	(sp)+,d0-a6
	clr.l	d0
	rts

.gadget_Table
	dc.l	GD_DBRegX,CPU_X,2
	dc.l	GD_DBRegY,CPU_Y,2
	dc.l	GD_DBRegS,CPU_S,2
	dc.l	GD_DBRegA,CPU_A,2
	dc.l	GD_DBRegP,CPU_P,2
	dc.l	GD_DBRegPC,CPU_PC,2
	dc.l	GD_DBRegD,CPU_D,2
	dc.l	GD_DBRegPB,CPU_PB,1
	dc.l	GD_DBRegDB,CPU_DB,1
	dc.l	GD_DBCurrOp,CPU_Opcode+3,1

	dc.l	-1

prg_TempTag	dc.l	GTTX_Text,prg_TempText,TAG_END
prg_TempText	dc.b	"0000",0

	cnop	0,4

EMU_DumpValue	;d0

	movem.l	d0-a6,-(sp)

	move.l	d0,out_v

	move.l	_DosBase,a6
	move.l	#out_s,d1
	move.l	#out_v,d2
	jsr	_LVOVPrintf(a6)

	movem.l	(sp)+,d0-a6

	rts

EMU_DumpRegs

	movem.l	d0-a6,-(sp)

	move.l	a0,a1
	lea.l	regdump,a0

	move.l	d6,d0
	move.w	d0,(a0)+	;X
	swap	d0
	move.w	d0,(a0)+	;Y

	move.l	a5,d0
	swap	d0
	move.w	d0,(a0)+	;S

	move.l	d7,d0
	move.w	d0,(a0)+	;A

	move.l	a4,d0
	move.w	d0,(a0)+	;PC

	move.l	d7,d0
	swap	d0
	move.w	d0,(a0)+	;D

	move.l	a4,d0
	swap	d0
	move.w	d0,(a0)+	;PB/DB

	move.l	a5,d0
	move.w	d0,(a0)+	;P

	move.l	CPU_Opcode(a1),d0
	lea.l	prg_MnemonicTable,a1
	;move.l	d0,(a0)+
	;move.l	(a1,d0*4),(a0)+

	move.l	_DosBase,a6
	move.l	#DumpRegs,d1
	move.l	#regdump,d2
	jsr	_LVOVPrintf(a6)

	movem.l	(sp)+,d0-a6
	rts

	section	data,data

DumpRegs	dc.b	"X:$%x Y:$%x S:$%x A:$%x PC:$%x D:$%x PB/DB:$%x P:$%x\n",0
;DumpRegs	dc.b	"S:$%x PC:$%x OP:%s\n",0

regdump
	ds.l	1	;X
	ds.l	1	;Y
	ds.l	1	;S
	ds.l	1	;A
	ds.l	1	;PC
	ds.l	1	;D
	ds.l	1	;PB/DB
	ds.l	1	;P
	ds.l	1	;OP
out_v	ds.l	1
out_s	dc.b	"DEBUG: %lx\n",0

	* SNES memory-map

prg_MemoryMap

	;bank $00-$2f

	rept	$30

	blk.b	$20,MTYPE_LRAM
	;blk.b	$01,MTYPE_ILLEGAL
	blk.b	$02,MTYPE_HWARE
	blk.b	$1e,MTYPE_ILLEGAL
	blk.b	$04,MTYPE_HWARE
	blk.b	$1c,MTYPE_ILLEGAL
	blk.b	$20,MTYPE_ILLEGAL	;reserved?
	blk.b	$80,MTYPE_LROM

	endr

	;bank $30-3f

	rept	$10

	blk.b	$20,MTYPE_LRAM
	blk.b	$01,MTYPE_ILLEGAL
	blk.b	$01,MTYPE_HWARE
	blk.b	$1e,MTYPE_ILLEGAL
	blk.b	$04,MTYPE_HWARE
	blk.b	$1c,MTYPE_ILLEGAL
	blk.b	$20,MTYPE_ILLEGAL	;SRAM in mode 21
	blk.b	$80,MTYPE_LROM

	endr

	;bank $40-6f

	rept	$30

	blk.b	$80,MTYPE_HROM		;ROM in mode 21
	blk.b	$80,MTYPE_LROM

	endr

	;bank $70-$77

	rept	$8

	blk.b	$100,MTYPE_SRAM

	endr

	;bank $78-7d

	rept	$6

	blk.b	$100,MTYPE_ILLEGAL	;unused

	endr

	;bank $7e

	blk.b	$20,MTYPE_LRAM
	blk.b	$60,MTYPE_HRAM
	blk.b	$80,MTYPE_ERAM

	;bank $7f

	blk.b	$100,MTYPE_ERAM

	;only half of the map left to do...

prg_EmulationScreenTags

	dc.l	SA_BitMap,0
	dc.l	SA_DisplayID,0
	dc.l	SA_Depth,8
	dc.l	SA_Title,0
	dc.l	SA_ShowTitle,0
	dc.l	SA_PubName,prg_PubName
	dc.l	SA_Type,PUBLICSCREEN|CUSTOMBITMAP
	dc.l	SA_Width,256
	dc.l	SA_Height,240
	dc.l	SA_AutoScroll,1
	dc.l	SA_Pens,DefPens
	dc.l	TAG_END

prg_EmulationWindowTags
	dc.l	WA_CustomScreen,0
	dc.l	WA_Width,256
	dc.l	WA_Height,240
	dc.l	WA_Borderless,1
	dc.l	WA_RMBTrap,1
	dc.l	WA_Backdrop,1
	dc.l	WA_Activate,1
	dc.l	WA_GimmeZeroZero,1
	dc.l	WA_IDCMP,IDCMP_RAWKEY
	dc.l	TAG_END

DefPens	dc.l	-1

prg_DisplayBitMap
	dc.w	32
	dc.w	240
	dc.b	0
	dc.b	0
	dc.w	0
	ds.l	8

prg_RenderBitMap
	dc.w	32
	dc.w	240
	dc.b	0
	dc.b	0
	dc.w	0
	ds.l	8

prg_PubName	dc.b	"AmiSNESE Screen",0

	section	bss,bss

prg_BlankSprite		ds.l	8

ptr_ScreenBitMapA	ds.l	1
ptr_ScreenBitMapB	ds.l	1

ptr_ScreenDBuffer	ds.l	1

ptr_SCBuffer		ds.l	1

ptr_RenderBufferBG1	ds.l	1
ptr_RenderBufferBG2	ds.l	1
ptr_RenderBufferBG3	ds.l	1
ptr_RenderBufferBG4	ds.l	1

ptr_RenderMask		ds.l	1

ptr_RenderBuffer	ds.l	1
ptr_DisplayBuffer	ds.l	1

ptr_EmulationScreen	ds.l	1
ptr_EmulationWindow	ds.l	1

ptr_PublicPool		ds.l	1

ptr_SNESRom		ds.l	1
ptr_SNESRam		ds.l	1
ptr_SNESSRam		ds.l	1
ptr_SNESVRam	ds.l	1

ptr_DebugMessage	ds.l	1

ptr_SNESHardware	ds.l	1

prg_FrameSkip		ds.l	1

prg_EmulError		ds.l	1

prg_CPUStructure	ds.b	CPU_SIZEOF

