⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 65816emu.cpp

📁 SNES game emulator. C and asm files.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*  65816EMU.CPP - Emulates one mode of the 65816.  There are four different 
	versions depending on the mode of the processor.
*/

#undef XYTYPE
#undef ATYPE
#undef SIGNED_XYTYPE
#undef SIGNED_ATYPE
#undef XY_IS16BIT
#undef A_IS16BIT
#undef INDEX_X
#undef INDEX_Y
#undef ACCUM
#undef NV_SHIFT
#undef SIGN_BIT
#undef SIGN_BIT_XY
#undef SIGN_BIT_NUMBER
#undef BCDADDADJUST
#undef BCDSUBADJUST

#ifdef XY_16BIT
	#define XYTYPE unsigned short
	#define SIGNED_XYTYPE signed short
	#define XY_IS16BIT 1
	#define INDEX_X reg.X
	#define INDEX_Y reg.Y
#else
	#define XYTYPE unsigned char
	#define SIGNED_XYTYPE signed char
	#define XY_IS16BIT 0
	#define INDEX_X reg.X_lo
	#define INDEX_Y reg.Y_lo
#endif

#ifdef A_16BIT
	#define ATYPE unsigned short
	#define SIGNED_ATYPE signed short
	#define A_IS16BIT 1
	#define NV_SHIFT 8
	#define BCDADDADJUST bcdaddadjust_word
	#define BCDSUBADJUST bcdsubadjust_word
	#define ACCUM reg.A
#else
	#define ATYPE unsigned char
	#define SIGNED_ATYPE signed char
	#define A_IS16BIT 0
	#define NV_SHIFT 0
	#define BCDADDADJUST bcdaddadjust_byte
	#define BCDSUBADJUST bcdsubadjust_byte
	#define ACCUM reg.A_lo
#endif

#ifndef ADDRESSING_MODES
#define ADDRESSING_MODES

#define OPBYTE ((byte) opdata)
#define OPWORD ((word) opdata)
#define OPLONG opdata

	// Using these returns a pointer to the appropriate memory address.
	// The PC relative modes aren't listed since what is contained at the new location
	//   is irrelevant to the current instruction.
#define IMM_BYTE OPBYTE
	// OPC %#b
#define IMM_ACCUM ((ATYPE) opdata)
	// OPA %#
#define IMM_INDEX ((XYTYPE) opdata)
	// OPX %#i
#define ABS (SNESMEM ((DBR << 16) + OPWORD))
	// OPC %w
#define ABS_LONG (SNESMEM (OPLONG))
	// OPC $%L
#define DIR (SNESMEM ((D + OPBYTE) & 0xFFFF))
	// OPC <%b
#define DIR_INDIR_INDEX_Y ( _tmp = *(word*)SNESMEM(D + OPBYTE) + (DBR << 16) + INDEX_Y, SNESMEM(_tmp) )
	// OPC (<%b),Y
#define DIR_INDIR_LONG ( _tmp = (*(dword*)SNESMEM( (D + OPBYTE)&0xFFFF )) & 0xFFFFFF, SNESMEM (_tmp) )
	// OPC [<%b]
#define DIR_INDIR_LONG_INDEX_Y ( _tmp = ((*(dword*)SNESMEM( (D+OPBYTE)&0xFFFF )) & 0xFFFFFF) + INDEX_Y, SNESMEM (_tmp) )
	// OPC [<%b],Y
#define DIR_INDEX_INDIR_X ( _tmp = *(word *)SNESMEM( (((D+OPBYTE)&0xFFFF) + INDEX_X) & 0xFFFF ) + (DBR << 16), SNESMEM (_tmp) )
	// OPC (<%b,X)
#define DIR_INDEX_X ( SNESMEM(D + OPBYTE + INDEX_X) )
	// OPC <%b,X
#define DIR_INDEX_Y ( SNESMEM(D + OPBYTE + INDEX_Y) )
	// OPC <%b,Y
#define ABS_INDEX_X ( _tmp = (DBR << 16) + OPWORD + INDEX_X, SNESMEM(_tmp) )
	// OPC %w,X
#define ABS_INDEX_Y ( _tmp = (DBR << 16) + OPWORD + INDEX_Y, SNESMEM(_tmp) )
	// OPC %w, Y
#define ABS_LONG_INDEX_X ( SNESMEM(OPLONG + INDEX_X) )
	// OPC %L,X
#define ABS_INDIR ( /*_tmp = *(word*)SNESMEM(OPWORD),*/ SNESMEM (OPWORD) )
	// JML (%w) or JMP (%w)
#define DIR_INDIR ( _tmp = *(word*)SNESMEM((D + OPBYTE) & 0xFFFF) + (DBR << 16), SNESMEM (_tmp) )
	// OPC (<%b)
#define ABS_INDEX_INDIR_X ( _tmp = OPWORD + INDEX_X + (DBR << 16), SNESMEM(_tmp) )
	// OPC (%w,X)
#define ABS_INDEX_INDIR_X_JMP ( _tmp = OPWORD + INDEX_X + (PC & 0xFF0000), *(word*)SNESMEM(_tmp) | (PC & 0xFF0000) )
	// JMP (%w,X) - returns the new value for the PC.  As evidenced by Tetris Attack, the PBR (not DBR)
	// should be used for both bank values.
#define S_REL (SNESMEM (S + OPBYTE))
	// OPC <%b,S
#define S_REL_INDIR_INDEX_Y ( _tmp = *(word*)SNESMEM (S + OPBYTE) + (DBR << 16) + INDEX_Y, SNESMEM (_tmp) )
	// OPC (<%b,S),Y

#define PUSHBYTE(b) ( *(byte*)SNESMEM(S) = (byte)(b), (*(word*)&S)-- )
#define PUSHWORD(w) ( *(word*)SNESMEM(S-1) = (word)(w), (*(word*)&S) -= 2 )

#define PULLBYTE(db) ( (*(word*)&S)++, (db) = *(byte*)SNESMEM(S) )
#define PULLWORD(dw) ( (*(word*)&S) += 2, (dw) = *(word*)SNESMEM(S-1) )

#endif

#ifdef A_16BIT
	#define SIGN_BIT 0x8000
	#define SIGN_BIT_NUMBER 15
#else
	#define SIGN_BIT 0x80
	#define SIGN_BIT_NUMBER 7
#endif
#ifdef XY_16BIT
	#define SIGN_BIT_XY 0x8000
#else
	#define SIGN_BIT_XY 0x80
#endif

#define SAVE(A) (oldA = (A))
#define ADCSETCARRY(_tmpc) ((_tmpc) & (SIGN_BIT << 1) ? P |= CARRY : P &= ~CARRY)
#define SBCSETCARRY(_tmpc) ((_tmpc) & (SIGN_BIT << 1) ? P &= ~CARRY : P |= CARRY)
#define SETZERO(A) ((A) == 0 ? P |= ZERO : P &= ~ZERO)
#define SETNEGATIVE(A) ((A) & SIGN_BIT ? P |= NEGATIVE : P &= ~NEGATIVE)
#define SETNEGATIVEXY(XY) (((XY) & SIGN_BIT_XY) ? P |= NEGATIVE : P &= ~NEGATIVE)
#define SETOVERFLOW(A,oldA) ( ((A ^ oldA) & SIGN_BIT) && ((A>oldA?A-oldA:oldA-A) <= SIGN_BIT) ? P |= OVERFLOW : P &= ~OVERFLOW)
//#define SETOVERFLOW(A,oldA) ( (((SIGNED_ATYPE)A>(SIGNED_ATYPE)oldA?(int)((SIGNED_ATYPE)A)-(int)((SIGNED_ATYPE)oldA):(int)((SIGNED_ATYPE)oldA)-(int)((SIGNED_ATYPE)A))\
	> SIGN_BIT) ? P |= OVERFLOW : P &= ~OVERFLOW)
	// For an overflow condition:
	// - The signs have to change, and
	// - The value of (greater - smaller) is <= 32768

#define TRAPREAD(ptr)  (ptr >= registers && ptr <= (registers+0x4000) ? trapregread(ptr,ISWORDOP) : ptr)
#define TRAPWRITE(ptr) if (ptr >= registers && ptr <= (registers+0x4000)) trapregwrite(ptr,ISWORDOP)
	// TRAPWRITE should be called after the write and before any flags get set based on the new value.

#define ISWORDOP A_IS16BIT

#define P reg.P
#define S reg.S
#define D reg.D
#define E reg.E
#define DBR reg.DBR
#define PC reg.PC
#define ACCUM_16BIT reg.A
#define INDEX_X_16BIT reg.X
#define INDEX_Y_16BIT reg.Y
#define cycles scan_cycles

#define DOBREAK break

void EMUROUTINE ()
{
	//register dword PC;
	//static dword S;
	//static XYTYPE XYTYPE_X;
	//static XYTYPE XYTYPE_Y;
	//static byte DBR;
	//static word D;
	//static ATYPE ATYPE_A;
	//static byte P;
	//static boolean E; // Emulation mode flag (mostly ignored)
	static byte opcode;
	static dword opdata;
	dword _tmp, _tmp2, _tmpc;
	ATYPE oldA; // used by macros
	XYTYPE oldXY;
	ATYPE *amem;
	byte *mem;
	char unasm [20], lastop;

	(void)unasm;
	//PC = reg.PC;
	//S = reg.S;
	//XYTYPE_X = (XYTYPE) reg.X;
	//XYTYPE_Y = (XYTYPE) reg.Y;
	//DBR = reg.DBR;
	//D = reg.D;
	//ATYPE_A = (ATYPE) reg.A;
	//P = reg.P;
	//E = reg.E;

	//#define MAKE2(y) #y
	//#define MAKESTR(x) MAKE2(x)
	//if (debug_slice < 0) debug0 ("Entered: %s PC=%X P=%X S=%X", MAKESTR(EMUROUTINE), PC, P, S);
	assert ((S & 0xFFFF) == S);
	assert ((PC & 0xFFFFFF) == PC);
	while ((cycles & 0x80000000) == 0) {
		//if (!(PC & 0x8000)) {
			//addmessage ("warning! PC set to 0x%X", PC);
			//returntogui = true;
			//frame_cycles -= 100000;
			//cycles -= 200;
			//return;
		//}
		debug_instr++;

		opdata = *(dword*) SNESMEM(PC);
		//if (debug_instr >= 20250 && debug_instr < 20270) {
		//	unassemble (opdata,unasm,P);
		//	debug0 ("<-instr PC$%X (cycles=%d) asm:%s",PC,cycles,unasm);
		//}
//		debug thing
/*		debug_thing -= 2;
		*(word*)(expram + (debug_thing*6)+2) = (word)PC;
		*(word*)(expram + (debug_thing*6)+4) = (word)opdata;
		*(word*)(expram + (debug_thing*6)+6) = (word)S;
		*(word*)(expram + (debug_thing*6)+8) = (word)0;
		*(word*)(expram + (debug_thing*6)+10)= (word)E;
		*(word*)(expram + (debug_thing*6)+12)= (word)P;
		*(word*)expram = (0x6002 + debug_thing*6);
*/
		opcode = (byte)opdata;
		opdata >>= 8;

		// Another debug thing
		//if (opcode == 0x50 || opcode == 0x70)
			instr_tally[lastop][(P >> 3) & 1]++;
		lastop = opcode;
		
		switch (opcode) {
		case 0x00: //   "BRK", 2, 8, Has a signature word: %w two bytes ignored
			PC += 2; // Add 2 because RTI adds one more
			//PUSHBYTE (PC >> 16);
			//PUSHWORD ((word)PC);
			//PUSHBYTE (P);
			//PC = *(word *)SNESMEM (E? 0x00FFFE : 0x00FFE6);
			addmessage ("Warning: BRK encountered at $%LX", PC-2);
													cycles -= 200; frame_cycles -= 100000; returntogui = true;
			cycles -= 8;
			return;

			//DOBREAK;
		case 0x01: //   "ORA (<%b,X)", 2, 6,
			mem = DIR_INDEX_INDIR_X;
			ACCUM |= *(ATYPE*)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 6+A_IS16BIT; DOBREAK;
		case 0x02: //   "CSP", 2, 8, Has one-byte signature %b
			PC += 2; // Add one because RTI adds one more -- wait, add 2??
			PUSHBYTE (PC >> 16);
			PUSHWORD ((word)PC);
			PUSHBYTE (P);
			PC = *(word *)SNESMEM (E? 0x00FFF4 : 0x00FFE4);
			cycles -= 8; DOBREAK;
		case 0x03: //   "ORA <%b,S", 2, 4,
			mem = S_REL;
			ACCUM |= *(ATYPE*)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 4+A_IS16BIT; DOBREAK;
		case 0x04: //   "TSB <%b", 2, 5,
			amem = (ATYPE*)DIR;
			SETZERO (*amem & ACCUM);
			*amem |= ACCUM;
			TRAPWRITE((byte*)amem);
			PC += 2; cycles -= 5+A_IS16BIT; DOBREAK;
		case 0x05: //   "ORA <%b", 2, 3,
			mem = DIR;
			ACCUM |= *(ATYPE*)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 3+A_IS16BIT; DOBREAK;
		case 0x06: //   "SHL <%b", 2, 5,
			if (*(amem = (ATYPE*)DIR) & SIGN_BIT) P |= CARRY;
			else P &= ~CARRY;
			*amem <<= 1;
			TRAPWRITE ((byte*)amem);
			SETZERO (*amem);
			SETNEGATIVE (*amem);
			PC += 2; cycles -= 5+A_IS16BIT; DOBREAK;
		case 0x07: //   "ORA [<%b]", 2, 6,
			mem = DIR_INDIR_LONG;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 6+A_IS16BIT; DOBREAK;
		case 0x08: //   "PSH P", 1, 3, // PHP
			PUSHBYTE (P);
			PC += 1; cycles -= 3; DOBREAK;
		case 0x09: //   "ORA %#", 2, 2,
			ACCUM |= IMM_ACCUM;
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2+A_IS16BIT; cycles -= 2+A_IS16BIT; DOBREAK;
		case 0x0A: //   "SHL A", 1, 2,
			if (ACCUM & SIGN_BIT) P |= CARRY;
			else P &= ~CARRY;
			ACCUM <<= 1;
			SETZERO (ACCUM);
			SETNEGATIVE (ACCUM);
			PC += 1; cycles -= 2; DOBREAK;
		case 0x0B: //   "PSH D", 1, 4, // PHD Push Direct
			PUSHWORD (D);
			PC += 1; cycles -= 4; DOBREAK;
		case 0x0C: //   "TSB %w", 3, 6, 
			amem = (ATYPE*)ABS;
			SETZERO (*amem & ACCUM);
			*amem |= ACCUM;
			TRAPWRITE ((byte*)amem);
			PC += 3; cycles -= 6+A_IS16BIT; DOBREAK;
		case 0x0D: //   "ORA %w", 3, 4,
			mem = ABS;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 3; cycles -= 4+A_IS16BIT; DOBREAK;
		case 0x0E: //   "SHL %w", 3, 6,
			if (*(amem = (ATYPE*)ABS) & SIGN_BIT) P |= CARRY;
			else P &= ~CARRY;
			*amem <<= 1;
			TRAPWRITE ((byte*)amem);
			SETZERO (*amem);
			SETNEGATIVE (*amem);
			PC += 3; cycles -= 6+A_IS16BIT; DOBREAK;
		case 0x0F: //   "ORA %L", 4, 5,
			mem = ABS_LONG;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 4; cycles -= 5+A_IS16BIT; DOBREAK;
		case 0x10: //   "BPL @%b", 2, 2,
			if (P & NEGATIVE) { // False
				PC += 2; cycles -= 2; DOBREAK;
			}
			PC += 2 + ((signed char) opdata);
			cycles -= 3; DOBREAK;
		case 0x11: //   "ORA (<%b),Y", 2, 5,
			mem = DIR_INDIR_INDEX_Y;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 5+A_IS16BIT; DOBREAK;
		case 0x12: //   "ORA (<%b)", 2, 5,
			mem = DIR_INDIR;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 5+A_IS16BIT; DOBREAK;
		case 0x13: //   "ORA (<%b,S),Y", 2, 7,
			mem = S_REL_INDIR_INDEX_Y;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 7+A_IS16BIT; DOBREAK;
		case 0x14: //   "TRB <%b", 2, 5,
			amem = (ATYPE*)DIR;
			SETZERO (*amem & ACCUM);
			*amem &= ~ACCUM;
			TRAPWRITE ((byte*)amem);
			PC += 2; cycles -= 5+A_IS16BIT; DOBREAK;
		case 0x15: //   "ORA <%b,X", 2, 4,
			mem = DIR_INDEX_X;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 4+A_IS16BIT; DOBREAK;
		case 0x16: //   "SHL <%b,X",2, 6,
			if (*(amem = (ATYPE*)DIR_INDEX_X) & SIGN_BIT) P |= CARRY;
			else P &= ~CARRY;
			*amem <<= 1;
			TRAPWRITE ((byte*)amem);
			SETZERO (*amem);
			SETNEGATIVE (*amem);
			PC += 2; cycles -= 6+A_IS16BIT; DOBREAK;
		case 0x17: //   "ORA [<%b],Y", 2, 6,
			mem = DIR_INDIR_LONG_INDEX_Y;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 2; cycles -= 6+A_IS16BIT; DOBREAK;
		case 0x18: //   "CLC", 1, 2,
			P &= ~CARRY;
			PC += 1; cycles -= 2; DOBREAK;
		case 0x19: //   "ORA %w,Y", 3, 4,
			mem = ABS_INDEX_Y;
			ACCUM |= *(ATYPE *)TRAPREAD(mem);
			SETZERO (ACCUM); SETNEGATIVE (ACCUM);
			PC += 3; cycles -= 4+A_IS16BIT; DOBREAK;
		case 0x1A: //   "INC A", 1, 2,
			ACCUM++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -