diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs index 24685ad908..0dba320f46 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs @@ -35,17 +35,17 @@ namespace BizHawk.Emulation.Common.Components.LR35902 IDLE, IDLE, IDLE, - IDLE, - IDLE, DEC16, SPl, SPh, IDLE, WR, SPl, SPh, PCh, - INT_GET, // NOTE: here is where we check for a cancelled IRQ - DEC16, SPl, SPh, IDLE, + INT_GET, W,// NOTE: here is where we check for a cancelled IRQ + DEC16, SPl, SPh, WR, SPl, SPh, PCl, IDLE, IDLE, + IDLE, + IDLE, TR, PCl, W, ASGN, PCh, 0, IDLE, diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs index 6ca017c6d8..401f1fe397 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs @@ -387,9 +387,6 @@ namespace BizHawk.Emulation.Common.Components.LR35902 case INT_GET: // check if any interrupts got cancelled along the way // interrupt src = 5 sets the PC to zero as observed - - Console.WriteLine(int_src); - if (int_src == 0) { if (interrupt_enable.Bit(0)) { interrupt_src -= 1; } @@ -429,8 +426,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; } - Regs[W] = INT_vectors[int_src]; - + Regs[cur_instr[instr_pntr++]] = INT_vectors[int_src]; break; } totalExecutedCycles++; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs index 04310f2455..5d3cbe082c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs @@ -1,117 +1,118 @@ -using System; - -using BizHawk.Common; -using BizHawk.Common.BufferExtensions; -using BizHawk.Emulation.Common; -using BizHawk.Common.NumberExtensions; - -namespace BizHawk.Emulation.Cores.Nintendo.GBHawk +using System; + +using BizHawk.Common; +using BizHawk.Common.BufferExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { // Audio Emulation - public class Audio : ISoundProvider - { - 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 static int[] DIVISOR = new int[] { 8, 16, 32, 48, 64, 80, 96, 112 }; - - - public const int NR10 = 0; - public const int NR11 = 1; - public const int NR12 = 2; - public const int NR13 = 3; - public const int NR14 = 4; - public const int NR21 = 5; - public const int NR22 = 6; - public const int NR23 = 7; - public const int NR24 = 8; - public const int NR30 = 9; - public const int NR31 = 10; - public const int NR32 = 11; - public const int NR33 = 12; - public const int NR34 = 13; - public const int NR41 = 14; - public const int NR42 = 15; - public const int NR43 = 16; - public const int NR44 = 17; - public const int NR50 = 18; - public const int NR51 = 19; - public const int NR52 = 20; - - public static int[] unused_bits = new int[] { 0x80, 0x3F, 0x00, 0xFF, 0xBF, - 0x3F, 0x00, 0xFF, 0xBF, - 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, - 0xFF, 0x00, 0x00, 0xBF, - 0x00, 0x00, 0x70}; - - public byte[] Audio_Regs = new byte[21]; - + public class Audio : ISoundProvider + { + 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 static int[] DIVISOR = new int[] { 8, 16, 32, 48, 64, 80, 96, 112 }; + + + public const int NR10 = 0; + public const int NR11 = 1; + public const int NR12 = 2; + public const int NR13 = 3; + public const int NR14 = 4; + public const int NR21 = 5; + public const int NR22 = 6; + public const int NR23 = 7; + public const int NR24 = 8; + public const int NR30 = 9; + public const int NR31 = 10; + public const int NR32 = 11; + public const int NR33 = 12; + public const int NR34 = 13; + public const int NR41 = 14; + public const int NR42 = 15; + public const int NR43 = 16; + public const int NR44 = 17; + public const int NR50 = 18; + public const int NR51 = 19; + public const int NR52 = 20; + + public static int[] unused_bits = new int[] { 0x80, 0x3F, 0x00, 0xFF, 0xBF, + 0x3F, 0x00, 0xFF, 0xBF, + 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, + 0xFF, 0x00, 0x00, 0xBF, + 0x00, 0x00, 0x70}; + + public byte[] Audio_Regs = new byte[21]; + public byte[] Wave_RAM = new byte[16]; // Audio Variables // derived - public bool WAVE_DAC_pow; - public bool NOISE_wdth_md; - public bool SQ1_negate; - public bool SQ1_trigger, SQ2_trigger, WAVE_trigger, NOISE_trigger; - public bool SQ1_len_en, SQ2_len_en, WAVE_len_en, NOISE_len_en; - public bool SQ1_env_add, SQ2_env_add, NOISE_env_add; - public byte WAVE_vol_code; - public byte NOISE_clk_shft; - public byte NOISE_div_code; - public byte SQ1_shift; + public bool WAVE_DAC_pow; + public bool NOISE_wdth_md; + public bool SQ1_negate; + public bool SQ1_trigger, SQ2_trigger, WAVE_trigger, NOISE_trigger; + public bool SQ1_len_en, SQ2_len_en, WAVE_len_en, NOISE_len_en; + public bool SQ1_env_add, SQ2_env_add, NOISE_env_add; + public byte WAVE_vol_code; + public byte NOISE_clk_shft; + public byte NOISE_div_code; + public byte SQ1_shift; public byte SQ1_duty, SQ2_duty; public byte SQ1_st_vol, SQ2_st_vol, NOISE_st_vol; - public byte SQ1_per, SQ2_per, NOISE_per; - public byte SQ1_swp_prd; - public int SQ1_frq, SQ2_frq, WAVE_frq; + public byte SQ1_per, SQ2_per, NOISE_per; + public byte SQ1_swp_prd; + public int SQ1_frq, SQ2_frq, WAVE_frq; public ushort SQ1_length, SQ2_length, WAVE_length, NOISE_length; // state + public bool WAVE_can_get; public bool SQ1_calc_done; public bool SQ1_swp_enable; public bool SQ1_vol_done, SQ2_vol_done, NOISE_vol_done; - public bool SQ1_enable, SQ2_enable, WAVE_enable, NOISE_enable; - public byte SQ1_vol_state, SQ2_vol_state, NOISE_vol_state; - public byte SQ1_duty_cntr, SQ2_duty_cntr; - public byte WAVE_wave_cntr; - public int SQ1_frq_shadow; + public bool SQ1_enable, SQ2_enable, WAVE_enable, NOISE_enable; + public byte SQ1_vol_state, SQ2_vol_state, NOISE_vol_state; + public byte SQ1_duty_cntr, SQ2_duty_cntr; + public byte WAVE_wave_cntr; + public int SQ1_frq_shadow; public int SQ1_intl_cntr, SQ2_intl_cntr, WAVE_intl_cntr, NOISE_intl_cntr; - public int SQ1_vol_per, SQ2_vol_per, NOISE_vol_per; - public int SQ1_intl_swp_cnt; - public int NOISE_LFSR; + public int SQ1_vol_per, SQ2_vol_per, NOISE_vol_per; + public int SQ1_intl_swp_cnt; + public int NOISE_LFSR; public ushort SQ1_len_cntr, SQ2_len_cntr, WAVE_len_cntr, NOISE_len_cntr; // computed public int SQ1_output, SQ2_output, WAVE_output, NOISE_output; // Contol Variables - public bool AUD_CTRL_vin_L_en; - public bool AUD_CTRL_vin_R_en; - public bool AUD_CTRL_sq1_L_en; - public bool AUD_CTRL_sq2_L_en; - public bool AUD_CTRL_wave_L_en; - public bool AUD_CTRL_noise_L_en; - public bool AUD_CTRL_sq1_R_en; - public bool AUD_CTRL_sq2_R_en; - public bool AUD_CTRL_wave_R_en; - public bool AUD_CTRL_noise_R_en; - public bool AUD_CTRL_power; - public byte AUD_CTRL_vol_L; - public byte AUD_CTRL_vol_R; - - public int sequencer_len, sequencer_vol, sequencer_swp, sequencer_tick; - - public int master_audio_clock; - - public byte ReadReg(int addr) - { - byte ret = 0; - - switch (addr) + public bool AUD_CTRL_vin_L_en; + public bool AUD_CTRL_vin_R_en; + public bool AUD_CTRL_sq1_L_en; + public bool AUD_CTRL_sq2_L_en; + public bool AUD_CTRL_wave_L_en; + public bool AUD_CTRL_noise_L_en; + public bool AUD_CTRL_sq1_R_en; + public bool AUD_CTRL_sq2_R_en; + public bool AUD_CTRL_wave_R_en; + public bool AUD_CTRL_noise_R_en; + public bool AUD_CTRL_power; + public byte AUD_CTRL_vol_L; + public byte AUD_CTRL_vol_R; + + public int sequencer_len, sequencer_vol, sequencer_swp, sequencer_tick; + + public int master_audio_clock; + + public byte ReadReg(int addr) + { + byte ret = 0; + + switch (addr) { case 0xFF10: ret = (byte)(Audio_Regs[NR10] | unused_bits[NR10]); break; // NR10 (sweep) case 0xFF11: ret = (byte)(Audio_Regs[NR11] | unused_bits[NR11]); break; // NR11 (sound length / wave pattern duty %) @@ -136,104 +137,110 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0xFF26: ret = (byte)(Read_NR52() | unused_bits[NR52]); break; // NR52 (ctrl) // wave ram table - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - ret = Wave_RAM[addr & 0x0F]; - break; - } - - return ret; - } - - public void WriteReg(int addr, byte value) + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + if (WAVE_enable) + { + if (WAVE_can_get) { ret = Wave_RAM[WAVE_wave_cntr >> 1]; } + else { ret = 0xFF; } + } + else { ret = Wave_RAM[addr & 0x0F]; } + + break; + } + + return ret; + } + + public void WriteReg(int addr, byte value) { // while power is on, everything is writable - if (AUD_CTRL_power) - { - switch (addr) - { + if (AUD_CTRL_power) + { + switch (addr) + { case 0xFF10: // NR10 (sweep) - Audio_Regs[NR10] = value; - SQ1_swp_prd = (byte)((value & 0x70) >> 4); - SQ1_negate = (value & 8) > 0; - SQ1_shift = (byte)(value & 7); - - if (!SQ1_negate && SQ1_calc_done) { SQ1_enable = false; } - break; + Audio_Regs[NR10] = value; + SQ1_swp_prd = (byte)((value & 0x70) >> 4); + SQ1_negate = (value & 8) > 0; + SQ1_shift = (byte)(value & 7); + + if (!SQ1_negate && SQ1_calc_done) { SQ1_enable = false; } + break; case 0xFF11: // NR11 (sound length / wave pattern duty %) - Audio_Regs[NR11] = value; - SQ1_duty = (byte)((value & 0xC0) >> 6); - SQ1_length = (ushort)(64 - (value & 0x3F)); - SQ1_len_cntr = SQ1_length; - break; + Audio_Regs[NR11] = value; + SQ1_duty = (byte)((value & 0xC0) >> 6); + SQ1_length = (ushort)(64 - (value & 0x3F)); + SQ1_len_cntr = SQ1_length; + break; case 0xFF12: // NR12 (envelope) - Audio_Regs[NR12] = value; - SQ1_st_vol = (byte)((value & 0xF0) >> 4); - SQ1_env_add = (value & 8) > 0; - SQ1_per = (byte)(value & 7); - if (SQ1_per == 0) { SQ1_per = 8; } - if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; } - break; + Audio_Regs[NR12] = value; + SQ1_st_vol = (byte)((value & 0xF0) >> 4); + SQ1_env_add = (value & 8) > 0; + SQ1_per = (byte)(value & 7); + if (SQ1_per == 0) { SQ1_per = 8; } + if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; } + break; case 0xFF13: // NR13 (freq low) - Audio_Regs[NR13] = value; - SQ1_frq &= 0x700; - SQ1_frq |= value; - break; + Audio_Regs[NR13] = value; + SQ1_frq &= 0x700; + SQ1_frq |= value; + break; case 0xFF14: // NR14 (freq hi) - Audio_Regs[NR14] = value; - SQ1_trigger = (value & 0x80) > 0; - SQ1_frq &= 0xFF; - SQ1_frq |= (ushort)((value & 7) << 8); - - if (((sequencer_len & 1) > 0)) - { - if (!SQ1_len_en && ((value & 0x40) > 0) && (SQ1_len_cntr > 0)) - { - SQ1_len_cntr--; - if ((SQ1_len_cntr == 0) && !SQ1_trigger) { SQ1_enable = SQ1_swp_enable = false; } - } - } - - if (SQ1_trigger) - { - SQ1_enable = true; - SQ1_vol_done = false; - if (SQ1_len_cntr == 0) - { - SQ1_len_cntr = 64; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { SQ1_len_cntr--; } - } - SQ1_intl_cntr = 0; - SQ1_vol_state = SQ1_st_vol; - SQ1_vol_per = (SQ1_per > 0) ? SQ1_per : 8; - SQ1_frq_shadow = SQ1_frq; - - SQ1_intl_swp_cnt = SQ1_swp_prd > 0 ? SQ1_swp_prd : 8; - SQ1_calc_done = false; - + Audio_Regs[NR14] = value; + SQ1_trigger = (value & 0x80) > 0; + SQ1_frq &= 0xFF; + SQ1_frq |= (ushort)((value & 7) << 8); + + if (((sequencer_len & 1) > 0)) + { + if (!SQ1_len_en && ((value & 0x40) > 0) && (SQ1_len_cntr > 0)) + { + SQ1_len_cntr--; + if ((SQ1_len_cntr == 0) && !SQ1_trigger) { SQ1_enable = SQ1_swp_enable = false; } + } + } + + if (SQ1_trigger) + { + SQ1_enable = true; + SQ1_vol_done = false; + if (SQ1_len_cntr == 0) + { + SQ1_len_cntr = 64; + if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { SQ1_len_cntr--; } + } + SQ1_vol_state = SQ1_st_vol; + SQ1_vol_per = (SQ1_per > 0) ? SQ1_per : 8; + SQ1_frq_shadow = SQ1_frq; + SQ1_intl_cntr = (2048 - SQ1_frq_shadow) * 4; + + SQ1_intl_swp_cnt = SQ1_swp_prd > 0 ? SQ1_swp_prd : 8; + SQ1_calc_done = false; + if ((SQ1_shift > 0) || (SQ1_swp_prd > 0)) { SQ1_swp_enable = true; - } + } else { SQ1_swp_enable = false; - } - + } + if (SQ1_shift > 0) { int shadow_frq = SQ1_frq_shadow; @@ -251,461 +258,479 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (SQ1_negate) { SQ1_calc_done = true; } } - if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; } + if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; } } - SQ1_len_en = (value & 0x40) > 0; - break; + SQ1_len_en = (value & 0x40) > 0; + break; case 0xFF16: // NR21 (sound length / wave pattern duty %) - Audio_Regs[NR21] = value; - SQ2_duty = (byte)((value & 0xC0) >> 6); - SQ2_length = (ushort)(64 - (value & 0x3F)); - SQ2_len_cntr = SQ2_length; - break; + Audio_Regs[NR21] = value; + SQ2_duty = (byte)((value & 0xC0) >> 6); + SQ2_length = (ushort)(64 - (value & 0x3F)); + SQ2_len_cntr = SQ2_length; + break; case 0xFF17: // NR22 (envelope) - Audio_Regs[NR22] = value; - SQ2_st_vol = (byte)((value & 0xF0) >> 4); - SQ2_env_add = (value & 8) > 0; + Audio_Regs[NR22] = value; + SQ2_st_vol = (byte)((value & 0xF0) >> 4); + SQ2_env_add = (value & 8) > 0; SQ2_per = (byte)(value & 7); //if (SQ2_per == 0) { SQ2_per = 8; } - if ((value & 0xF8) == 0) { SQ2_enable = false; } - break; + if ((value & 0xF8) == 0) { SQ2_enable = false; } + break; case 0xFF18: // NR23 (freq low) - Audio_Regs[NR23] = value; - SQ2_frq &= 0x700; - SQ2_frq |= value; - break; + Audio_Regs[NR23] = value; + SQ2_frq &= 0x700; + SQ2_frq |= value; + break; case 0xFF19: // NR24 (freq hi) - Audio_Regs[NR24] = value; - SQ2_trigger = (value & 0x80) > 0; - SQ2_frq &= 0xFF; - SQ2_frq |= (ushort)((value & 7) << 8); - - if ((sequencer_len & 1) > 0) - { - if (!SQ2_len_en && ((value & 0x40) > 0) && (SQ2_len_cntr > 0)) - { - SQ2_len_cntr--; - if ((SQ2_len_cntr == 0) && !SQ2_trigger) { SQ2_enable = false; } - } - } - - if (SQ2_trigger) - { - SQ2_enable = true; - SQ2_vol_done = false; - - if (SQ2_len_cntr == 0) - { - SQ2_len_cntr = 64; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { SQ2_len_cntr--; } - } - SQ2_intl_cntr = 0; - SQ2_vol_state = SQ2_st_vol; - SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; - if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; } - } - - SQ2_len_en = (value & 0x40) > 0; - - break; - case 0xFF1A: // NR30 (on/off) - Audio_Regs[NR30] = value; - WAVE_DAC_pow = (value & 0x80) > 0; - if (!WAVE_DAC_pow) { WAVE_enable = false; } - break; - case 0xFF1B: // NR31 (length) - Audio_Regs[NR31] = value; - WAVE_length = (ushort)(256 - value); - WAVE_len_cntr = WAVE_length; - break; - case 0xFF1C: // NR32 (level output) - Audio_Regs[NR32] = value; - WAVE_vol_code = (byte)((value & 0x60) >> 5); - break; - case 0xFF1D: // NR33 (freq low) - Audio_Regs[NR33] = value; - WAVE_frq &= 0x700; - WAVE_frq |= value; - break; - case 0xFF1E: // NR34 (freq hi) - Audio_Regs[NR34] = value; - WAVE_trigger = (value & 0x80) > 0; - WAVE_frq &= 0xFF; - WAVE_frq |= (ushort)((value & 7) << 8); - - if ((sequencer_len & 1) > 0) - { - if (!WAVE_len_en && ((value & 0x40) > 0) && (WAVE_len_cntr > 0)) - { - WAVE_len_cntr--; - if ((WAVE_len_cntr == 0) && !WAVE_trigger) { WAVE_enable = false; } - } - } - - if (WAVE_trigger) - { - WAVE_enable = true; - - if (WAVE_len_cntr == 0) - { - WAVE_len_cntr = 256; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { WAVE_len_cntr--; } - } - WAVE_intl_cntr = 0; - WAVE_wave_cntr = 0; - if (!WAVE_DAC_pow) { WAVE_enable = false; } - } - - WAVE_len_en = (value & 0x40) > 0; - - break; - case 0xFF20: // NR41 (length) - Audio_Regs[NR41] = value; - NOISE_length = (ushort)(64 - (value & 0x3F)); - NOISE_len_cntr = NOISE_length; - break; - case 0xFF21: // NR42 (envelope) - Audio_Regs[NR42] = value; - NOISE_st_vol = (byte)((value & 0xF0) >> 4); - NOISE_env_add = (value & 8) > 0; - NOISE_per = (byte)(value & 7); - //if (NOISE_per == 0) { NOISE_per = 8; } - if ((value & 0xF8) == 0) { NOISE_enable = false; } - break; - case 0xFF22: // NR43 (shift) - Audio_Regs[NR43] = value; - NOISE_clk_shft = (byte)((value & 0xF0) >> 4); - NOISE_wdth_md = (value & 8) > 0; - NOISE_div_code = (byte)(value & 7); - break; - case 0xFF23: // NR44 (trigger) - Audio_Regs[NR44] = value; - NOISE_trigger = (value & 0x80) > 0; - - if ((sequencer_len & 1) > 0) - { - if (!NOISE_len_en && ((value & 0x40) > 0) && (NOISE_len_cntr > 0)) - { - NOISE_len_cntr--; - if ((NOISE_len_cntr == 0) && !NOISE_trigger) { NOISE_enable = false; } - } - } - - if (NOISE_trigger) - { - NOISE_enable = true; - NOISE_vol_done = false; - - if (NOISE_len_cntr == 0) - { - NOISE_len_cntr = 64; - if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { NOISE_len_cntr--; } - } - NOISE_intl_cntr = 0; - NOISE_vol_state = NOISE_st_vol; - NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8; - NOISE_LFSR = 0x7FFF; - if ((NOISE_vol_state == 0) && !NOISE_env_add) { NOISE_enable = false; } + Audio_Regs[NR24] = value; + SQ2_trigger = (value & 0x80) > 0; + SQ2_frq &= 0xFF; + SQ2_frq |= (ushort)((value & 7) << 8); + + if ((sequencer_len & 1) > 0) + { + if (!SQ2_len_en && ((value & 0x40) > 0) && (SQ2_len_cntr > 0)) + { + SQ2_len_cntr--; + if ((SQ2_len_cntr == 0) && !SQ2_trigger) { SQ2_enable = false; } + } } - NOISE_len_en = (value & 0x40) > 0; - break; + if (SQ2_trigger) + { + SQ2_enable = true; + SQ2_vol_done = false; + + if (SQ2_len_cntr == 0) + { + SQ2_len_cntr = 64; + if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { SQ2_len_cntr--; } + } + SQ2_intl_cntr = (2048 - SQ2_frq) * 4; + SQ2_vol_state = SQ2_st_vol; + SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; + if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; } + } + + SQ2_len_en = (value & 0x40) > 0; + + break; + case 0xFF1A: // NR30 (on/off) + Audio_Regs[NR30] = value; + WAVE_DAC_pow = (value & 0x80) > 0; + if (!WAVE_DAC_pow) { WAVE_enable = false; } + break; + case 0xFF1B: // NR31 (length) + Audio_Regs[NR31] = value; + WAVE_length = (ushort)(256 - value); + WAVE_len_cntr = WAVE_length; + break; + case 0xFF1C: // NR32 (level output) + Audio_Regs[NR32] = value; + WAVE_vol_code = (byte)((value & 0x60) >> 5); + break; + case 0xFF1D: // NR33 (freq low) + Audio_Regs[NR33] = value; + WAVE_frq &= 0x700; + WAVE_frq |= value; + break; + case 0xFF1E: // NR34 (freq hi) + Audio_Regs[NR34] = value; + WAVE_trigger = (value & 0x80) > 0; + WAVE_frq &= 0xFF; + WAVE_frq |= (ushort)((value & 7) << 8); + + if ((sequencer_len & 1) > 0) + { + if (!WAVE_len_en && ((value & 0x40) > 0) && (WAVE_len_cntr > 0)) + { + WAVE_len_cntr--; + if ((WAVE_len_cntr == 0) && !WAVE_trigger) { WAVE_enable = false; } + } + } + + if (WAVE_trigger) + { + // some corruption occurs if triggering while reading + if (WAVE_enable && WAVE_intl_cntr == 2) + { + // we want to use the previous wave cntr value since it was just incremented + int t_wave_cntr = (WAVE_wave_cntr + 1) & 31; + if ((t_wave_cntr >> 1) < 4) + { + Wave_RAM[0] = Wave_RAM[t_wave_cntr >> 1]; + } + else + { + Wave_RAM[0] = Wave_RAM[(t_wave_cntr >> 3) * 4]; + Wave_RAM[1] = Wave_RAM[(t_wave_cntr >> 3) * 4 + 1]; + Wave_RAM[2] = Wave_RAM[(t_wave_cntr >> 3) * 4 + 2]; + Wave_RAM[3] = Wave_RAM[(t_wave_cntr >> 3) * 4 + 3]; + } + } + + WAVE_enable = true; + + if (WAVE_len_cntr == 0) + { + WAVE_len_cntr = 256; + if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { WAVE_len_cntr--; } + } + WAVE_intl_cntr = (2048 - WAVE_frq) * 2 + 6; // trigger delay for wave channel + WAVE_wave_cntr = 0; + if (!WAVE_DAC_pow) { WAVE_enable = false; } + } + + WAVE_len_en = (value & 0x40) > 0; + + break; + case 0xFF20: // NR41 (length) + Audio_Regs[NR41] = value; + NOISE_length = (ushort)(64 - (value & 0x3F)); + NOISE_len_cntr = NOISE_length; + break; + case 0xFF21: // NR42 (envelope) + Audio_Regs[NR42] = value; + NOISE_st_vol = (byte)((value & 0xF0) >> 4); + NOISE_env_add = (value & 8) > 0; + NOISE_per = (byte)(value & 7); + //if (NOISE_per == 0) { NOISE_per = 8; } + if ((value & 0xF8) == 0) { NOISE_enable = false; } + break; + case 0xFF22: // NR43 (shift) + Audio_Regs[NR43] = value; + NOISE_clk_shft = (byte)((value & 0xF0) >> 4); + NOISE_wdth_md = (value & 8) > 0; + NOISE_div_code = (byte)(value & 7); + break; + case 0xFF23: // NR44 (trigger) + Audio_Regs[NR44] = value; + NOISE_trigger = (value & 0x80) > 0; + + if ((sequencer_len & 1) > 0) + { + if (!NOISE_len_en && ((value & 0x40) > 0) && (NOISE_len_cntr > 0)) + { + NOISE_len_cntr--; + if ((NOISE_len_cntr == 0) && !NOISE_trigger) { NOISE_enable = false; } + } + } + + if (NOISE_trigger) + { + NOISE_enable = true; + NOISE_vol_done = false; + + if (NOISE_len_cntr == 0) + { + NOISE_len_cntr = 64; + if (((value & 0x40) > 0) && ((sequencer_len & 1) > 0)) { NOISE_len_cntr--; } + } + NOISE_intl_cntr = (DIVISOR[NOISE_div_code] << NOISE_clk_shft); + NOISE_vol_state = NOISE_st_vol; + NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8; + NOISE_LFSR = 0x7FFF; + if ((NOISE_vol_state == 0) && !NOISE_env_add) { NOISE_enable = false; } + } + + NOISE_len_en = (value & 0x40) > 0; + break; case 0xFF24: // NR50 (ctrl) - Audio_Regs[NR50] = value; - AUD_CTRL_vin_L_en = (value & 0x80) > 0; - AUD_CTRL_vol_L = (byte)((value & 0x70) >> 4); - AUD_CTRL_vin_R_en = (value & 8) > 0; - AUD_CTRL_vol_R = (byte)(value & 7); - break; + Audio_Regs[NR50] = value; + AUD_CTRL_vin_L_en = (value & 0x80) > 0; + AUD_CTRL_vol_L = (byte)((value & 0x70) >> 4); + AUD_CTRL_vin_R_en = (value & 8) > 0; + AUD_CTRL_vol_R = (byte)(value & 7); + break; case 0xFF25: // NR51 (ctrl) - Audio_Regs[NR51] = value; - AUD_CTRL_noise_L_en = (value & 0x80) > 0; - AUD_CTRL_wave_L_en = (value & 0x40) > 0; - AUD_CTRL_sq2_L_en = (value & 0x20) > 0; - AUD_CTRL_sq1_L_en = (value & 0x10) > 0; - AUD_CTRL_noise_R_en = (value & 8) > 0; - AUD_CTRL_wave_R_en = (value & 4) > 0; - AUD_CTRL_sq2_R_en = (value & 2) > 0; - AUD_CTRL_sq1_R_en = (value & 1) > 0; - break; - case 0xFF26: // NR52 (ctrl) - AUD_CTRL_power = (value & 0x80) > 0; - - if (!AUD_CTRL_power) { power_off(); } + Audio_Regs[NR51] = value; + AUD_CTRL_noise_L_en = (value & 0x80) > 0; + AUD_CTRL_wave_L_en = (value & 0x40) > 0; + AUD_CTRL_sq2_L_en = (value & 0x20) > 0; + AUD_CTRL_sq1_L_en = (value & 0x10) > 0; + AUD_CTRL_noise_R_en = (value & 8) > 0; + AUD_CTRL_wave_R_en = (value & 4) > 0; + AUD_CTRL_sq2_R_en = (value & 2) > 0; + AUD_CTRL_sq1_R_en = (value & 1) > 0; + break; + case 0xFF26: // NR52 (ctrl) + AUD_CTRL_power = (value & 0x80) > 0; + + if (!AUD_CTRL_power) { power_off(); } break; // wave ram table - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - Wave_RAM[addr & 0x0F] = value; - break; - } + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + if (WAVE_enable) + { + if (WAVE_can_get) { Wave_RAM[WAVE_wave_cntr >> 1] = value; } + } + else { Wave_RAM[addr & 0xF] = value; } + + break; + } } // when power is off, only length counters and waveRAM are effected by writes - else - { - switch (addr) - { + else + { + switch (addr) + { case 0xFF11: // NR11 (sound length / wave pattern duty %) - SQ1_length = (ushort)(64 - (value & 0x3F)); - SQ1_len_cntr = SQ1_length; - break; + SQ1_length = (ushort)(64 - (value & 0x3F)); + SQ1_len_cntr = SQ1_length; + break; case 0xFF16: // NR21 (sound length / wave pattern duty %) - SQ2_length = (ushort)(64 - (value & 0x3F)); - SQ2_len_cntr = SQ2_length; - break; + SQ2_length = (ushort)(64 - (value & 0x3F)); + SQ2_len_cntr = SQ2_length; + break; case 0xFF1B: // NR31 (length) - WAVE_length = (ushort)(256 - value); - WAVE_len_cntr = WAVE_length; - break; + WAVE_length = (ushort)(256 - value); + WAVE_len_cntr = WAVE_length; + break; case 0xFF20: // NR41 (length) - NOISE_length = (ushort)(64 - (value & 0x3F)); - NOISE_len_cntr = NOISE_length; - break; - case 0xFF26: // NR52 (ctrl) - AUD_CTRL_power = (value & 0x80) > 0; + NOISE_length = (ushort)(64 - (value & 0x3F)); + NOISE_len_cntr = NOISE_length; + break; + case 0xFF26: // NR52 (ctrl) + AUD_CTRL_power = (value & 0x80) > 0; if (AUD_CTRL_power) { sequencer_vol = 0; sequencer_len = 0; sequencer_swp = 0; - } + } break; // wave ram table - case 0xFF30: - case 0xFF31: - case 0xFF32: - case 0xFF33: - case 0xFF34: - case 0xFF35: - case 0xFF36: - case 0xFF37: - case 0xFF38: - case 0xFF39: - case 0xFF3A: - case 0xFF3B: - case 0xFF3C: - case 0xFF3D: - case 0xFF3E: - case 0xFF3F: - Wave_RAM[addr & 0x0F] = value; - break; - } - } - } - - public void tick() + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + Wave_RAM[addr & 0x0F] = value; + break; + } + } + } + + public void tick() { // calculate square1's output - if (SQ1_enable) - { - SQ1_intl_cntr++; - if (SQ1_intl_cntr >= (2048 - SQ1_frq_shadow) * 4) - { - SQ1_intl_cntr = 0; - SQ1_duty_cntr++; - SQ1_duty_cntr &= 7; - - SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr]; - SQ1_output *= SQ1_vol_state; - } + if (SQ1_enable) + { + SQ1_intl_cntr--; + if (SQ1_intl_cntr == 0) + { + SQ1_intl_cntr = (2048 - SQ1_frq_shadow) * 4; + SQ1_duty_cntr++; + SQ1_duty_cntr &= 7; + + SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr]; + SQ1_output *= SQ1_vol_state; + } } // calculate square2's output - if (SQ2_enable) - { - SQ2_intl_cntr++; - if (SQ2_intl_cntr >= (2048 - SQ2_frq) * 4) - { - SQ2_intl_cntr = 0; - SQ2_duty_cntr++; - SQ2_duty_cntr &= 7; - - SQ2_output = DUTY_CYCLES[SQ2_duty * 8 + SQ2_duty_cntr]; - SQ2_output *= SQ2_vol_state; - } + if (SQ2_enable) + { + SQ2_intl_cntr--; + if (SQ2_intl_cntr == 0) + { + SQ2_intl_cntr = (2048 - SQ2_frq) * 4; + SQ2_duty_cntr++; + SQ2_duty_cntr &= 7; + + SQ2_output = DUTY_CYCLES[SQ2_duty * 8 + SQ2_duty_cntr]; + SQ2_output *= SQ2_vol_state; + } } // calculate wave output - if (WAVE_enable) - { - WAVE_intl_cntr++; - if (WAVE_intl_cntr >= (2048 - WAVE_frq) * 2) - { - WAVE_intl_cntr = 0; - WAVE_wave_cntr++; - WAVE_wave_cntr &= 0x1F; - - byte sample = Wave_RAM[WAVE_wave_cntr >> 1]; - - if ((WAVE_wave_cntr & 1) == 0) - { - sample = (byte)(sample >> 4); - } - - if (WAVE_vol_code == 0) - { - sample = (byte)((sample & 0xF) >> 4); - } - else if (WAVE_vol_code == 1) - { - sample = (byte)(sample & 0xF); - } - else if (WAVE_vol_code == 2) - { - sample = (byte)((sample & 0xF) >> 1); - } - else - { - sample = (byte)((sample & 0xF) >> 2); - } - - WAVE_output = sample; - - if (!WAVE_DAC_pow) { WAVE_output = 0; } - } + WAVE_can_get = false; + if (WAVE_enable) + { + WAVE_intl_cntr--; + + if (WAVE_intl_cntr == 0) + { + WAVE_intl_cntr = (2048 - WAVE_frq) * 2; + WAVE_wave_cntr++; + WAVE_wave_cntr &= 0x1F; + + WAVE_can_get = true; + + byte sample = Wave_RAM[WAVE_wave_cntr >> 1]; + + if ((WAVE_wave_cntr & 1) == 0) + { + sample = (byte)(sample >> 4); + } + + if (WAVE_vol_code == 0) + { + sample = (byte)((sample & 0xF) >> 4); + } + else if (WAVE_vol_code == 1) + { + sample = (byte)(sample & 0xF); + } + else if (WAVE_vol_code == 2) + { + sample = (byte)((sample & 0xF) >> 1); + } + else + { + sample = (byte)((sample & 0xF) >> 2); + } + + WAVE_output = sample; + + if (!WAVE_DAC_pow) { WAVE_output = 0; } + } } // calculate noise output - if (NOISE_enable) - { - NOISE_intl_cntr++; - if (NOISE_intl_cntr >= (DIVISOR[NOISE_div_code] << NOISE_clk_shft)) - { - NOISE_intl_cntr = 0; - int bit_lfsr = (NOISE_LFSR & 1) ^ ((NOISE_LFSR & 2) >> 1); - - NOISE_LFSR = (NOISE_LFSR >> 1) & 0x3FFF; - NOISE_LFSR |= (bit_lfsr << 14); - - if (NOISE_wdth_md) - { - NOISE_LFSR = NOISE_LFSR & 0x7FBF; - NOISE_LFSR |= (bit_lfsr << 6); - } - - NOISE_output = NOISE_LFSR & 1; - NOISE_output *= NOISE_vol_state; - } + if (NOISE_enable) + { + NOISE_intl_cntr--; + if (NOISE_intl_cntr == 0) + { + NOISE_intl_cntr = (DIVISOR[NOISE_div_code] << NOISE_clk_shft); + int bit_lfsr = (NOISE_LFSR & 1) ^ ((NOISE_LFSR & 2) >> 1); + + NOISE_LFSR = (NOISE_LFSR >> 1) & 0x3FFF; + NOISE_LFSR |= (bit_lfsr << 14); + + if (NOISE_wdth_md) + { + NOISE_LFSR = NOISE_LFSR & 0x7FBF; + NOISE_LFSR |= (bit_lfsr << 6); + } + + NOISE_output = NOISE_LFSR & 1; + NOISE_output *= NOISE_vol_state; + } } // add up components to each channel - int L_final = 0; - int R_final = 0; - - if (AUD_CTRL_sq1_L_en) { L_final += SQ1_output; } - if (AUD_CTRL_sq2_L_en) { L_final += SQ2_output; } - if (AUD_CTRL_wave_L_en) { L_final += WAVE_output; } - if (AUD_CTRL_noise_L_en) { L_final += NOISE_output; } - - if (AUD_CTRL_sq1_R_en) { R_final += SQ1_output; } - if (AUD_CTRL_sq2_R_en) { R_final += SQ2_output; } - if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; } - if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; } - - L_final *= (AUD_CTRL_vol_L + 1); + int L_final = 0; + int R_final = 0; + + if (AUD_CTRL_sq1_L_en) { L_final += SQ1_output; } + if (AUD_CTRL_sq2_L_en) { L_final += SQ2_output; } + if (AUD_CTRL_wave_L_en) { L_final += WAVE_output; } + if (AUD_CTRL_noise_L_en) { L_final += NOISE_output; } + + if (AUD_CTRL_sq1_R_en) { R_final += SQ1_output; } + if (AUD_CTRL_sq2_R_en) { R_final += SQ2_output; } + if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; } + if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; } + + L_final *= (AUD_CTRL_vol_L + 1); R_final *= (AUD_CTRL_vol_R + 1); // send out an actual sample every 94 cycles - master_audio_clock++; - if (master_audio_clock == 94) - { - master_audio_clock = 0; - if (AudioClocks < 1500) - { + master_audio_clock++; + if (master_audio_clock == 94) + { + master_audio_clock = 0; + if (AudioClocks < 1500) + { AudioSamples[AudioClocks] = (short)(L_final * 4); - /* - Console_Write(SQ1_output); - Console_Write(" "); - Console_Write(SQ2_output); - Console_Write(" "); - Console_Write(WAVE_output); - Console_Write(" "); - Console_WriteLine(NOISE_output); - */ - AudioClocks++; - AudioSamples[AudioClocks] = (short)(R_final * 4); - AudioClocks++; - } + AudioClocks++; + AudioSamples[AudioClocks] = (short)(R_final * 4); + AudioClocks++; + } } // 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_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) > 0) - { - if (SQ1_len_en && SQ1_len_cntr > 0) - { - SQ1_len_cntr--; - if (SQ1_len_cntr == 0) { SQ1_enable = SQ1_swp_enable = false; } - } - if (SQ2_len_en && SQ2_len_cntr > 0) - { - SQ2_len_cntr--; - if (SQ2_len_cntr == 0) { SQ2_enable = false; } - } - if (WAVE_len_en && WAVE_len_cntr > 0) - { - WAVE_len_cntr--; - if (WAVE_len_cntr == 0) { WAVE_enable = false; } - } - if (NOISE_len_en && NOISE_len_cntr > 0) - { - NOISE_len_cntr--; - if (NOISE_len_cntr == 0) { NOISE_enable = false; } - } + if ((sequencer_len & 1) > 0) + { + if (SQ1_len_en && SQ1_len_cntr > 0) + { + SQ1_len_cntr--; + if (SQ1_len_cntr == 0) { SQ1_enable = SQ1_swp_enable = false; } + } + if (SQ2_len_en && SQ2_len_cntr > 0) + { + SQ2_len_cntr--; + if (SQ2_len_cntr == 0) { SQ2_enable = false; } + } + if (WAVE_len_en && WAVE_len_cntr > 0) + { + WAVE_len_cntr--; + if (WAVE_len_cntr == 0) { WAVE_enable = false; } + } + if (NOISE_len_en && NOISE_len_cntr > 0) + { + NOISE_len_cntr--; + if (NOISE_len_cntr == 0) { NOISE_enable = false; } + } } // clock the sweep - if ((sequencer_swp == 3) || (sequencer_swp == 7)) - { - SQ1_intl_swp_cnt--; - if ((SQ1_intl_swp_cnt == 0) && SQ1_swp_enable) - { - SQ1_intl_swp_cnt = SQ1_swp_prd > 0 ? SQ1_swp_prd : 8; - - if ((SQ1_swp_prd > 0)) - { - int shadow_frq = SQ1_frq_shadow; - shadow_frq = shadow_frq >> SQ1_shift; - if (SQ1_negate) { shadow_frq = -shadow_frq; } + if ((sequencer_swp == 3) || (sequencer_swp == 7)) + { + SQ1_intl_swp_cnt--; + if ((SQ1_intl_swp_cnt == 0) && SQ1_swp_enable) + { + SQ1_intl_swp_cnt = SQ1_swp_prd > 0 ? SQ1_swp_prd : 8; + + if ((SQ1_swp_prd > 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; // set negate mode flag that disables channel is negate clerar if (SQ1_negate) { SQ1_calc_done = true; } // disable channel if overflow - if ((uint)shadow_frq > 2047) - { - SQ1_enable = SQ1_swp_enable = false; - } - else + if ((uint)shadow_frq > 2047) + { + SQ1_enable = SQ1_swp_enable = false; + } + else { if (SQ1_shift > 0) { @@ -727,22 +752,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if ((uint)shadow_frq > 2047) { SQ1_enable = SQ1_swp_enable = false; - } - } - } - } - } + } + } + } + } + } } // clock the volume envelope - if (sequencer_vol == 0) - { - if (SQ1_per > 0) - { - SQ1_vol_per--; - if (SQ1_vol_per == 0) - { - SQ1_vol_per = (SQ1_per > 0) ? SQ1_per : 8; + if (sequencer_vol == 0) + { + if (SQ1_per > 0) + { + SQ1_vol_per--; + if (SQ1_vol_per == 0) + { + SQ1_vol_per = (SQ1_per > 0) ? SQ1_per : 8; if (!SQ1_vol_done) { if (SQ1_env_add) @@ -755,15 +780,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (SQ1_vol_state >= 1) { SQ1_vol_state--; } else { SQ1_vol_done = true; } } - } - } - } - if (SQ2_per > 0) - { - SQ2_vol_per--; - if (SQ2_vol_per == 0) - { - SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; + } + } + } + if (SQ2_per > 0) + { + SQ2_vol_per--; + if (SQ2_vol_per == 0) + { + SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; if (!SQ2_vol_done) { if (SQ2_env_add) @@ -776,15 +801,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (SQ2_vol_state >= 1) { SQ2_vol_state--; } else { SQ2_vol_done = true; } } - } - } - } - if (NOISE_per > 0) - { - NOISE_vol_per--; - if (NOISE_vol_per == 0) - { - NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8; + } + } + } + if (NOISE_per > 0) + { + NOISE_vol_per--; + if (NOISE_vol_per == 0) + { + NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8; if (!NOISE_vol_done) { if (NOISE_env_add) @@ -797,190 +822,192 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (NOISE_vol_state >= 1) { NOISE_vol_state--; } else { NOISE_vol_done = true; } } - } - } - } - } - } - } - - public void power_off() - { - for (int i = 0; i < 21; i++) - { - Audio_Regs[i] = 0; + } + } + } + } + } + } + + public void power_off() + { + for (int i = 0; i < 21; i++) + { + Audio_Regs[i] = 0; } // reset derived values - sync_channels(); - - // reset state variables - SQ1_enable = SQ1_swp_enable = false; - SQ2_enable = false; - WAVE_enable = false; - NOISE_enable = false; - - SQ1_len_en = false; - SQ2_len_en = false; - WAVE_len_en = false; - NOISE_len_en = false; - - sequencer_len = 0; - sequencer_vol = 0; - sequencer_swp = 0; - - master_audio_clock = 0; - } - - public void Reset() - { - Wave_RAM = new byte[16]; - - Audio_Regs = new byte[21]; - - AudioClocks = 0; - master_audio_clock = 0; - - sequencer_len = 0; - sequencer_swp = 0; - sequencer_vol = 0; - sequencer_tick = 0; - } - - public void SyncState(Serializer ser) - { - ser.Sync("Audio_Regs", ref Audio_Regs, false); + sync_channels(); + + // reset state variables + SQ1_enable = SQ1_swp_enable = false; + SQ2_enable = false; + WAVE_enable = false; + NOISE_enable = false; + + SQ1_len_en = false; + SQ2_len_en = false; + WAVE_len_en = false; + NOISE_len_en = false; + + sequencer_len = 0; + sequencer_vol = 0; + sequencer_swp = 0; + + master_audio_clock = 0; + } + + public void Reset() + { + Wave_RAM = new byte[] { 0x84, 0x40, 0x43, 0xAA, 0x2D, 0x78, 0x92, 0x3C, + 0x60, 0x59, 0x59, 0xB0, 0x34, 0xB8, 0x2E, 0xDA }; + + Audio_Regs = new byte[21]; + + AudioClocks = 0; + master_audio_clock = 0; + + sequencer_len = 0; + sequencer_swp = 0; + sequencer_vol = 0; + sequencer_tick = 0; + } + + public void SyncState(Serializer ser) + { + ser.Sync("Audio_Regs", ref Audio_Regs, false); ser.Sync("Wave_Ram", ref Wave_RAM, false); // save state variables + ser.Sync("WAVE_can_get", ref WAVE_can_get); ser.Sync("SQ1_vol_done", ref SQ1_vol_done); ser.Sync("SQ2_vol_done", ref SQ2_vol_done); ser.Sync("NOISE_vol_done", ref NOISE_vol_done); ser.Sync("SQ1_calc_done", ref SQ1_calc_done); ser.Sync("SQ1_swp_enable", ref SQ1_swp_enable); - ser.Sync("SQ1_length_counter", ref SQ1_len_cntr); - ser.Sync("SQ2_length_counter", ref SQ2_len_cntr); - ser.Sync("WAVE_length_counter", ref WAVE_len_cntr); - ser.Sync("NOISE_length_counter", ref NOISE_len_cntr); - ser.Sync("SQ1_enable", ref SQ1_enable); - ser.Sync("SQ2_enable", ref SQ2_enable); - ser.Sync("WAVE_enable", ref WAVE_enable); - ser.Sync("NOISE_enable", ref NOISE_enable); - ser.Sync("SQ1_vol_state", ref SQ1_vol_state); - ser.Sync("SQ2_vol_state", ref SQ2_vol_state); - ser.Sync("NOISE_vol_state", ref NOISE_vol_state); - ser.Sync("SQ1_duty_cntr", ref SQ1_duty_cntr); - ser.Sync("SQ2_duty_cntr", ref SQ2_duty_cntr); - ser.Sync("WAVE_wave_cntr", ref WAVE_wave_cntr); - ser.Sync("SQ1_frq_shadow", ref SQ1_frq_shadow); - ser.Sync("SQ1_intl_cntr", ref SQ1_intl_cntr); - ser.Sync("SQ2_intl_cntr", ref SQ2_intl_cntr); - ser.Sync("WAVE_intl_cntr", ref WAVE_intl_cntr); - ser.Sync("NOISE_intl_cntr", ref NOISE_intl_cntr); - ser.Sync("SQ1_vol_per", ref SQ1_vol_per); - ser.Sync("SQ2_vol_per", ref SQ2_vol_per); - ser.Sync("NOISE_vol_per", ref NOISE_vol_per); - ser.Sync("SQ1_intl_swp_cnt", ref SQ1_intl_swp_cnt); - ser.Sync("NOISE_LFSR", ref NOISE_LFSR); - ser.Sync("SQ1_len_cntr", ref SQ1_len_cntr); - ser.Sync("SQ2_len_cntr", ref SQ2_len_cntr); - ser.Sync("WAVE_len_cntr", ref WAVE_len_cntr); - ser.Sync("NOISE_len_cntr", ref NOISE_len_cntr); - - - ser.Sync("sequencer_len", ref sequencer_len); - ser.Sync("sequencer_vol", ref sequencer_vol); - ser.Sync("sequencer_swp", ref sequencer_swp); - ser.Sync("sequencer_tick", ref sequencer_tick); - + ser.Sync("SQ1_length_counter", ref SQ1_len_cntr); + ser.Sync("SQ2_length_counter", ref SQ2_len_cntr); + ser.Sync("WAVE_length_counter", ref WAVE_len_cntr); + ser.Sync("NOISE_length_counter", ref NOISE_len_cntr); + ser.Sync("SQ1_enable", ref SQ1_enable); + ser.Sync("SQ2_enable", ref SQ2_enable); + ser.Sync("WAVE_enable", ref WAVE_enable); + ser.Sync("NOISE_enable", ref NOISE_enable); + ser.Sync("SQ1_vol_state", ref SQ1_vol_state); + ser.Sync("SQ2_vol_state", ref SQ2_vol_state); + ser.Sync("NOISE_vol_state", ref NOISE_vol_state); + ser.Sync("SQ1_duty_cntr", ref SQ1_duty_cntr); + ser.Sync("SQ2_duty_cntr", ref SQ2_duty_cntr); + ser.Sync("WAVE_wave_cntr", ref WAVE_wave_cntr); + ser.Sync("SQ1_frq_shadow", ref SQ1_frq_shadow); + ser.Sync("SQ1_intl_cntr", ref SQ1_intl_cntr); + ser.Sync("SQ2_intl_cntr", ref SQ2_intl_cntr); + ser.Sync("WAVE_intl_cntr", ref WAVE_intl_cntr); + ser.Sync("NOISE_intl_cntr", ref NOISE_intl_cntr); + ser.Sync("SQ1_vol_per", ref SQ1_vol_per); + ser.Sync("SQ2_vol_per", ref SQ2_vol_per); + ser.Sync("NOISE_vol_per", ref NOISE_vol_per); + ser.Sync("SQ1_intl_swp_cnt", ref SQ1_intl_swp_cnt); + ser.Sync("NOISE_LFSR", ref NOISE_LFSR); + ser.Sync("SQ1_len_cntr", ref SQ1_len_cntr); + ser.Sync("SQ2_len_cntr", ref SQ2_len_cntr); + ser.Sync("WAVE_len_cntr", ref WAVE_len_cntr); + ser.Sync("NOISE_len_cntr", ref NOISE_len_cntr); + + + ser.Sync("sequencer_len", ref sequencer_len); + ser.Sync("sequencer_vol", ref sequencer_vol); + ser.Sync("sequencer_swp", ref sequencer_swp); + ser.Sync("sequencer_tick", ref sequencer_tick); + ser.Sync("master_audio_clock", ref master_audio_clock); // get derived state - if (ser.IsReader) - { - sync_channels(); - } - } - - public void sync_channels() - { - - SQ1_swp_prd = (byte)((Audio_Regs[NR10] & 0x70) >> 4); - SQ1_negate = (Audio_Regs[NR10] & 8) > 0; - SQ1_shift = (byte)(Audio_Regs[NR10] & 7); - - SQ1_duty = (byte)((Audio_Regs[NR11] & 0xC0) >> 6); - SQ1_length = (ushort)(64 - Audio_Regs[NR11] & 0x3F); - - SQ1_st_vol = (byte)((Audio_Regs[NR12] & 0xF0) >> 4); - SQ1_env_add = (Audio_Regs[NR12] & 8) > 0; - SQ1_per = (byte)(Audio_Regs[NR12] & 7); - - SQ1_frq &= 0x700; - SQ1_frq |= Audio_Regs[NR13]; - - SQ1_trigger = (Audio_Regs[NR14] & 0x80) > 0; - SQ1_len_en = (Audio_Regs[NR14] & 0x40) > 0; - SQ1_frq &= 0xFF; + if (ser.IsReader) + { + sync_channels(); + } + } + + public void sync_channels() + { + + SQ1_swp_prd = (byte)((Audio_Regs[NR10] & 0x70) >> 4); + SQ1_negate = (Audio_Regs[NR10] & 8) > 0; + SQ1_shift = (byte)(Audio_Regs[NR10] & 7); + + SQ1_duty = (byte)((Audio_Regs[NR11] & 0xC0) >> 6); + SQ1_length = (ushort)(64 - Audio_Regs[NR11] & 0x3F); + + SQ1_st_vol = (byte)((Audio_Regs[NR12] & 0xF0) >> 4); + SQ1_env_add = (Audio_Regs[NR12] & 8) > 0; + SQ1_per = (byte)(Audio_Regs[NR12] & 7); + + SQ1_frq &= 0x700; + SQ1_frq |= Audio_Regs[NR13]; + + SQ1_trigger = (Audio_Regs[NR14] & 0x80) > 0; + SQ1_len_en = (Audio_Regs[NR14] & 0x40) > 0; + SQ1_frq &= 0xFF; SQ1_frq |= (ushort)((Audio_Regs[NR14] & 7) << 8); - SQ2_duty = (byte)((Audio_Regs[NR21] & 0xC0) >> 6); - SQ2_length = (ushort)(64 - Audio_Regs[NR21] & 0x3F); - - SQ2_st_vol = (byte)((Audio_Regs[NR22] & 0xF0) >> 4); - SQ2_env_add = (Audio_Regs[NR22] & 8) > 0; - SQ2_per = (byte)(Audio_Regs[NR22] & 7); - - SQ2_frq &= 0x700; - SQ2_frq |= Audio_Regs[NR23]; - - SQ2_trigger = (Audio_Regs[NR24] & 0x80) > 0; - SQ2_len_en = (Audio_Regs[NR24] & 0x40) > 0; - SQ2_frq &= 0xFF; - SQ2_frq |= (ushort)((Audio_Regs[NR24] & 7) << 8); - - WAVE_DAC_pow = (Audio_Regs[NR30] & 0x80) > 0; - - WAVE_length = (ushort)(256 - Audio_Regs[NR31]); - - WAVE_vol_code = (byte)((Audio_Regs[NR32] & 0x60) >> 5); - - WAVE_frq &= 0x700; - WAVE_frq |= Audio_Regs[NR33]; - - WAVE_trigger = (Audio_Regs[NR34] & 0x80) > 0; - WAVE_len_en = (Audio_Regs[NR34] & 0x40) > 0; - WAVE_frq &= 0xFF; - WAVE_frq |= (ushort)((Audio_Regs[NR34] & 7) << 8); - - NOISE_length = (ushort)(64 - Audio_Regs[NR41] & 0x3F); - - NOISE_st_vol = (byte)((Audio_Regs[NR42] & 0xF0) >> 4); - NOISE_env_add = (Audio_Regs[NR42] & 8) > 0; - NOISE_per = (byte)(Audio_Regs[NR42] & 7); - - NOISE_clk_shft = (byte)((Audio_Regs[NR43] & 0xF0) >> 4); - NOISE_wdth_md = (Audio_Regs[NR43] & 8) > 0; - NOISE_div_code = (byte)(Audio_Regs[NR43] & 7); - - WAVE_trigger = (Audio_Regs[NR44] & 0x80) > 0; - WAVE_len_en = (Audio_Regs[NR44] & 0x40) > 0; - - AUD_CTRL_vin_L_en = (Audio_Regs[NR50] & 0x80) > 0; - AUD_CTRL_vol_L = (byte)((Audio_Regs[NR50] & 0x70) >> 4); - AUD_CTRL_vin_R_en = (Audio_Regs[NR50] & 8) > 0; - AUD_CTRL_vol_R = (byte)(Audio_Regs[NR50] & 7); - - AUD_CTRL_noise_L_en = (Audio_Regs[NR51] & 0x80) > 0; - AUD_CTRL_wave_L_en = (Audio_Regs[NR51] & 0x40) > 0; - AUD_CTRL_sq2_L_en = (Audio_Regs[NR51] & 0x20) > 0; - AUD_CTRL_sq1_L_en = (Audio_Regs[NR51] & 0x10) > 0; - AUD_CTRL_noise_R_en = (Audio_Regs[NR51] & 8) > 0; - AUD_CTRL_wave_R_en = (Audio_Regs[NR51] & 4) > 0; - AUD_CTRL_sq2_R_en = (Audio_Regs[NR51] & 2) > 0; - AUD_CTRL_sq1_R_en = (Audio_Regs[NR51] & 1) > 0; - - AUD_CTRL_power = (Audio_Regs[NR51] & 0x80) > 0; + SQ2_duty = (byte)((Audio_Regs[NR21] & 0xC0) >> 6); + SQ2_length = (ushort)(64 - Audio_Regs[NR21] & 0x3F); + + SQ2_st_vol = (byte)((Audio_Regs[NR22] & 0xF0) >> 4); + SQ2_env_add = (Audio_Regs[NR22] & 8) > 0; + SQ2_per = (byte)(Audio_Regs[NR22] & 7); + + SQ2_frq &= 0x700; + SQ2_frq |= Audio_Regs[NR23]; + + SQ2_trigger = (Audio_Regs[NR24] & 0x80) > 0; + SQ2_len_en = (Audio_Regs[NR24] & 0x40) > 0; + SQ2_frq &= 0xFF; + SQ2_frq |= (ushort)((Audio_Regs[NR24] & 7) << 8); + + WAVE_DAC_pow = (Audio_Regs[NR30] & 0x80) > 0; + + WAVE_length = (ushort)(256 - Audio_Regs[NR31]); + + WAVE_vol_code = (byte)((Audio_Regs[NR32] & 0x60) >> 5); + + WAVE_frq &= 0x700; + WAVE_frq |= Audio_Regs[NR33]; + + WAVE_trigger = (Audio_Regs[NR34] & 0x80) > 0; + WAVE_len_en = (Audio_Regs[NR34] & 0x40) > 0; + WAVE_frq &= 0xFF; + WAVE_frq |= (ushort)((Audio_Regs[NR34] & 7) << 8); + + NOISE_length = (ushort)(64 - Audio_Regs[NR41] & 0x3F); + + NOISE_st_vol = (byte)((Audio_Regs[NR42] & 0xF0) >> 4); + NOISE_env_add = (Audio_Regs[NR42] & 8) > 0; + NOISE_per = (byte)(Audio_Regs[NR42] & 7); + + NOISE_clk_shft = (byte)((Audio_Regs[NR43] & 0xF0) >> 4); + NOISE_wdth_md = (Audio_Regs[NR43] & 8) > 0; + NOISE_div_code = (byte)(Audio_Regs[NR43] & 7); + + WAVE_trigger = (Audio_Regs[NR44] & 0x80) > 0; + WAVE_len_en = (Audio_Regs[NR44] & 0x40) > 0; + + AUD_CTRL_vin_L_en = (Audio_Regs[NR50] & 0x80) > 0; + AUD_CTRL_vol_L = (byte)((Audio_Regs[NR50] & 0x70) >> 4); + AUD_CTRL_vin_R_en = (Audio_Regs[NR50] & 8) > 0; + AUD_CTRL_vol_R = (byte)(Audio_Regs[NR50] & 7); + + AUD_CTRL_noise_L_en = (Audio_Regs[NR51] & 0x80) > 0; + AUD_CTRL_wave_L_en = (Audio_Regs[NR51] & 0x40) > 0; + AUD_CTRL_sq2_L_en = (Audio_Regs[NR51] & 0x20) > 0; + AUD_CTRL_sq1_L_en = (Audio_Regs[NR51] & 0x10) > 0; + AUD_CTRL_noise_R_en = (Audio_Regs[NR51] & 8) > 0; + AUD_CTRL_wave_R_en = (Audio_Regs[NR51] & 4) > 0; + AUD_CTRL_sq2_R_en = (Audio_Regs[NR51] & 2) > 0; + AUD_CTRL_sq1_R_en = (Audio_Regs[NR51] & 1) > 0; + + AUD_CTRL_power = (Audio_Regs[NR51] & 0x80) > 0; } public byte Read_NR52() @@ -993,53 +1020,53 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ((NOISE_enable ? 1 : 0) << 3)); } - #region audio + #region audio - public bool CanProvideAsync => false; - - public int AudioClocks; - public short[] AudioSamples = new short[1500]; - - public void SetSyncMode(SyncSoundMode mode) - { - if (mode != SyncSoundMode.Sync) - { - throw new InvalidOperationException("Only Sync mode is supported_"); - } - } - - public SyncSoundMode SyncMode => SyncSoundMode.Sync; - - public void GetSamplesSync(out short[] samples, out int nsamp) - { - nsamp = AudioClocks / 2; - short[] temp_samp = new short[AudioClocks]; - - for (int i = 0; i < AudioClocks; i++) - { - temp_samp[i] = AudioSamples[i]; - } - - samples = temp_samp; - - AudioClocks = 0; - } - - public void GetSamplesAsync(short[] samples) - { - throw new NotSupportedException("Async is not available"); - } - - public void DiscardSamples() - { - AudioClocks = 0; - } - - private void GetSamples(short[] samples) - { - + public bool CanProvideAsync => false; + + public int AudioClocks; + public short[] AudioSamples = new short[1500]; + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Sync) + { + throw new InvalidOperationException("Only Sync mode is supported_"); + } } - #endregion - } + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + nsamp = AudioClocks / 2; + short[] temp_samp = new short[AudioClocks]; + + for (int i = 0; i < AudioClocks; i++) + { + temp_samp[i] = AudioSamples[i]; + } + + samples = temp_samp; + + AudioClocks = 0; + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + AudioClocks = 0; + } + + private void GetSamples(short[] samples) + { + + } + + #endregion + } } \ No newline at end of file