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
|
#define PPU_CTRL_NMI 0x80
#define PPU_CTRL_BG_TILE_SELECT 0x10
#define PPU_CTRL_SPRITE_TILE_SELECT 0x08
#define PPU_CTRL_VRAM_INCREMENT 0x04
// Define constants for PPU control and mask bits
#define PPU_CTRL_NMI 0x80
#define PPU_CTRL_SPRITE_HEIGHT 0x20
#define PPU_CTRL_SPRITE_TILE 0x08
#define PPU_CTRL_VRAM_INCREMENT 0x04
#define PPU_MASK_SHOW_BG 0x08
#define PPU_MASK_SHOW_SPRITES 0x10
// Define mirroring modes
#define MIRROR_HORIZONTAL 0
#define MIRROR_VERTICAL 1
#define MIRROR_FOURSCREEN 2
struct ppu_state {
uint32_t scanline;
uint32_t dot;
uint32_t bg_shift_pattern_low;
uint32_t bg_shift_pattern_high;
uint32_t bg_shift_attrib_low;
uint32_t bg_shift_attrib_high;
uint8_t bg_next_tile_id;
uint8_t bg_next_tile_attrib;
uint8_t bg_next_tile_lsb;
uint8_t bg_next_tile_msb;
uint8_t oam_addr;
uint8_t oam_data;
uint8_t even_frame;
uint8_t oam[256];
uint8_t secondary_oam[32];
uint8_t palette[0x20];
uint8_t sprite_indexes[8];
uint32_t sprite_patterns[8];
uint8_t sprite_positions[8];
uint8_t sprite_priorities[8];
uint8_t sprite_shift_lo[8];
uint8_t sprite_shift_hi[8];
uint8_t reg_ctrl;
uint8_t reg_mask;
uint8_t reg_status;
uint32_t vram_addr;
uint32_t temp_addr;
uint32_t fine_x;
uint8_t vram_read_buffer;
uint8_t write_latch;
uint8_t open_bus;
uint8_t frame_ready;
uint8_t sprite_zero_hit_possible;
uint8_t sprite_count;
} __attribute__((aligned(64)));
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) -- does not exist outside the stack
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!
} __attribute__((aligned(64)));
struct ines_state {
uint32_t mapper;
uint32_t submapper;
uint8_t mirroring; // 0 = H, 1 = V, 2 = 4-screen
uint32_t prg_size;
uint32_t chr_size;
};
struct nes_state {
size_t cycles;
struct ines_state ines;
struct cpu_state cpu;
uint8_t irq_pending;
uint8_t nmi_pending;
uint8_t input[2]; // Controller 1 & 2
uint8_t input_latch[2]; // Latched inputs after strobe
uint8_t input_strobe; // Control bit (0 or 1)
uint8_t input_bit[2]; // Current bit position being shifted out
struct ppu_state ppu;
struct mapper_entry mapper;
union mapper_data map;
uint8_t *pixels;
uint8_t *ram;
uint8_t *sram;
uint8_t *ciram;
uint8_t *prg_rom;
uint8_t *chr_rom;
uint8_t *chr_ram;
};
__attribute__((aligned(4096))) static uint32_t nes_palette[64] = {
0x585858ff, 0x00237cff, 0x0d1099ff, 0x300092ff, 0x4f006cff, 0x600035ff, 0x5c0500ff, 0x461800ff,
0x272d00ff, 0x093e00ff, 0x004500ff, 0x004106ff, 0x003545ff, 0x000000ff, 0x000000ff, 0x000000ff,
0xa1a1a1ff, 0x0b53d7ff, 0x3337feff, 0x6621f7ff, 0x9515beff, 0xac166eff, 0xa62721ff, 0x864300ff,
0x596200ff, 0x2d7a00ff, 0x0c8500ff, 0x007f2aff, 0x006d85ff, 0x000000ff, 0x000000ff, 0x000000ff,
0xffffffff, 0x51a5feff, 0x8084feff, 0xbc6afeff, 0xf15bfeff, 0xfe5ec4ff, 0xfe7269ff, 0xe19321ff,
0xadb600ff, 0x79d300ff, 0x51df21ff, 0x3ad974ff, 0x39c3dfff, 0x424242ff, 0x000000ff, 0x000000ff,
0xffffffff, 0xb5d9feff, 0xcacafeff, 0xe3befeff, 0xf9b8feff, 0xfebae7ff, 0xfec3bcff, 0xf4d199ff,
0xdee086ff, 0xc6ec87ff, 0xb2f29dff, 0xa7f0c3ff, 0xa8e7f0ff, 0xacacacff, 0x000000ff, 0x000000ff
};
|