// #define PPU_CTRL_NMI_ENABLE 0x80 // #define PPU_CTRL_MASTER_SLAVE 0x40 // #define PPU_CTRL_SPRITE_HEIGHT 0x20 // #define PPU_CTRL_BG_TILE_SELECT 0x10 // #define PPU_CTRL_SPRITE_TILE_SELECT 0x08 // #define PPU_CTRL_NT_SELECT_Y 0x04 // #define PPU_CTRL_NT_SELECT_X 0x02 // #define PPU_CTRL_VRAM_INCREMENT 0x01 // #define PPU_MASK_SHOW_BG 0x08 // #define PPU_MASK_SHOW_SPRITES 0x10 // #define PPU_STATUS_VBLANK 0x80 // #define PPU_STATUS_SPRITE0_HIT 0x40 // #define PPU_STATUS_OVERFLOW 0x20 #define PPU_CTRL_BG_TILE_SELECT 0x10 #define PPU_CTRL_SPRITE_TILE_SELECT 0x08 #define PPU_CTRL_NMI 0x80 #define PPU_CTRL_VRAM_INCREMENT 0x04 // Define constants for PPU control and mask bits #define PPU_CTRL_NMI 0x80 #define PPU_CTRL_VRAM_INCREMENT 0x04 #define PPU_CTRL_SPRITE_HEIGHT 0x20 #define PPU_CTRL_SPRITE_TILE 0x08 #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 nes_state; struct ppu_state { uint8_t pixels[256 * 240]; uint8_t oam[256]; uint8_t oam_addr; uint8_t oam_data; uint8_t secondary_oam[32]; uint8_t reg_ctrl; uint8_t reg_mask; uint8_t reg_status; uint8_t reg_scroll[2]; uint8_t reg_addr[2]; uint8_t reg_latch; uint32_t vram_addr; uint32_t temp_addr; uint32_t fine_x; uint8_t vram_read_buffer; uint8_t write_latch; uint8_t palette[0x20]; uint32_t scanline; uint32_t dot; uint8_t even_frame; uint8_t frame_ready; uint8_t sprite_indexes[8]; uint8_t sprite_zero_hit_possible; uint8_t sprite_count; 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]; 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; }; 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 { uint32_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, uint32_t addr); void (*write)(struct nes_state *state, uint32_t addr, uint8_t value); void (*tick)(struct nes_state *state); }; union mapper_data { struct mapper_066 m066; }; struct nes_state { struct ines_state ines; struct cpu_state cpu; struct ppu_state ppu; struct mapper mapper; union mapper_data map; size_t cycles; uint8_t irq_pending; uint8_t nmi_pending; uint8_t ram[0x800]; uint8_t sram[0x2000]; uint8_t ciram[0x1000]; // NOTE(peter): Originally 0x800 bytes, but extended as it should work for up to fourway, this is optimization, reality is 2kb, but there is no side-effects, so this is fine! uint8_t rom[4 * 1024 * 1024]; uint8_t chrrom[4 * 1024 * 1024]; }; 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 };