浏览代码

Fix interupt handling

- Passes Klaus Dormann's interrupt tests
v2
Nathaniel Walizer 9 个月前
父节点
当前提交
d4c74c9fe4
共有 2 个文件被更改,包括 92 次插入59 次删除
  1. +84
    -54
      src/f6502.c
  2. +8
    -5
      src/f6502.h

+ 84
- 54
src/f6502.c 查看文件

@@ -1,3 +1,5 @@
#include <stdbool.h>

#include "f6502.h" #include "f6502.h"
#include "f6502_consts.h" #include "f6502_consts.h"


@@ -67,8 +69,9 @@ static inline uint16_t f6502_read16(f6502_Memory* mem,
((uint16_t)f6502_read(mem, addr + 1) << 8)); ((uint16_t)f6502_read(mem, addr + 1) << 8));
} }


static inline void f6502_write(f6502_Memory* mem,
uint16_t addr, uint8_t val) {
static inline int f6502_write(f6502_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
@@ -80,10 +83,19 @@ static inline void f6502_write(f6502_Memory* mem,
int irq = val & 0b01; int irq = val & 0b01;
int nmi = val & 0b10; int nmi = val & 0b10;


f6502_wire_interrupts(core,
(irq ? f6502_Int_IRQ : 0) |
(nmi ? f6502_Int_NMI : 0)
);
#ifdef F6502_TRACE
if (!irq ^ !(core->interrupts & f6502_Int_IRQ)) {
fprintf(stdout, "%s IRQ\n", irq ? "Set" : "Clear");
}
if (!nmi ^ !(core->interrupts & f6502_Int_NMI)) {
fprintf(stdout, "%s NMI\n", nmi ? "Set" : "Clear");
}
#endif

f6502_set_NMI(core, nmi);
f6502_set_IRQ(core, irq);

ret = 1; // Interrupt [may have been] triggered
} }
#endif #endif
mem->ram[addr] = val; mem->ram[addr] = val;
@@ -91,12 +103,12 @@ static inline void f6502_write(f6502_Memory* mem,
// TODO // TODO
memval = val; memval = val;
#endif #endif
return ret;
} }




void f6502_init(f6502_Core* core) { void f6502_init(f6502_Core* core) {
core->int_state = f6502_Int_NMI | f6502_Int_IRQ;
core->int_wiring = f6502_Int_NMI | f6502_Int_IRQ;
// TODO: ???
} }


void f6502_reset(f6502_Core* core) { void f6502_reset(f6502_Core* core) {
@@ -106,9 +118,14 @@ void f6502_reset(f6502_Core* core) {
core->registers.P |= (f6502_Status_B | f6502_Status_1); core->registers.P |= (f6502_Status_B | f6502_Status_1);
} }


void f6502_wire_interrupts(f6502_Core* core,
f6502_Interrupt ints) {
core->int_wiring = ints;
void f6502_set_NMI(f6502_Core* core, bool active) {
if (active) core->interrupts |= f6502_Int_NMI;
else core->interrupts &= ~(f6502_Int_NMI | f6502_Int_NMI_Serviced);
}

void f6502_set_IRQ(f6502_Core* core, bool active) {
if (active) core->interrupts |= f6502_Int_IRQ;
else core->interrupts &= ~f6502_Int_IRQ;
} }


#define PUSH(core, S, val) \ #define PUSH(core, S, val) \
@@ -128,32 +145,31 @@ void f6502_wire_interrupts(f6502_Core* core,
#define SET(R, flags) R |= (flags) #define SET(R, flags) R |= (flags)


static inline int f6502_interrupt(f6502_Core* core, static inline int f6502_interrupt(f6502_Core* core,
f6502_Interrupt interrupt,
uint16_t addr) { uint16_t addr) {
core->int_state &= ~interrupt;
core->int_state |= (core->int_wiring & interrupt);
PUSH16(core, core->registers.S, core->registers.PC); PUSH16(core, core->registers.S, core->registers.PC);
PUSH(core, core->registers.S, PUSH(core, core->registers.S,
core->registers.P & ~f6502_Status_B); core->registers.P & ~f6502_Status_B);
CLR(core->registers.P, f6502_Status_D);
SET(core->registers.P, f6502_Status_I); SET(core->registers.P, f6502_Status_I);
core->registers.PC = f6502_read16(&core->memory, addr); core->registers.PC = f6502_read16(&core->memory, addr);
return 7; return 7;
} }


static inline int f6502_int_ready(const f6502_Core* core,
f6502_Interrupt interrupt) {
return ((core->int_state ^ core->int_wiring) & interrupt);
static inline bool f6502_nmi_ready(const f6502_Core* core) {
return ( (core->interrupts & f6502_Int_NMI) &&
!(core->interrupts & f6502_Int_NMI_Serviced));
}

static inline bool f6502_irq_ready(const f6502_Core* core) {
return ( (core->interrupts & f6502_Int_IRQ) &&
!(core->registers.P & f6502_Status_I));
} }


static inline int f6502_check_interrupts(f6502_Core* core) { static inline int f6502_check_interrupts(f6502_Core* core) {
if (f6502_int_ready(core, f6502_Int_NMI)) {
return f6502_interrupt(core, f6502_Int_NMI,
f6502_Vector_NMI);
} else if ( f6502_int_ready(core, f6502_Int_IRQ) &&
!(core->registers.P & f6502_Status_I)) {
return f6502_interrupt(core, f6502_Int_IRQ,
f6502_Vector_IRQ);
if (f6502_nmi_ready(core)) {
core->interrupts |= f6502_Int_NMI_Serviced;
return f6502_interrupt(core, f6502_Vector_NMI);
} else if (f6502_irq_ready(core)) {
return f6502_interrupt(core, f6502_Vector_IRQ);
} }
return 0; return 0;
} }
@@ -223,19 +239,18 @@ static inline int f6502_check_interrupts(f6502_Core* core) {
A = res; \ A = res; \
} }
#define AND(v) A &= (v); TEST(A) #define AND(v) A &= (v); TEST(A)
#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); \
register uint16_t addr = a; \ register uint16_t addr = a; \
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; \
f6502_write(&core->memory, addr, val); \
}
int_trig = 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); \
SET(P, table_asl[A]); \ SET(P, table_asl[A]); \
A <<= 1 A <<= 1

#ifdef F6502_HCF #ifdef F6502_HCF
#define BIF_HCF() \ #define BIF_HCF() \
if (pc_prev == PC + 2) { \ if (pc_prev == PC + 2) { \
@@ -268,22 +283,24 @@ static inline int f6502_check_interrupts(f6502_Core* core) {
SET(P, table_test[diff & 0xFFU]); \ SET(P, table_test[diff & 0xFFU]); \
if (diff < 0x100) SET(P, f6502_Status_C); \ if (diff < 0x100) SET(P, f6502_Status_C); \
} }
#define DEC(a) { \
#define DEC(a) ({ \
register uint16_t addr = a; \ register uint16_t addr = a; \
register uint8_t val = f6502_read(&core->memory, addr); \ register uint8_t val = f6502_read(&core->memory, addr); \
f6502_write(&core->memory, addr, --val); \
--val; \
TEST(val); \ TEST(val); \
}
int_trig = 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) ({ \
register uint16_t addr = a; \ register uint16_t addr = a; \
register uint8_t val = f6502_read(&core->memory, addr); \ register uint8_t val = f6502_read(&core->memory, addr); \
f6502_write(&core->memory, addr, ++val); \
++val; \
TEST(val); \ TEST(val); \
}
int_trig = 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)
#define LSR(a) { \
#define LSR(a) ({ \
register uint16_t addr = a; \ register uint16_t addr = a; \
register uint8_t val = f6502_read(&core->memory, addr); \ register uint8_t val = f6502_read(&core->memory, addr); \
CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \ CLR(P, f6502_Status_N | f6502_Status_Z | f6502_Status_C); \
@@ -291,8 +308,8 @@ 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); \
f6502_write(&core->memory, addr, val); \
}
int_trig = 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); \
SET(P, A & f6502_Status_C); \ SET(P, A & f6502_Status_C); \
@@ -300,7 +317,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) {
SET(P, A & f6502_Status_N); \ SET(P, A & f6502_Status_N); \
if (!A) SET(P, f6502_Status_Z) if (!A) SET(P, f6502_Status_Z)
#define ORA(v) A |= (v); TEST(A) #define ORA(v) A |= (v); TEST(A)
#define ROL(a) { \
#define ROL(a) ({ \
register uint16_t addr = a; \ register uint16_t addr = a; \
register uint8_t val = f6502_read(&core->memory, addr); \ register uint8_t val = f6502_read(&core->memory, addr); \
register uint8_t new_c = (A & 0x80) ? f6502_Status_C : 0; \ register uint8_t new_c = (A & 0x80) ? f6502_Status_C : 0; \
@@ -309,8 +326,8 @@ 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); \
f6502_write(&core->memory, addr, val); \
}
int_trig = 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; \
A = (A << 1) | (P & f6502_Status_C); \ A = (A << 1) | (P & f6502_Status_C); \
@@ -319,7 +336,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) {
if (!A) SET(P, f6502_Status_Z); \ if (!A) SET(P, f6502_Status_Z); \
SET(P, A & f6502_Status_N); \ SET(P, A & f6502_Status_N); \
} }
#define ROR(a) { \
#define ROR(a) ({ \
register uint16_t addr = a; \ register uint16_t addr = a; \
register uint8_t val = f6502_read(&core->memory, addr); \ register uint8_t val = f6502_read(&core->memory, addr); \
register uint8_t new_c = (val & f6502_Status_C); \ register uint8_t new_c = (val & f6502_Status_C); \
@@ -329,10 +346,10 @@ 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)); \
f6502_write(&core->memory, addr, val); \
}
int_trig = 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); \
A >>= 1; \ A >>= 1; \
if (P & f6502_Status_C) A |= f6502_Status_N; \ if (P & f6502_Status_C) A |= f6502_Status_N; \
CLR(P, f6502_Status_C | f6502_Status_Z | f6502_Status_N); \ CLR(P, f6502_Status_C | f6502_Status_Z | f6502_Status_N); \
@@ -352,7 +369,7 @@ static inline int f6502_check_interrupts(f6502_Core* core) {
} \ } \
A = res; \ A = res; \
} }
#define ST(reg, a) f6502_write(&core->memory, (a), reg)
#define ST(reg, a) int_trig = 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) {
@@ -365,11 +382,21 @@ 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;


while (clocks_elapsed < clocks) {
register bool int_trig = 0;

while (clocks_elapsed < clocks && !int_trig) {
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",
S, A, X, Y, P); S, A, X, Y, P);

printf("$%04x:", (int)S + f6502_Base_Stack);
for (int i = S; i < 256; ++i)
printf(" %02x", (int)f6502_read(&core->memory, i + f6502_Base_Stack));
putc('\n', stdout);

printf("INT %02x\n", core->interrupts);

printf("$%04x: ", PC - 1); printf("$%04x: ", PC - 1);
f6502_dump_instr(core, PC - 1); f6502_dump_instr(core, PC - 1);
printf(" -> "); printf(" -> ");
@@ -605,9 +632,10 @@ static int f6502_do_step(f6502_Core* core, int clocks) {


case 0x40: // RTI case 0x40: // RTI
POP(core, S, P); POP(core, S, P);
SET(P, f6502_Status_1);
SET(P, f6502_Status_1 | f6502_Status_B);
POP16(core, S, PC); POP16(core, S, PC);
CLK(6); CLK(6);
int_trig = 1;
break; break;


case 0x41: // EOR (zp, X) case 0x41: // EOR (zp, X)
@@ -705,14 +733,10 @@ static int f6502_do_step(f6502_Core* core, int clocks) {
CLR(P, f6502_Status_I); CLR(P, f6502_Status_I);
CLK(2); CLK(2);
if ( (p_old & f6502_Status_I) && if ( (p_old & f6502_Status_I) &&
f6502_int_ready(core, f6502_Int_IRQ)) {
core->int_state &= ~f6502_Int_IRQ;
core->int_state |= ( core->int_wiring &
f6502_Int_IRQ);
(core->interrupts & f6502_Int_IRQ)) {
CLK(7); CLK(7);
PUSH16(core, S, PC); PUSH16(core, S, PC);
PUSH(core, S, P & ~f6502_Status_B); PUSH(core, S, P & ~f6502_Status_B);
CLR(P, f6502_Status_D);
SET(P, f6502_Status_I); SET(P, f6502_Status_I);
PC = f6502_read16(&core->memory, PC = f6502_read16(&core->memory,
f6502_Vector_IRQ); f6502_Vector_IRQ);
@@ -1380,6 +1404,10 @@ static int f6502_do_step(f6502_Core* core, int clocks) {
} }
} }


#ifdef F6502_TRACE
if (int_trig) printf("Possible interrupt trigger\n");
#endif

step_done: step_done:
core->registers = (f6502_Registers){ core->registers = (f6502_Registers){
.PC = PC, .PC = PC,
@@ -1396,10 +1424,12 @@ step_done:
int f6502_step(f6502_Core* core, int clocks) { int f6502_step(f6502_Core* core, int clocks) {
int clocks_elapsed = 0; int clocks_elapsed = 0;
// TODO: Why are we processing seven clocks prior to NMI? // TODO: Why are we processing seven clocks prior to NMI?
if (f6502_int_ready(core, f6502_Int_NMI)) {
/*
if (f6502_nmi_ready(core)) {
clocks_elapsed += f6502_do_step(core, 7); clocks_elapsed += f6502_do_step(core, 7);
clocks -= clocks_elapsed; clocks -= clocks_elapsed;
} }
*/
clocks_elapsed += f6502_check_interrupts(core); clocks_elapsed += f6502_check_interrupts(core);
return (clocks_elapsed + f6502_do_step(core, clocks)); return (clocks_elapsed + f6502_do_step(core, clocks));
} }

+ 8
- 5
src/f6502.h 查看文件

@@ -1,8 +1,10 @@
#ifndef F6502_H_ #ifndef F6502_H_
#define F6502_H_ #define F6502_H_


#include <stdbool.h>
#include <stdint.h> #include <stdint.h>



#define F6502_RAM_SIZE (0x2000U) #define F6502_RAM_SIZE (0x2000U)




@@ -34,8 +36,9 @@ typedef struct __attribute__ ((__packed__)) {
} f6502_Registers; } f6502_Registers;


typedef enum { typedef enum {
f6502_Int_NMI = 0b01,
f6502_Int_IRQ = 0b10,
f6502_Int_NMI = 0b00000001,
f6502_Int_IRQ = 0b00000010,
f6502_Int_NMI_Serviced = 0b10000000,
} f6502_Interrupt; } f6502_Interrupt;


typedef struct __attribute__ ((__packed__)) { typedef struct __attribute__ ((__packed__)) {
@@ -51,15 +54,15 @@ typedef struct __attribute__ ((__packed__)) {


typedef struct __attribute__ ((__packed__)) { typedef struct __attribute__ ((__packed__)) {
f6502_Registers registers; f6502_Registers registers;
f6502_Interrupt int_state:2;
f6502_Interrupt int_wiring:2;
f6502_Interrupt interrupts;
f6502_Memory memory; f6502_Memory memory;
} f6502_Core; } f6502_Core;


void f6502_init(f6502_Core*); void f6502_init(f6502_Core*);
void f6502_reset(f6502_Core*); void f6502_reset(f6502_Core*);
int f6502_step(f6502_Core*, int clocks); int f6502_step(f6502_Core*, int clocks);
void f6502_wire_interrupts(f6502_Core*, f6502_Interrupt ints);
void f6502_set_NMI(f6502_Core*, bool active);
void f6502_set_IRQ(f6502_Core*, bool active);




#endif // F6502_H_ #endif // F6502_H_

正在加载...
取消
保存