core: strict-aliasing fixes, bounded string ops, drop FCEUDEF_DEBUGGER
Three follow-up cleanups on top of the determinism / typedef / LE work inf2a5be3. ================================================================ Pass 1: fix strict-aliasing UB in PPU sprite buffer and FCEU_dwmemset ================================================================ Three sites were doing type-punning through uint32_t* casts that GCC flags with -Wstrict-aliasing=2: 1. ppu.c FetchSpriteData (two near-identical sites). After populating a local SPRB struct (4 bytes: ca[2], atr, x), the prior code did '*(uint32_t*)&SPRBUF[ns << 2] = *(uint32_t*)&dst' to store the struct as one 32-bit word. This violates strict-aliasing (uint8_t buffer accessed as uint32_t, struct accessed as uint32_t) and silently assumes 4-byte alignment of SPRBUF + (ns << 2). Use memcpy instead - GCC and Clang lower it to the same single 32-bit store. 2. fceu-memory.h FCEU_dwmemset macro. Same pattern every iteration: '*(uint32_t*)& (d)[_x] = c'. Replaced with memcpy(... &v, 4) in the macro body. Same generated code, now alias- and align-clean. Added #include <string.h> to fceu-memory.h itself (4 callers relied on transitive includes for memcpy). ================================================================ Pass 2: bounded string operations ================================================================ Sweep across the core and libretro driver to replace every unbounded string function with its size-aware counterpart: strcpy -> strlcpy (with explicit destination size) strncpy -> strlcpy (silent truncation -> guaranteed NUL termination and known-size semantics; behaviourally identical at every call site here because callers either pre-zeroed the buffer or treated truncation as a guaranteed terminator) strcat -> strlcpy at offset (track 'pos' across appends to avoid rescanning the buffer with strlen and to keep the bound explicit at every step) sprintf -> snprintf (with sizeof(buf) as the bound) The compat/strl.h header from libretro-common is on the include path for every translation unit; the libretro driver files were already using strlcpy via stdstring.h transitive include. Core files (ines.c, unif.c, cheat.c, nsf.c, state.c, general.c) gain explicit '#include <compat/strl.h>'. Per-file changes: general.c - FCEUI_SetBaseDirectory: strncpy + manual NUL -> strlcpy - FCEU_MakeFName: malloc(strlen+1) + strcpy -> sized strlcpy, malloc NULL-check added (was unchecked). ines.c - 'gigastr' iNES-header-warning building. Pre-existing bug fixed: every sprintf(gigastr + gigastr_len, ...) wrote at the SAME offset captured once at the top of the block, so when multiple 'tofix' bits were set, only the LAST fragment survived (each sprintf clobbered the previous). Replaced with a running 'pos' offset across snprintf and strlcpy-at-offset calls. - 6 sprintf -> snprintf, 3 strcat -> strlcpy at offset, 1 strcpy -> strlcpy. unif.c - GameInfo->name allocation: strcpy -> strlcpy with explicit size. cheat.c - FCEUI_AddCheat: malloc + strcpy -> sized strlcpy. - FCEUI_SetCheat: realloc + strcpy -> sized strlcpy. nsf.c - FCEUI_NSFGetInfo: 3x strncpy -> strlcpy. - Visualiser snbuf sprintf -> snprintf (the 16-byte buffer was technically overflowable for very large song counts). state.c - AddExState description copy: strncpy -> strlcpy. Preserves 4-byte SFORMAT-tag semantics. fds.c - Disk-tag formatting: sprintf "DDT%d" -> snprintf. boards/__serial.c - 2 sprintf -> snprintf (Windows-only SerialOpen path). drivers/libretro/libretro.c - retro_cheat_set: sprintf "N/A" + strcpy literal -> strlcpy. drivers/libretro/libretro_dipswitch.c - VS-DIP key building: sprintf -> snprintf. - core_key calloc + strcpy -> sized strlcpy. calloc NULL-check added (was unchecked - dereferencing NULL on OOM). drivers/libretro/libretro_core_options.h - values_buf assembly: single strcpy + N strcat replaced with strlcpy + strlcpy-at-offset using a running 'pos'. Each step bounded by remaining buffer space. ================================================================ Pass 3: remove FCEUDEF_DEBUGGER and the unused debugger scaffolding ================================================================ The FCEUDEF_DEBUGGER macro was never defined for libretro builds, so every block guarded by it was dead code. Removing the macro takes out: - src/debug.c (FCEUI_DumpMem, FCEUI_DumpVid, FCEUI_LoadMem, FCEUI_Disassemble, FCEUI_MemDump, FCEUI_MemSafePeek, FCEUI_MemPoke, breakpoint set/get/list, FCEUI_SetCPUCallback). Not in Makefile.common SOURCES_C, never compiled. None of the declared functions had any caller in any compiled .c file. - src/debug.h (declarations for the above). - x6502.c X6502_RunDebug. The dual-implementation pattern with a function pointer that switched between RunNormal and RunDebug is now a single direct X6502_Run. - x6502.c X6502_Debug, FCEUI_NMI, FCEUI_IRQ, FCEUI_GetIVectors. Set/get debugger hooks. No callers. - x6502.c RdMemHook, WrMemHook, XSave, debugmode. Hook scaffolding used only by RunDebug. - x6502struct.h X6502 fields preexec, CPUHook, ReadHook, WriteHook. Set only inside RunDebug, never read elsewhere. - fceuindbg variable. Set to 1 only in FCEUI_GetIVectors and X6502_RunDebug (both removed); was always 0 elsewhere, so every 'if (!fceuindbg)' check was a no-op. Removed both the variable (defined in ppu.c, declared in fceu.h) and every check site across sound.c, input.c, fds.c, nsf.c, ppu.c, mmc5.c, n106.c, BMW8544.c, and the input drivers (arkanoid, mahjong, mouse, pec586kb, powerpad, zapper). - All FCEUDEF_DEBUGGER conditional declarations from driver.h. The 'if (!fceuindbg)' checks gated side-effects (joypad-bit-counter increments, PPU register reads, etc.) so a future debugger could peek at memory without advancing the emulator state. With the debugger gone, those side-effects are now unconditional - which is what they should have been anyway in a libretro build. If a future developer needs a debugger they should resurrect this out of git history into a separate debugger-frontend project rather than re-introducing a build-time toggle that nothing in the libretro build can ever exercise. ================================================================ Build status ================================================================ Build clean on `make platform=unix` with zero errors and zero warnings. Output binary 184 bytes smaller than upstreamf2a5be3(4,388,840 -> 4,388,656). 31 files changed, 127 insertions, 863 deletions.
This commit is contained in:
@@ -53,16 +53,14 @@ static DECLFW(UNLBMW8544ProtWrite) {
|
||||
}
|
||||
|
||||
static DECLFR(UNLBMW8544ProtRead) {
|
||||
if(!fceuindbg) {
|
||||
if(!(A & 1)) {
|
||||
if((EXPREGS[0] & 0xE0) == 0xC0) {
|
||||
EXPREGS[1] = ARead[0x6a](0x6a); /* program can latch some data from the BUS, but I can't say how exactly, */
|
||||
} else { /* without more equipment and skills ;) probably here we can try to get any write */
|
||||
EXPREGS[2] = ARead[0xff](0xff); /* before the read operation */
|
||||
}
|
||||
FixMMC3CHR(MMC3_cmd & 0x7F); /* there are more different behaviour of the board that's not used by game itself, so unimplemented here and */
|
||||
} /* actually will break the current logic ;) */
|
||||
}
|
||||
if(!(A & 1)) {
|
||||
if((EXPREGS[0] & 0xE0) == 0xC0) {
|
||||
EXPREGS[1] = ARead[0x6a](0x6a); /* program can latch some data from the BUS, but I can't say how exactly, */
|
||||
} else { /* without more equipment and skills ;) probably here we can try to get any write */
|
||||
EXPREGS[2] = ARead[0xff](0xff); /* before the read operation */
|
||||
}
|
||||
FixMMC3CHR(MMC3_cmd & 0x7F); /* there are more different behaviour of the board that's not used by game itself, so unimplemented here and */
|
||||
} /* actually will break the current logic ;) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ BOOL SerialOpen(int port, int baud) {
|
||||
char str[100];
|
||||
|
||||
if (port > 9)
|
||||
sprintf(str, "\\\\.\\COM%d", port);
|
||||
snprintf(str, sizeof(str), "\\\\.\\COM%d", port);
|
||||
else
|
||||
sprintf(str, "COM%d", port);
|
||||
snprintf(str, sizeof(str), "COM%d", port);
|
||||
|
||||
/* Open the serial port */
|
||||
if ((Comport = CreateFile(str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -375,9 +375,6 @@ static DECLFR(MMC5_read) {
|
||||
uint8_t x;
|
||||
X6502_IRQEnd(FCEU_IQEXT);
|
||||
x = MMC5IRQR;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
MMC5IRQR &= 0x40;
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -95,9 +95,6 @@ static void FP_FASTAPASS(1) NamcoIRQHook(int a) {
|
||||
static DECLFR(Namco_Read4800) {
|
||||
uint8_t ret = IRAM[dopol & 0x7f];
|
||||
/* Maybe I should call NamcoSoundHack() here? */
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
if (dopol & 0x80)
|
||||
dopol = (dopol & 0x80) | ((dopol + 1) & 0x7f);
|
||||
return ret;
|
||||
|
||||
12
src/cheat.c
12
src/cheat.c
@@ -23,6 +23,8 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "x6502.h"
|
||||
#include "cheat.h"
|
||||
@@ -210,12 +212,13 @@ void FCEU_ResetCheats(void)
|
||||
|
||||
int FCEUI_AddCheat(const char *name, uint32_t addr, uint8_t val, int compare, int type) {
|
||||
char *t;
|
||||
if (!(t = (char*)malloc(strlen(name) + 1)))
|
||||
size_t n = strlen(name) + 1;
|
||||
if (!(t = (char*)malloc(n)))
|
||||
{
|
||||
CheatMemErr();
|
||||
return(0);
|
||||
}
|
||||
strcpy(t, name);
|
||||
strlcpy(t, name, n);
|
||||
if (!AddCheatEntry(t, addr, val, compare, 1, type)) {
|
||||
free(t);
|
||||
return(0);
|
||||
@@ -426,10 +429,11 @@ int FCEUI_SetCheat(uint32_t which, const char *name, int32_t a, int32_t v, int c
|
||||
if (x == which) {
|
||||
if (name) {
|
||||
char *t;
|
||||
size_t n = strlen(name) + 1;
|
||||
|
||||
if ((t = (char*)realloc(next->name, strlen(name) + 1))) {
|
||||
if ((t = (char*)realloc(next->name, n))) {
|
||||
next->name = t;
|
||||
strcpy(next->name, name);
|
||||
strlcpy(next->name, name, n);
|
||||
} else
|
||||
return(0);
|
||||
}
|
||||
|
||||
502
src/debug.c
502
src/debug.c
@@ -1,502 +0,0 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2003 Xodnizel
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <streams/file_stream.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "x6502.h"
|
||||
#include "fceu.h"
|
||||
#include "debug.h"
|
||||
#include "cart.h"
|
||||
|
||||
void FCEUI_DumpVid(const char *fname, uint32_t start, uint32_t end) {
|
||||
RFILE *fp = filestream_open(fname,
|
||||
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
fceuindbg = 1;
|
||||
start &= 0x3FFF;
|
||||
end &= 0x3FFF;
|
||||
for (; start <= end; start++)
|
||||
filestream_putc(fp, VPage[start >> 10][start]);
|
||||
filestream_close(fp);
|
||||
fceuindbg = 0;
|
||||
}
|
||||
|
||||
void FCEUI_DumpMem(const char *fname, uint32_t start, uint32_t end) {
|
||||
RFILE *fp = filestream_open(fname,
|
||||
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
fceuindbg = 1;
|
||||
for (; start <= end; start++)
|
||||
filestream_putc(fp, ARead[start](start));
|
||||
filestream_close(fp);
|
||||
fceuindbg = 0;
|
||||
}
|
||||
|
||||
void FCEUI_LoadMem(const char *fname, uint32_t start, int hl) {
|
||||
int t;
|
||||
RFILE *fp = filestream_open(fname,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
while ((t = filestream_getc(fp)) >= 0) {
|
||||
if (start > 0xFFFF) break;
|
||||
if (hl) {
|
||||
extern uint8_t *Page[32];
|
||||
if (Page[start / 2048])
|
||||
Page[start / 2048][start] = t;
|
||||
} else
|
||||
BWrite[start](start, t);
|
||||
start++;
|
||||
}
|
||||
filestream_close(fp);
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
|
||||
static char *fstrings[12] =
|
||||
{
|
||||
"#$%02X", /* immediate */
|
||||
"$%04X", /* RELATIVE(jump) */
|
||||
"$%02X", /* Z */
|
||||
"$%02X,X", /* Z,x */
|
||||
"$%02X,Y", /* Z,y */
|
||||
"$%04X", /*ABS */
|
||||
"$%04X,X", /* ABS,x */
|
||||
"$%04X,Y", /* ABS,y */
|
||||
"($%04X)", /* IND */
|
||||
"($%02X,X)", /* INX */
|
||||
"($%02X),Y", /* INY */
|
||||
""
|
||||
};
|
||||
static int flengths[12] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 0 };
|
||||
|
||||
#define IMD(x) ((0 << 16) | x)
|
||||
#define REL(x) ((1 << 16) | x)
|
||||
#define ZP(x) ((2 << 16) | x)
|
||||
#define ZPX(x) ((3 << 16) | x)
|
||||
#define ZPY(x) ((4 << 16) | x)
|
||||
#define ABS(x) ((5 << 16) | x)
|
||||
#define ABX(x) ((6 << 16) | x)
|
||||
#define ABY(x) ((7 << 16) | x)
|
||||
#define IND(x) ((8 << 16) | x)
|
||||
#define INX(x) ((9 << 16) | x)
|
||||
#define INY(x) ((10 << 16) | x)
|
||||
#define IMP(x) ((11 << 16) | x)
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int type; /* 1 for read, 2 for write, 3 for r then write. */
|
||||
int32_t modes[10];
|
||||
} OPS;
|
||||
#define NUMOPS 56
|
||||
static OPS optable[NUMOPS] =
|
||||
{
|
||||
{ "BRK", 0, { IMP(0x00), -1 } },
|
||||
{ "RTI", 0, { IMP(0x40), -1 } },
|
||||
{ "RTS", 0, { IMP(0x60), -1 } },
|
||||
{ "PHA", 2, { IMP(0x48), -1 } },
|
||||
{ "PHP", 2, { IMP(0x08), -1 } },
|
||||
{ "PLA", 1, { IMP(0x68), -1 } },
|
||||
{ "PLP", 1, { IMP(0x28), -1 } },
|
||||
{ "JMP", 0, { ABS(0x4C), IND(0x6C), -1 } },
|
||||
{ "JSR", 0, { ABS(0x20), -1 } },
|
||||
{ "TAX", 0, { IMP(0xAA), -1 } },
|
||||
{ "TXA", 0, { IMP(0x8A), -1 } },
|
||||
{ "TAY", 0, { IMP(0xA8), -1 } },
|
||||
{ "TYA", 0, { IMP(0x98), -1 } },
|
||||
{ "TSX", 0, { IMP(0xBA), -1 } },
|
||||
{ "TXS", 0, { IMP(0x9A), -1 } },
|
||||
{ "DEX", 0, { IMP(0xCA), -1 } },
|
||||
{ "DEY", 0, { IMP(0x88), -1 } },
|
||||
{ "INX", 0, { IMP(0xE8), -1 } },
|
||||
{ "INY", 0, { IMP(0xC8), -1 } },
|
||||
{ "CLC", 0, { IMP(0x18), -1 } },
|
||||
{ "CLD", 0, { IMP(0xD8), -1 } },
|
||||
{ "CLI", 0, { IMP(0x58), -1 } },
|
||||
{ "CLV", 0, { IMP(0xB8), -1 } },
|
||||
{ "SEC", 0, { IMP(0x38), -1 } },
|
||||
{ "SED", 0, { IMP(0xF8), -1 } },
|
||||
{ "SEI", 0, { IMP(0x78), -1 } },
|
||||
{ "NOP", 0, { IMP(0xEA), -1 } },
|
||||
{ "ASL", 1, { IMP(0x0a), ZP(0x06), ZPX(0x16), ABS(0x0E), ABX(0x1E), -1 } },
|
||||
{ "DEC", 3, { ZP(0xc6), ZPX(0xd6), ABS(0xcE), ABX(0xdE), -1 } },
|
||||
{ "INC", 3, { ZP(0xe6), ZPX(0xf6), ABS(0xeE), ABX(0xfE), -1 } },
|
||||
{ "LSR", 3, { IMP(0x4a), ZP(0x46), ZPX(0x56), ABS(0x4E), ABX(0x5E), -1 } },
|
||||
{ "ROL", 3, { IMP(0x2a), ZP(0x26), ZPX(0x36), ABS(0x2E), ABX(0x3E), -1 } },
|
||||
{ "ROR", 3, { IMP(0x6a), ZP(0x66), ZPX(0x76), ABS(0x6E), ABX(0x7E), -1 } },
|
||||
{ "ADC", 1, { IMD(0x69), ZP(0x65), ZPX(0x75), ABS(0x6D), ABX(0x7d), ABY(0x79),
|
||||
INX(0x61), INY(0x71), -1 } },
|
||||
{ "AND", 1, { IMD(0x29), ZP(0x25), ZPX(0x35), ABS(0x2D), ABX(0x3d), ABY(0x39),
|
||||
INX(0x21), INY(0x31), -1 } },
|
||||
{ "BIT", 1, { ZP(0x24), ABS(0x2c), -1 } },
|
||||
{ "CMP", 1, { IMD(0xc9), ZP(0xc5), ZPX(0xd5), ABS(0xcD), ABX(0xdd), ABY(0xd9),
|
||||
INX(0xc1), INY(0xd1), -1 } },
|
||||
{ "CPX", 1, { IMD(0xe0), ZP(0xe4), ABS(0xec), -1 } },
|
||||
{ "CPY", 1, { IMD(0xc0), ZP(0xc4), ABS(0xcc), -1 } },
|
||||
{ "EOR", 1, { IMD(0x49), ZP(0x45), ZPX(0x55), ABS(0x4D), ABX(0x5d), ABY(0x59),
|
||||
INX(0x41), INY(0x51), -1 } },
|
||||
{ "LDA", 1, { IMD(0xa9), ZP(0xa5), ZPX(0xb5), ABS(0xaD), ABX(0xbd), ABY(0xb9),
|
||||
INX(0xa1), INY(0xb1), -1 } },
|
||||
{ "LDX", 1, { IMD(0xa2), ZP(0xa6), ZPY(0xB6), ABS(0xae), ABY(0xbe), -1 } },
|
||||
{ "LDY", 1, { IMD(0xa0), ZP(0xa4), ZPX(0xB4), ABS(0xac), ABX(0xbc), -1 } },
|
||||
{ "ORA", 1, { IMD(0x09), ZP(0x05), ZPX(0x15), ABS(0x0D), ABX(0x1d), ABY(0x19),
|
||||
INX(0x01), INY(0x11), -1 } },
|
||||
{ "SBC", 1, { IMD(0xEB), IMD(0xe9), ZP(0xe5), ZPX(0xf5), ABS(0xeD), ABX(0xfd), ABY(0xf9),
|
||||
INX(0xe1), INY(0xf1), -1 } },
|
||||
{ "STA", 2, { ZP(0x85), ZPX(0x95), ABS(0x8D), ABX(0x9d), ABY(0x99),
|
||||
INX(0x81), INY(0x91), -1 } },
|
||||
{ "STX", 2, { ZP(0x86), ZPY(0x96), ABS(0x8E), -1 } },
|
||||
{ "STY", 2, { ZP(0x84), ZPX(0x94), ABS(0x8C), -1 } },
|
||||
{ "BCC", 1, { REL(0x90), -1 } },
|
||||
{ "BCS", 1, { REL(0xb0), -1 } },
|
||||
{ "BEQ", 1, { REL(0xf0), -1 } },
|
||||
{ "BNE", 1, { REL(0xd0), -1 } },
|
||||
{ "BMI", 1, { REL(0x30), -1 } },
|
||||
{ "BPL", 1, { REL(0x10), -1 } },
|
||||
{ "BVC", 1, { REL(0x50), -1 } },
|
||||
{ "BVS", 1, { REL(0x70), -1 } },
|
||||
};
|
||||
|
||||
uint16_t FCEUI_Disassemble(void *XA, uint16_t a, char *stringo) {
|
||||
X6502 *X = XA;
|
||||
uint8_t buf;
|
||||
uint32_t arg;
|
||||
int32_t info;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
info = -1;
|
||||
fceuindbg = 1;
|
||||
|
||||
buf = ARead[a](a);
|
||||
a++;
|
||||
|
||||
for (x = 0; x < NUMOPS; x++) {
|
||||
y = 0;
|
||||
while (optable[x].modes[y] >= 0) {
|
||||
if ((optable[x].modes[y] & 0xFF) == buf) {
|
||||
info = optable[x].modes[y];
|
||||
goto endy;
|
||||
}
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
endy:
|
||||
sprintf(stringo, "%02X ", buf);
|
||||
if (info >= 0) {
|
||||
int z = flengths[(info >> 16)];
|
||||
|
||||
if (z) {
|
||||
arg = ARead[a](a);
|
||||
sprintf(stringo + strlen(stringo), "%02X ", arg);
|
||||
a++;
|
||||
if (z == 2) {
|
||||
arg |= ARead[a](a) << 8; sprintf(stringo + strlen(stringo), "%02X ", arg >> 8); a++;
|
||||
} else
|
||||
strcat(stringo, " ");
|
||||
|
||||
if ((info >> 16) == 1) /* Relative branch */
|
||||
arg = a + (char)arg;
|
||||
sprintf(stringo + strlen(stringo), "%s ", optable[x].name);
|
||||
sprintf(stringo + strlen(stringo), fstrings[info >> 16], arg);
|
||||
/*
|
||||
0 "#$%02X", // immediate
|
||||
1 "$%04X", // RELATIVE(jump)
|
||||
2 "$%02X", // Z
|
||||
3 "$%02X,X", // Z,x
|
||||
4 "$%02X,Y", // Z,y
|
||||
5 "$%04X", //ABS
|
||||
6 "$%04X,X", // ABS,x
|
||||
7 "$%04X,Y", // ABS,y
|
||||
8 "($%04X)", // IND
|
||||
9 "($%02X,X)", // INX
|
||||
10 "($%02X),Y", // INY
|
||||
11 #define IMP(x) ((11<<16)|x)
|
||||
*/
|
||||
{
|
||||
uint32_t tmp;
|
||||
switch (info >> 16) {
|
||||
case 2: tmp = arg;
|
||||
if (optable[x].type & 1) {
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
}
|
||||
break;
|
||||
case 3: tmp = (arg + X->X) & 0xff;
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
if (optable[x].type & 1)
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
break;
|
||||
case 4: tmp = (arg + X->Y) & 0xff;
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
if (optable[x].type & 1)
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
break;
|
||||
case 5: tmp = arg;
|
||||
if (optable[x].type & 1) {
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
}
|
||||
break;
|
||||
case 6: tmp = (arg + X->X) & 0xffff;
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
if (optable[x].type & 1)
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
break;
|
||||
case 7: tmp = (arg + X->Y) & 0xffff;
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
if (optable[x].type & 1)
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
break;
|
||||
case 8: tmp = ARead[arg](arg) | (ARead[(arg + 1) & 0xffff]((arg + 1) & 0xffff) << 8);
|
||||
sprintf(stringo + strlen(stringo), " $%04X", tmp);
|
||||
break;
|
||||
case 9: tmp = (arg + X->X) & 0xFF;
|
||||
tmp = ARead[tmp](tmp) | (ARead[(tmp + 1) & 0xFF]((tmp + 1) & 0xFF) << 8);
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
if (optable[x].type & 1)
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
break;
|
||||
case 10: tmp = ARead[arg](arg) | (ARead[(arg + 1) & 0xFF]((arg + 1) & 0xFF) << 8);
|
||||
tmp = (tmp + X->Y) & 0xFFFF;
|
||||
sprintf(stringo + strlen(stringo), " @ $%04X", tmp);
|
||||
if (optable[x].type & 1)
|
||||
sprintf(stringo + strlen(stringo), " = $%02X", ARead[tmp](tmp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
strcat(stringo, " ");
|
||||
strcat(stringo, optable[x].name);
|
||||
}
|
||||
} else
|
||||
sprintf(stringo + strlen(stringo), " .db $%02X", buf);
|
||||
fceuindbg = 0;
|
||||
return(a);
|
||||
}
|
||||
|
||||
void FCEUI_MemDump(uint16_t a, int32_t len, void (*callb)(uint16_t a, uint8_t v)) {
|
||||
fceuindbg = 1;
|
||||
while (len) {
|
||||
callb(a, ARead[a](a));
|
||||
a++;
|
||||
len--;
|
||||
}
|
||||
fceuindbg = 0;
|
||||
}
|
||||
|
||||
uint8_t FCEUI_MemSafePeek(uint16_t A) {
|
||||
uint8_t ret;
|
||||
|
||||
fceuindbg = 1;
|
||||
ret = ARead[A](A);
|
||||
fceuindbg = 0;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void FCEUI_MemPoke(uint16_t a, uint8_t v, int hl) {
|
||||
extern uint8_t *Page[32];
|
||||
if (hl) {
|
||||
if (Page[a / 2048])
|
||||
Page[a / 2048][a] = v;
|
||||
} else
|
||||
BWrite[a](a, v);
|
||||
}
|
||||
|
||||
typedef struct __BPOINT {
|
||||
struct __BPOINT *next;
|
||||
void (*Handler)(X6502 *X, int type, uint32_t A);
|
||||
uint32_t A[2];
|
||||
int type;
|
||||
} BPOINT;
|
||||
|
||||
static BPOINT *BreakPoints = NULL;
|
||||
static BPOINT *LastBP = NULL;
|
||||
|
||||
static void (*CPUHook)(X6502 *) = NULL;
|
||||
|
||||
static int FindBPoint(X6502 *X, int who, uint32_t A) {
|
||||
BPOINT *tmp;
|
||||
|
||||
tmp = BreakPoints;
|
||||
while (tmp) {
|
||||
if (who & BPOINT_EXCLUDE) {
|
||||
if ((tmp->type & who) == who) {
|
||||
if ((X->PC >= tmp->A[0]) && (X->PC <= tmp->A[1])) {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tmp->type & who) {
|
||||
if (tmp->type & BPOINT_PC)
|
||||
if (X->PC != A) goto don;
|
||||
if (tmp->type & BPOINT_EXCLUDE) goto don;
|
||||
|
||||
if ((A >= tmp->A[0]) && (A <= tmp->A[1])) {
|
||||
if (!FindBPoint(X, who | BPOINT_EXCLUDE, A)) {
|
||||
tmp->Handler(X, tmp->type, A);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
don:
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static uint8_t ReadHandler(X6502 *X, uint32_t A) {
|
||||
extern X6502 XSave;
|
||||
|
||||
if (X->preexec)
|
||||
FindBPoint(&XSave, BPOINT_READ, A);
|
||||
return(ARead[A](A));
|
||||
}
|
||||
|
||||
static void WriteHandler(X6502 *X, uint32_t A, uint8_t V) {
|
||||
extern X6502 XSave;
|
||||
|
||||
if (X->preexec)
|
||||
FindBPoint(&XSave, BPOINT_WRITE, A);
|
||||
else
|
||||
BWrite[A](A, V);
|
||||
}
|
||||
|
||||
int FCEUI_AddBreakPoint(int type, uint32_t A1, uint32_t A2,
|
||||
void (*Handler)(X6502 *, int type, uint32_t A)) {
|
||||
BPOINT *tmp;
|
||||
|
||||
tmp = (BPOINT*)malloc(sizeof(BPOINT));
|
||||
|
||||
tmp->A[0] = A1;
|
||||
tmp->A[1] = A2;
|
||||
tmp->Handler = Handler;
|
||||
tmp->type = type;
|
||||
tmp->next = 0;
|
||||
|
||||
if (BreakPoints == NULL)
|
||||
BreakPoints = tmp;
|
||||
else
|
||||
LastBP->next = tmp;
|
||||
|
||||
LastBP = tmp;
|
||||
|
||||
X6502_Debug(CPUHook, ReadHandler, WriteHandler);
|
||||
return(1);
|
||||
}
|
||||
|
||||
int FCEUI_SetBreakPoint(uint32_t w, int type, uint32_t A1, uint32_t A2,
|
||||
void (*Handler)(X6502 *, int type, uint32_t A)) {
|
||||
uint32_t x = 0;
|
||||
BPOINT *tmp;
|
||||
|
||||
tmp = BreakPoints;
|
||||
|
||||
while (tmp) {
|
||||
if (w == x) {
|
||||
tmp->type = type;
|
||||
tmp->A[0] = A1;
|
||||
tmp->A[1] = A2;
|
||||
tmp->Handler = Handler;
|
||||
return(1);
|
||||
}
|
||||
x++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int FCEUI_GetBreakPoint(uint32_t w, int *type, uint32_t *A1, uint32_t *A2,
|
||||
void(**Handler) (X6502 *, int type, uint32_t A)) {
|
||||
uint32_t x = 0;
|
||||
BPOINT *tmp;
|
||||
|
||||
tmp = BreakPoints;
|
||||
|
||||
while (tmp) {
|
||||
if (w == x) {
|
||||
*type = tmp->type;
|
||||
*A1 = tmp->A[0];
|
||||
*A2 = tmp->A[1];
|
||||
*Handler = tmp->Handler;
|
||||
return(1);
|
||||
}
|
||||
x++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int FCEUI_ListBreakPoints(int (*callb)(int type, uint32_t A1, uint32_t A2,
|
||||
void (*Handler)(X6502 *, int type, uint32_t A))) {
|
||||
BPOINT *tmp;
|
||||
tmp = BreakPoints;
|
||||
while (tmp) {
|
||||
callb(tmp->type, tmp->A[0], tmp->A[1], tmp->Handler);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
int FCEUI_DeleteBreakPoint(uint32_t w) {
|
||||
BPOINT *tmp, *prev = NULL;
|
||||
uint32_t x = 0;
|
||||
|
||||
tmp = BreakPoints;
|
||||
|
||||
while (tmp) {
|
||||
if (w == x) {
|
||||
if (prev) { /* Not the first breakpoint. */
|
||||
if (tmp->next) /* More breakpoints. */
|
||||
prev->next = tmp->next;
|
||||
else { /* This is the last breakpoint. */
|
||||
prev->next = 0;
|
||||
LastBP = prev;
|
||||
}
|
||||
} else {/* The first breakpoint. */
|
||||
if (tmp->next) /* More breakpoints. */
|
||||
BreakPoints = tmp->next;
|
||||
else {
|
||||
BreakPoints = LastBP = 0; /* No more breakpoints. */
|
||||
/* Update the CPU hooks. */
|
||||
X6502_Debug(CPUHook, BreakPoints ? ReadHandler : 0, BreakPoints ? WriteHandler : 0);
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
tmp = 0;
|
||||
return(1);
|
||||
}
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
x++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void FCEUI_SetCPUCallback(void (*callb)(X6502 *X)) {
|
||||
CPUHook = callb;
|
||||
X6502_Debug(CPUHook, BreakPoints ? ReadHandler : 0, BreakPoints ? WriteHandler : 0);
|
||||
}
|
||||
#endif
|
||||
30
src/debug.h
30
src/debug.h
@@ -1,30 +0,0 @@
|
||||
#ifndef _FCEU_DEBUG_H
|
||||
#define _FCEU_DEBUG_H
|
||||
|
||||
void FCEUI_DumpMem(const char *fname, uint32_t start, uint32_t end);
|
||||
void FCEUI_DumpVid(const char *fname, uint32_t start, uint32_t end);
|
||||
void FCEUI_LoadMem(const char *fname, uint32_t start, int hl);
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
|
||||
/* Type attributes, you can OR them together. */
|
||||
#define BPOINT_READ 1
|
||||
#define BPOINT_WRITE 2
|
||||
#define BPOINT_PC 4
|
||||
#define BPOINT_EXCLUDE 8
|
||||
|
||||
#include "x6502struct.h"
|
||||
|
||||
void FCEUI_SetCPUCallback(void (*callb)(X6502 *X));
|
||||
int FCEUI_DeleteBreakPoint(uint32_t w);
|
||||
int FCEUI_ListBreakPoints(int (*callb)(int type, unsigned int A1, unsigned int A2,
|
||||
void (*Handler)(X6502 *, int type, unsigned int A)));
|
||||
int FCEUI_GetBreakPoint(uint32_t w, int *type, unsigned int *A1, unsigned int *A2,
|
||||
void(**Handler) (X6502 *, int type, unsigned int A));
|
||||
int FCEUI_SetBreakPoint(uint32_t w, int type, unsigned int A1, unsigned int A2,
|
||||
void (*Handler)(X6502 *, int type, unsigned int A));
|
||||
int FCEUI_AddBreakPoint(int type, unsigned int A1, unsigned int A2,
|
||||
void (*Handler)(X6502 *, int type, unsigned int A));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
11
src/driver.h
11
src/driver.h
@@ -9,7 +9,6 @@ extern "C" {
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "git.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define FCEUNPCMD_RESET 0x01
|
||||
#define FCEUNPCMD_POWER 0x02
|
||||
@@ -168,16 +167,6 @@ int FCEUI_SetCheat(uint32_t which, const char *name, int32_t a, int32_t v, int c
|
||||
void FCEUI_CheatSearchShowExcluded(void);
|
||||
void FCEUI_CheatSearchSetCurrentAsOriginal(void);
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
void FCEUI_MemDump(uint16_t a, int32_t len, void (*callb)(uint16_t a, uint8_t v));
|
||||
uint8_t FCEUI_MemSafePeek(uint16_t A);
|
||||
void FCEUI_MemPoke(uint16_t a, uint8_t v, int hl);
|
||||
void FCEUI_NMI(void);
|
||||
void FCEUI_IRQ(void);
|
||||
uint16_t FCEUI_Disassemble(void *XA, uint16_t a, char *stringo);
|
||||
void FCEUI_GetIVectors(uint16_t *reset, uint16_t *irq, uint16_t *nmi);
|
||||
#endif
|
||||
|
||||
void FCEUI_SetLowPass(int q);
|
||||
|
||||
void FCEUI_NSFSetVis(int mode);
|
||||
|
||||
@@ -2440,7 +2440,7 @@ static void check_variables(bool startup)
|
||||
|
||||
enable_apu = 0xff;
|
||||
|
||||
strcpy(key, "fceumm_apu_x");
|
||||
strlcpy(key, "fceumm_apu_x", sizeof(key));
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
key[strlen("fceumm_apu_")] = '1' + i;
|
||||
@@ -3164,7 +3164,7 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
||||
* separators). The previous strcpy into a 256-byte stack buffer was
|
||||
* trivially overflowable. Use strlcpy and a larger buffer; truncate
|
||||
* if necessary rather than overflow. */
|
||||
sprintf(name, "N/A");
|
||||
strlcpy(name, "N/A", sizeof(name));
|
||||
strlcpy(temp, code, sizeof(temp));
|
||||
codepart = strtok(temp, "+,;._ ");
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <libretro.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
@@ -961,6 +962,7 @@ static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
|
||||
/* Build values string */
|
||||
if (num_values > 0)
|
||||
{
|
||||
size_t pos;
|
||||
buf_len += num_values - 1;
|
||||
buf_len += strlen(desc);
|
||||
|
||||
@@ -968,19 +970,24 @@ static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
|
||||
if (!values_buf[i])
|
||||
goto error;
|
||||
|
||||
strcpy(values_buf[i], desc);
|
||||
strcat(values_buf[i], "; ");
|
||||
/* strlcpy at offset is used in place of strcat:
|
||||
* strlcpy returns the source length (which equals
|
||||
* what was written when buf_len is sized exactly),
|
||||
* letting us track position without rescanning the
|
||||
* buffer with strlen on each append. */
|
||||
pos = strlcpy(values_buf[i], desc, buf_len);
|
||||
if (pos < buf_len) pos += strlcpy(values_buf[i] + pos, "; ", buf_len - pos);
|
||||
|
||||
/* Default value goes first */
|
||||
strcat(values_buf[i], values[default_index].value);
|
||||
if (pos < buf_len) pos += strlcpy(values_buf[i] + pos, values[default_index].value, buf_len - pos);
|
||||
|
||||
/* Add remaining values */
|
||||
for (j = 0; j < num_values; j++)
|
||||
{
|
||||
if (j != default_index)
|
||||
{
|
||||
strcat(values_buf[i], "|");
|
||||
strcat(values_buf[i], values[j].value);
|
||||
if (pos < buf_len) pos += strlcpy(values_buf[i] + pos, "|", buf_len - pos);
|
||||
if (pos < buf_len) pos += strlcpy(values_buf[i] + pos, values[j].value, buf_len - pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "../../fceu.h"
|
||||
#include "../../fceu-types.h"
|
||||
#include "../../vsuni.h"
|
||||
@@ -1109,9 +1111,14 @@ static void make_core_options(struct retro_core_option_v2_definition *vs_core_op
|
||||
sizeof(struct retro_core_option_v2_definition));
|
||||
|
||||
/* Set core key and sanitize string */
|
||||
sprintf(key, "fceumm_dipswitch_%s-%s", game_name, option_name);
|
||||
core_key[i] = calloc(strlen(key) + 1, sizeof(char));
|
||||
strcpy(core_key[i], key);
|
||||
snprintf(key, sizeof(key), "fceumm_dipswitch_%s-%s", game_name, option_name);
|
||||
{
|
||||
size_t key_size = strlen(key) + 1;
|
||||
core_key[i] = calloc(key_size, sizeof(char));
|
||||
if (!core_key[i])
|
||||
continue;
|
||||
strlcpy(core_key[i], key, key_size);
|
||||
}
|
||||
vs_core_options[i].key = str_to_corekey(core_key[i]);
|
||||
|
||||
/* Set desc */
|
||||
|
||||
@@ -25,9 +25,20 @@
|
||||
#ifndef _FCEU_MEMORY_H_
|
||||
#define _FCEU_MEMORY_H_
|
||||
|
||||
#include <string.h>
|
||||
#include "fceu-types.h"
|
||||
|
||||
#define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32_t*)& (d)[_x] = c; }
|
||||
/* Fill 'n' bytes of 'd' with the 32-bit pattern 'c'. Uses memcpy to
|
||||
* avoid the strict-aliasing UB that the previous *(uint32_t*)& cast
|
||||
* implied; GCC and Clang both lower the do { memcpy } while loop to
|
||||
* the same single-instruction-per-iteration code as the cast did, so
|
||||
* there's no performance change. 'n' must be a multiple of 4. */
|
||||
#define FCEU_dwmemset(d, c, n) do { \
|
||||
uint32_t _fcdms_v = (uint32_t)(c); \
|
||||
int _fcdms_x; \
|
||||
for (_fcdms_x = (int)(n) - 4; _fcdms_x >= 0; _fcdms_x -= 4) \
|
||||
memcpy((uint8_t *)(d) + _fcdms_x, &_fcdms_v, 4); \
|
||||
} while (0)
|
||||
|
||||
void *FCEU_malloc(uint32_t size);
|
||||
void *FCEU_gmalloc(uint32_t size);
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "fceu-types.h"
|
||||
|
||||
extern int fceuindbg;
|
||||
|
||||
/* Overclocking-related */
|
||||
extern unsigned overclock_enabled;
|
||||
extern unsigned overclocked;
|
||||
|
||||
@@ -255,9 +255,6 @@ static DECLFR(FDSRead4030) {
|
||||
if (X.IRQlow & FCEU_IQEXT) ret |= 1;
|
||||
if (X.IRQlow & FCEU_IQEXT2) ret |= 2;
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
X6502_IRQEnd(FCEU_IQEXT);
|
||||
X6502_IRQEnd(FCEU_IQEXT2);
|
||||
@@ -748,7 +745,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||
|
||||
for (x = 0; x < TotalSides; x++) {
|
||||
char temp[5];
|
||||
sprintf(temp, "DDT%d", x);
|
||||
snprintf(temp, sizeof(temp), "DDT%d", x);
|
||||
AddExState(diskdata[x], 65500, 0, temp);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <file/file_path.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
@@ -46,14 +47,14 @@ static char BaseDirectory[2048] = {0};
|
||||
|
||||
void FCEUI_SetBaseDirectory(const char *dir)
|
||||
{
|
||||
strncpy(BaseDirectory, dir, 2047);
|
||||
BaseDirectory[2047] = 0;
|
||||
strlcpy(BaseDirectory, dir, sizeof(BaseDirectory));
|
||||
}
|
||||
|
||||
char *FCEU_MakeFName(int type, int id1, char *cd1)
|
||||
{
|
||||
char tmp[4096 + 512] = {0}; /* +512 for no reason :D */
|
||||
char *ret = 0;
|
||||
size_t len;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -75,8 +76,10 @@ char *FCEU_MakeFName(int type, int id1, char *cd1)
|
||||
|
||||
FCEU_printf(" FCEU_MakeFName: %s\n", tmp);
|
||||
|
||||
ret = (char*)malloc(strlen(tmp) * sizeof(char) + 1);
|
||||
strcpy(ret, tmp);
|
||||
len = strlen(tmp) + 1;
|
||||
ret = (char*)malloc(len);
|
||||
if (!ret) return NULL;
|
||||
strlcpy(ret, tmp, len);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
62
src/ines.c
62
src/ines.c
@@ -24,6 +24,8 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "x6502.h"
|
||||
#include "fceu.h"
|
||||
@@ -394,38 +396,66 @@ static void CheckHInfo(void)
|
||||
iNESCart.mirror = 2;
|
||||
|
||||
if (tofix) {
|
||||
size_t gigastr_len;
|
||||
char gigastr[768];
|
||||
strcpy(gigastr, " The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
|
||||
gigastr_len = strlen(gigastr);
|
||||
if (tofix & 1)
|
||||
sprintf(gigastr + gigastr_len, "Current mapper # is %d. The mapper number should be set to %d. ", current_mapper, iNESCart.mapper);
|
||||
size_t pos;
|
||||
|
||||
/* Each piece appends to the running buffer rather than (as the
|
||||
* previous code did) clobbering the same suffix from a fixed
|
||||
* offset captured once at the start. snprintf into the tail
|
||||
* keeps writes bounded; strlcpy at offset replaces strcat. */
|
||||
pos = strlcpy(gigastr, " The iNES header contains incorrect information. For now, the information will be corrected in RAM. ", sizeof(gigastr));
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
|
||||
if (tofix & 1) {
|
||||
int n = snprintf(gigastr + pos, sizeof(gigastr) - pos,
|
||||
"Current mapper # is %d. The mapper number should be set to %d. ",
|
||||
current_mapper, iNESCart.mapper);
|
||||
if (n > 0) pos += (size_t)n;
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
}
|
||||
if (tofix & 2) {
|
||||
uint8_t *mstr[3] = { (uint8_t*)"Horizontal", (uint8_t*)"Vertical", (uint8_t*)"Four-screen" };
|
||||
sprintf(gigastr + gigastr_len, "Current mirroring is %s. Mirroring should be set to \"%s\". ", mstr[cur_mirr & 3], mstr[iNESCart.mirror & 3]);
|
||||
int n = snprintf(gigastr + pos, sizeof(gigastr) - pos,
|
||||
"Current mirroring is %s. Mirroring should be set to \"%s\". ",
|
||||
mstr[cur_mirr & 3], mstr[iNESCart.mirror & 3]);
|
||||
if (n > 0) pos += (size_t)n;
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
}
|
||||
if (tofix & 4) {
|
||||
pos += strlcpy(gigastr + pos, "The battery-backed bit should be set. ", sizeof(gigastr) - pos);
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
}
|
||||
if (tofix & 8) {
|
||||
pos += strlcpy(gigastr + pos, "This game should not have any CHR ROM. ", sizeof(gigastr) - pos);
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
}
|
||||
if (tofix & 4)
|
||||
strcat(gigastr, "The battery-backed bit should be set. ");
|
||||
if (tofix & 8)
|
||||
strcat(gigastr, "This game should not have any CHR ROM. ");
|
||||
if (tofix & 16) {
|
||||
uint8_t *rstr[4] = { (uint8_t*)"NTSC", (uint8_t*)"PAL", (uint8_t*)"Multi", (uint8_t*)"Dendy" };
|
||||
sprintf(gigastr + gigastr_len, "This game should run with \"%s\" timings.", rstr[iNESCart.region]);
|
||||
int n = snprintf(gigastr + pos, sizeof(gigastr) - pos,
|
||||
"This game should run with \"%s\" timings.",
|
||||
rstr[iNESCart.region]);
|
||||
if (n > 0) pos += (size_t)n;
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
}
|
||||
if (tofix & 32) {
|
||||
unsigned PRGRAM = iNESCart.PRGRamSize + iNESCart.PRGRamSaveSize;
|
||||
unsigned CHRRAM = iNESCart.CHRRamSize + iNESCart.CHRRamSaveSize;
|
||||
if (PRGRAM || CHRRAM) {
|
||||
int n;
|
||||
if (iNESCart.PRGRamSaveSize == 0)
|
||||
sprintf(gigastr + gigastr_len, "workram: %d KB, ", PRGRAM / 1024);
|
||||
n = snprintf(gigastr + pos, sizeof(gigastr) - pos, "workram: %d KB, ", PRGRAM / 1024);
|
||||
else if (iNESCart.PRGRamSize == 0)
|
||||
sprintf(gigastr + gigastr_len, "saveram: %d KB, ", PRGRAM / 1024);
|
||||
n = snprintf(gigastr + pos, sizeof(gigastr) - pos, "saveram: %d KB, ", PRGRAM / 1024);
|
||||
else
|
||||
sprintf(gigastr + gigastr_len, "workram: %d KB (%dKB battery-backed), ", PRGRAM / 1024, iNESCart.PRGRamSaveSize / 1024);
|
||||
sprintf(gigastr + gigastr_len, "chrram: %d KB.", (CHRRAM + iNESCart.CHRRamSaveSize) / 1024);
|
||||
n = snprintf(gigastr + pos, sizeof(gigastr) - pos, "workram: %d KB (%dKB battery-backed), ", PRGRAM / 1024, iNESCart.PRGRamSaveSize / 1024);
|
||||
if (n > 0) pos += (size_t)n;
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
n = snprintf(gigastr + pos, sizeof(gigastr) - pos, "chrram: %d KB.", (CHRRAM + iNESCart.CHRRamSaveSize) / 1024);
|
||||
if (n > 0) pos += (size_t)n;
|
||||
if (pos >= sizeof(gigastr)) pos = sizeof(gigastr) - 1;
|
||||
}
|
||||
}
|
||||
strcat(gigastr, "\n");
|
||||
strlcpy(gigastr + pos, "\n", sizeof(gigastr) - pos);
|
||||
FCEU_printf("%s\n", gigastr);
|
||||
}
|
||||
|
||||
|
||||
@@ -156,9 +156,6 @@ static uint8_t FP_FASTAPASS(1) ReadGPVS(int w) {
|
||||
ret = 1;
|
||||
else {
|
||||
ret = ((joy[w] >> (joy_readbit[w])) & 1);
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
joy_readbit[w]++;
|
||||
}
|
||||
return ret;
|
||||
@@ -179,9 +176,6 @@ static uint8_t FP_FASTAPASS(1) ReadGP(int w) {
|
||||
if (joy_readbit[w] == 19 - w)
|
||||
ret |= 1;
|
||||
}
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
joy_readbit[w]++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -41,9 +41,6 @@ static uint8_t FP_FASTAPASS(2) ReadARKFC(int w, uint8_t ret) {
|
||||
ret |= 2;
|
||||
else {
|
||||
ret |= ((FCArk.mzx >> (7 - FCArk.readbit)) & 1) << 1;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
FCArk.readbit++;
|
||||
}
|
||||
} else
|
||||
@@ -78,9 +75,6 @@ static uint8_t FP_FASTAPASS(1) ReadARK(int w) {
|
||||
ret |= 1 << 4;
|
||||
else {
|
||||
ret |= ((NESArk[w].mzx >> (7 - NESArk[w].readbit)) & 1) << 4;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
NESArk[w].readbit++;
|
||||
}
|
||||
ret |= (NESArk[w].mzb & 1) << 3;
|
||||
|
||||
@@ -28,9 +28,6 @@ static uint8_t FP_FASTAPASS(2) MJ_Read(int w, uint8_t ret) {
|
||||
/* ret|=(MRet&1)<<1; */
|
||||
ret |= ((MRet & 0x80) >> 6) & 2;
|
||||
/* MRet>>=1; */
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
MRet <<= 1;
|
||||
}
|
||||
return(ret);
|
||||
|
||||
@@ -48,9 +48,6 @@ static uint8_t FP_FASTAPASS(1) ReadMOUSE(int w) {
|
||||
ret |= 1;
|
||||
else {
|
||||
ret |= (Mouse.data >> Mouse.readbit) & 1;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
Mouse.readbit++;
|
||||
}
|
||||
return(ret);
|
||||
|
||||
@@ -62,9 +62,6 @@ static void FP_FASTAPASS(1) PEC586KB_Write(uint8_t v) {
|
||||
}
|
||||
|
||||
static uint8_t FP_FASTAPASS(2) PEC586KB_Read(int w, uint8_t ret) {
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg) {
|
||||
#endif
|
||||
if (w) {
|
||||
ret &= ~2;
|
||||
if(bufit[matrix[kspos][7-ksindex]])
|
||||
@@ -72,9 +69,6 @@ static uint8_t FP_FASTAPASS(2) PEC586KB_Read(int w, uint8_t ret) {
|
||||
ksindex++;
|
||||
ksindex&=7;
|
||||
}
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
}
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,6 @@ static uint8_t FP_FASTAPASS(1) ReadPP(int w) {
|
||||
if (pprsb[w] >= 8)
|
||||
ret |= 0x08;
|
||||
}
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
pprsb[w]++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -132,9 +132,6 @@ static uint8_t FP_FASTAPASS(1) ReadZapperVS(int w) {
|
||||
ret |= 0x1;
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
ZD[w].zap_readbit++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
17
src/nsf.c
17
src/nsf.c
@@ -23,6 +23,8 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "x6502.h"
|
||||
#include "fceu.h"
|
||||
@@ -357,15 +359,9 @@ static DECLFR(NSF_read) {
|
||||
|
||||
switch (A) {
|
||||
case 0x3ff0: x = SongReload;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
SongReload = 0;
|
||||
return x;
|
||||
case 0x3ff1:
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
memset(RAM, 0x00, 0x800);
|
||||
|
||||
@@ -486,7 +482,7 @@ void DrawNSF(uint8_t *XBuf) {
|
||||
DrawTextTrans(XBuf + 42 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Copyright)) << 2)), 256, NSFHeader.Copyright, 6);
|
||||
|
||||
DrawTextTrans(XBuf + 70 * 256 + 4 + (((31 - strlen("Song:")) << 2)), 256, (uint8_t*)"Song:", 6);
|
||||
sprintf(snbuf, "<%d/%d>", CurrentSong, NSFHeader.TotalSongs);
|
||||
snprintf(snbuf, sizeof(snbuf), "<%d/%d>", CurrentSong, NSFHeader.TotalSongs);
|
||||
DrawTextTrans(XBuf + 82 * 256 + 4 + (((31 - strlen(snbuf)) << 2)), 256, (uint8_t*)snbuf, 6);
|
||||
|
||||
{
|
||||
@@ -540,8 +536,9 @@ int FCEUI_NSFChange(int amount) {
|
||||
|
||||
/* Returns total songs */
|
||||
int FCEUI_NSFGetInfo(uint8_t *name, uint8_t *artist, uint8_t *copyright, int maxlen) {
|
||||
strncpy((char*)name, (const char*)NSFHeader.SongName, (size_t)maxlen);
|
||||
strncpy((char*)artist, (const char*)NSFHeader.Artist, (size_t)maxlen);
|
||||
strncpy((char*)copyright, (const char*)NSFHeader.Copyright, (size_t)maxlen);
|
||||
if (maxlen <= 0) return NSFHeader.TotalSongs;
|
||||
strlcpy((char*)name, (const char*)NSFHeader.SongName, (size_t)maxlen);
|
||||
strlcpy((char*)artist, (const char*)NSFHeader.Artist, (size_t)maxlen);
|
||||
strlcpy((char*)copyright, (const char*)NSFHeader.Copyright, (size_t)maxlen);
|
||||
return(NSFHeader.TotalSongs);
|
||||
}
|
||||
|
||||
25
src/ppu.c
25
src/ppu.c
@@ -90,7 +90,6 @@ static void makeppulut(void) {
|
||||
|
||||
static uint8_t ppudead = 1;
|
||||
static uint8_t kook = 0;
|
||||
int fceuindbg = 0;
|
||||
|
||||
int MMC5Hack = 0, PEC586Hack = 0;
|
||||
uint32_t MMC5HackVROMMask = 0;
|
||||
@@ -152,9 +151,6 @@ static DECLFR(A2002) {
|
||||
ret = PPU_status;
|
||||
ret |= PPUGenLatch & 0x1F;
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
vtoggle = 0;
|
||||
PPU_status &= 0x7F;
|
||||
@@ -185,9 +181,6 @@ static DECLFR(A2007) {
|
||||
ret = PALRAM[tmp & 0x1F];
|
||||
if (GRAYSCALE)
|
||||
ret &= 0x30;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
if ((tmp - 0x1000) < 0x2000)
|
||||
VRAMBuffer = VPage[(tmp - 0x1000) >> 10][tmp - 0x1000];
|
||||
@@ -197,9 +190,6 @@ static DECLFR(A2007) {
|
||||
}
|
||||
} else {
|
||||
ret = VRAMBuffer;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
if (PPU_hook) PPU_hook(tmp);
|
||||
PPUGenLatch = VRAMBuffer;
|
||||
@@ -210,9 +200,6 @@ static DECLFR(A2007) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
if ((ScreenON || SpriteON) && (scanline < 240)) {
|
||||
uint32_t rad = RefreshAddr;
|
||||
@@ -375,9 +362,6 @@ static void ResetRL(uint8_t *target) {
|
||||
static uint8_t sprlinebuf[256 + 8];
|
||||
|
||||
void FCEUPPU_LineUpdate(void) {
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
if (Pline) {
|
||||
int l = GETLASTPIXEL;
|
||||
RefreshLine(l);
|
||||
@@ -805,7 +789,12 @@ static void FetchSpriteData(void) {
|
||||
dst.x = spr->x;
|
||||
dst.atr = spr->atr;
|
||||
|
||||
*(uint32_t*)&SPRBUF[ns << 2] = *(uint32_t*)&dst;
|
||||
/* memcpy avoids the strict-aliasing UB of casting
|
||||
* a uint8_t buffer and a struct SPRB through a
|
||||
* uint32_t* and also dodges the alignment trap on
|
||||
* strict-alignment hosts. The compiler emits the
|
||||
* same single 32-bit move on x86/ARM. */
|
||||
memcpy(&SPRBUF[ns << 2], &dst, 4);
|
||||
}
|
||||
|
||||
ns++;
|
||||
@@ -858,7 +847,7 @@ static void FetchSpriteData(void) {
|
||||
dst.atr = spr->atr;
|
||||
|
||||
|
||||
*(uint32_t*)&SPRBUF[ns << 2] = *(uint32_t*)&dst;
|
||||
memcpy(&SPRBUF[ns << 2], &dst, 4);
|
||||
}
|
||||
|
||||
ns++;
|
||||
|
||||
@@ -334,9 +334,6 @@ static DECLFR(StatusRead) {
|
||||
for (x = 0; x < 4; x++) ret |= lengthcount[x] ? (1 << x) : 0;
|
||||
if (DMCSize) ret |= 0x10;
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
if (!fceuindbg)
|
||||
#endif
|
||||
{
|
||||
SIRQStat &= ~0x40;
|
||||
X6502_IRQEnd(FCEU_IQFCOUNT);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "x6502.h"
|
||||
#include "fceu.h"
|
||||
@@ -344,7 +346,7 @@ void AddExState(void *v, uint32_t s, int type, char *desc)
|
||||
}
|
||||
memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||
if (desc)
|
||||
strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||
strlcpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||
SFMDATA[SFEXINDEX].v = v;
|
||||
SFMDATA[SFEXINDEX].s = s;
|
||||
if (type)
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "fceu.h"
|
||||
@@ -201,10 +203,11 @@ static int NAME(FCEUFILE *fp) {
|
||||
FCEU_printf(" Name: %s\n", namebuf);
|
||||
|
||||
if (!GameInfo->name) {
|
||||
GameInfo->name = malloc(strlen(namebuf) + 1);
|
||||
size_t n = strlen(namebuf) + 1;
|
||||
GameInfo->name = malloc(n);
|
||||
if (!GameInfo->name)
|
||||
return(0);
|
||||
strcpy((char*)GameInfo->name, namebuf);
|
||||
strlcpy((char*)GameInfo->name, namebuf, n);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
181
src/x6502.c
181
src/x6502.c
@@ -29,10 +29,6 @@
|
||||
X6502 X;
|
||||
uint8_t encryptOpcodes =0;
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
void (*X6502_Run)(int32_t cycles);
|
||||
#endif
|
||||
|
||||
uint32_t timestamp;
|
||||
uint32_t sound_timestamp;
|
||||
void FP_FASTAPASS(1) (*MapIRQHook)(int a);
|
||||
@@ -66,24 +62,6 @@ static INLINE void WrMemNorm(uint32_t A, uint8_t V) {
|
||||
BWrite[A](A, V);
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
X6502 XSave; /* This is getting ugly. */
|
||||
|
||||
static INLINE uint8_t RdMemHook(uint32_t A) {
|
||||
if (X.ReadHook)
|
||||
return(_DB = X.ReadHook(&X, A));
|
||||
else
|
||||
return(_DB = ARead[A](A));
|
||||
}
|
||||
|
||||
static INLINE void WrMemHook(uint32_t A, uint8_t V) {
|
||||
if (X.WriteHook)
|
||||
X.WriteHook(&X, A, V);
|
||||
else
|
||||
BWrite[A](A, V);
|
||||
}
|
||||
#endif
|
||||
|
||||
static INLINE uint8_t RdRAMFast(uint32_t A) {
|
||||
return(_DB = RAM[A]);
|
||||
}
|
||||
@@ -370,30 +348,6 @@ void TriggerNMI2(void) {
|
||||
_IRQlow |= FCEU_IQNMI2;
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
/* Called from debugger. */
|
||||
void FCEUI_NMI(void) {
|
||||
_IRQlow |= FCEU_IQNMI;
|
||||
}
|
||||
|
||||
void FCEUI_IRQ(void) {
|
||||
_IRQlow |= FCEU_IQTEMP;
|
||||
}
|
||||
|
||||
void FCEUI_GetIVectors(uint16_t *reset, uint16_t *irq, uint16_t *nmi) {
|
||||
fceuindbg = 1;
|
||||
|
||||
*reset = RdMemNorm(0xFFFC);
|
||||
*reset |= RdMemNorm(0xFFFD) << 8;
|
||||
*nmi = RdMemNorm(0xFFFA);
|
||||
*nmi |= RdMemNorm(0xFFFB) << 8;
|
||||
*irq = RdMemNorm(0xFFFE);
|
||||
*irq |= RdMemNorm(0xFFFF) << 8;
|
||||
fceuindbg = 0;
|
||||
}
|
||||
static int debugmode;
|
||||
#endif
|
||||
|
||||
void X6502_Reset(void) {
|
||||
_IRQlow = FCEU_IQRESET;
|
||||
}
|
||||
@@ -409,9 +363,6 @@ void X6502_Init(void) {
|
||||
ZNTable[x] = N_FLAG;
|
||||
else
|
||||
ZNTable[x] = 0;
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
X6502_Debug(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void X6502_Power(void) {
|
||||
@@ -421,124 +372,7 @@ void X6502_Power(void) {
|
||||
X6502_Reset();
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
static void X6502_RunDebug(int32_t cycles) {
|
||||
#define RdRAM RdMemHook
|
||||
#define WrRAM WrMemHook
|
||||
#define RdMem RdMemHook
|
||||
#define WrMem WrMemHook
|
||||
|
||||
if (PAL)
|
||||
cycles *= 15; /* 15*4=60 */
|
||||
else
|
||||
cycles *= 16; /* 16*4=64 */
|
||||
|
||||
_count += cycles;
|
||||
|
||||
while (_count > 0) {
|
||||
int32_t temp;
|
||||
uint8_t b1;
|
||||
|
||||
if (_IRQlow) {
|
||||
if (_IRQlow & FCEU_IQRESET) {
|
||||
_PC = RdMem(0xFFFC);
|
||||
_PC |= RdMem(0xFFFD) << 8;
|
||||
_jammed = 0;
|
||||
_PI = _P = I_FLAG;
|
||||
_IRQlow &= ~FCEU_IQRESET;
|
||||
} else if (_IRQlow & FCEU_IQNMI2) {
|
||||
_IRQlow &= ~FCEU_IQNMI2;
|
||||
_IRQlow |= FCEU_IQNMI;
|
||||
} else if (_IRQlow & FCEU_IQNMI) {
|
||||
if (!_jammed) {
|
||||
ADDCYC(7);
|
||||
PUSH(_PC >> 8);
|
||||
PUSH(_PC);
|
||||
PUSH((_P & ~B_FLAG) | (U_FLAG));
|
||||
_P |= I_FLAG;
|
||||
_PC = RdMem(0xFFFA);
|
||||
_PC |= RdMem(0xFFFB) << 8;
|
||||
_IRQlow &= ~FCEU_IQNMI;
|
||||
}
|
||||
} else {
|
||||
if (!(_PI & I_FLAG) && !_jammed) {
|
||||
ADDCYC(7);
|
||||
PUSH(_PC >> 8);
|
||||
PUSH(_PC);
|
||||
PUSH((_P & ~B_FLAG) | (U_FLAG));
|
||||
_P |= I_FLAG;
|
||||
_PC = RdMem(0xFFFE);
|
||||
_PC |= RdMem(0xFFFF) << 8;
|
||||
}
|
||||
}
|
||||
_IRQlow &= ~(FCEU_IQTEMP);
|
||||
if (_count <= 0) {
|
||||
_PI = _P;
|
||||
return;
|
||||
} /* Should increase accuracy without a
|
||||
* major speed hit.
|
||||
*/
|
||||
}
|
||||
|
||||
if (X.CPUHook) X.CPUHook(&X);
|
||||
/* Ok, now the real fun starts.
|
||||
* Do the pre-exec voodoo.
|
||||
*/
|
||||
if (X.ReadHook || X.WriteHook) {
|
||||
uint32_t tsave = timestamp;
|
||||
XSave = X;
|
||||
|
||||
fceuindbg = 1;
|
||||
X.preexec = 1;
|
||||
b1 = RdMem(_PC);
|
||||
_PC++;
|
||||
if (encryptOpcodes ==12) b1 =b1 &0x39 | b1 >>1 &0x42 | b1 <<1 &0x84;
|
||||
if (encryptOpcodes ==14) b1 =b1 &0x3F | b1 >>1 &0x40 | b1 <<1 &0x80;
|
||||
switch (b1) {
|
||||
#include "ops.h"
|
||||
}
|
||||
|
||||
timestamp = tsave;
|
||||
|
||||
/* In case an NMI/IRQ/RESET was triggered by the debugger.
|
||||
* Should we also copy over the other hook variables?
|
||||
*/
|
||||
XSave.IRQlow = X.IRQlow;
|
||||
XSave.ReadHook = X.ReadHook;
|
||||
XSave.WriteHook = X.WriteHook;
|
||||
XSave.CPUHook = X.CPUHook;
|
||||
X = XSave;
|
||||
fceuindbg = 0;
|
||||
}
|
||||
|
||||
_PI = _P;
|
||||
b1 = RdMem(_PC);
|
||||
ADDCYC(CycTable[b1]);
|
||||
|
||||
temp = _tcount;
|
||||
_tcount = 0;
|
||||
if (MapIRQHook) MapIRQHook(temp);
|
||||
|
||||
if (!overclocked)
|
||||
FCEU_SoundCPUHook(temp);
|
||||
|
||||
_PC++;
|
||||
if (encryptOpcodes ==12) b1 =b1 &0x39 | b1 >>1 &0x42 | b1 <<1 &0x84;
|
||||
if (encryptOpcodes ==14) b1 =b1 &0x3F | b1 >>1 &0x40 | b1 <<1 &0x80;
|
||||
switch (b1) {
|
||||
#include "ops.h"
|
||||
}
|
||||
}
|
||||
#undef RdRAM
|
||||
#undef WrRAM
|
||||
#undef RdMem
|
||||
#undef WrMem
|
||||
}
|
||||
|
||||
static void X6502_RunNormal(int32_t cycles)
|
||||
#else
|
||||
void X6502_Run(int32_t cycles)
|
||||
#endif
|
||||
{
|
||||
#define RdRAM RdRAMFast
|
||||
#define WrRAM WrRAMFast
|
||||
@@ -635,18 +469,3 @@ void X6502_Run(int32_t cycles)
|
||||
#undef RdRAM
|
||||
#undef WrRAM
|
||||
}
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
void X6502_Debug(void (*CPUHook)(X6502 *), uint8_t (*ReadHook)(X6502 *, uint32_t), void (*WriteHook)(X6502 *, uint32_t, uint8_t)) {
|
||||
debugmode = (ReadHook || WriteHook || CPUHook) ? 1 : 0;
|
||||
X.ReadHook = ReadHook;
|
||||
X.WriteHook = WriteHook;
|
||||
X.CPUHook = CPUHook;
|
||||
|
||||
if (!debugmode)
|
||||
X6502_Run = X6502_RunNormal;
|
||||
else
|
||||
X6502_Run = X6502_RunDebug;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,15 +23,7 @@
|
||||
|
||||
#include "x6502struct.h"
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
void X6502_Debug(void (*CPUHook)(X6502 *),
|
||||
uint8_t (*ReadHook)(X6502 *, uint32_t),
|
||||
void (*WriteHook)(X6502 *, uint32_t, uint8_t));
|
||||
|
||||
extern void (*X6502_Run)(int32_t cycles);
|
||||
#else
|
||||
void X6502_Run(int32_t cycles);
|
||||
#endif
|
||||
|
||||
extern uint32_t timestamp;
|
||||
extern uint32_t sound_timestamp;
|
||||
|
||||
@@ -13,14 +13,6 @@ typedef struct __X6502 {
|
||||
uint32_t IRQlow; /* Simulated IRQ pin held low(or is it high?).
|
||||
And other junk hooked on for speed reasons.*/
|
||||
uint8_t DB; /* Data bus "cache" for reads from certain areas */
|
||||
|
||||
int preexec; /* Pre-exec'ing for debug breakpoints. */
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
void (*CPUHook)(struct __X6502 *);
|
||||
uint8_t (*ReadHook)(struct __X6502 *, uint32_t);
|
||||
void (*WriteHook)(struct __X6502 *, uint32_t, uint8_t);
|
||||
#endif
|
||||
} X6502;
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user