1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#include <stdint.h>
#include <stdio.h>
#include <string.h>
// REMOVE FOR NES!!!!!
// #define ENABLE_DECIMAL_MODE
__attribute__((always_inline))
static inline uint8_t pack_flags(struct cpu_state *cpu) {
return (cpu->n << 7) | (cpu->v << 6) | (1 << 5) | (cpu->d << 3) | (cpu->i << 2) | (cpu->z << 1) | cpu->c;
}
__attribute__((always_inline))
static inline void unpack_flags(struct cpu_state *cpu, uint8_t value) {
cpu->n = (value >> 7) & 1;
cpu->v = (value >> 6) & 1;
cpu->d = (value >> 3) & 1;
cpu->i = (value >> 2) & 1;
cpu->z = (value >> 1) & 1;
cpu->c = value & 1;
}
static inline void update_zn(struct cpu_state *cpu, uint8_t result) {
cpu->z = (result == 0);
cpu->n = (result & 0x80) != 0;
}
static void (*opcode_lut[256*2])(struct nes_state *) __attribute__((aligned(4096)));
struct addr_result {
uint32_t addr;
uint8_t value;
};
#include "cpu_opcodes.c"
#include "cpu_opcodes_ud.c"
__attribute__((hot))
static inline void do_nmi(struct nes_state * restrict state) {
struct cpu_state * restrict cpu = &state->cpu;
memory_read_dummy(state, cpu->pc); // T1: dummy read (fetch suppressed)
uint8_t pcl = cpu->pc & 0xff;
uint8_t pch = cpu->pc >> 8;
memory_write(state, 0x0100 + cpu->sp--, pch); // T2
memory_write(state, 0x0100 + cpu->sp--, pcl); // T3
memory_write(state, 0x0100 + cpu->sp--, pack_flags(cpu) & ~0x10); // T4: push P (B flag clear)
uint8_t lo = memory_read(state, 0xfffa); // T5
uint8_t hi = memory_read(state, 0xfffb); // T6
cpu->pc = lo | (hi << 8); // T7
cpu->i = 1;
}
__attribute__((hot))
static inline void do_irq(struct nes_state * restrict state) {
struct cpu_state * restrict cpu = &state->cpu;
memory_read_dummy(state, cpu->pc); // T1: dummy read (fetch suppressed)
uint8_t pcl = cpu->pc & 0xff;
uint8_t pch = cpu->pc >> 8;
memory_write(state, 0x0100 + cpu->sp--, pch); // T2
memory_write(state, 0x0100 + cpu->sp--, pcl); // T3
memory_write(state, 0x0100 + cpu->sp--, pack_flags(cpu) & ~0x10); // T4: push P (B flag clear)
uint8_t lo = memory_read(state, 0xfffe); // T5
uint8_t hi = memory_read(state, 0xffff); // T6
cpu->pc = lo | (hi << 8); // T7
cpu->i = 1;
}
__attribute__((hot))
static inline void check_interrupts(struct nes_state * restrict state) {
struct cpu_state * restrict cpu = &state->cpu;
if(state->nmi_pending) {
state->nmi_pending = 0;
do_nmi(state);
} else if(state->irq_pending && cpu->i == 0) {
state->irq_pending = 0;
do_irq(state);
}
}
__attribute__((hot))
static void cpu_tick(struct nes_state *state) {
struct cpu_state * restrict cpu = &state->cpu;
check_interrupts(state);
uint8_t opcode;
// printf("%4.4x: ", cpu->pc);
opcode = memory_read(state, cpu->pc++);
// printf("%2.2x a:%2.2x x:%2.2x y:%2.2x p:%2.2x sp:%2.2x cycle: %ld\n", opcode, cpu->a, cpu->x, cpu->y, pack_flags(cpu), cpu->sp, state->cycles);
opcode_lut[opcode](state);
}
|