cpu.cpp
来自「SNES game emulator. C and asm files.」· C++ 代码 · 共 2,151 行 · 第 1/5 页
CPP
2,151 行
state.oldjoybit[true]++;
break;
}
if (wordread)
trapregread (ptr + 1, false);
return ptr;
}
inline void changevram (int where, byte what)
{
if (vram [where] == what)
return;
vram [where] = what;
cstatus [where >> 4] = 0;
// The following checks are usually redundant, but not always...
if ((where & 0x10) && (cstatus [(where >> 4) - 1] & 3) == 1)
cstatus [(where >> 4) - 1] = 0;
if ((where & 0x30) == 0x20 && (cstatus [(where >> 4) - 2] & 3) == 3)
cstatus [(where >> 4) - 2] = 0;
else if ((where & 0x30) == 0x30 && (cstatus [(where >> 4) - 3] & 3) == 3)
cstatus [(where >> 4) - 3] = 0;
}
byte _cdecl near *trapregwrite (byte *ptr, boolean wordwrite)
{
int x;
if (ptr-registers+0x2000 >= 0x4200 && ptr-registers+0x2000 <= 0x43FF)
mmio_wtally [ptr-registers+0x2000-0x4200+256]++;
if (ptr-registers+0x2000 >= 0x2100 && ptr-registers+0x2000 <= 0x21FF)
mmio_wtally [ptr-registers+0x2000-0x2100]++;
debug_readtrap = false; debug_trapaddr = ptr - registers + 0x2000;
switch (ptr - registers + 0x2000) {
case 0x2100:
break;
case 0x2101:
if (*REG2101 != state.reg2101) {
state.reg2101 = *REG2101;
memset (spr8x8size, 0, sizeof (spr8x8size));
}
break;
case 0x2102: case 0x2103: // OAM address
state.oampointer = *REG2102;
break;
case 0x2104: // OAM Data Write
if (oam[state.oampointer] != *ptr) {
if (state.oampointer >= 512) {
spr8x8size [((state.oampointer - 512) << 2)] =
spr8x8size [((state.oampointer - 512) << 2) + 1] =
spr8x8size [((state.oampointer - 512) << 2) + 2] =
spr8x8size [((state.oampointer - 512) << 2) + 3] = 0;
oamposchange = true;
} else if (state.oampointer & 2) {
spr8x8size [state.oampointer >> 2] = 0;
} else {
oamposchange = true;
}
}
oam[state.oampointer] = *ptr;
state.oampointer = (state.oampointer + 1) % 544;
break;
case 0x2105: // Screen mode register
break;
case 0x210D: case 0x210F: case 0x2111: case 0x2113:
case 0x210E: case 0x2110: case 0x2112: case 0x2114:
x = ptr - registers - 0x010D;
state.scrollreg[x] = (state.scrollreg[x] >> 8) | (*ptr << 8);
break;
case 0x2115: // VRAM upload control register; b7:0=inc at 2118?
switch (*REG2115 & 0x03) {
case 0: state.vramincrate = 2; break;
case 1: state.vramincrate = 64; break;
case 2: state.vramincrate = 128; break;
case 3: state.vramincrate = 256; break;
}
break;
case 0x2116: case 0x2117: // VRAM address register
state.vrampointer = *REG2116 * 2;
state.vrampointer &= 0xFFFF;
state.dummyread2139 = true;
break;
case 0x2118: // VRAM Write register low
changevram (state.vrampointer, *(byte*)REG2118);
if (!(*REG2115 & 0x80)) {
state.vrampointer = ((state.vrampointer + state.vramincrate) & 0xFFFF);
*REG2118 = 0;
}
break;
case 0x2119: // VRAM Write register high
changevram (state.vrampointer + 1, *((byte*)REG2118 + 1));
if (*REG2115 & 0x80) {
state.vrampointer = ((state.vrampointer + state.vramincrate) & 0xFFFF);
*REG2118 = 0;
}
break;
case 0x211B: case 0x211C:
case 0x211D: case 0x211E:
case 0x211F: case 0x2120:
if (ptr == REG211B) { // Mode 7 multiply, 16-bit value
state.reg211B = (((unsigned short)state.reg211B) >> 8) + (*ptr << 8);
} else if (ptr == REG211C) {
state.reg211C = *REG211C;
x = state.reg211B * state.reg211C;
*REG2134 = x;
}
state.m7var[ptr-REG211B] = (((unsigned short)state.m7var[ptr-REG211B]) >> 8) | (*ptr << 8);
break;
case 0x2121: // Palette (color #) selection register
state.colorpointer = *REG2121 * 2;
break;
case 0x2122: // Palette data write register
cgram [state.colorpointer] = *REG2122;
state.colorpointer = (state.colorpointer + 1) & 0x1FF;
break;
case 0x212C: // Main screen designation
break;
case 0x212D: // Sub screen designation
break;
case 0x2131: // Addition/Subtraction for screens, BGs and OBJs
for (x = 0; x < 6; x++) {
if ((*REG2131 >> x) & 1)
state.reg2131setting[x] = (*REG2131 & 192);
}
break;
case 0x2133: // Screen mode
break;
case 0x2180: // WRAM data
// Accesses only RAM?
x = (*REG2181) & 0x1FFFF;
ram[x] = *REG2180;
(*(word*)REG2181)++;
if (*(word*)REG2181 == 0)
(*(((byte*)REG2181) + 2))++;
//x = (*REG2181) & 0xFFFFFF;
//*SNESMEM(x) = *REG2180;
//(*(word*)REG2181)++;
break;
case 0x4016:
case 0x4017:
// New theory: * Writing to either 16 or 17 resets BOTH joypads;
// * It is only reset properly if non-zero is written followed by 0.
// * If *only* a 0 is written, the next returned value on read will be 1.
// * This sets oldjoybit to -1, so return 1 if oldjoybit < 0.
// ...wait, nope, forget that theory.
for (x = 0; x < 2; x++) {
state.oldjoybit[x] = 0;
/* if (*ptr == 0 && state.oldjoybit[x] == -2)
state.oldjoybit[x] = 0;
else if (*ptr == 0 && state.oldjoybit[x] != -2)
state.oldjoybit[x] = -1;
else if (*ptr != 0)
state.oldjoybit[x] = -2;*/
}
break;
case 0x4200: // Counter enable
break;
case 0x4201: // I/O Port out
*REG4213 = *REG4201;
break;
case 0x4206: // It's important (Metroid 3) NOT to trap 4204/5.
if (*REG4206 != 0) { // Not divide by zero
*REG4214 = (*REG4204 / *REG4206); // Unsigned division
*REG4216 = (*REG4204 % *REG4206);
} else {
debug0 ("Divide by 0 - %X", ptr - registers + 0x2000);
}
break;
case 0x4203: // Multiplicand 'B' - written second
*REG4216 = (word)*REG4202 * (word)*REG4203;
break;
case 0x420B:
{ word dmacount, modeoffset;
byte regoffset;
dword cpu, reg;
char debugline [50];
//debug0 ("DMA transfer initiated; PC=$%X instr=%d", ::reg.PC, debug_instr);
for (x = 0; x < 8; x++) {
if (!(*REG420B & ~(*REG420C) & (1 << x)))
continue;
dmacount = *REG4305(x);
modeoffset = regoffset = 0;
cpu = *REG4302(x) & 0xFFFFFF;
reg = 0x2100 | *REG4301(x);
//debug0 ("DMA transfer on channel %d cpu=$%X reg=$%X dmacount=%d $43?0=$%X state.vramincrate%d", x, cpu, reg, dmacount, *REG4300(x), state.vramincrate);
if (debugmode) {
sprintf (debugline, "[DMA ch%d mode:%X a$%X b$%X cnt$%X]", x, *REG4300(x), cpu, reg, dmacount);
//sprintf (debugline, "[reg$%X]", reg);
//debug0 ("reg:%X", reg);
adddebugline (debugline, false, '*');
}
do {
switch (*REG4300(x) & 7) {
case 1: regoffset = modeoffset & 1; break;
case 3: regoffset = (modeoffset >> 1) & 1; break;
case 4: regoffset = modeoffset & 3; break;
}
if (*REG4300(x) & 0x80) {
*SNESMEM(cpu) = *trapregread (SNESMEM(reg+regoffset), false);
} else {
*SNESMEM(reg+regoffset) = *SNESMEM(cpu);
trapregwrite (SNESMEM(reg+regoffset), false);
}
if (!(*REG4300(x) & 8)) {
if (*REG4300(x) & 0x10) // decrement
cpu = (cpu & 0xFF0000) | ((cpu - 1) & 0xFFFF);
else // Increment
cpu = (cpu & 0xFF0000) | ((cpu + 1) & 0xFFFF);
}
dmacount--;
modeoffset++;
cpu &= 0xFFFFFF;
} while (dmacount != 0);
*REG4302(x) = (*REG4302(x) & 0xFF000000) | cpu;
*REG4305(x) = dmacount; //0
}
*REG420B = 0;
}
break;
}
if (wordwrite)
trapregwrite (ptr + 1, false);
return ptr;
}
/*
Known potential CPU problems
Wraparound problems:
When a reference is made that crosses a bank boundary, often the wraparound does NOT
occur. Some wraparounds are implemented (e.g. stack decrement), but most are not
(e.g. pushing a word onto the stack with one byte at 0 and the other at 0xFFFF, will
screw up, and so will doing a relative long BRL accross a bank boundary).
Memory-mapped I/O problems:
All memory accesses are supposed to be trapped for full emulation, but for simplicity
and speed, many accesses are NOT trapped. Here's a list of known non-traps:
PC - opcode+data fetches are not intercepted
S - Stack operations (PUSH and PULL) are not intercepted (although stack relative
operations are.)
Indirection - The final address resulting from an indirection is intercepted, but
the pointer variable itself is not. e.g.: LDA ($2139)
This cannot trigger the VRAM-read data mechanism. But, if this is used: LDA
(<$0) and $0 contains: $39 $21 then the VRAM read/increment will occur.
RMW operations: Currently, when a read-modify-write operation occurs (e.g. ROL $xxxx),
only either the read is trapped or the write is trapped. Certain operations (like
INC,DEC) only check the read and some operations (ROL,SHR) only check the write.
I know, life sucks. Also, when a write is checked, the flags are set *after* the
write intercept. I don't know if this is the correct behavior.
Block move instructions: block move instructions are not intercepted.
Indirect jump: Indirect jumps are not intercepted.
ROM:
- ROM Writes are NOT prevented
- FastROM handling is a bit iffy
SRAM: The header information is NOT checked for SRAM size, and reads/writes are NOT
intercepted - a game can always read and write to the full 512 kbits of SRAM address
space.
Invalid addresses: I can't IMAGINE what will happen if you try to access an invalid
address (GPF probably...)
Debugger problems: You should only attempt to view one memory area at a time. For example,
you shouldn't try to look at the place where the register address space meets up with
the scratchpad memory space (e.g. M$1FF0)
*/
struct instructioninfo {
char mnemonic[4];
char *descr;
} instrlist [] = {
"ADC", "Add memory to accumulator with carry",
"AND", "AND arg with accumulator (A&=arg)",
"SHL", "(ASL) Shift left arg (C set to MSB)",
"BCC", "Branch if Carry Clear",
"BCS", "Branch if carry set",
"BEQ", "Branch if zero (or branch if equal)",
"BIT", "And A w/ arg, N=bit 7, V=bit 6, discard result",
"BMI", "Branch if minus (if N=1)",
"BNE", "Branch if not zero (branch if not equal)",
"BPL", "Branch if plus (if N=0)",
"BRA", "Branch always (Relative)",
"BRK", "Break (Push PC+2; Call Interrupt *0.FFE6)",
"BRL", "Branch Long (16-bit JMP)",
"BVC", "Branch if Overflow Clear",
"BVS", "Branch if overflow set",
"CLC", "Clear the Cary Bit (P&~1)",
"CLD", "Clear the BCD mode bit (P&~8)",
"CLI", "Clear the Interrupt disable bit (P&~4)",
"CLV", "Clear the overflow bit (P&~64)",
"CMP", "Compare arg with A: A>=a?C=1:N=1,A=a?Z=1:Z=0",
"CSP", "(COP) Call Sys.Proc. (Push PC; Call Int. *0.FFE4)",
"CPX", "Compare arg with X",
"CPY", "Compare arg with Y",
"DEC", "Decrement arg (A or a memory location)",
"DEX", "Decrement X",
"DEY", "Decrement Y",
"XOR", "(EOR) Exclusive OR A with arg (A^=arg)",
"INC", "Increment arg (A or a memory location)",
"INX", "Increment X",
"INY", "Increment Y",
"JML", "Jump Long (PC=16bit arg->24bit address)",
"JMP", "Jump (PC=arg or PC=*arg)",
"JSL", "Jump to Subroutine Long (PC=24bit arg)",
"JSR", "Jump to Subroutine",
"LDA", "Load A with a value",
"LDX", "Load Index X with a value",
"LDY", "Load Index Y with a value",
"SHR", "(LSR) Shift Right (C set to LSB)",
"MVN", "Move- (DBR=arg;while(A){*Y=*arg2.X;X++,Y++,A--})",
"MVN", "Move+ (DBR=arg;while(A){*Y=*arg2.X;X--,Y--,A--})",
"NOP", "No operation--waste two cycles",
"ORA", "OR arg with accumulator (A|=arg)",
"PSH", "(PE?,PH?) Push onto the stack",
"PUL", "(PL?) Pull from the stack",
"CLP", "(REP) Clear status bits in P",
"ROL", "Rotate arg left (carry included)",
"ROR", "Rotate arg right (carry included)",
"RTI", "Return from interrupt & restore flags",
"RTL", "Return from Subroutine Long",
"RTS", "Return from Subroutine",
"SBC", "Subtract from Accumulator with Carry (Borrow)",
"SEC", "Set the Carry bit to 1",
"SED", "Set the BCD mode bit to 1",
"SEI", "Set the Interrupt Disable bit to 1",
"SEP", "Set status bits in P",
"HLT", "(STP-Stop the clock) Halt CPU until reset",
"STA", "Store Accumulator in memory",
"STX", "Store Index X in memory",
"STY", "Store Index Y in memory",
"CLR", "(STZ) Clear memory location",
"TRB", "Test and reset bits",
"TSB", "Test and set bits",
"TAX", "Transfer (copy) A into X",
"TXA", "Transfer (copy) X into A",
"TAY", "Transfer (copy) A into Y",
"TYA", "Transfer (copy) Y into A",
"TAD", "Transfer (copy) A into Direct",
"TDA", "Transfer (copy) Direct into A",
"TAS", "Transfer (copy) A into Stack Pointer",
"TSA", "Transfer (copy) Stack pointer into A",
"TSX", "Transfer (copy) Stack pointer into X",
"TXS", "Transfer (copy) X into Stack pointer",
"TXY", "Transfer (copy) X into Y",
"TYX", "Transfer (copy) Y into X",
"WAI", "Wait for interrupt",
"SWA", "(XBA) Swap 16-bit accumulator halves",
"XCE", "Exchange the Carry and Emulation bits",
"???", "UNASSIGNED OPCODE $42",
"\0\0\0", "[Description search error]"
};
struct opcodeinfo opcodelist [] = {
// 0x0
"BRK", 2, 8,
"ORA (<%b,X)", 2, 6,
"CSP", 2, 8,
"ORA <%b,s", 2, 4,
"TSB <%b", 2, 5,
"ORA <%b", 2, 3,
"SHL <%b", 2, 5,
"ORA [<%b]", 2, 6,
// 0x8
"PSH P", 1, 3, // PHP
"ORA %#", 2, 2,
"SHL A", 1, 2,
"PSH D", 1, 4, // PHD Push Direct
"TSB %w", 3, 6,
"ORA %w", 3, 4,
"SHL %w", 3, 6,
"ORA %L", 4, 5,
// 0x10
"BPL @%b", 2, 2,
"ORA (<%b),Y", 2, 5,
"ORA (<%b)", 2, 5,
"ORA (<%b,S),Y", 2, 7,
"TRB <%b", 2, 5,
"ORA <%b,X", 2, 4,
"SHL <%b,X",2, 6,
"ORA [<%b],Y", 2, 6,
// 0x18
"CLC", 1, 2,
"ORA %w,Y", 3, 4,
"INC A", 1, 2,
"TAS", 1, 2,
"TRB %w", 3, 6,
"ORA %w,X", 3, 4,
"SHL %w,X", 3, 7,
"ORA %L,X", 4, 5,
// 0x20
"JSR %w", 3, 6,
"AND (<%b,X)", 2, 6,
"JSL %L", 4, 8,
"AND <%b,s", 2, 4,
"BIT <%b", 2, 3,
"AND <%b", 2, 3,
"ROL <%b", 2, 5,
"AND [<%b]", 2, 6,
// 0x28
"PUL P", 1, 4, // PLP
"AND %#", 2, 2,
"ROL A", 1, 2,
"PUL D", 1, 5, // PLD Pull Direct
"BIT %w", 3, 4,
"AND %w", 3, 4,
"ROL %w", 3, 6,
"AND %L", 4, 5,
// 0x30
"BMI @%b", 2, 2,
"AND (<%b),Y", 2, 5,
"AND (<%b)", 2, 5,
"AND (<%b,s),Y", 2, 7,
"BIT <%b,X", 2, 4,
"AND <%b,X", 2, 4,
"ROL <%b,X", 2, 6,
"AND [<%b],Y", 2, 6,
// 0x38
"SEC", 1, 2,
"AND %w,Y", 3, 4,
"DEC A", 1, 2,
"TSA", 1, 2,
"BIT %w,X", 3, 4,
"AND %w,X", 3, 4,
"ROL %w,X", 3, 7,
"AND %L,X", 4, 5,
// 0x40
"RTI", 1, 7,
"XOR (<%b,X)", 2, 6,
"???", 2, 2,
"XOR <%b,s", 2, 4,
"MVP XYA %w", 3, 7,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?