From 574a78ee8643d4d00ce1f874bebec86b895fa6fd Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 14 Nov 2017 14:43:58 -0500 Subject: [PATCH] GBHawk: mapper and audio updates --- .../Consoles/Nintendo/GBHawk/Audio.cs | 121 +++++++++++++++++- .../Consoles/Nintendo/GBHawk/GBHawk.cs | 65 +++++----- .../Nintendo/GBHawk/Mappers/Mapper_MBC2.cs | 58 ++++++--- 3 files changed, 197 insertions(+), 47 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs index a0d5dfc8ab..dbdaeeeed6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs @@ -12,6 +12,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { public GBHawk Core { get; set; } + public static int[] DUTY_CYCLES = new int[] {0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 0}; + public const int NR10 = 0; public const int NR11 = 1; public const int NR12 = 2; @@ -55,7 +60,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public byte st_vol; public bool env_add; public byte per; - public ushort frq; + public int frq; public bool trigger; public bool len_en; public bool DAC_pow; @@ -66,6 +71,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // channel states public byte length_counter; + public byte volume_state; + public int frq_shadow; + public int internal_cntr; + public byte duty_counter; + public bool enable; + + // channel non-states + public int output; } struct CTRL_Object @@ -346,7 +359,113 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public void tick() { + // calculate square1's output + if (SQ1.enable) + { + SQ1.internal_cntr++; + if (SQ1.internal_cntr == (2048 - SQ1.frq_shadow) * 4) + { + SQ1.internal_cntr = 0; + SQ1.duty_counter++; + SQ1.duty_counter &= 7; + SQ1.output = DUTY_CYCLES[SQ1.duty * 8 + SQ1.duty_counter]; + SQ1.output *= SQ1.volume_state; + } + } + + // calculate square2's output + if (SQ2.enable) + { + SQ2.internal_cntr++; + if (SQ2.internal_cntr == (2048 - SQ2.frq) * 4) + { + SQ2.internal_cntr = 0; + SQ2.duty_counter++; + SQ2.duty_counter &= 7; + + SQ2.output = DUTY_CYCLES[SQ2.duty * 8 + SQ2.duty_counter]; + SQ2.output *= SQ2.volume_state; + } + } + + // calculate wave output + + // calculate noise output + + + + + + // frame sequencer ticks at a rate of 512 hz (or every time a 13 bit counter rolls over) + sequencer_tick++; + + if (sequencer_tick==8192) + { + sequencer_tick = 0; + + sequencer_vol++; sequencer_vol &= 0x7; + sequencer_len++; sequencer_len &= 0x7; + sequencer_swp++; sequencer_swp &= 0x7; + + // clock the lengths + if ((sequencer_len == 1) || (sequencer_len == 3) || (sequencer_len == 5) || (sequencer_len == 7)) + { + if (SQ1.len_en && SQ1.length_counter > 0) { SQ1.length_counter--; if (SQ1.length_counter == 0) { SQ1.enable = false; } } + if (SQ2.len_en && SQ2.length_counter > 0) { SQ2.length_counter--; if (SQ2.length_counter == 0) { SQ2.enable = false; } } + if (WAVE.len_en && WAVE.length_counter > 0) { WAVE.length_counter--; if (WAVE.length_counter == 0) { WAVE.enable = false; } } + if (NOISE.len_en && NOISE.length_counter > 0) { NOISE.length_counter--; if (NOISE.length_counter == 0) { NOISE.enable = false; } } + } + + // clock the sweep + if ((sequencer_swp == 3) || (sequencer_swp == 7)) + { + if (((SQ1.swp_period > 0) || (SQ1.shift > 0)) && (SQ1.swp_period > 0)) + { + int shadow_frq = SQ1.frq_shadow; + shadow_frq = shadow_frq >> SQ1.shift; + if (SQ1.negate) { shadow_frq = -shadow_frq; } + shadow_frq += SQ1.frq_shadow; + + // disable channel if overflow + if ((uint) shadow_frq > 2047) + { + SQ1.enable = false; + } + else + { + shadow_frq &= 0x7FF; + SQ1.frq = shadow_frq; + SQ1.frq_shadow = shadow_frq; + + // note that we also write back the frequency to the actual register + Audio_Regs[NR13] = (byte)(SQ1.frq & 0xFF); + Audio_Regs[NR14] &= 0xF8; + Audio_Regs[NR14] |= (byte)((SQ1.frq >> 8) & 7); + + // after writing, we repeat the process and do another overflow check + shadow_frq = SQ1.frq_shadow; + shadow_frq = shadow_frq >> SQ1.shift; + if (SQ1.negate) { shadow_frq = -shadow_frq; } + shadow_frq += SQ1.frq_shadow; + + if ((uint)shadow_frq > 2047) + { + SQ1.enable = false; + } + } + } + } + + // clock the volume envelope + if (sequencer_vol == 0) + { + if (SQ1.per > 0) { if (SQ1.env_add) { SQ1.volume_state++; } else { SQ1.volume_state--; } } + if (SQ2.per > 0) { if (SQ2.env_add) { SQ2.volume_state++; } else { SQ2.volume_state--; } } + if (WAVE.per > 0) { if (WAVE.env_add) { WAVE.volume_state++; } else { WAVE.volume_state--; } } + if (NOISE.per > 0) { if (NOISE.env_add) { NOISE.volume_state++; } else { NOISE.volume_state--; } } + } + } } public void power_off() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index 471b2a6b09..fd1d50b131 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -142,36 +142,38 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk private void Setup_Mapper() { // setup up mapper based on header entry + string mppr; + switch (header[0x47]) { - case 0x0: mapper = new MapperDefault(); break; - case 0x1: mapper = new MapperMBC1(); break; - case 0x2: mapper = new MapperMBC1(); break; - case 0x3: mapper = new MapperMBC1(); break; - case 0x5: mapper = new MapperMBC2(); break; - case 0x6: mapper = new MapperMBC2(); break; - case 0x8: mapper = new MapperDefault(); break; - case 0x9: mapper = new MapperDefault(); break; - case 0xB: mapper = new MapperMMM01(); break; - case 0xC: mapper = new MapperMMM01(); break; - case 0xD: mapper = new MapperMMM01(); break; - case 0xF: mapper = new MapperMBC3(); break; - case 0x10: mapper = new MapperMBC3(); break; - case 0x11: mapper = new MapperMBC3(); break; - case 0x12: mapper = new MapperMBC3(); break; - case 0x13: mapper = new MapperMBC3(); break; - case 0x19: mapper = new MapperMBC5(); break; - case 0x1A: mapper = new MapperMBC5(); break; - case 0x1B: mapper = new MapperMBC5(); break; - case 0x1C: mapper = new MapperMBC5(); break; - case 0x1D: mapper = new MapperMBC5(); break; - case 0x1E: mapper = new MapperMBC5(); break; - case 0x20: mapper = new MapperMBC6(); break; - case 0x22: mapper = new MapperMBC7(); break; - case 0xFC: mapper = new MapperCamera(); break; - case 0xFD: mapper = new MapperTAMA5(); break; - case 0xFE: mapper = new MapperHuC3(); break; - case 0xFF: mapper = new MapperHuC1(); break; + case 0x0: mapper = new MapperDefault(); mppr = "NROM"; break; + case 0x1: mapper = new MapperMBC1(); mppr = "MBC1"; break; + case 0x2: mapper = new MapperMBC1(); mppr = "MBC1"; break; + case 0x3: mapper = new MapperMBC1(); mppr = "MBC1"; break; + case 0x5: mapper = new MapperMBC2(); mppr = "MBC2"; break; + case 0x6: mapper = new MapperMBC2(); mppr = "MBC2"; break; + case 0x8: mapper = new MapperDefault(); mppr = "NROM"; break; + case 0x9: mapper = new MapperDefault(); mppr = "NROM"; break; + case 0xB: mapper = new MapperMMM01(); mppr = "MMM01"; break; + case 0xC: mapper = new MapperMMM01(); mppr = "MMM01"; break; + case 0xD: mapper = new MapperMMM01(); mppr = "MMM01"; break; + case 0xF: mapper = new MapperMBC3(); mppr = "MBC3"; break; + case 0x10: mapper = new MapperMBC3(); mppr = "MBC3"; break; + case 0x11: mapper = new MapperMBC3(); mppr = "MBC3"; break; + case 0x12: mapper = new MapperMBC3(); mppr = "MBC3"; break; + case 0x13: mapper = new MapperMBC3(); mppr = "MBC3"; break; + case 0x19: mapper = new MapperMBC5(); mppr = "MBC5"; break; + case 0x1A: mapper = new MapperMBC5(); mppr = "MBC5"; break; + case 0x1B: mapper = new MapperMBC5(); mppr = "MBC5"; break; + case 0x1C: mapper = new MapperMBC5(); mppr = "MBC5"; break; + case 0x1D: mapper = new MapperMBC5(); mppr = "MBC5"; break; + case 0x1E: mapper = new MapperMBC5(); mppr = "MBC5"; break; + case 0x20: mapper = new MapperMBC6(); mppr = "MBC6"; break; + case 0x22: mapper = new MapperMBC7(); mppr = "MBC7"; break; + case 0xFC: mapper = new MapperCamera(); mppr = "CAM"; break; + case 0xFD: mapper = new MapperTAMA5(); mppr = "TAMA5"; break; + case 0xFE: mapper = new MapperHuC3(); mppr = "HuC3"; break; + case 0xFF: mapper = new MapperHuC1(); mppr = "HuC1"; break; case 0x4: case 0x7: @@ -202,7 +204,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } Console.Write("Mapper: "); - Console.WriteLine(header[0x47]); + Console.WriteLine(mppr); cart_RAM = null; @@ -223,7 +225,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 5: cart_RAM = new byte[0x10000]; break; + } + // mbc2 carts have built in RAM + if (mppr == "MBC2") + { + cart_RAM = new byte[0x200]; } mapper.Core = this; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs index b131098538..6327d00491 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC2.cs @@ -4,30 +4,39 @@ using System; namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { - // Default mapper with no bank switching + // MBC1 with bank switching and RAM public class MapperMBC2 : MapperBase { + public int ROM_bank; + public int RAM_bank; + public bool RAM_enable; + public int ROM_mask; + public override void Initialize() { - // nothing to initialize + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; } public override byte ReadMemory(ushort addr) { - if (addr < 0x8000) + if (addr < 0x4000) { return Core._rom[addr]; } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else if ((addr >= 0xA000) && (addr < 0xA200)) + { + return Core.cart_RAM[addr - 0xA000]; + } else { - if (Core.cart_RAM != null) - { - return Core.cart_RAM[addr - 0xA000]; - } - else - { - return 0; - } + return 0xFF; } } @@ -38,22 +47,37 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public override void WriteMemory(ushort addr, byte value) { - if (addr < 0x8000) + if (addr < 0x2000) { - // no mapping hardware available + RAM_enable = (addr & 0x100) > 0; } - else + else if (addr < 0x4000) { - if (Core.cart_RAM != null) + if ((addr & 0x100) > 0) { - Core.cart_RAM[addr - 0xA000] = value; + ROM_bank = value & 0xF; } } + else if ((addr >= 0xA000) && (addr < 0xA200)) + { + if (RAM_enable) + { + Core.cart_RAM[addr - 0xA000] = (byte)(value & 0xF); + } + } } public override void PokeMemory(ushort addr, byte value) { WriteMemory(addr, value); } + + public override void SyncState(Serializer ser) + { + ser.Sync("ROM_Bank", ref ROM_bank); + ser.Sync("ROM_Mask", ref ROM_mask); + ser.Sync("RAM_Bank", ref RAM_bank); + ser.Sync("RAM_enable", ref RAM_enable); + } } -} +} \ No newline at end of file