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

📄 cpu.cpp

📁 SNES game emulator. C and asm files.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
			// ^ Pointer to pre-table
			*(word*)REG4305(x) = *(word*)SNESMEM ((*(dword*)REG4302(x) & 0xFFFFFF) + 1);
			//*((byte*)REG4305(x) + 2) = *((byte*)REG4302(x) + 2); // Bank
			//Apparently the bank should be set in regular HDMA and not indirect HDMA
			// ^ Pointer to final table (data values)
		} else { // Regular HDMA
			*(word*)REG4305(x) = *(word*)REG4302(x); // Not used in regular HDMA?  Or perhaps used for continuous mode.  Yes, that's it.
			*((byte*)REG4305(x) + 2) = *((byte*)REG4302(x) + 2); // Bank
			*REG4308(x) = *(word*)REG4302(x); // Pointer to table
		}
		*REG430A(x) = getcount (x);

		//*REG430A(x) = *SNESMEM(*REG4302(x) & 0xFFFFFF) - 1;
			// Get count byte, first byte of table
		debug0 ("HDMA Channel %d mode $%X cpu$%X reg$%X waitcount%d", x, *REG4300(x), *REG4302(x) & 0xFFFFFF, *REG4301(x) | 0x2100, *REG430A(x));
		//tmp = SNESMEM (*REG4302(x) & 0xFFFFFF);
		//for (y=0; y < 3; y++) {
		//	debug0 ("Table: %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X", tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], tmp[9]);
		//	tmp += 10;
		//}
	}
	debug0 ("Inprogress this frame: %0.2X", state.hdma_inprogress);
	//dohdmaline(); // First line
}

inline int dmadatasize (int mode)
{
	static int modes[] = { 1,2,2,4,4,0,0,0 };
	return modes [mode & 7];
}

int writehdma (int mode, int addr, int breg)
{	// Returns size of data written.
	int size, regand;
	byte *cpu, *reg;
	int y;

	switch (mode & 0x7) {
	case 0: size = 1; regand = 0; break;
	case 1: size = 2; regand = 1; break;
	case 2: size = 2; regand = 0; break;
	case 3: size = 4; regand = 2; break;
	case 4: size = 4; regand = 3; break;
	default:size = 0; regand = 0; debug0 ("Invalid HDMA Mode %d b$%X",mode,breg); break;
	}
	//debug0 ("HDMA sc%d mem%X %X %X %X ", screen_scanline, *SNESMEM(addr), *SNESMEM(addr+1), *SNESMEM(addr+2), *SNESMEM(addr+3));
	for (y = 0; y < size; y++) {
		cpu = SNESMEM (addr + y); // Value to write
		reg = SNESMEM (0x2100 | (breg + (regand == 2 ? (y >> 1) : (y & regand))));
		*reg = *cpu;
		trapregwrite (reg, false);
	}
	return size;
}

void getpointers (int x, int &addr, int &iaddr)
{
	if (!(*REG4300(x) & 0x40)) {
		addr = HBCOMBINE (*REG4308(x));
		// addr is SNES address of HDMA table at current offset
		iaddr = (*(dword*)REG4305(x) + 1) & 0xFFFFFF; // Equal to addr+1 when NOT in continuous mode.
		// iaddr is address of the actual value(s) to write
	} else {
		// REG4305,6,7 used as address after indirection; 4308,9 used before.
		addr = HBCOMBINE (*REG4308(x));
		// addr is SNES address of HDMA pre-table at current offset
		iaddr = *(dword*)REG4305(x) & 0xFFFFFF; // Equal to addr+1 when NOT in continuous mode.
		// iaddr is address of the actual value(s) to write
	}
}

void dohdmaline ()
{
	int x;
	int addr, iaddr, size;

	for (x = 0; x < 8; x++) {
		if (!(state.hdma_inprogress & (1 << x)))
			continue;
		if (*REG430A(x) == 0) {
			if (!(*REG4300(x) & 0x40)) {
				(*REG4305(x))++;
				*REG4308(x) = *REG4305(x);
			} else {
				(*REG4308(x)) += 3; // Pre-table entries are always spaced three bytes apart.
				*REG4305(x) = *(word*)SNESMEM(HBCOMBINE(*REG4308(x)+1));
			}
			*REG430A(x) = getcount (x);
			if (!(state.hdma_inprogress & (1 << x)))
				continue;
		}
		getpointers (x, addr, iaddr);
		if (*REG430A(x) == getcount (x) || *SNESMEM(addr) & 0x80) {
			size = writehdma (*REG4300(x), iaddr, *REG4301(x));
			*(word*)REG4305(x) += size;
		}
		(*REG430A(x))--;
	}
}

inline void executecpu ()
{
#ifdef USE_C_CPU_CORE
	switch (reg.P & (MEMORY | INDEX)) {
	case 0:
		emulate_m0_x0 (); return;
	case MEMORY:
		emulate_m1_x0 (); return;
	case INDEX:
		emulate_m0_x1 (); return;
	case MEMORY | INDEX:
		emulate_m1_x1 (); return;
	}
#else
	doemulate ();
#endif
}

void debug_executecpu (int cycles)
{
	int left, temp;

	// frame cycles initted to 0, so cpu frame is always started at the beginning of the frame.
	// If debugger is entered from game, new frame will already be initted.
	if (frame_cycles <= 0) {
		startcpuframe ();
		total_frames++;
		startscanline ();
		debug0 ("Frame %d: debug_instr=%d", total_frames, debug_instr);
	}
	temp = scan_cycles;
	scan_cycles = cycles;
	executecpu ();
	left = scan_cycles;
	scan_cycles = temp + left - cycles;
	if (scan_cycles < 0) {
		frame_cycles -= cycles_per_scan;
		scan_cycles += cycles_per_scan;
		screen_scanline++;
		startscanline ();
		//if (screen_scanline < 10 || screen_scanline > 220)
		//	debug0 ("scanline %d new scan_cycles %d frame_cycles %d PC$%X", screen_scanline, scan_cycles, frame_cycles, reg.PC);
	}
}

boolean debug_nmistart;

void startvblank ()
{
	int x;

	state.reg4210 |= 0x80; // VBL start occurred--Required even if screen is off
	if (!(*REG4200 & 0x80)) {
		return; // NMI Disabled
	}
	if (reg.E) x = *(word*)SNESMEM(0x00FFFA);
	else x = *(word*)SNESMEM(0x00FFEA);
	if (x != 0) {
		if (debugmode) adddebugline ("[Jumped to NMI vector]", false, '*');
		state.end_wai = true;
		*(byte*)SNESMEM(reg.S) = (byte)(reg.PC >> 16); (*(word*)&reg.S)--;
		*(word*)SNESMEM(reg.S-1) = (word)(reg.PC); (*(word*)&reg.S) -= 2;
		*(byte*)SNESMEM(reg.S) = (byte)(reg.P); (*(word*)&reg.S)--;
			// Push PC and P
		reg.P |= 4; // Interrupt flag
		reg.PC = x;
		debug0 ("Jumped to NMI Vector: %LX; E = %d", reg.PC, reg.E);
		debug_nmistart = true;
	}
}

void startcpuframe ()
{
	int hz;

	state.reg4210 &= ~0x80; // NMI over

	// decide on how many cycles to do this frame
	if (curheader.fastrom && (*SNESMEM (0x420D) & 1) && !curgs->ignorefastrom) { // fastrom
		hz = 3580000 * curgs->cpupercent / 100;
		curfastrom = true;
	} else {
		hz = 2680000 * curgs->cpupercent / 100;
		curfastrom = false;
	}
	if (ispal ()) {
		frame_cycles = hz / 50;
	} else {
		frame_cycles = hz / 60;
	}

	cycles_per_scan = scan_cycles = frame_cycles / 260;
	screen_scanline = 0; // start with scanline 0

	// Restart HDMA here
	resethdma ();

	resetscreenframe ();

	setjoypadreg (0);
	setjoypadreg (1);
	setjoypadreg (2);
	setjoypadreg (3);
}

void startscanline ()
{
	int x;

	if (!(reg.P & 0x4) /*&& !(state.reg4211 & 0x80)*/) { // IRQs possible
		//if (((*REG4200 & 0x10) && ((*REG4207 & 0x1FF) <= 339)) || // H-IRQs
		//    ((*REG4200 & 0x20) && ((*REG4209 & 0x1FF) == screen_scanline))) { // V-IRQs
		if ((*REG4200 & 0x30) && (*REG4209 & 0x1FF) == screen_scanline) {
			state.reg4211 |= 0x80; // IRQ start occurred
			if (reg.E) x = *(word*)SNESMEM(0x00FFFE);
			else x = *(word*)SNESMEM(0x00FFEE);
			if (x != 0) {
				state.end_wai = true;
				*(byte*)SNESMEM(reg.S) = (byte)(reg.PC >> 16); (*(word*)&reg.S)--;
				*(word*)SNESMEM(reg.S-1) = (word)(reg.PC); (*(word*)&reg.S) -= 2;
				*(byte*)SNESMEM(reg.S) = (byte)(reg.P); (*(word*)&reg.S)--;
					// Push PC and P
				reg.P |= 4; // Interrupt flag
				reg.PC = x;
			}
		}
	}
	if (screen_scanline == scans_before_vbl()) {
		startvblank ();  // After the frame is done, do a VBL int
	}
	dohdmaline ();
	if (!debugmode && screen_scanline < scans_before_vbl() && frameskipwait < 0) {
		drawnextscanline ();
	}
}

#define MAXDEBUGHISTORY 20
#define MAXDEBUGLINELEN 40

char *debug_input(int &scancode)
{   // gets a debug command from user.
	// if scancode != 0, special key was pressed and returned
	static char line [MAXDEBUGHISTORY][MAXDEBUGLINELEN];
		// [0]=most recent line
	static int history = 0;
	int key, x, seekline = 0;

	scancode = 0;
	for (;;) {
		while (!kbhit()) {
			drawbox (0, 238, 255, 248, 0);
			setcolor (30); printf8 (0, 240, "Command:");
			setcolor (63); printf8 (50, 240, "%s%c", line[0], (tmsec & 128) ? '_' : ' ');
			copyscreen ();
		}
		key = getch ();
		if (key == 8 && strlen (line[0]) > 0)
			line[0][strlen(line[0])-1] = '\0';
		if (key == 13) {
			if (line [0][0] == '\0')
				return line[0];
			for (x = MAXDEBUGHISTORY-1; x > 0; x--) {
				strcpy (line[x], line[x-1]);
			}
			if (history < MAXDEBUGHISTORY)
				history++;
			line [0][0] = '\0';
			return line [1];
		}
		if (key >= 32 && key <= 127) {
			x = strlen (line[0]);
			if (x < MAXDEBUGLINELEN) {
				line[0][x] = toupper (key);
				line[0][x + 1] = '\0';
			}
		}
		if (key == 0) {
			key = getch ();
			switch (key) {
			case 'H': // up
				if (seekline < MAXDEBUGHISTORY - 1) {
					seekline++;
					strcpy (line[0], line[seekline]);
				}
				break;
			case 'P': // down
				if (seekline > 0) {
					seekline--;
					strcpy (line[0], line[seekline]);
				}
				break;
			}
			if ((key >= 59 && key <= 68) || key == 87 || key == 88) {
				scancode = key;
				return line[0];
			}
		}
		if (key == 27) {
			scancode = key;
			return line[0];
		}
	}
}

int grabnumber (char *line, int &i)
{
	int x;

	i = 0;
	while ((line[i] < '0' || line[i] > '9') && line[i] != '-' && line[i] != '$') {
		if (line[i] == '\0')
			return 0;
		i++;
	}
	if (line[i] == '$') {
		i++;
		x = 0;
		while ((line[i] >= '0' && line[i] <= '9') || (line[i] >= 'A' && line[i] <= 'F')) {
			x <<= 4;
			if (line[i] >= '0' && line[i] <= '9')
				x += line[i] - '0';
			if (line[i] >= 'A' && line[i] <= 'F')
				x += line[i] - 'A' + 10;
			i++;
		}
	} else {
		x = 0;
		while (line[i] >= '0' && line[i] <= '9') {
			x = x * 10 + (line[i] - '0');
			i++;
		}
	}
	return x;
}

void dodebugmode ()
{
	char *debugline, debuglinetext [55];
	boolean newinstr;
	dword opdata;
	int x, i, n, n2, esccount, key;
	FILE *fp;

	#define DEBUG_DOESCCHECK esccount = (esccount + 1) & 0x3F; if (esccount == 0 && kbhit() && getch () == 27) break

	(void) fp;
	newinstr = true;
	debugscreen = 1;
	applycustompalette ();
	while (!returntogui && debugmode) {
		if (newinstr) {
			newinstr = false;
			opdata = *(dword*)SNESMEM (reg.PC);
			unassemble (opdata, debuglinetext, reg.P);
			adddebugline (debuglinetext, true);
			applycustompalette ();
			if ((reg.A_dummy & 0xFFFF0000) || (reg.X_dummy & 0xFFFF0000) || (reg.Y_dummy & 0xFFFF0000)) {
				sprintf (debuglinetext, "Err! A$%0.8X X%0.8X Y%0.8X", reg.A_dummy, reg.X_dummy, reg.Y_dummy);
				adddebugline (debuglinetext, false, '@');
			}
			if ((reg.D_dummy & 0xFFFF0000) || (reg.S_dummy & 0xFFFF0000) || (reg.P_dummy & 0xFFFFFF00)) {
				sprintf (debuglinetext, "Err! D$%0.8X S%0.8X P%0.8X", reg.D_dummy, reg.S_dummy, reg.P_dummy);
				adddebugline (debuglinetext, false, '@');
			}
			if (reg.DBR_dummy1 || reg.DBR_dummy2 || reg.DBR_dummy3 || (reg.PC & 0xFF000000)) {
				sprintf (debuglinetext, "Err! D1$%0.2X D2$%0.2X D3$%0.2X PC$%0.8X", reg.DBR_dummy1, reg.DBR_dummy2, reg.DBR_dummy3, reg.PC);
				adddebugline (debuglinetext, false, '@');
			}
		}
		rendersnesscreen ();
		debugline = debug_input (key);
		if (key == 0) {
			if (debugline[0] == '\0') {
				debug_executecpu (0);
				newinstr = true;
			}
			for (x = 0; debugline[x] != '\0'; x++) {
				while (debugline[x] == ' ')
					x++;
				if (debugline [x] >= '0' && debugline[x] <= '9')
					debugscreen = debugline[x] - '0';
				switch (debugline [x]) {
				case 'T': // Trace
					n = grabnumber (debugline + x + 1, i);
					x += i;
					sprintf (debuglinetext, "[Tracing for %d instructions; ESC stops]", n);
					adddebugline (debuglinetext, false, '*');
					rendersnesscreen ();
					copyscreen ();
					while (n > 0 && !returntogui) {
						debug_executecpu(0);
						n--;
						DEBUG_DOESCCHECK;
					}
					newinstr = true;
					break;
				case 'W': // Wait for instruction
					while (debugline[x+1] == ' ')
						x++;
					for (n = 0; n < 256; n++) {
						if (stricmp (opcodelist[n].format, debugline + x+1) == 0) {
							break;
						}
					}
					if (n >= 256) {
						adddebugline ("[Format spec not found, waiting for string]", false, '*');
						do {
							debug_executecpu(0);
							DEBUG_DOESCCHECK;
							opdata = *(dword*)SNESMEM (reg.PC);
							unassemble (opdata, debuglinetext, reg.P);
							for (i = 0; *(debugline+x+1+i); i++)
								if (*(debugline+x+1+i) == '?' && debuglinetext[i] != '\0')
									debuglinetext[i] = '?';
						} while (strcmp (debugline+x+1, debuglinetext) != 0 && !returntogui);
						x += strlen (debugline + x+1);
						newinstr = true;
						break;
					}
					x += strlen (debugline + x+1);
					sprintf (debuglinetext, "[Tracing for opcode $%X; ESC stops]", n, opcodelist[n].format);
					adddebugline (debuglinetext, false, '*');
					rendersnesscreen ();
					copyscreen ();
					do {
						debug_executecpu(0);
			

⌨️ 快捷键说明

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