;-----------------------------------------------------------------------
;WinSTon 68000 Decoder, with instruction and ccode emulation
;
;There are faster emulations out there that dynamically build up sections of code which is better
;for the PC's cache but this code has been written for accuracy and reliability - which is what
;WinSTon is all about! An emulator's speed is totally irrelavent if it fails to run applications!
;-----------------------------------------------------------------------

	.486P
.model FLAT

USE_DEBUGGER=1													;Used to enable check breakpointer/history output
TRAP_OPCODE_0=0													;Used to cause breakpoint on OpCode 0, ie ORI.B #0,D0

include code\68000asm\decode.inc

;-----------------------------------------------------------------------
;BSS
;-----------------------------------------------------------------------
_BSS	SEGMENT

_PCCodeTable_NZV_CX_SAME	DB	4096		DUP (?)			;Condition code look up tables
_PCCodeTable_NZVC			DB	4096		DUP (?)
_ShiftCycleTable_ByteWord	DD	64			DUP (?)
_ShiftCycleTable_Long		DD	64			DUP (?)
_Regs						DD	(16+1)		DUP (?)			;68000 registers(+ addition SP)
_STRamEnd					DD	1			DUP (?)			;End of ST Ram, above this address is no-mans-land and hardware vectors
_STRamEnd_BusErr			DD	1			DUP (?)			;as above, but start of BUS error exception
_PendingInterruptCount		DW	1			DUP (?)			;MUST follow each other in memory so can read as a 'long'
_PendingInterruptFlag		DW	1			DUP (?)			;see above
_PendingInterruptFunction	DD	1			DUP (?)
_InsPC						DD	1			DUP (?)
_SoundCycles				DD	1			DUP (?)
_PC							DD	1			DUP (?)
_SR							DW	1			DUP (?)
_SR_Before					DW	1			DUP (?)
_bInSuperMode				DD	1			DUP (?)
_Reg_SuperSP				DD	1			DUP (?)
_Reg_UserSP					DD	1			DUP (?)
_EmuCCode					DD	1			DUP (?)
_StackSave					DD	1			DUP (?)
_ExceptionVector			DD	1			DUP (?)
_BusAddressLocation			DD	1			DUP (?)

;Decode tables
_DecodeTable	DD	(65536*SIZEOF_DECODE)	DUP (?)			;Structure for each 68000 opcode (vastly improves speed)

;Instruction history, used for debugging
_InstructionHistory			DD	8192		DUP (?)
_InstructionHistoryIndex	DD	1			DUP (?)

_AddressBreakpoints			DD	8			DUP (?)			;Possible address breakpoints

MovePAddr					DD	1			DUP (?)
NumRegsStored				DD	1			DUP (?)
PostIncRegister				DD	1			DUP (?)
MovemWord					DD	1			DUP (?)
MovemPtr					DD	1			DUP (?)
Overflow					DB	1			DUP (?)			;Local assembler variables used for workspace

_BSS	ENDS

;-----------------------------------------------------------------------
;Data
;-----------------------------------------------------------------------
_DATA	SEGMENT

_BreakPointInstruction		DD	BRK_DISABLED
_BreakOnAddress				DD	0								;TRUE if break out decode loop due to debug address intercept
_CPUStopped					DD	0								;CPU stopped?

_DATA	ENDS

;-----------------------------------------------------------------------
;Text
;-----------------------------------------------------------------------
_TEXT	SEGMENT

;-----------------------------------------------------------------------
;Chec our list of breakpoint addresses, set 'BreakOnAddress' if match found
;'ebp' is our address
check_address_breakpoints PROC NEAR
	push	ecx

	mov		ecx,8-1
address_loop:
	cmp		ebp,_AddressBreakpoints[ecx*4]
	jne		no_address
	mov		[_BreakOnAddress],1
no_address:
	dec		ecx
	jge		address_loop

	pop		ecx
	ret
check_address_breakpoints ENDP

;-----------------------------------------------------------------------
;Check if swap between user/super mode and toggle Regs[REG_A7] with Regs[REG_A8] and 'bInSuperMode' flag
;Pass new SR in 'ax', store to SR_Before and call 'C' handler
asm_check_usersuper_swap PROC NEAR
	mov		bx,[_SR]											;Copy SR to SR_Before
	mov		[_SR_Before],bx
	mov		[_SR],ax											;Store new SR
	shl		eax,4												;Put ccodes back into emulation format

	SAVE_ASSEM_REGS												;Save assembly registers
	call	_M68000_CheckUserSuperToggle
	RESTORE_ASSEM_REGS											;Restore assembly registers
	ret
asm_check_usersuper_swap ENDP

;-----------------------------------------------------------------------
;Handle 'Exception' by re-directing to 'C' handler after storing/restoring registers
asm_exception PROC NEAR
	SAVE_ASSEM_REGS												;Save assembly registers
	call	_M68000_Exception
	RESTORE_ASSEM_REGS											;Restore assembly registers
	ret
asm_exception ENDP

;-----------------------------------------------------------------------
_RunIntructions PROC NEAR
	;Store off all registers
	push	ebp
	push	edi
	push	esi
	push	ebx

	mov		[_InstructionHistoryIndex],0						;Reset circular instruction history buffer

	mov		[_StackSave],esp									;Store off stack here!!!
	RESTORE_ASSEM_REGS											;Restore assembly registers
	jmp		DecodeNextInstruction								;Start decoding(by-pass interrupt check)
_RunIntructions ENDP

;-----------------------------------------------------------------------

include code\68000asm\ccodes.asm								;Condition code handlers

;BIG WARNING!!!!!!!
;RUN-THROUGH (oo-er)

;-----------------------------------------------------------------------
;Instruction decoder
_InstructionLoop PROC NEAR
	;Check for any interrupts or flag to service, check -ve 'PendingInterruptCount' and any '_PendingInterruptFlag' bits
	test	DWORD PTR [_PendingInterruptCount],0ffff8000h
	jne		PossibleInterrupt

DecodeNextInstruction LABEL NEAR

	;Do we need need to check for breakpoints/store history? Used for debugging only
IF USE_DEBUGGER
	cmp		[_BreakOnAddress],1									;Breakout after address breakpoint?
	je		BreakOnInstruction									;Yes

	cmp		[_BreakPointInstruction],BRK_STOP					;Do we wish to stop execution?
	je		BreakOnInstruction									;Yes
	cmp		[_BreakPointInstruction],BRK_SINGLE_INSTRUCTION		;Are we trying to single step?
	jne		no_single_step										;No
	mov		[_BreakPointInstruction],BRK_STOP					;Yes, set to break out on next loop
	
no_single_step:
	test	[_BreakPointInstruction],0							;Do have instruction breakpoint?(+ve address)
	jl		no_breakpoint										;No, skip check

	mov		ebx,esi												;Get PC
	sub		ebx,STRAM_OFFSET									;As ST address space
	MASK_24BIT_ADDR(ebx)
	cmp		ebx,[_BreakPointInstruction]						;Break on this PC?
	je		BreakOnInstruction									;Yes
no_breakpoint:

	;Save instruction history
	mov		ebx,esi
	sub		ebx,OFFSET [_STRam]									;Store 68000 PC in circular history buffer
	mov		ecx,[_InstructionHistoryIndex]
	mov		_InstructionHistory[ecx*4],ebx
	inc		[_InstructionHistoryIndex]							;Increment circular index
	and		[_InstructionHistoryIndex],INSTRUCTION_HISTORY_MASK
ENDIF

	;Read 'opcode' and decode
	movzx	ecx,WORD PTR [esi]									;Opcode in lower 16-bits (upper 16 are zeroed)
IF TRAP_OPCODE_0
	or		ecx,ecx
	je		BreakOnInstruction									;Yes
ENDIF
	shl		ecx,5												;Index into DecodeTable[][], NOTE ecx is wrong endian
	mov		[_InsPC],esi										;Store PC so can later read off cycle count, address, instruction etc...
	add		ecx,OFFSET _DecodeTable								;as pointer
	mov		ebx,DECODE_CYCLES[ecx]								;(99% cache miss)
	add		esi,SIZE_WORD										;Increase program counter				
	add		[_SoundCycles],ebx									;Add in cycle time to get cycle-accurate sample playback
	sub		[_PendingInterruptCount],bx							;Add cycle time including effective address time
	
	jmp		DWORD PTR DECODE_FUNCTION[ecx]						;and call decode function! ('esi' is 68000 PC in PC's memory, 'edx' is OpCode, 'ecx' is DecodeFunctions table)	
	;Will never get here! All decode functions jump back to 'DecodeNextInstruction'

;We need to service either an interrupt,mfp interrupt or trace flag
PossibleInterrupt:
	test	[_PendingInterruptFlag],PENDING_INTERRUPT_FLAG_TRACE
	je		DoneTraceModeCheck
	call	_M68000_TraceModeTriggered							;Is a trace?
DoneTraceModeCheck:
	test	[_PendingInterruptFlag],PENDING_INTERRUPT_FLAG_MFP
	jne		MFPInterruptTriggered								;Is an MFP interrupt?
DoneMFPCheck:
	cmp		[_PendingInterruptCount],0
	jg		DecodeNextInstruction								;Is a general interrupt?

InterruptTriggered:	
	mov		ebx,[_PendingInterruptFunction]						;Get interrupt handler
	or		ebx,ebx
	je		QuitSafely											;Interrupt function is NULL - quit safely

	call	ebx
	jmp		DecodeNextInstruction								;Back to decode loop(no interrupt)
	;Will never get here!

MFPInterruptTriggered:
	call	_MFP_CheckPendingInterrupts							;Check which MFP has requested service and call handler
	jmp		DoneMFPCheck										;Any others to service?
	
BreakOnInstruction:
	mov		[_BreakOnAddress],0									;Clear breakout flag
	SAVE_ASSEM_REGS												;Save assembly registers

QuitSafely:
	;Restore all registers
	pop		ebx
	pop		esi
	pop		edi
	pop		ebp
	ret
_InstructionLoop ENDP

;-----------------------------------------------------------------------
;Effective address decoding - NOTE for cache we keep this close to the decode loop

include code\68000asm\effaddr.asm

;-----------------------------------------------------------------------
;Instruction decoding - NOTE each instruction is listed in order of profile
;as decode speed is greatly dependent on cache misses. MMX machines decode
;a lot faster as they have a larger cache size

include code\68000asm\move.asm
include code\68000asm\bcc.asm
include code\68000asm\cmp.asm
include code\68000asm\sub.asm
include code\68000asm\add.asm
include code\68000asm\dbcc.asm
include code\68000asm\subq.asm
include code\68000asm\movem.asm
include code\68000asm\tst.asm
include code\68000asm\movea.asm
include code\68000asm\lea.asm
include code\68000asm\or.asm
include code\68000asm\bra.asm
include code\68000asm\moveq.asm
include code\68000asm\and.asm
include code\68000asm\swap.asm
include code\68000asm\rol.asm
include code\68000asm\cmpi.asm
include code\68000asm\rts.asm
include code\68000asm\adda.asm
include code\68000asm\btst.asm
include code\68000asm\addq.asm
include code\68000asm\clr.asm
include code\68000asm\andi.asm
include code\68000asm\lsl.asm
include code\68000asm\jsr.asm
include code\68000asm\cmpa.asm
include code\68000asm\addi.asm
include code\68000asm\link.asm
include code\68000asm\unlk.asm
include code\68000asm\jmp.asm
include code\68000asm\eor.asm
include code\68000asm\bsr.asm
include code\68000asm\lsr.asm
include code\68000asm\asl.asm
include code\68000asm\not.asm
include code\68000asm\subi.asm
include code\68000asm\divs.asm
include code\68000asm\ror.asm
include code\68000asm\rte.asm
include code\68000asm\ori.asm
include code\68000asm\mulu.asm
include code\68000asm\trap.asm
include code\68000asm\eori.asm
include code\68000asm\ext.asm
include code\68000asm\asr.asm
include code\68000asm\suba.asm
include code\68000asm\bclr.asm
include code\68000asm\neg.asm
include code\68000asm\addx.asm
include code\68000asm\muls.asm
include code\68000asm\cmpm.asm
include code\68000asm\roxl.asm
include code\68000asm\scc.asm
include code\68000asm\movep.asm
include code\68000asm\bset.asm
include code\68000asm\exg.asm
include code\68000asm\divu.asm
include code\68000asm\nop.asm
include code\68000asm\pea.asm
include code\68000asm\reset.asm
include code\68000asm\abcd.asm
include code\68000asm\bchg.asm
include code\68000asm\chk.asm
include code\68000asm\illegal.asm
include code\68000asm\nbcd.asm
include code\68000asm\negx.asm
include code\68000asm\roxr.asm
include code\68000asm\rtr.asm
include code\68000asm\sbcd.asm
include code\68000asm\stop.asm
include code\68000asm\subx.asm
include code\68000asm\tas.asm
include code\68000asm\trapv.asm

_TEXT	ENDS


END

