From a24f8bee233a02b98b77d34edc66e7c19c13dd3a Mon Sep 17 00:00:00 2001 From: scrimpeh Date: Wed, 5 Aug 2015 19:59:48 +0200 Subject: [PATCH] NEShawk - Mapper 90 --- .../Consoles/Nintendo/NES/Boards/Mapper090.cs | 787 ++++++++++++------ output/gamedb/gamedb.txt | 1 + 2 files changed, 529 insertions(+), 259 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper090.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper090.cs index a557c8d3c9..a7c15e8043 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper090.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper090.cs @@ -1,4 +1,7 @@ -using System; +//#define SET_DIPSWITCH_0 +//#define SET_DIPSWITCH_1 + +using System; using BizHawk.Common; using BizHawk.Common.NumberExtensions; @@ -6,149 +9,421 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { public sealed class Mapper090 : NES.NESBoardBase { - ByteBuffer prg_banks = new ByteBuffer(4); - IntBuffer chr_banks = new IntBuffer(8); - int prg_bank_mask_8k; - int prg_bank_mask_16k; - int prg_bank_mask_32k; + ByteBuffer prg_regs = new ByteBuffer(4); + IntBuffer chr_regs = new IntBuffer(8); + IntBuffer nt_regs = new IntBuffer(4); + IntBuffer prg_banks = new IntBuffer(4); + IntBuffer chr_banks = new IntBuffer(8); + + ByteBuffer ram_bytes = new ByteBuffer(5); + + bool[] dipswitches = new bool[2]; + + int prg_bank_mask_8k; int chr_bank_mask_1k; - int chr_bank_mask_2k; - int chr_bank_mask_4k; - int chr_bank_mask_8k; byte prg_mode_select = 0; byte chr_mode_select = 0; bool sram_prg = false; - + + int ram_bank; + + bool mapper_090 = false; + bool mapper_209 = false; + bool mapper_211 = false; + + bool nt_advanced_control = false; + bool nt_ram_disable = false; + + bool nt_ram_select = false; + + bool mirror_chr = false; + bool chr_block_mode = true; + byte chr_block = 0; + + int multiplicator = 0; + int multiplicand = 0; + int multiplication_result = 0; + + //Irq Stuff + bool irq_enable = false; + bool irq_pending = false; + + bool irq_count_down = false; + bool irq_count_up = false; + int irq_prescaler_size; + byte irq_source = 0; + + byte prescaler; + byte irq_counter; + byte xor_reg; + + int a12_old; + public override bool Configure(NES.EDetectionOrigin origin) { switch (Cart.board_type) { case "MAPPER090": + mapper_090 = true; + nt_advanced_control = false; break; case "MAPPER209": - //TODO: Set some flag for 209 mirroring + mapper_209 = true; + break; + case "MAPPER211": + nt_advanced_control = true; + mapper_211 = true; break; default: return false; } prg_bank_mask_8k = Cart.prg_size / 8 - 1; - prg_bank_mask_16k = Cart.prg_size / 16 - 1; - prg_bank_mask_32k = Cart.prg_size / 32 - 1; + chr_bank_mask_1k = Cart.chr_size - 1; - chr_bank_mask_1k = Cart.chr_size / 1 - 1; - chr_bank_mask_2k = Cart.chr_size / 2 - 1; - chr_bank_mask_4k = Cart.chr_size / 4 - 1; - chr_bank_mask_8k = Cart.chr_size / 8 - 1; +#if SET_DIPSWITCH_0 + dipswitches[0] = true; +#endif +#if SET_DIPSWITCH_1 + dipswitches[1] = true; +#endif + + Sync(); return true; } public override void SyncState(Serializer ser) { + base.SyncState(ser); + + ser.Sync("prg_regs", ref prg_regs); + ser.Sync("chr_regs", ref chr_regs); + ser.Sync("nt_regs", ref nt_regs); + ser.Sync("prg_banks", ref prg_banks); ser.Sync("chr_banks", ref chr_banks); + ser.Sync("ram_bytes", ref ram_bytes); + + ser.Sync("dipswitches", ref dipswitches, false); + + ser.Sync("prg_bank_mask_8k", ref prg_bank_mask_8k); + ser.Sync("chr_bank_mask_1k", ref chr_bank_mask_1k); + ser.Sync("prg_mode_select", ref prg_mode_select); - ser.Sync("chr_mode_select", ref prg_mode_select); + ser.Sync("chr_mode_select", ref chr_mode_select); ser.Sync("sram_prg", ref sram_prg); - base.SyncState(ser); + ser.Sync("ram_bank", ref ram_bank); + + ser.Sync("mapper_090", ref mapper_090); + ser.Sync("mapper_209", ref mapper_209); + ser.Sync("mapper_211", ref mapper_211); + + ser.Sync("nt_advanced_control", ref nt_advanced_control); + ser.Sync("nt_ram_disable", ref nt_ram_disable); + ser.Sync("nt_ram_select", ref nt_ram_select); + + ser.Sync("mirror_chr", ref mirror_chr); + ser.Sync("chr_block_mode", ref chr_block_mode); + ser.Sync("chr_block", ref chr_block); + + ser.Sync("multiplicator", ref multiplicator); + ser.Sync("multiplicand", ref multiplicand); + ser.Sync("multiplication_result", ref multiplication_result); + + ser.Sync("irq_enable", ref irq_enable); + ser.Sync("irq_pending", ref irq_pending); + ser.Sync("irq_count_down", ref irq_count_down); + ser.Sync("irq_count_up", ref irq_count_up); + ser.Sync("irq_prescaler_size", ref irq_prescaler_size); + ser.Sync("irq_source", ref irq_source); + ser.Sync("prescaler", ref prescaler); + ser.Sync("irq_counter", ref irq_counter); + ser.Sync("xor_reg", ref xor_reg); + ser.Sync("a12_old", ref a12_old); + + Sync(); + } + + public override void Dispose() + { + prg_regs.Dispose(); + chr_regs.Dispose(); + nt_regs.Dispose(); + + prg_banks.Dispose(); + chr_banks.Dispose(); + + ram_bytes.Dispose(); + } + + //TODO: No interface for changing dipswitches exists in Bizhawk + public void SetDipswitch(int index, bool value) + { + if (index < dipswitches.Length) + { + dipswitches[index] = value; + } + } + + public bool ReadDipswitch(int index) + { + return dipswitches[index]; + } + + private void Sync() + { + SyncIRQ(); + SyncPRGBanks(); + SyncCHRBanks(); + SyncNametables(); + } + + private void SetBank(IntBuffer target, byte offset, byte size, int value) + { + for (int i = 0; i < size; i++) + { + int index = i + offset; + target[index] = value; + value++; + } + } + + private byte BitRev7(byte value) //adelikat: Bit reverses a 7 bit register, ugly but gets the job done + { + int newvalue = 0; + + newvalue |= (value & 0x01) << 6; + newvalue |= ((value >> 1) & 0x01) << 5; + newvalue |= ((value >> 2) & 0x01) << 4; + newvalue |= value & 0x08; + newvalue |= ((value >> 4) & 0x01) << 2; + newvalue |= ((value >> 5) & 0x01) << 1; + newvalue |= (value >> 6) & 0x01; + + return (byte)newvalue; + } + + private void SyncPRGBanks() + { + switch (prg_mode_select) + { + case 0: + SetBank(prg_banks, 0, 4, prg_bank_mask_8k - 3); + ram_bank = (prg_regs[3] << 2) + 3; + break; + case 1: + SetBank(prg_banks, 0, 2, prg_regs[1]); + SetBank(prg_banks, 2, 2, prg_bank_mask_8k - 1); + ram_bank = (prg_regs[3] << 1) + 1; + break; + case 2: + SetBank(prg_banks, 0, 1, prg_regs[0]); + SetBank(prg_banks, 1, 1, prg_regs[1]); + SetBank(prg_banks, 2, 1, prg_regs[2]); + SetBank(prg_banks, 3, 1, prg_bank_mask_8k); + ram_bank = prg_regs[3]; + break; + case 3: + SetBank(prg_banks, 0, 1, BitRev7(prg_regs[0])); + SetBank(prg_banks, 1, 1, BitRev7(prg_regs[1])); + SetBank(prg_banks, 2, 1, BitRev7(prg_regs[2])); + SetBank(prg_banks, 3, 1, prg_bank_mask_8k); + ram_bank = BitRev7(prg_regs[3]); + break; + case 4: + SetBank(prg_banks, 0, 4, prg_regs[3]); + ram_bank = (prg_regs[3] << 2) + 3; + break; + case 5: + SetBank(prg_banks, 0, 2, prg_regs[1]); + SetBank(prg_banks, 2, 2, prg_regs[3]); + ram_bank = (prg_regs[3] << 1) + 1; + break; + case 6: + SetBank(prg_banks, 0, 1, prg_regs[0]); + SetBank(prg_banks, 1, 1, prg_regs[1]); + SetBank(prg_banks, 2, 1, prg_regs[2]); + SetBank(prg_banks, 3, 1, prg_regs[3]); + ram_bank = prg_regs[3]; + break; + case 7: + SetBank(prg_banks, 0, 1, BitRev7(prg_regs[0])); + SetBank(prg_banks, 1, 1, BitRev7(prg_regs[1])); + SetBank(prg_banks, 2, 1, BitRev7(prg_regs[2])); + SetBank(prg_banks, 3, 1, BitRev7(prg_regs[3])); + ram_bank = BitRev7(prg_regs[3]); + break; + } + } + + private void SyncCHRBanks() + { + int mirror_chr_9002 = mirror_chr ? 0 : 2; + int mirror_chr_9003 = mirror_chr ? 1 : 3; + + switch (chr_mode_select) + { + case 0: + SetBank(chr_banks, 0, 8, (chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[0]) * 8); + break; + case 1: + SetBank(chr_banks, 0, 4, (chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[0]) * 4); + SetBank(chr_banks, 4, 4, (chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[4]) * 4); + break; + case 2: + SetBank(chr_banks, 0, 2, (chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[0]) * 2); + SetBank(chr_banks, 2, 2, (chr_block_mode ? (chr_block << 8) | chr_regs[mirror_chr_9002] & 0xFF : chr_regs[mirror_chr_9002]) * 2); + SetBank(chr_banks, 4, 2, (chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[4]) * 2); + SetBank(chr_banks, 6, 2, (chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[6]) * 2); + break; + case 3: + SetBank(chr_banks, 0, 1, chr_block_mode ? (chr_block << 8) | chr_regs[0] & 0xFF : chr_regs[0]); + SetBank(chr_banks, 1, 1, chr_block_mode ? (chr_block << 8) | chr_regs[1] & 0xFF : chr_regs[1]); + SetBank(chr_banks, 2, 1, chr_block_mode ? (chr_block << 8) | chr_regs[mirror_chr_9002] & 0xFF : chr_regs[mirror_chr_9002]); + SetBank(chr_banks, 3, 1, chr_block_mode ? (chr_block << 8) | chr_regs[mirror_chr_9003] & 0xFF : chr_regs[mirror_chr_9003]); + SetBank(chr_banks, 4, 1, chr_block_mode ? (chr_block << 8) | chr_regs[4] & 0xFF : chr_regs[4]); + SetBank(chr_banks, 5, 1, chr_block_mode ? (chr_block << 8) | chr_regs[5] & 0xFF : chr_regs[5]); + SetBank(chr_banks, 6, 1, chr_block_mode ? (chr_block << 8) | chr_regs[6] & 0xFF : chr_regs[6]); + SetBank(chr_banks, 7, 1, chr_block_mode ? (chr_block << 8) | chr_regs[7] & 0xFF : chr_regs[7]); + break; + } + } + + private void SyncNametables() + { + if (nt_advanced_control) + { + int[] m = new int[4]; + for (var i = 0; i < 4; i++) + { + m[i] = nt_regs[i] & 0x01; + } + SetMirroring(m[0], m[1], m[2], m[3]); + } } public override void WritePRG(int addr, byte value) { - switch (addr) + switch (addr & 0x7007) { - case 0x0000: - case 0x0004: - prg_banks[0] = (byte)(value & 0x7F); - break; + case 0x0000: //0x8000: PRG ROM select case 0x0001: - case 0x0005: - prg_banks[1] = (byte)(value & 0x7F); - break; case 0x0002: - case 0x0006: - prg_banks[2] = (byte)(value & 0x7F); - break; case 0x0003: + case 0x0004: + case 0x0005: + case 0x0006: case 0x0007: - prg_banks[3] = (byte)(value & 0x7F); + prg_regs[addr & 3] = (byte)(value & 0x7F); + SyncPRGBanks(); break; - case 0x1000: - chr_banks[0] &= 0xff00; - chr_banks[0] |= value; - break; + case 0x1000: //0x9000: CHR ROM lower 8 bits select case 0x1001: - chr_banks[1] &= 0xff00; - chr_banks[1] |= value; - break; case 0x1002: - chr_banks[2] &= 0xff00; - chr_banks[2] |= value; - break; case 0x1003: - chr_banks[3] &= 0xff00; - chr_banks[3] |= value; - break; case 0x1004: - chr_banks[4] &= 0xff00; - chr_banks[4] |= value; - break; case 0x1005: - chr_banks[5] &= 0xff00; - chr_banks[5] |= value; - break; case 0x1006: - chr_banks[6] &= 0xff00; - chr_banks[6] |= value; - break; case 0x1007: - chr_banks[7] &= 0xff00; - chr_banks[7] |= value; + chr_regs[addr & 7] &= 0xff00; + chr_regs[addr & 7] |= value; + SyncCHRBanks(); break; - case 0x2000: - chr_banks[0] &= 0x00ff; - chr_banks[0] |= (value << 8); - break; + case 0x2000: //0xA000: CHR ROM upper 8 bits select case 0x2001: - chr_banks[1] &= 0x00ff; - chr_banks[1] |= (value << 8); - break; case 0x2002: - chr_banks[2] &= 0x00ff; - chr_banks[2] |= (value << 8); - break; case 0x2003: - chr_banks[3] &= 0x00ff; - chr_banks[3] |= (value << 8); - break; case 0x2004: - chr_banks[4] &= 0x00ff; - chr_banks[4] |= (value << 8); - break; case 0x2005: - chr_banks[5] &= 0x00ff; - chr_banks[5] |= (value << 8); - break; case 0x2006: - chr_banks[6] &= 0x00ff; - chr_banks[6] |= (value << 8); - break; case 0x2007: - chr_banks[7] &= 0x00ff; - chr_banks[7] |= (value << 8); + chr_regs[addr & 7] &= 0x00ff; + chr_regs[addr & 7] |= (value << 8); + SyncCHRBanks(); break; - case 0x5000: + case 0x3000: //0xB000 Nametable Regs + case 0x3001: + case 0x3002: + case 0x3003: + nt_regs[addr & 3] &= 0xff00; + nt_regs[addr & 3] |= value; + SyncNametables(); + break; + + case 0x3004: + case 0x3005: + case 0x3006: + case 0x3007: + nt_regs[addr & 3] &= 0x00ff; + nt_regs[addr & 3] |= (value << 8); + SyncNametables(); + break; + + case 0x4000: //0xC000 IRQ operation + if (value.Bit(0)) + { + goto case 0x4002; + } + else + { + goto case 0x4003; + } + case 0x4001: //IRQ control + irq_count_down = value.Bit(7); + irq_count_up = value.Bit(6); + //Bit 3 enables IRQ prescaler adjusting at 0xC007. + irq_prescaler_size = value.Bit(2) ? 8 : 256; + + //TODO: Mode 4 (CPU reads) not implemented. No game actually seems to use it, however. + irq_source = (byte)(value & 0x03); + break; + case 0x4002: //IRQ acknowledge and disable + irq_pending = false; + irq_enable = false; + SyncIRQ(); + break; + case 0x4003: //IRQ enable + irq_enable = true; + SyncIRQ(); + break; + case 0x4004: //Prescaler + prescaler = (byte)(value ^ xor_reg); + break; + case 0x4005: //IRQ_Counter + irq_counter = (byte)(value ^ xor_reg); + break; + case 0x4006: //XOR Reg + xor_reg = value; + break; + case 0x4007: //IRQ prescaler adjust + //Poorly understood, and no games actually appear to use it. + //We therefore forego emulating it. + break; + + case 0x5000: //0xD000 Mapper Banking Control and Mirroring + case 0x5004: + //Only Mapper 209 can set this. It is always clear for Mapper 90 and always set for Mapper 211 + if (mapper_209) + { + nt_advanced_control = value.Bit(5); + } + nt_ram_disable = value.Bit(6); prg_mode_select = (byte)(value & 0x07); chr_mode_select = (byte)((value >> 3) & 0x03); sram_prg = value.Bit(7); + + SyncPRGBanks(); + SyncCHRBanks(); + SyncNametables(); break; - case 0x5001: //TODO: mapper 90 flag + case 0x5001: //0xD001: Mirroring + case 0x5005: switch (value & 0x3) { case 0: @@ -165,208 +440,202 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES break; } break; + case 0x5002: + case 0x5006: + nt_ram_select = value.Bit(7); + SyncNametables(); + break; + case 0x5003: + case 0x5007: + mirror_chr = value.Bit(7); + chr_block_mode = !value.Bit(5); + chr_block = (byte)(value & 0x1F); + SyncCHRBanks(); + break; } } - private byte BitRev7(byte value) //adelikat: Bit reverses a 7 bit register, ugly but gets the job done - { - byte newvalue = 0; - newvalue |= (byte)((value & 0x01) << 6); - newvalue |= (byte)(((value >> 1) & 0x01) << 5); - newvalue |= (byte)(((value >> 2) & 0x01) << 4); - newvalue |= (byte)(value & 0x08); - newvalue |= (byte)(((value >> 4) & 0x01 ) << 2); - newvalue |= (byte)(((value >> 5) & 0x01) << 1); - newvalue |= (byte)((value >> 6) & 0x01); - - return newvalue; - } - public override byte ReadPRG(int addr) { - int bank = 0; - switch (prg_mode_select) - { - case 0: - bank = 0xFF & prg_bank_mask_32k; - return ROM[(bank * 0x8000) + (addr & 0x7FFF)]; - case 1: - if (addr < 0x4000) - { - bank = prg_banks[0] & prg_bank_mask_16k; - } - else - { - bank = 0xFF & prg_bank_mask_16k; - - } - return ROM[(bank * 0x4000) + (addr & 0x3FFF)]; - case 2: - case 3: - if (addr < 0x2000) - { - bank = BitRev7(prg_banks[0]) & prg_bank_mask_8k; - } - else if (addr < 0x4000) - { - bank = BitRev7(prg_banks[1]) & prg_bank_mask_8k; - } - else if (addr < 0x6000) - { - bank = BitRev7(prg_banks[2]) & prg_bank_mask_8k; - } - else - { - bank = 0xFF & prg_bank_mask_8k; - } - return ROM[(bank * 0x2000) + (addr & 0x1FFF)]; - case 4: - bank = prg_banks[3] & prg_bank_mask_32k; - return ROM[(bank * 0x8000) + (addr & 0x7FFF)]; - case 5: - if (addr < 0x4000) - { - bank = prg_banks[0] & prg_bank_mask_16k; - } - else - { - bank = prg_banks[1] & prg_bank_mask_16k; - - } - return ROM[(bank * 0x4000) + (addr & 0x3FFF)]; - case 6: - case 7: - if (addr < 0x2000) - { - bank = BitRev7(prg_banks[0]) & prg_bank_mask_8k; - } - else if (addr < 0x4000) - { - bank = BitRev7(prg_banks[1]) & prg_bank_mask_8k; - } - else if (addr < 0x6000) - { - bank = BitRev7(prg_banks[2]) & prg_bank_mask_8k; - } - else - { - bank = BitRev7(prg_banks[3]) & prg_bank_mask_8k; - } - return ROM[(bank * 0x2000) + (addr & 0x1FFF)]; - } - - bank = prg_banks[0]; + int offset = addr & 0x1FFF; + int bank = prg_banks[addr >> 13]; bank &= prg_bank_mask_8k; - return ROM[(bank * 0x2000) + (addr & 0x1FFF)]; + return ROM[bank << 13 | offset]; } public override byte ReadWRAM(int addr) { - if (sram_prg) + return sram_prg ? ROM[ram_bank << 13 | addr & 0x1FFF] : base.ReadWRAM(addr); + } + + public override byte ReadEXP(int addr) + { + switch (addr) { - int bank = 0; - switch (prg_mode_select) + case 0x1000: + int value = dipswitches[0] ? 0x80 : 0x00; + value = dipswitches[1] ? value | 0x40 : value; + return (byte)(value | (NES.DB & 0x3F)); + case 0x1800: + return (byte)multiplication_result; + case 0x1801: + return (byte)(multiplication_result >> 8); + case 0x1803: + case 0x1804: + case 0x1805: + case 0x1806: + case 0x1807: + return ram_bytes[addr - 0x1803]; + default: + return base.ReadEXP(addr); + } + } + + public override void WriteEXP(int addr, byte value) + { + switch (addr) + { + case 0x1800: + multiplicator = value; + multiplication_result = multiplicator * multiplicand; + break; + case 0x1801: + multiplicand = value; + multiplication_result = multiplicator * multiplicand; + break; + case 0x1803: //It's not known if 0x1804 - 0x1807 are actually RAM. For safety, we'll assume it is. + case 0x1804: + case 0x1805: + case 0x1806: + case 0x1807: + ram_bytes[addr - 0x1803] = value; + break; + } + } + + public override void ClockCPU() + { + if (irq_source == 0) + { + ClockIRQ(); + } + } + + public void ClockIRQ() + { + int mask = irq_prescaler_size - 1; + + if (irq_count_up && !irq_count_down) + { + prescaler++; + if((prescaler & mask) == 0) { - case 0: - case 4: - bank = (prg_banks[3] << 2) + 3; - break; - case 1: - case 5: - bank = (prg_banks[3] << 1) + 3; - break; - case 2: - - case 6: - bank = prg_banks[3]; - break; - case 3: - case 7: - bank = BitRev7(prg_banks[3]); - break; + irq_counter++; + if(irq_counter == 0) + { + irq_pending = irq_enable; + } } - return ROM[(bank * 0x2000) + (addr + 0x1FFF)]; + } + + if (irq_count_down && !irq_count_up) + { + prescaler--; + if((prescaler & mask) == mask) + { + irq_counter--; + if(irq_counter == 0xFF) + { + irq_pending = irq_enable; + } + } + } + + SyncIRQ(); + } + + public void SyncIRQ() + { + SyncIRQ(irq_pending); + } + + public override void AddressPPU(int addr) + { + int a12 = (addr >> 12) & 1; + bool rising_edge = (a12 == 1 && a12_old == 0); + + if (rising_edge && irq_source == 1) + { + ClockIRQ(); + } + + a12_old = a12; + } + + public override byte PeekPPU(int addr) + { + if (addr < 0x2000) //Read CHR + { + int bank = chr_banks[addr >> 10]; + bank &= chr_bank_mask_1k; + int offset = addr & 0x3FF; + + return VROM[bank << 10 | offset]; + } + + if (nt_advanced_control) //Read from Nametables + { + addr -= 0x2000; + int nt = nt_regs[addr >> 10]; + int offset = addr & 0x3FF; + + if (!nt_ram_disable) + { + if(nt.Bit(7) == nt_ram_select) + { + return nt.Bit(0) ? NES.CIRAM[0x400 | offset] : NES.CIRAM[offset]; + } + } + + return VROM[nt << 10 | offset]; } else { - return base.ReadWRAM(addr); + return base.PeekPPU(addr); } } public override byte ReadPPU(int addr) { - if (addr < 0x2000) + if (irq_source == 2) { - int bank = 0; - switch (chr_mode_select) + ClockIRQ(); //No game ever should use this. + } + + if (addr < 0x2000) //Read CHR + { + int bank = chr_banks[addr >> 10]; + bank &= chr_bank_mask_1k; + int offset = addr & 0x3FF; + + return VROM[bank << 10 | offset]; + } + + if (nt_advanced_control) //Read from Nametables + { + addr -= 0x2000; + int nt = nt_regs[addr >> 10]; + int offset = addr & 0x3FF; + + if (!nt_ram_disable) { - default: - case 0: - bank = chr_banks[0] & chr_bank_mask_8k; - return VROM[(bank * 0x2000) + (addr & 0x1FFF)]; - case 1: - if (addr < 0x1000) - { - bank = chr_banks[0] & chr_bank_mask_4k; - } - else - { - bank = chr_banks[4] & chr_bank_mask_4k; - } - return VROM[(bank * 0x1000) + (addr & 0x0FFF)]; - case 2: - if (addr < 0x800) - { - bank = chr_banks[0] & chr_bank_mask_2k; - } - else if (addr < 0x1000) - { - bank = chr_banks[2] & chr_bank_mask_2k; - } - else if (addr < 0x1800) - { - bank = chr_banks[4] & chr_bank_mask_2k; - } - else - { - bank = chr_banks[6] & chr_bank_mask_2k; - } - return VROM[(bank * 0x0800) + (addr & 0x07FF)]; - case 3: - if (addr < 0x0400) - { - bank = chr_banks[0] & chr_bank_mask_1k; - } - else if (addr < 0x0800) - { - bank = chr_banks[1] & chr_bank_mask_1k; - } - else if (addr < 0x0C00) - { - bank = chr_banks[2] & chr_bank_mask_1k; - } - else if (addr < 0x1000) - { - bank = chr_banks[3] & chr_bank_mask_1k; - } - else if (addr < 0x1400) - { - bank = chr_banks[4] & chr_bank_mask_1k; - } - else if (addr < 0x1800) - { - bank = chr_banks[5] & chr_bank_mask_1k; - } - else if (addr < 0x1C00) - { - bank = chr_banks[6] & chr_bank_mask_1k; - } - else - { - bank = chr_banks[7] & chr_bank_mask_1k; - } - return VROM[(bank * 0x0400) + (addr & 0x03FF)]; + if(nt.Bit(7) == nt_ram_select) + { + return nt.Bit(0) ? NES.CIRAM[0x400 | offset] : NES.CIRAM[offset]; + } } + + return VROM[nt << 10 | offset]; } else { diff --git a/output/gamedb/gamedb.txt b/output/gamedb/gamedb.txt index ee9d567bd4..beb2dcef41 100644 --- a/output/gamedb/gamedb.txt +++ b/output/gamedb/gamedb.txt @@ -96,6 +96,7 @@ sha1:6DF9AECF5787C0833B0F05A9A83D0E58A6153977 Rumblestation 15-in-1 (Unl) NES sha1:E4BFD5AB3C3649DBD36B9A7280CF431641BCBCEC Peek-A-Boo Poker (Unl) NES board=NES-CNROM;PRG=32;CHR=24;WRAM=0 sha1:39294394A0631708F58397371CE14075AE1FB7E6 Peek-A-Boo Poker (Panesian) NES board=NES-CNROM;PRG=32;CHR=64;WRAM=0 sha1:C87E7E6A68DD9C7E24652CD2C7D390A14E8ADF04 Lagrange Point NES board=KONAMI-VRC-7;PRG=512;CHR=0;WRAM=8;PRAM=8;PCB=352402;BATT=true +sha1:2E0889131DA5BA9505A15B94887113F4360D98CD Shin Samurai Spirits 2 - Haoumaru Jigoku Hen (Unl) NES board=MAPPER209;PRG=128;CHR=512;WRAM=8 ;;;;;;;;;;;;;;;;;;;----------------------------------------------------------------------- ;;;;;;;;;;;;;;;;;;;-----------------------------------------------------------------------