|
|
@@ -34,6 +34,17 @@ static inline uint16_t f6502_read16_zp(nes_Memory* mem, |
|
|
((uint16_t)f6502_read_zp(mem, addr + 1) << 8)); |
|
|
((uint16_t)f6502_read_zp(mem, addr + 1) << 8)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline uint8_t read_gamepad_bit(nes_Gamepad* gamepad) { |
|
|
|
|
|
uint8_t state = 1; |
|
|
|
|
|
if (gamepad->shift < 0) { |
|
|
|
|
|
state = (gamepad->buttons >> Button_A) & 1; |
|
|
|
|
|
} else if (gamepad->shift < nes_controller_num_buttons) { |
|
|
|
|
|
state = (gamepad->buttons >> gamepad->shift) & 1; |
|
|
|
|
|
gamepad->shift++; |
|
|
|
|
|
} |
|
|
|
|
|
return state; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static inline uint8_t f6502_read(nes_Memory* mem, |
|
|
static inline uint8_t f6502_read(nes_Memory* mem, |
|
|
uint16_t addr) { |
|
|
uint16_t addr) { |
|
|
#ifdef F6502_FLAT |
|
|
#ifdef F6502_FLAT |
|
|
@@ -78,7 +89,17 @@ static inline uint8_t f6502_read(nes_Memory* mem, |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case 0x4000: |
|
|
case 0x4000: |
|
|
// TODO: APU Reg |
|
|
|
|
|
|
|
|
switch (addr & 0x1FU) { |
|
|
|
|
|
case 0x16: |
|
|
|
|
|
case 0x17: |
|
|
|
|
|
{ nes_Gamepad* gamepad = &mem->input.gamepads[addr & 1]; |
|
|
|
|
|
return ((addr >> 8) & nes_controller_bus_mask) | |
|
|
|
|
|
read_gamepad_bit(gamepad); |
|
|
|
|
|
} break; |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
|
// TODO: APU Reg |
|
|
|
|
|
} |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case 0x6000: |
|
|
case 0x6000: |
|
|
@@ -98,9 +119,9 @@ static inline uint16_t f6502_read16(nes_Memory* mem, |
|
|
((uint16_t)f6502_read(mem, addr + 1) << 8)); |
|
|
((uint16_t)f6502_read(mem, addr + 1) << 8)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static inline bool f6502_write(nes_Memory* mem, |
|
|
|
|
|
uint16_t addr, uint8_t val) { |
|
|
|
|
|
bool ret = 0; |
|
|
|
|
|
|
|
|
static inline int f6502_write(nes_Memory* mem, |
|
|
|
|
|
uint16_t addr, uint8_t val) { |
|
|
|
|
|
int ret = 0; |
|
|
#ifdef F6502_TRACE |
|
|
#ifdef F6502_TRACE |
|
|
printf("W $%04X <- %02X\n", addr, val); |
|
|
printf("W $%04X <- %02X\n", addr, val); |
|
|
#endif |
|
|
#endif |
|
|
@@ -124,7 +145,10 @@ static inline bool f6502_write(nes_Memory* mem, |
|
|
f6502_set_NMI(core, nmi); |
|
|
f6502_set_NMI(core, nmi); |
|
|
f6502_set_IRQ(core, irq); |
|
|
f6502_set_IRQ(core, irq); |
|
|
|
|
|
|
|
|
ret = 1; // Interrupt [may have been] triggered |
|
|
|
|
|
|
|
|
// Interrupt [may have been] triggered |
|
|
|
|
|
// We're not strictly counting cycles, |
|
|
|
|
|
// so just overload the counter |
|
|
|
|
|
ret = 1000; |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
mem->ram[addr] = val; |
|
|
mem->ram[addr] = val; |
|
|
@@ -229,7 +253,7 @@ static inline bool f6502_write(nes_Memory* mem, |
|
|
case 0x4000: |
|
|
case 0x4000: |
|
|
// TODO: APU |
|
|
// TODO: APU |
|
|
switch (addr & 0x1FU) { |
|
|
switch (addr & 0x1FU) { |
|
|
case 0x14: |
|
|
|
|
|
|
|
|
case 0x14: // OAM DMA |
|
|
{ uint8_t* src = NULL; |
|
|
{ uint8_t* src = NULL; |
|
|
// OAM DMA |
|
|
// OAM DMA |
|
|
switch (val >> 5) { |
|
|
switch (val >> 5) { |
|
|
@@ -253,9 +277,18 @@ static inline bool f6502_write(nes_Memory* mem, |
|
|
if (NULL != src) { |
|
|
if (NULL != src) { |
|
|
memcpy(mem->ppu.oam, src, NES_PPU_OAM_SIZE); |
|
|
memcpy(mem->ppu.oam, src, NES_PPU_OAM_SIZE); |
|
|
} |
|
|
} |
|
|
// TODO: Spend 513 cycles |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
ret = 513; |
|
|
|
|
|
} break; |
|
|
|
|
|
|
|
|
|
|
|
case 0x16: // Reset Gamepad |
|
|
|
|
|
if (val & 1) { |
|
|
|
|
|
mem->input.gamepads[0].shift = -1; |
|
|
|
|
|
mem->input.gamepads[1].shift = -1; |
|
|
|
|
|
} else { |
|
|
|
|
|
mem->input.gamepads[0].shift = 0; |
|
|
|
|
|
mem->input.gamepads[1].shift = 0; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@@ -412,7 +445,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
SET(P, table_asl[val]); \ |
|
|
SET(P, table_asl[val]); \ |
|
|
val <<= 1; \ |
|
|
val <<= 1; \ |
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
|
|
|
|
|
clocks_elapsed += f6502_write(&core->memory, addr, val); \ |
|
|
}) |
|
|
}) |
|
|
#define ASL_A() \ |
|
|
#define ASL_A() \ |
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
@@ -455,7 +488,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
--val; \ |
|
|
--val; \ |
|
|
TEST(val); \ |
|
|
TEST(val); \ |
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
|
|
|
|
|
clocks_elapsed += f6502_write(&core->memory, addr, val); \ |
|
|
}) |
|
|
}) |
|
|
#define EOR(v) A ^= (v); TEST(A) |
|
|
#define EOR(v) A ^= (v); TEST(A) |
|
|
#define INC(a) ({ \ |
|
|
#define INC(a) ({ \ |
|
|
@@ -463,7 +496,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
register uint8_t val = f6502_read(&core->memory, addr); \ |
|
|
++val; \ |
|
|
++val; \ |
|
|
TEST(val); \ |
|
|
TEST(val); \ |
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
|
|
|
|
|
clocks_elapsed += f6502_write(&core->memory, addr, val); \ |
|
|
}) |
|
|
}) |
|
|
#define JMP(a) PC = (a) |
|
|
#define JMP(a) PC = (a) |
|
|
#define LD(reg, v) reg = (v); TEST(reg) |
|
|
#define LD(reg, v) reg = (v); TEST(reg) |
|
|
@@ -475,7 +508,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
val >>= 1; \ |
|
|
val >>= 1; \ |
|
|
SET(P, val & f6502_Status_N); \ |
|
|
SET(P, val & f6502_Status_N); \ |
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
|
|
|
|
|
clocks_elapsed += f6502_write(&core->memory, addr, val); \ |
|
|
}) |
|
|
}) |
|
|
#define LSR_A() \ |
|
|
#define LSR_A() \ |
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ |
|
|
@@ -493,7 +526,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
P |= new_c; \ |
|
|
P |= new_c; \ |
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
SET(P, val & f6502_Status_N); \ |
|
|
SET(P, val & f6502_Status_N); \ |
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
|
|
|
|
|
clocks_elapsed += f6502_write(&core->memory, addr, val); \ |
|
|
}) |
|
|
}) |
|
|
#define ROL_A() { \ |
|
|
#define ROL_A() { \ |
|
|
register uint8_t new_c = (A & 0x80) ? f6502_Status_C : 0; \ |
|
|
register uint8_t new_c = (A & 0x80) ? f6502_Status_C : 0; \ |
|
|
@@ -513,7 +546,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
P |= new_c; \ |
|
|
P |= new_c; \ |
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
if (!val) SET(P, f6502_Status_Z); \ |
|
|
SET(P, (val & f6502_Status_N)); \ |
|
|
SET(P, (val & f6502_Status_N)); \ |
|
|
int_trig = f6502_write(&core->memory, addr, val); \ |
|
|
|
|
|
|
|
|
clocks_elapsed += f6502_write(&core->memory, addr, val); \ |
|
|
}) |
|
|
}) |
|
|
#define ROR_A() { \ |
|
|
#define ROR_A() { \ |
|
|
register uint8_t new_c = (A & f6502_Status_C); \ |
|
|
register uint8_t new_c = (A & f6502_Status_C); \ |
|
|
@@ -536,7 +569,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) { |
|
|
} \ |
|
|
} \ |
|
|
A = res; \ |
|
|
A = res; \ |
|
|
} |
|
|
} |
|
|
#define ST(reg, a) int_trig = f6502_write(&core->memory, (a), reg) |
|
|
|
|
|
|
|
|
#define ST(reg, a) clocks_elapsed += f6502_write(&core->memory, (a), reg) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
@@ -549,9 +582,7 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
register uint8_t Y = core->registers.Y; |
|
|
register uint8_t Y = core->registers.Y; |
|
|
register uint8_t P = core->registers.P; |
|
|
register uint8_t P = core->registers.P; |
|
|
|
|
|
|
|
|
register bool int_trig = 0; |
|
|
|
|
|
|
|
|
|
|
|
while (clocks_elapsed < clocks && !int_trig) { |
|
|
|
|
|
|
|
|
while (clocks_elapsed < clocks) { |
|
|
uint8_t opcode = f6502_read(&core->memory, PC++); |
|
|
uint8_t opcode = f6502_read(&core->memory, PC++); |
|
|
#ifdef F6502_TRACE |
|
|
#ifdef F6502_TRACE |
|
|
printf("S:%02x A:%02x X:%02x Y:%02x P:%02x\n", |
|
|
printf("S:%02x A:%02x X:%02x Y:%02x P:%02x\n", |
|
|
@@ -804,7 +835,8 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
SET(P, f6502_Status_1 | f6502_Status_B); |
|
|
SET(P, f6502_Status_1 | f6502_Status_B); |
|
|
POP16(core, S, PC); |
|
|
POP16(core, S, PC); |
|
|
CLK(6); |
|
|
CLK(6); |
|
|
int_trig = 1; |
|
|
|
|
|
|
|
|
// Interrupt might be triggered; break out |
|
|
|
|
|
clocks = 0; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case 0x41: // EOR (zp, X) |
|
|
case 0x41: // EOR (zp, X) |
|
|
@@ -1573,7 +1605,7 @@ static int f6502_do_step(f6502_Core* core, int clocks) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef F6502_TRACE |
|
|
#ifdef F6502_TRACE |
|
|
if (int_trig) printf("Possible interrupt trigger\n"); |
|
|
|
|
|
|
|
|
// if (int_trig) printf("Possible interrupt trigger\n"); |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
#ifdef F6502_HCF |
|
|
#ifdef F6502_HCF |
|
|
|