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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
// PPUSTATUS ($2002) flags
#define PPU_STATUS_VBLANK 0x80
#define PPU_STATUS_SPRITE0_HIT 0x40
#define PPU_STATUS_OVERFLOW 0x20
// PPUMASK ($2001) flags
#define PPU_MASK_SHOW_BG 0x08
#define PPU_MASK_SHOW_SPRITES 0x10
// PPUCTRL ($2000) flags
#define PPU_CTRL_NMI_ENABLE 0x80
#define PPU_CTRL_MASTER_SLAVE 0x40
#define PPU_CTRL_SPRITE_HEIGHT 0x20
#define PPU_CTRL_BG_TABLE 0x10
#define PPU_CTRL_SPRITE_TABLE 0x08
#define PPU_CTRL_INCREMENT 0x04
#define PPU_CTRL_NT_SELECT_Y 0x02
#define PPU_CTRL_NT_SELECT_X 0x01
struct nes_state;
struct ppu_state {
uint8_t pixels[240*256];
uint8_t sprite_pixels[256]; // Sprite pixel color indexes (BG priority resolved)
uint8_t sprite_zero_flags[256]; // 1 if pixel came from sprite #0 and is nonzero
// Sprite memory
uint8_t oam[256];
uint8_t sec_oam[32];
uint8_t oam_addr;
uint8_t read_buffer;
uint32_t scanline; // 0–261
uint32_t dot; // 0–340
// Scroll state
uint32_t coarse_x_offs;
uint32_t coarse_y_offs;
uint32_t fine_x;
uint32_t fine_y;
uint32_t nt_base_x;
uint32_t nt_base_y;
// Latch state for $2005/$2006
uint8_t write_toggle;
uint32_t temp_coarse_x_offs;
uint32_t temp_coarse_y_offs;
uint32_t temp_fine_x;
uint32_t temp_fine_y;
uint32_t temp_nt_base_x;
uint32_t temp_nt_base_y;
// Background shift registers
uint32_t bg_tile_lsb;
uint32_t bg_tile_msb;
uint32_t bg_attr_lsb;
uint32_t bg_attr_msb;
// Tile fetch latches
uint8_t nt_byte;
uint8_t attr_byte;
uint8_t tile_lsb;
uint8_t tile_msb;
// Control and status
uint8_t ctrl; // $2000
uint8_t mask; // $2001
uint8_t status; // $2002
// Flags
uint8_t frame_even;
uint8_t nmi_occurred;
uint8_t nmi_output;
};
struct cpu_state {
uint32_t pc; // Program Counter
uint8_t sp; // Stack Pointer
uint8_t a; // Accumulator
uint8_t x; // X Register
uint8_t y; // Y Register
uint8_t p; // Processor Status Flags (this can be expanded with separate flags if needed)
uint8_t n; // Negative Flag
uint8_t v; // Overflow Flag
// uint8_t b; // Break Flag (Set by BRK instruction)
uint8_t d; // Decimal Flag
uint8_t i; // Interrupt Disable Flag
uint8_t z; // Zero Flag
uint8_t c; // Carry Flag
// --
uint8_t die; // KIL instruction found!
};
struct ines_state {
uint16_t mapper;
uint8_t mirroring; // 0 = H, 1 = V, 2 = 4-screen
uint32_t prg_size;
uint32_t chr_size;
};
struct mapper {
void (*init)(struct nes_state *state);
uint8_t (*read)(struct nes_state *state, uint16_t addr);
void (*write)(struct nes_state *state, uint16_t addr, uint8_t value);
void (*tick)(struct nes_state *state);
};
union mapper_data {
// struct nrom_mapper nrom;
// struct mmc1_mapper mmc1;
// ... others
};
struct nes_state {
struct ines_state ines;
struct cpu_state cpu;
struct ppu_state ppu;
struct mapper mapper;
union mapper_data map;
size_t cycle;
uint8_t ram[2048];
uint8_t rom[4 * 1024 * 1024];
uint8_t chrrom[4 * 1024 * 1024];
uint8_t ciram[2048];
uint8_t palette[0x20];
uint8_t irq_pending;
uint8_t nmi_pending;
};
static const uint32_t nes_palette_argb[64] = {
0xff757575, 0xff8f1b27, 0xffab0000, 0xff9f0047, 0xff77008f, 0xff1300ab, 0xff0000a7, 0xff000b7f,
0xff002f43, 0xff004700, 0xff005100, 0xff173f00, 0xff5f3f1b, 0xff000000, 0xff000000, 0xff000000,
0xffbcbcbc, 0xffef7300, 0xffef3b23, 0xfff30083, 0xffbf00bf, 0xff5b00e7, 0xff002bdb, 0xff0f4fcb,
0xff00738b, 0xff009700, 0xff00ab00, 0xff3b9300, 0xff8b8300, 0xff000000, 0xff000000, 0xff000000,
0xffffffff, 0xffffbf3f, 0xffff975f, 0xfffd8ba7, 0xffff7bff, 0xffb777ff, 0xff6377ff, 0xff3b9bff,
0xff3fbff3, 0xff13d383, 0xff4bdf4f, 0xff98f858, 0xffdbeb00, 0xff000000, 0xff000000, 0xff000000,
0xffffffff, 0xffffe7ab, 0xffffd7c7, 0xffffcbd7, 0xffffc7ff, 0xffdbc7ff, 0xffb3bfff, 0xffabdbff,
0xffa3e7ff, 0xff83f7c7, 0xffb3ffbf, 0xffcfffb3, 0xfff3ff9f, 0xff000000, 0xff000000, 0xff000000
};
|