GBHawk: mapper and audio updates

This commit is contained in:
alyosha-tas 2017-11-14 14:43:58 -05:00
parent ff815dec65
commit 574a78ee86
3 changed files with 197 additions and 47 deletions

View File

@ -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()

View File

@ -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;

View File

@ -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);
}
}
}
}