- Gun Nac still crashing after first title screen - SMB3 halts after game startmaster
| @@ -55,21 +55,15 @@ static inline void mmc3_update_rom_mode(mmc3_mapper* map) { | |||||
| static inline void mmc3_update_prg(mmc3_mapper* map, uint8_t bank) { | static inline void mmc3_update_prg(mmc3_mapper* map, uint8_t bank) { | ||||
| int reg = (map->bank_select & mmc3_Bank_Select_Reg); | int reg = (map->bank_select & mmc3_Bank_Select_Reg); | ||||
| if (!(map->bank_select & mmc3_Bank_Select_PRG)) { | |||||
| if (reg == 7) { | |||||
| mmc3_map_prg(map, 1, bank); | |||||
| } else { | |||||
| mmc3_map_prg(map, 0, bank); | |||||
| } | |||||
| if (reg == 7) { | |||||
| mmc3_map_prg(map, 1, bank); | |||||
| } else { | } else { | ||||
| if (reg == 7) { | |||||
| mmc3_map_prg(map, 1, bank); | |||||
| if (!(map->bank_select & mmc3_Bank_Select_PRG)) { | |||||
| mmc3_map_prg(map, 0, bank); | |||||
| } else { | } else { | ||||
| mmc3_map_prg(map, 2, bank); | mmc3_map_prg(map, 2, bank); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static inline uint8_t* mmc3_chr_bank(mmc3_mapper* map, int bank) { | static inline uint8_t* mmc3_chr_bank(mmc3_mapper* map, int bank) { | ||||
| @@ -169,7 +163,7 @@ static uint8_t mmc3_read(nes_mapper* nes_map, uint16_t addr) { | |||||
| } else if ( addr >= nes_mem_wram_start && | } else if ( addr >= nes_mem_wram_start && | ||||
| (map->flags & mmc3_Flag_WRAM_Enabled)) { | (map->flags & mmc3_Flag_WRAM_Enabled)) { | ||||
| ptr = mmc3_wram_addr(map, addr); | ptr = mmc3_wram_addr(map, addr); | ||||
| MAP_LOG("WRAM: $%04x > %02x", addr, *ptr); | |||||
| // MAP_LOG("WRAM: $%04x > %02x", addr, *ptr); | |||||
| } | } | ||||
| uint8_t val = (NULL == ptr ? 0 : *ptr); | uint8_t val = (NULL == ptr ? 0 : *ptr); | ||||
| @@ -226,16 +220,36 @@ static void mmc3_write(nes_mapper* nes_map, | |||||
| } else if (addr < 0xE000U) { | } else if (addr < 0xE000U) { | ||||
| if (addr & 1) { | if (addr & 1) { | ||||
| // TODO: IRQ reload | |||||
| MAP_LOG("IRQ Reload"); | |||||
| map->irq_count = 0; | |||||
| } else { | } else { | ||||
| // TODO: IRQ latch | |||||
| MAP_LOG("IRQ Latch: %d", val); | |||||
| map->irq_latch = val; | |||||
| } | } | ||||
| } else { | } else { | ||||
| MAP_LOG("IRQ %s", (addr & 1) ? "Enable" : "Disable"); | |||||
| if (addr & 1) { | if (addr & 1) { | ||||
| // TODO: IRQ enable | |||||
| map->flags |= mmc3_Flag_IRQ_Enabled; | |||||
| } else { | } else { | ||||
| // TODO: IRQ disable | |||||
| map->flags &= ~mmc3_Flag_IRQ_Enabled; | |||||
| nes_map_trigger_irq(nes_map, 0); | |||||
| } | |||||
| } | |||||
| } | |||||
| static void mmc3_scanline(nes_mapper* nes_map) { | |||||
| mmc3_mapper* map = (mmc3_mapper*)nes_map->data; | |||||
| if (map->irq_count == 0) { | |||||
| map->irq_count = map->irq_latch; | |||||
| } else { | |||||
| map->irq_count--; | |||||
| if ( map->irq_count <= 0 && | |||||
| (map->flags & mmc3_Flag_IRQ_Enabled)) { | |||||
| MAP_LOG("IRQ Trigger"); | |||||
| nes_map_trigger_irq(nes_map, 1); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -267,4 +281,5 @@ nes_mapper mapper_mmc3 = { | |||||
| .chr_addr = mmc3_chr_addr, | .chr_addr = mmc3_chr_addr, | ||||
| .vram_addr = mmc3_vram_addr, | .vram_addr = mmc3_vram_addr, | ||||
| .chr_write = mmc3_chr_write, | .chr_write = mmc3_chr_write, | ||||
| .scanline = mmc3_scanline, | |||||
| }; | }; | ||||
| @@ -10,15 +10,23 @@ | |||||
| struct nes_cart_t; | struct nes_cart_t; | ||||
| typedef struct nes_mapper_t { | typedef struct nes_mapper_t { | ||||
| void* data; | |||||
| int (*init)(struct nes_mapper_t*, struct nes_cart_t* cart); | int (*init)(struct nes_mapper_t*, struct nes_cart_t* cart); | ||||
| void (*reset)(struct nes_mapper_t*); | void (*reset)(struct nes_mapper_t*); | ||||
| void (*done)(struct nes_mapper_t*); | void (*done)(struct nes_mapper_t*); | ||||
| uint8_t (*read)(struct nes_mapper_t*, uint16_t addr); | uint8_t (*read)(struct nes_mapper_t*, uint16_t addr); | ||||
| void (*write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | void (*write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | ||||
| uint8_t* (*chr_addr)(struct nes_mapper_t*, uint16_t addr); | uint8_t* (*chr_addr)(struct nes_mapper_t*, uint16_t addr); | ||||
| uint8_t* (*vram_addr)(struct nes_mapper_t*, uint16_t addr); | uint8_t* (*vram_addr)(struct nes_mapper_t*, uint16_t addr); | ||||
| void (*chr_write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | void (*chr_write)(struct nes_mapper_t*, uint16_t addr, uint8_t val); | ||||
| void* data; | |||||
| void (*scanline)(struct nes_mapper_t*); | |||||
| void (*irq_callback)(void*, int); | |||||
| void* irq_arg; | |||||
| } nes_mapper; | } nes_mapper; | ||||
| static inline int nes_map_init(nes_mapper* map, | static inline int nes_map_init(nes_mapper* map, | ||||
| @@ -34,6 +42,18 @@ static inline void nes_map_done(nes_mapper* map) { | |||||
| map->done(map); | map->done(map); | ||||
| } | } | ||||
| static inline void nes_map_set_irq(nes_mapper* map, | |||||
| void(*callback)(void*, int), | |||||
| void* arg) { | |||||
| map->irq_callback = callback; | |||||
| map->irq_arg = arg; | |||||
| } | |||||
| static inline void nes_map_trigger_irq(nes_mapper* map, | |||||
| int active) { | |||||
| map->irq_callback(map->irq_arg, active); | |||||
| } | |||||
| static inline uint8_t nes_map_read(nes_mapper* map, | static inline uint8_t nes_map_read(nes_mapper* map, | ||||
| uint16_t addr) { | uint16_t addr) { | ||||
| return map->read(map, addr); | return map->read(map, addr); | ||||
| @@ -75,6 +95,7 @@ static inline void nes_vram_write(nes_mapper* map, | |||||
| *(nes_map_vram_addr(map, addr)) = val; | *(nes_map_vram_addr(map, addr)) = val; | ||||
| } | } | ||||
| extern nes_mapper* nes_mappers[]; | extern nes_mapper* nes_mappers[]; | ||||
| @@ -58,9 +58,14 @@ void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) { | |||||
| } | } | ||||
| } | } | ||||
| static void nes_irq(void* sys, int active) { | |||||
| e6502_set_irq(&((nes*)sys)->cpu, active); | |||||
| } | |||||
| int nes_init(nes* sys) { | int nes_init(nes* sys) { | ||||
| e6502_init(&sys->cpu, (e6502_Read*)nes_mem_read, | e6502_init(&sys->cpu, (e6502_Read*)nes_mem_read, | ||||
| (e6502_Write*)nes_mem_write, sys); | (e6502_Write*)nes_mem_write, sys); | ||||
| nes_map_set_irq(sys->cart.mapper, nes_irq, sys); | |||||
| return nes_ppu_init(&sys->ppu, &sys->cart); | return nes_ppu_init(&sys->ppu, &sys->cart); | ||||
| } | } | ||||
| @@ -195,7 +195,15 @@ int nes_ppu_init(nes_ppu* ppu, const nes_cart* cart) { | |||||
| int nes_ppu_run(nes_ppu* ppu, int cycles) { | int nes_ppu_run(nes_ppu* ppu, int cycles) { | ||||
| nes_ppu_Result result = ppu_Result_Running; | nes_ppu_Result result = ppu_Result_Running; | ||||
| ppu->cycle += cycles; | |||||
| int next_cycle = ppu->cycle + cycles; | |||||
| if ( NULL != ppu->mapper->scanline && | |||||
| ppu->scanline < nes_ppu_render && | |||||
| ppu->cycle < 260 && next_cycle >= 260) { | |||||
| ppu->mapper->scanline(ppu->mapper); | |||||
| } | |||||
| ppu->cycle = next_cycle; | |||||
| while (ppu->cycle >= nes_ppu_dots) { | while (ppu->cycle >= nes_ppu_dots) { | ||||
| ppu->cycle -= nes_ppu_dots; | ppu->cycle -= nes_ppu_dots; | ||||
| @@ -38,9 +38,9 @@ struct nes_cart_t; | |||||
| #define nes_ppu_postrender (1U) | #define nes_ppu_postrender (1U) | ||||
| #define nes_ppu_vblank (20U) | #define nes_ppu_vblank (20U) | ||||
| #define nes_ppu_active (nes_ppu_prerender + \ | |||||
| nes_ppu_height + \ | |||||
| nes_ppu_postrender) | |||||
| #define nes_ppu_render (nes_ppu_prerender + nes_ppu_height) | |||||
| #define nes_ppu_active (nes_ppu_render + nes_ppu_postrender) | |||||
| #define nes_ppu_frame (nes_ppu_active + nes_ppu_vblank) | #define nes_ppu_frame (nes_ppu_active + nes_ppu_vblank) | ||||