// created on 10/30/2004 at 09:54 using System; public class Mapper { public Cartridge mapperCartridge; Nes nes; public uint [] current_prg_rom_page; public uint [] current_chr_rom_page; public bool timer_irq_enabled; public bool timer_reload_next; public uint timer_irq_count, timer_irq_reload; bool timer_zero_pulse; //the single pulse timer public Mapper(Nes nes) { this.nes = nes; current_prg_rom_page = new uint[8]; current_chr_rom_page = new uint[8]; timer_irq_enabled = false; } public void SetUpMapperDefaults() { Switch32kPrgRom(0); Switch8kChrRom(0); } public byte ReadChrRom(ushort address) { byte returnvalue = 0xff; if (address < 0x400) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[0]][address]; } else if (address < 0x800) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[1]][address - 0x400]; } else if (address < 0xC00) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[2]][address - 0x800]; } else if (address < 0x1000) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[3]][address - 0xC00]; } else if (address < 0x1400) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[4]][address - 0x1000]; } else if (address < 0x1800) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[5]][address - 0x1400]; } else if (address < 0x1C00) { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[6]][address - 0x1800]; } else { returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[7]][address - 0x1C00]; } return returnvalue; } void Switch32kPrgRom(int start) { int i; switch (mapperCartridge.prg_rom_pages) { case (2): start = (start & 0x7); break; case (4): start = (start & 0xf); break; case (8): start = (start & 0x1f); break; case (16): start = (start & 0x3f); break; case (32): start = (start & 0x7f); break; } for (i = 0; i < 8; i++) { current_prg_rom_page[i] = (uint)(start + i); } } void Switch8kChrRom(int start) { int i; switch (mapperCartridge.chr_rom_pages) { case (2): start = (start & 0xf); break; case (4): start = (start & 0x1f); break; case (8): start = (start & 0x3f); break; case (16): start = (start & 0x7f); break; case (32): start = (start & 0xff); break; } for (i = 0; i < 8; i++) { current_chr_rom_page[i] = (uint)(start + i); } } public byte ReadPrgRom(ushort address) { byte returnvalue = 0xff; if (address < 0x9000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[0]][address - 0x8000]; } else if (address < 0xA000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[1]][address - 0x9000]; } else if (address < 0xB000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[2]][address - 0xA000]; } else if (address < 0xC000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[3]][address - 0xB000]; } else if (address < 0xD000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[4]][address - 0xC000]; } else if (address < 0xE000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[5]][address - 0xD000]; } else if (address < 0xF000) { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[6]][address - 0xE000]; } else { returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[7]][address - 0xF000]; } return returnvalue; } public void TickTimer() { if (nes.myPPU.currentScanline < 240) { if ((timer_reload_next)&&(timer_irq_enabled)) { //Console.WriteLine("Timer reloaded with: {0} in scanline: {1}", timer_irq_reload, myEngine.myPPU.currentScanline); timer_irq_count = timer_irq_reload; timer_reload_next = false; } else { if (timer_irq_enabled) { if (timer_irq_count == 0) { //Count down complete, fire our irq //Special case: if we're doing a single pulse because of a zero //being written to C000 if (timer_irq_reload > 0) { //if (myEngine.my6502.interrupt_flag == 0) { nes.my6502.Push16(nes.my6502.pc_register); nes.my6502.PushStatus(); nes.my6502.pc_register = nes.ReadMemory16(0xFFFE); nes.my6502.interrupt_flag = 1; } timer_irq_enabled = false; } else if (timer_zero_pulse) { nes.my6502.Push16(nes.my6502.pc_register); nes.my6502.PushStatus(); nes.my6502.pc_register = nes.ReadMemory16(0xFFFE); timer_zero_pulse = false; } //Make sure that we also carry in the timer timer_reload_next = true; } else { if ((nes.myPPU.backgroundVisible) || ( nes.myPPU.spritesVisible)) timer_irq_count = timer_irq_count - 1; } } } } } }