From 79fecef41b91ef5c866d6af035c0e0dc624d7e94 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 24 Mar 2020 19:44:11 -0400 Subject: [PATCH] GBHawk: more transformation work --- libHawk/GBHawk/GBHawk/AY_3_8910.h | 442 -------- libHawk/GBHawk/GBHawk/Core.h | 124 +-- libHawk/GBHawk/GBHawk/GBAudio.h | 1396 ++++++++++++++++++++++++++ libHawk/GBHawk/GBHawk/GBHawk.cpp | 4 +- libHawk/GBHawk/GBHawk/GBHawk.vcxproj | 2 +- libHawk/GBHawk/GBHawk/LR35902.cpp | 10 +- libHawk/GBHawk/GBHawk/LR35902.h | 745 +++----------- libHawk/GBHawk/GBHawk/Memory.cpp | 206 +--- libHawk/GBHawk/GBHawk/Memory.h | 14 +- 9 files changed, 1564 insertions(+), 1379 deletions(-) delete mode 100644 libHawk/GBHawk/GBHawk/AY_3_8910.h create mode 100644 libHawk/GBHawk/GBHawk/GBAudio.h diff --git a/libHawk/GBHawk/GBHawk/AY_3_8910.h b/libHawk/GBHawk/GBHawk/AY_3_8910.h deleted file mode 100644 index 4892c2af17..0000000000 --- a/libHawk/GBHawk/GBHawk/AY_3_8910.h +++ /dev/null @@ -1,442 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace GBHawk -{ - class AY_3_8910 - { - public: - - #pragma region AY_3_8910 - - AY_3_8910() - { - Reset(); - } - - bool A_on, B_on, C_on; - bool A_up, B_up, C_up; - bool A_noise, B_noise, C_noise; - bool env_vol_A, env_vol_B, env_vol_C; - - uint8_t env_shape; - uint8_t port_sel; - uint8_t vol_A, vol_B, vol_C; - uint8_t Register[16] = {}; - - uint32_t psg_clock; - uint32_t sq_per_A, sq_per_B, sq_per_C; - uint32_t clock_A, clock_B, clock_C; - - uint32_t env_per; - uint32_t env_clock; - - int32_t env_E; - int32_t E_up_down; - - uint32_t noise_clock; - uint32_t noise_per; - uint32_t noise = 0x1; - - int32_t old_sample; - - // non stated if only on frame boundaries - bool sound_out_A; - bool sound_out_B; - bool sound_out_C; - - uint8_t Clock_Divider; - - int32_t current_sample; - uint32_t sampleclock; - uint32_t num_samples; - int32_t samples[9000] = {}; - - void Reset() - { - clock_A = clock_B = clock_C = 0x1000; - noise_clock = 0x20; - port_sel = 0; - - for (int i = 0; i < 16; i++) - { - Register[i] = 0x0; - } - sync_psg_state(); - } - - short Sample() - { - return current_sample; - } - - const uint32_t VolumeTable[16] = - { - 0x0000, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA, - 0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA - }; - - uint8_t ReadReg() - { - return Register[port_sel]; - } - - void sync_psg_state() - { - sq_per_A = (Register[0] & 0xFF) | (((Register[1] & 0xF) << 8)); - if (sq_per_A == 0) - { - sq_per_A = 0x1000; - } - - sq_per_B = (Register[2] & 0xFF) | (((Register[3] & 0xF) << 8)); - if (sq_per_B == 0) - { - sq_per_B = 0x1000; - } - - sq_per_C = (Register[4] & 0xFF) | (((Register[5] & 0xF) << 8)); - if (sq_per_C == 0) - { - sq_per_C = 0x1000; - } - - env_per = (Register[11] & 0xFF) | (((Register[12] & 0xFF) << 8)); - if (env_per == 0) - { - env_per = 0x10000; - } - - env_per *= 2; - - A_on = (Register[7] & 0x1) > 0; - B_on = (Register[7] & 0x2) > 0; - C_on = (Register[7] & 0x4) > 0; - A_noise = (Register[7] & 0x8) > 0; - B_noise = (Register[7] & 0x10) > 0; - C_noise = (Register[7] & 0x20) > 0; - - noise_per = Register[6] & 0x1F; - if (noise_per == 0) - { - noise_per = 0x20; - } - - uint8_t shape_select = Register[13] & 0xF; - - if (shape_select < 4) { env_shape = 0; } - else if (shape_select < 8) { env_shape = 1; } - else { env_shape = 2 + (shape_select - 8); } - - vol_A = Register[8] & 0xF; - env_vol_A = ((Register[8] >> 4) & 0x1) > 0; - - vol_B = Register[9] & 0xF; - env_vol_B = ((Register[9] >> 4) & 0x1) > 0; - - vol_C = Register[10] & 0xF; - env_vol_C = ((Register[10] >> 4) & 0x1) > 0; - } - - void WriteReg(uint8_t value) - { - value &= 0xFF; - - if (port_sel != 0xE) { Register[port_sel] = value; } - - - sync_psg_state(); - - if (port_sel == 13) - { - env_clock = env_per; - - if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5) - { - env_E = 15; - E_up_down = -1; - } - else - { - env_E = 0; - E_up_down = 1; - } - } - } - - void generate_sound() - { - // there are 8 cpu cycles for every psg cycle - clock_A--; - clock_B--; - clock_C--; - - noise_clock--; - env_clock--; - - // clock noise - if (noise_clock == 0) - { - noise = (noise >> 1) ^ (((noise &0x1) > 0) ? 0x10004 : 0); - noise_clock = noise_per; - } - - if (env_clock == 0) - { - env_clock = env_per; - - env_E += E_up_down; - - if (env_E == 16 || env_E == -1) - { - // we just completed a period of the envelope, determine what to do now based on the envelope shape - if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9) - { - E_up_down = 0; - env_E = 0; - } - else if (env_shape == 5 || env_shape == 7) - { - E_up_down = 0; - env_E = 15; - } - else if (env_shape == 4 || env_shape == 8) - { - if (env_E == 16) - { - env_E = 15; - E_up_down = -1; - } - else - { - env_E = 0; - E_up_down = 1; - } - } - else if (env_shape == 2) - { - env_E = 15; - } - else - { - env_E = 0; - } - } - } - - if (clock_A == 0) - { - A_up = !A_up; - clock_A = sq_per_A; - } - - if (clock_B == 0) - { - B_up = !B_up; - clock_B = sq_per_B; - } - - if (clock_C == 0) - { - C_up = !C_up; - clock_C = sq_per_C; - } - - sound_out_A = (((noise & 0x1) > 0) | A_noise) & (A_on | A_up); - sound_out_B = (((noise & 0x1) > 0) | B_noise) & (B_on | B_up); - sound_out_C = (((noise & 0x1) > 0) | C_noise) & (C_on | C_up); - - // now calculate the volume of each channel and add them together - current_sample = 0; - - if (env_vol_A) - { - current_sample = (sound_out_A ? VolumeTable[env_E] : 0); - } - else - { - current_sample = (sound_out_A ? VolumeTable[vol_A] : 0); - } - - if (env_vol_B) - { - current_sample += (sound_out_B ? VolumeTable[env_E] : 0); - } - else - { - current_sample += (sound_out_B ? VolumeTable[vol_B] : 0); - } - - if (env_vol_C) - { - current_sample += (sound_out_C ? VolumeTable[env_E] : 0); - } - else - { - current_sample += (sound_out_C ? VolumeTable[vol_C] : 0); - } - - current_sample *= 2; - - if ((current_sample != old_sample) && (num_samples < 4500)) - { - samples[num_samples * 2] = sampleclock; - samples[num_samples * 2 + 1] = current_sample - old_sample; - num_samples++; - old_sample = current_sample; - } - } - - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - *saver = (uint8_t)(A_on ? 1 : 0); saver++; - *saver = (uint8_t)(B_on ? 1 : 0); saver++; - *saver = (uint8_t)(C_on ? 1 : 0); saver++; - *saver = (uint8_t)(A_up ? 1 : 0); saver++; - *saver = (uint8_t)(B_up ? 1 : 0); saver++; - *saver = (uint8_t)(C_up ? 1 : 0); saver++; - *saver = (uint8_t)(A_noise ? 1 : 0); saver++; - *saver = (uint8_t)(B_noise ? 1 : 0); saver++; - *saver = (uint8_t)(C_noise ? 1 : 0); saver++; - *saver = (uint8_t)(env_vol_A ? 1 : 0); saver++; - *saver = (uint8_t)(env_vol_B ? 1 : 0); saver++; - *saver = (uint8_t)(env_vol_C ? 1 : 0); saver++; - - *saver = env_shape; saver++; - *saver = port_sel; saver++; - *saver = vol_A; saver++; - *saver = vol_B; saver++; - *saver = vol_C; saver++; - - for (int i = 0; i < 16; i++) { *saver = Register[i]; saver++; } - - *saver = (uint8_t)(psg_clock & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((psg_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(sq_per_A & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 8) & 0xFF); saver++; - *saver = (uint8_t)((sq_per_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(sq_per_B & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 8) & 0xFF); saver++; - *saver = (uint8_t)((sq_per_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(sq_per_C & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 8) & 0xFF); saver++; - *saver = (uint8_t)((sq_per_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clock_A & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clock_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clock_B & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clock_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(clock_C & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 8) & 0xFF); saver++; - *saver = (uint8_t)((clock_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(env_per & 0xFF); saver++; *saver = (uint8_t)((env_per >> 8) & 0xFF); saver++; - *saver = (uint8_t)((env_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_per >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(env_clock & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((env_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(env_E & 0xFF); saver++; *saver = (uint8_t)((env_E >> 8) & 0xFF); saver++; - *saver = (uint8_t)((env_E >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_E >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(E_up_down & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 8) & 0xFF); saver++; - *saver = (uint8_t)((E_up_down >> 16) & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(noise_clock & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 8) & 0xFF); saver++; - *saver = (uint8_t)((noise_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(noise_per & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 8) & 0xFF); saver++; - *saver = (uint8_t)((noise_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(noise & 0xFF); saver++; *saver = (uint8_t)((noise >> 8) & 0xFF); saver++; - *saver = (uint8_t)((noise >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(old_sample & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 8) & 0xFF); saver++; - *saver = (uint8_t)((old_sample >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - A_on = *loader == 1; loader++; - B_on = *loader == 1; loader++; - C_on = *loader == 1; loader++; - A_up = *loader == 1; loader++; - B_up = *loader == 1; loader++; - C_up = *loader == 1; loader++; - A_noise = *loader == 1; loader++; - B_noise = *loader == 1; loader++; - C_noise = *loader == 1; loader++; - env_vol_A = *loader == 1; loader++; - env_vol_B = *loader == 1; loader++; - env_vol_C = *loader == 1; loader++; - - env_shape = *loader; loader++; - port_sel = *loader; loader++; - vol_A = *loader; loader++; - vol_B = *loader; loader++; - vol_C = *loader; loader++; - - for (int i = 0; i < 16; i++) { Register[i] = *loader; loader++; } - - psg_clock = *loader; loader++; psg_clock |= (*loader << 8); loader++; - psg_clock |= (*loader << 16); loader++; psg_clock |= (*loader << 24); loader++; - - sq_per_A = *loader; loader++; sq_per_A |= (*loader << 8); loader++; - sq_per_A |= (*loader << 16); loader++; sq_per_A |= (*loader << 24); loader++; - - sq_per_B = *loader; loader++; sq_per_B |= (*loader << 8); loader++; - sq_per_B |= (*loader << 16); loader++; sq_per_B |= (*loader << 24); loader++; - - sq_per_C = *loader; loader++; sq_per_C |= (*loader << 8); loader++; - sq_per_C |= (*loader << 16); loader++; sq_per_C |= (*loader << 24); loader++; - - clock_A = *loader; loader++; clock_A |= (*loader << 8); loader++; - clock_A |= (*loader << 16); loader++; clock_A |= (*loader << 24); loader++; - - clock_B = *loader; loader++; clock_B |= (*loader << 8); loader++; - clock_B |= (*loader << 16); loader++; clock_B |= (*loader << 24); loader++; - - clock_C = *loader; loader++; clock_C |= (*loader << 8); loader++; - clock_C |= (*loader << 16); loader++; clock_C |= (*loader << 24); loader++; - - env_per = *loader; loader++; env_per |= (*loader << 8); loader++; - env_per |= (*loader << 16); loader++; env_per |= (*loader << 24); loader++; - - env_clock = *loader; loader++; env_clock |= (*loader << 8); loader++; - env_clock |= (*loader << 16); loader++; env_clock |= (*loader << 24); loader++; - - env_E = *loader; loader++; env_E |= (*loader << 8); loader++; - env_E |= (*loader << 16); loader++; env_E |= (*loader << 24); loader++; - - E_up_down = *loader; loader++; E_up_down |= (*loader << 8); loader++; - E_up_down |= (*loader << 16); loader++; E_up_down |= (*loader << 24); loader++; - - noise_clock = *loader; loader++; noise_clock |= (*loader << 8); loader++; - noise_clock |= (*loader << 16); loader++; noise_clock |= (*loader << 24); loader++; - - noise_per = *loader; loader++; noise_per |= (*loader << 8); loader++; - noise_per |= (*loader << 16); loader++; noise_per |= (*loader << 24); loader++; - - noise = *loader; loader++; noise |= (*loader << 8); loader++; - noise |= (*loader << 16); loader++; noise |= (*loader << 24); loader++; - - old_sample = *loader; loader++; old_sample |= (*loader << 8); loader++; - old_sample |= (*loader << 16); loader++; old_sample |= (*loader << 24); loader++; - - return loader; - } - - #pragma endregion - }; -} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Core.h b/libHawk/GBHawk/GBHawk/Core.h index d937b697cb..0988c06d54 100644 --- a/libHawk/GBHawk/GBHawk/Core.h +++ b/libHawk/GBHawk/GBHawk/Core.h @@ -4,7 +4,7 @@ #include #include "LR35902.h" -#include "AY_3_8910.h" +#include "GBAudio.h" #include "TMS9918A.h" #include "Memory.h" @@ -21,13 +21,12 @@ namespace GBHawk cpu.mem_ctrl = &MemMap; vdp.IRQ_PTR = &cpu.FlagI; vdp.SHOW_BG = vdp.SHOW_SPRITES = true; - psg.Clock_Divider = 16; sl_case = 0; }; TMS9918A vdp; - Z80A cpu; - AY_3_8910 psg; + LR35902 cpu; + GBAudio psg; MemoryManager MemMap; uint8_t sl_case = 0; @@ -44,14 +43,6 @@ namespace GBHawk bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, uint8_t* kb_rows_ptr, bool render, bool rendersound) { - if ((MemMap.psg_pntr->Register[0xF] & 0x40) > 0) - { - MemMap.psg_pntr->Register[0xE] = controller_2; - } - else - { - MemMap.psg_pntr->Register[0xE] = controller_1; - } MemMap.controller_byte_1 = controller_1; MemMap.controller_byte_2 = controller_2; @@ -62,83 +53,6 @@ namespace GBHawk uint32_t scanlinesPerFrame = 262; vdp.SpriteLimit = true; - psg.num_samples = 0; - psg.sampleclock = 0; - - for (uint32_t i = 0; i < scanlinesPerFrame; i++) - { - vdp.ScanLine = i; - - vdp.RenderScanline(i); - - if (vdp.ScanLine == 192) - { - vdp.InterruptPendingSet(true); - - if (vdp.EnableInterrupts()) { cpu.FlagI = true; } - } - - switch (sl_case) - { - case 0: - for (int i = 0; i < 14; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock+=16; - psg.generate_sound(); - } - cpu.ExecuteOne(4); - psg.sampleclock += 4; - sl_case = 1; - break; - - case 1: - cpu.ExecuteOne(12); - psg.sampleclock += 12; - psg.generate_sound(); - - for (int i = 0; i < 13; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock += 16; - psg.generate_sound(); - } - cpu.ExecuteOne(8); - psg.sampleclock += 8; - sl_case = 2; - break; - - case 2: - cpu.ExecuteOne(8); - psg.sampleclock += 8; - psg.generate_sound(); - - for (int i = 0; i < 13; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock += 16; - psg.generate_sound(); - } - cpu.ExecuteOne(12); - psg.sampleclock += 12; - sl_case = 3; - break; - case 3: - cpu.ExecuteOne(4); - psg.sampleclock += 4; - psg.generate_sound(); - - for (int i = 0; i < 14; i++) - { - cpu.ExecuteOne(16); - psg.sampleclock += 16; - psg.generate_sound(); - } - sl_case = 0; - break; - } - } - return MemMap.lagged; } @@ -150,15 +64,21 @@ namespace GBHawk std::memcpy(dst, src, sizeof uint32_t * 256 * 192); } - uint32_t GetAudio(int32_t* dest, int32_t* n_samp) + uint32_t GetAudio(int32_t* dest_L, int32_t* n_samp_L, int32_t* dest_R, int32_t* n_samp_R) { - int32_t* src = psg.samples; - int32_t* dst = dest; + int32_t* src = psg.samples_L; + int32_t* dst = dest_L; - std::memcpy(dst, src, sizeof int32_t * psg.num_samples * 2); - n_samp[0] = psg.num_samples; + std::memcpy(dst, src, sizeof int32_t * psg.num_samples_L * 2); + n_samp_L[0] = psg.num_samples_L; - return psg.sampleclock; + src = psg.samples_R; + dst = dest_R; + + std::memcpy(dst, src, sizeof int32_t * psg.num_samples_R * 2); + n_samp_R[0] = psg.num_samples_R; + + return psg.master_audio_clock; } #pragma region State Save / Load @@ -189,11 +109,7 @@ namespace GBHawk uint8_t GetSysBus(uint32_t addr) { - cpu.bank_num = cpu.bank_offset = addr & 0xFFFF; - cpu.bank_offset &= cpu.low_mask; - cpu.bank_num = (cpu.bank_num >> cpu.bank_shift)& cpu.high_mask; - - return cpu.MemoryMap[cpu.bank_num][cpu.bank_offset]; + return cpu.PeekMemory(addr); } uint8_t GetVRAM(uint32_t addr) @@ -257,11 +173,15 @@ namespace GBHawk } else if (t == 1) { - memcpy(d, cpu.NMI_event, l); + memcpy(d, cpu.Un_halt_event, l); + } + else if (t == 2) + { + memcpy(d, cpu.IRQ_event, l); } else { - memcpy(d, cpu.IRQ_event, l); + memcpy(d, cpu.Un_halt_event, l); } } diff --git a/libHawk/GBHawk/GBHawk/GBAudio.h b/libHawk/GBHawk/GBHawk/GBAudio.h new file mode 100644 index 0000000000..c0ba759563 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/GBAudio.h @@ -0,0 +1,1396 @@ +#include +#include +#include +#include + +using namespace std; + +namespace GBHawk +{ + class GBAudio + { + public: + + #pragma region GBAudio + + uint32_t num_samples_L, num_samples_R; + int32_t samples_L[9000] = {}; + int32_t samples_R[9000] = {}; + + //GBHawk Core{ get; set; } + // Core variables + bool is_GBC, double_speed; + uint32_t timer_div_reg; + + bool DUTY_CYCLES[32] = {false, false, false, false, false, false, false, true, + true, false, false, false, false, false, false, true, + true, false, false, false, false, true, true, true, + false, true, true, true, true, true, true, false}; + + uint32_t DIVISOR[8] = { 8, 16, 32, 48, 64, 80, 96, 112 }; + + + uint32_t NR10 = 0; + uint32_t NR11 = 1; + uint32_t NR12 = 2; + uint32_t NR13 = 3; + uint32_t NR14 = 4; + uint32_t NR21 = 5; + uint32_t NR22 = 6; + uint32_t NR23 = 7; + uint32_t NR24 = 8; + uint32_t NR30 = 9; + uint32_t NR31 = 10; + uint32_t NR32 = 11; + uint32_t NR33 = 12; + uint32_t NR34 = 13; + uint32_t NR41 = 14; + uint32_t NR42 = 15; + uint32_t NR43 = 16; + uint32_t NR44 = 17; + uint32_t NR50 = 18; + uint32_t NR51 = 19; + uint32_t NR52 = 20; + + uint32_t unused_bits[21] = { 0x80, 0x3F, 0x00, 0xFF, 0xBF, + 0x3F, 0x00, 0xFF, 0xBF, + 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, + 0xFF, 0x00, 0x00, 0xBF, + 0x00, 0x00, 0x70}; + + uint8_t Audio_Regs[21]; + + uint8_t Wave_RAM[16]; + + + // Audio Variables + // derived + bool WAVE_DAC_pow; + bool NOISE_wdth_md; + bool SQ1_negate; + bool SQ1_trigger, SQ2_trigger, WAVE_trigger, NOISE_trigger; + bool SQ1_len_en, SQ2_len_en, WAVE_len_en, NOISE_len_en; + bool SQ1_env_add, SQ2_env_add, NOISE_env_add; + uint8_t WAVE_vol_code; + uint8_t NOISE_clk_shft; + uint8_t NOISE_div_code; + uint8_t SQ1_shift; + uint8_t SQ1_duty, SQ2_duty; + uint8_t SQ1_st_vol, SQ2_st_vol, NOISE_st_vol; + uint8_t SQ1_per, SQ2_per, NOISE_per; + uint8_t SQ1_swp_prd; + uint32_t SQ1_frq, SQ2_frq, WAVE_frq; + uint32_t SQ1_length, SQ2_length, WAVE_length, NOISE_length; + // state + bool WAVE_can_get; + bool SQ1_calc_done; + bool SQ1_swp_enable; + bool SQ1_vol_done, SQ2_vol_done, NOISE_vol_done; + bool SQ1_enable, SQ2_enable, WAVE_enable, NOISE_enable; + uint8_t SQ1_vol_state, SQ2_vol_state, NOISE_vol_state; + uint8_t SQ1_duty_cntr, SQ2_duty_cntr; + uint8_t WAVE_wave_cntr; + uint32_t SQ1_frq_shadow; + uint32_t SQ1_intl_cntr, SQ2_intl_cntr, WAVE_intl_cntr, NOISE_intl_cntr; + uint32_t SQ1_vol_per, SQ2_vol_per, NOISE_vol_per; + uint32_t SQ1_intl_swp_cnt; + uint32_t NOISE_LFSR; + uint32_t SQ1_len_cntr, SQ2_len_cntr, WAVE_len_cntr, NOISE_len_cntr; + // computed + uint32_t SQ1_output, SQ2_output, WAVE_output, NOISE_output; + + // Contol Variables + bool AUD_CTRL_vin_L_en; + bool AUD_CTRL_vin_R_en; + bool AUD_CTRL_sq1_L_en; + bool AUD_CTRL_sq2_L_en; + bool AUD_CTRL_wave_L_en; + bool AUD_CTRL_noise_L_en; + bool AUD_CTRL_sq1_R_en; + bool AUD_CTRL_sq2_R_en; + bool AUD_CTRL_wave_R_en; + bool AUD_CTRL_noise_R_en; + bool AUD_CTRL_power; + uint8_t AUD_CTRL_vol_L; + uint8_t AUD_CTRL_vol_R; + + uint32_t sequencer_len, sequencer_vol, sequencer_swp; + bool timer_bit_old; + + uint8_t sample; + + uint32_t master_audio_clock; + + uint32_t latched_sample_L, latched_sample_R; + + uint32_t SQ1_bias_gain, SQ2_bias_gain, WAVE_bias_gain, NOISE_bias_gain; + + uint8_t ReadReg(int addr) + { + uint8_t ret = 0; + + switch (addr) + { + case 0xFF10: ret = (uint8_t)(Audio_Regs[NR10] | unused_bits[NR10]); break; // NR10 (sweep) + case 0xFF11: ret = (uint8_t)(Audio_Regs[NR11] | unused_bits[NR11]); break; // NR11 (sound length / wave pattern duty %) + case 0xFF12: ret = (uint8_t)(Audio_Regs[NR12] | unused_bits[NR12]); break; // NR12 (envelope) + case 0xFF13: ret = (uint8_t)(Audio_Regs[NR13] | unused_bits[NR13]); break; // NR13 (freq low) + case 0xFF14: ret = (uint8_t)(Audio_Regs[NR14] | unused_bits[NR14]); break; // NR14 (freq hi) + case 0xFF16: ret = (uint8_t)(Audio_Regs[NR21] | unused_bits[NR21]); break; // NR21 (sound length / wave pattern duty %) + case 0xFF17: ret = (uint8_t)(Audio_Regs[NR22] | unused_bits[NR22]); break; // NR22 (envelope) + case 0xFF18: ret = (uint8_t)(Audio_Regs[NR23] | unused_bits[NR23]); break; // NR23 (freq low) + case 0xFF19: ret = (uint8_t)(Audio_Regs[NR24] | unused_bits[NR24]); break; // NR24 (freq hi) + case 0xFF1A: ret = (uint8_t)(Audio_Regs[NR30] | unused_bits[NR30]); break; // NR30 (on/off) + case 0xFF1B: ret = (uint8_t)(Audio_Regs[NR31] | unused_bits[NR31]); break; // NR31 (length) + case 0xFF1C: ret = (uint8_t)(Audio_Regs[NR32] | unused_bits[NR32]); break; // NR32 (level output) + case 0xFF1D: ret = (uint8_t)(Audio_Regs[NR33] | unused_bits[NR33]); break; // NR33 (freq low) + case 0xFF1E: ret = (uint8_t)(Audio_Regs[NR34] | unused_bits[NR34]); break; // NR34 (freq hi) + case 0xFF20: ret = (uint8_t)(Audio_Regs[NR41] | unused_bits[NR41]); break; // NR41 (length) + case 0xFF21: ret = (uint8_t)(Audio_Regs[NR42] | unused_bits[NR42]); break; // NR42 (envelope) + case 0xFF22: ret = (uint8_t)(Audio_Regs[NR43] | unused_bits[NR43]); break; // NR43 (shift) + case 0xFF23: ret = (uint8_t)(Audio_Regs[NR44] | unused_bits[NR44]); break; // NR44 (trigger) + case 0xFF24: ret = (uint8_t)(Audio_Regs[NR50] | unused_bits[NR50]); break; // NR50 (ctrl) + case 0xFF25: ret = (uint8_t)(Audio_Regs[NR51] | unused_bits[NR51]); break; // NR51 (ctrl) + case 0xFF26: ret = (uint8_t)(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: + if (WAVE_enable) + { + if (WAVE_can_get || is_GBC) { ret = Wave_RAM[WAVE_wave_cntr >> 1]; } + else { ret = 0xFF; } + } + else { ret = Wave_RAM[addr & 0x0F]; } + + break; + } + + return ret; + } + + void WriteReg(int addr, uint8_t value) + { + // while power is on, everything is writable + //Console.WriteLine((addr & 0xFF) + " " + value); + if (AUD_CTRL_power) + { + switch (addr) + { + case 0xFF10: // NR10 (sweep) + Audio_Regs[NR10] = value; + SQ1_swp_prd = (uint8_t)((value & 0x70) >> 4); + SQ1_negate = (value & 8) > 0; + SQ1_shift = (uint8_t)(value & 7); + + if (!SQ1_negate && SQ1_calc_done) { SQ1_enable = false; calculate_bias_gain_1(); } + break; + case 0xFF11: // NR11 (sound length / wave pattern duty %) + Audio_Regs[NR11] = value; + SQ1_duty = (uint8_t)((value & 0xC0) >> 6); + SQ1_length = (uint32_t)(64 - (value & 0x3F)); + SQ1_len_cntr = SQ1_length; + break; + case 0xFF12: // NR12 (envelope) + SQ1_st_vol = (uint8_t)((value & 0xF0) >> 4); + SQ1_env_add = (value & 8) > 0; + SQ1_per = (uint8_t)(value & 7); + + // several glitchy effects happen when writing to NRx2 during audio playing + if (((Audio_Regs[NR12] & 7) == 0) && !SQ1_vol_done) { SQ1_vol_state++; } + else if ((Audio_Regs[NR12] & 8) == 0) { SQ1_vol_state += 2; } + + if (((Audio_Regs[NR12] ^ value) & 8) > 0) { SQ1_vol_state = (uint8_t)(0x10 - SQ1_vol_state); } + + SQ1_vol_state &= 0xF; + + if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; } + Audio_Regs[NR12] = value; + + calculate_bias_gain_1(); + break; + case 0xFF13: // NR13 (freq low) + 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 |= (uint32_t)((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; + shadow_frq = shadow_frq >> SQ1_shift; + if (SQ1_negate) { shadow_frq = -shadow_frq; } + shadow_frq += SQ1_frq_shadow; + + // disable channel if overflow + if ((uint32_t)shadow_frq > 2047) + { + SQ1_enable = SQ1_swp_enable = false; + } + + // set negate mode flag that disables channel is negate clerar + if (SQ1_negate) { SQ1_calc_done = true; } + } + + if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; } + } + + calculate_bias_gain_1(); + SQ1_len_en = (value & 0x40) > 0; + break; + case 0xFF16: // NR21 (sound length / wave pattern duty %) + Audio_Regs[NR21] = value; + SQ2_duty = (uint8_t)((value & 0xC0) >> 6); + SQ2_length = (uint32_t)(64 - (value & 0x3F)); + SQ2_len_cntr = SQ2_length; + break; + case 0xFF17: // NR22 (envelope) + SQ2_st_vol = (uint8_t)((value & 0xF0) >> 4); + SQ2_env_add = (value & 8) > 0; + SQ2_per = (uint8_t)(value & 7); + + // several glitchy effects happen when writing to NRx2 during audio playing + if (((Audio_Regs[NR22] & 7) == 0) && !SQ2_vol_done) { SQ2_vol_state++; } + else if ((Audio_Regs[NR22] & 8) == 0) { SQ2_vol_state += 2; } + + if (((Audio_Regs[NR22] ^ value) & 8) > 0) { SQ2_vol_state = (uint8_t)(0x10 - SQ2_vol_state); } + + SQ2_vol_state &= 0xF; + if ((value & 0xF8) == 0) { SQ2_enable = false; } + Audio_Regs[NR22] = value; + + calculate_bias_gain_2(); + break; + case 0xFF18: // NR23 (freq low) + 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 |= (uint32_t)((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 = (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; } + } + calculate_bias_gain_2(); + 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; } + //calculate_bias_gain_w(); + break; + case 0xFF1B: // NR31 (length) + Audio_Regs[NR31] = value; + WAVE_length = (uint32_t)(256 - value); + WAVE_len_cntr = WAVE_length; + break; + case 0xFF1C: // NR32 (level output) + Audio_Regs[NR32] = value; + WAVE_vol_code = (uint8_t)((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 |= (uint32_t)((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) && !is_GBC) + { + // 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; } + } + + //calculate_bias_gain_w(); + WAVE_len_en = (value & 0x40) > 0; + break; + case 0xFF20: // NR41 (length) + Audio_Regs[NR41] = value; + NOISE_length = (uint32_t)(64 - (value & 0x3F)); + NOISE_len_cntr = NOISE_length; + break; + case 0xFF21: // NR42 (envelope) + NOISE_st_vol = (uint8_t)((value & 0xF0) >> 4); + NOISE_env_add = (value & 8) > 0; + NOISE_per = (uint8_t)(value & 7); + + // several glitchy effects happen when writing to NRx2 during audio playing + if (((Audio_Regs[NR42] & 7) == 0) && !NOISE_vol_done) { NOISE_vol_state++; } + else if ((Audio_Regs[NR42] & 8) == 0) { NOISE_vol_state += 2; } + + if (((Audio_Regs[NR42] ^ value) & 8) > 0) { NOISE_vol_state = (uint8_t)(0x10 - NOISE_vol_state); } + + NOISE_vol_state &= 0xF; + if ((value & 0xF8) == 0) { NOISE_enable = false; } + Audio_Regs[NR42] = value; + + calculate_bias_gain_n(); + break; + case 0xFF22: // NR43 (shift) + Audio_Regs[NR43] = value; + NOISE_clk_shft = (uint8_t)((value & 0xF0) >> 4); + NOISE_wdth_md = (value & 8) > 0; + NOISE_div_code = (uint8_t)(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; } + } + + calculate_bias_gain_n(); + 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 = (uint8_t)((value & 0x70) >> 4); + AUD_CTRL_vin_R_en = (value & 8) > 0; + AUD_CTRL_vol_R = (uint8_t)(value & 7); + + calculate_bias_gain_a(); + 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; + + calculate_bias_gain_a(); + break; + case 0xFF26: // NR52 (ctrl) + // NOTE: Make sure to do the power off first since it will call the write_reg function again + if ((value & 0x80) == 0) { power_off(); } + AUD_CTRL_power = (value & 0x80) > 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: + if (WAVE_enable) + { + if (WAVE_can_get || is_GBC) { 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 + // ON GBC, length counters cannot be written to either + else + { + switch (addr) + { + case 0xFF11: // NR11 (sound length / wave pattern duty %) + if (!is_GBC) + { + SQ1_length = (uint32_t)(64 - (value & 0x3F)); + SQ1_len_cntr = SQ1_length; + } + break; + case 0xFF16: // NR21 (sound length / wave pattern duty %) + if (!is_GBC) + { + SQ2_length = (uint32_t)(64 - (value & 0x3F)); + SQ2_len_cntr = SQ2_length; + } + break; + case 0xFF1B: // NR31 (length) + if (!is_GBC) + { + WAVE_length = (uint32_t)(256 - value); + WAVE_len_cntr = WAVE_length; + } + break; + case 0xFF20: // NR41 (length) + if (!is_GBC) + { + NOISE_length = (uint32_t)(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; + } + } + } + + void tick() + { + // calculate square1's output + if (SQ1_enable) + { + SQ1_intl_cntr--; + if (SQ1_intl_cntr == 0) + { + SQ1_intl_cntr = (2048 - SQ1_frq) * 4; + SQ1_duty_cntr++; + SQ1_duty_cntr &= 7; + + SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr] ? SQ1_vol_state : SQ1_bias_gain; + + // avoid aliasing at high frequenices + //if (SQ1_frq > 0x7F0) { SQ1_output = 0; } + } + } + + // calculate square2's output + 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_vol_state : SQ2_bias_gain; + + // avoid aliasing at high frequenices + //if (SQ2_frq > 0x7F0) { SQ2_output = 0; } + } + } + + // calculate wave output + WAVE_can_get = false; + if (WAVE_enable) + { + WAVE_intl_cntr--; + + if (WAVE_intl_cntr == 0) + { + WAVE_can_get = true; + + WAVE_intl_cntr = (2048 - WAVE_frq) * 2; + + if ((WAVE_wave_cntr & 1) == 0) + { + sample = (uint8_t)(sample >> 4); + } + + if (WAVE_vol_code == 0) + { + sample = (uint8_t)((sample & 0xF) >> 4); + } + else if (WAVE_vol_code == 1) + { + sample = (uint8_t)(sample & 0xF); + } + else if (WAVE_vol_code == 2) + { + sample = (uint8_t)((sample & 0xF) >> 1); + } + else + { + sample = (uint8_t)((sample & 0xF) >> 2); + } + + WAVE_output = sample; + + // NOTE: The sample buffer is only reloaded after the current sample is played, even if just triggered + WAVE_wave_cntr++; + WAVE_wave_cntr &= 0x1F; + sample = Wave_RAM[WAVE_wave_cntr >> 1]; + } + } + + // calculate noise output + 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) > 0 ? NOISE_bias_gain : 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) * 40; + R_final *= (AUD_CTRL_vol_R + 1) * 40; + + if (L_final != latched_sample_L) + { + samples_L[num_samples_L * 2] = master_audio_clock; + samples_L[num_samples_L * 2 + 1] = L_final - latched_sample_L; + + num_samples_L++; + + latched_sample_L = L_final; + } + + if (R_final != latched_sample_R) + { + samples_R[num_samples_R * 2] = master_audio_clock; + samples_R[num_samples_R * 2 + 1] = R_final - latched_sample_R; + + num_samples_R++; + + latched_sample_R = R_final; + } + + master_audio_clock++; + + // frame sequencer ticks at a rate of 512 hz (or every time a 13 bit counter rolls over) + // the sequencer is actually the timer DIV register + // so if it's constantly written to, these values won't update + bool check = double_speed ? ((timer_div_reg & 0x2000) > 0) : ((timer_div_reg & 0x1000) > 0); + + if (check && !timer_bit_old) + { + 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; calculate_bias_gain_1(); } + } + if (SQ2_len_en && SQ2_len_cntr > 0) + { + SQ2_len_cntr--; + if (SQ2_len_cntr == 0) { SQ2_enable = false; calculate_bias_gain_2(); } + } + if (WAVE_len_en && WAVE_len_cntr > 0) + { + WAVE_len_cntr--; + if (WAVE_len_cntr == 0) { WAVE_enable = false; calculate_bias_gain_w(); } + } + if (NOISE_len_en && NOISE_len_cntr > 0) + { + NOISE_len_cntr--; + if (NOISE_len_cntr == 0) { NOISE_enable = false; calculate_bias_gain_n(); } + } + } + + // 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; } + 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 ((uint32_t)shadow_frq > 2047) + { + SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1(); + } + else + { + if (SQ1_shift > 0) + { + 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] = (uint8_t)(SQ1_frq & 0xFF); + Audio_Regs[NR14] &= 0xF8; + Audio_Regs[NR14] |= (uint8_t)((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 ((uint32_t)shadow_frq > 2047) + { + SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1(); + } + } + } + } + } + } + + // 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 (!SQ1_vol_done) + { + if (SQ1_env_add) + { + if (SQ1_vol_state < 15) { SQ1_vol_state++; } + else { SQ1_vol_done = true; } + } + else + { + 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_vol_done) + { + if (SQ2_env_add) + { + if (SQ2_vol_state < 15) { SQ2_vol_state++; } + else { SQ2_vol_done = true; } + } + else + { + 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_vol_done) + { + if (NOISE_env_add) + { + if (NOISE_vol_state < 15) { NOISE_vol_state++; } + else { NOISE_vol_done = true; } + } + else + { + if (NOISE_vol_state >= 1) { NOISE_vol_state--; } + else { NOISE_vol_done = true; } + } + } + } + } + } + } + timer_bit_old = double_speed ? ((timer_div_reg & 0x2000) > 0) : ((timer_div_reg & 0x1000) > 0); + } + + void power_off() + { + for (int i = 0; i < 0x16; i++) + { + WriteReg(0xFF10 + i, 0); + } + + calculate_bias_gain_a(); + + // duty and length are reset + SQ1_duty_cntr = SQ2_duty_cntr = 0; + + // reset state variables + SQ1_enable = SQ1_swp_enable = SQ2_enable = WAVE_enable = NOISE_enable = false; + + SQ1_len_en = SQ2_len_en = WAVE_len_en = NOISE_len_en = false; + + SQ1_output = SQ2_output = WAVE_output = NOISE_output = 0; + + // on GBC, lengths are also reset + if (is_GBC) + { + SQ1_length = SQ2_length = WAVE_length = NOISE_length = 0; + SQ1_len_cntr = SQ2_len_cntr = WAVE_len_cntr = NOISE_len_cntr = 0; + } + + sequencer_len = 0; + sequencer_vol = 0; + sequencer_swp = 0; + } + + void Reset() + { + if (is_GBC) + { + Wave_RAM[0] = 0; Wave_RAM[2] = 0; Wave_RAM[4] = 0; Wave_RAM[6] = 0; + Wave_RAM[8] = 0; Wave_RAM[10] = 0; Wave_RAM[12] = 0; Wave_RAM[14] = 0; + + Wave_RAM[1] = 0xFF; Wave_RAM[3] = 0xFF; Wave_RAM[5] = 0xFF; Wave_RAM[7] = 0xFF; + Wave_RAM[9] = 0xFF; Wave_RAM[11] = 0xFF; Wave_RAM[13] = 0xFF; Wave_RAM[15] = 0xFF; + } + else + { + Wave_RAM[0] = 0x84; Wave_RAM[1] = 0x40; Wave_RAM[2] = 0x43; Wave_RAM[3] = 0xAA; + Wave_RAM[4] = 0x2D; Wave_RAM[5] = 0x78; Wave_RAM[6] = 0x92; Wave_RAM[7] = 0x3C; + + Wave_RAM[8] = 0x60; Wave_RAM[9] = 0x59; Wave_RAM[10] = 0x59; Wave_RAM[11] = 0xB0; + Wave_RAM[12] = 0x34; Wave_RAM[13] = 0xB8; Wave_RAM[14] = 0x2E; Wave_RAM[15] = 0xDA; + } + + for (int i = 0; i < 21; i++) + { + Audio_Regs[i] = 0; + } + + for (int i = 0; i < 0x16; i++) + { + WriteReg(0xFF10 + i, 0); + } + + calculate_bias_gain_a(); + + SQ1_duty_cntr = SQ2_duty_cntr = 0; + + SQ1_enable = SQ1_swp_enable = SQ2_enable = WAVE_enable = NOISE_enable = false; + + SQ1_len_en = SQ2_len_en = WAVE_len_en = NOISE_len_en = false; + + SQ1_output = SQ2_output = WAVE_output = NOISE_output = 0; + + SQ1_length = SQ2_length = WAVE_length = NOISE_length = 0; + SQ1_len_cntr = SQ2_len_cntr = WAVE_len_cntr = NOISE_len_cntr = 0; + + master_audio_clock = 0; + + sequencer_len = 0; + sequencer_swp = 0; + sequencer_vol = 0; + + sample = 0; + } + + void calculate_bias_gain_a() + { + if ((AUD_CTRL_sq1_R_en | AUD_CTRL_sq1_L_en) && ((Audio_Regs[NR12] & 0xF8) > 0)) + { + SQ1_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; + } + else + { + SQ1_bias_gain = 0; + } + if ((AUD_CTRL_sq2_R_en | AUD_CTRL_sq2_L_en) && ((Audio_Regs[NR22] & 0xF8) > 0)) + { + SQ2_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; + } + else + { + SQ2_bias_gain = 0; + } + if ((AUD_CTRL_wave_R_en | AUD_CTRL_wave_L_en) && WAVE_DAC_pow) + { + WAVE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; + } + else + { + WAVE_bias_gain = 0; + } + if ((AUD_CTRL_noise_R_en | AUD_CTRL_noise_L_en) && ((Audio_Regs[NR42] & 0xF8) > 0)) + { + NOISE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; + } + else + { + NOISE_bias_gain = 0; + } + + if (!SQ1_enable) { SQ1_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } + if (!SQ2_enable) { SQ2_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } + //if (!WAVE_enable) { WAVE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } + if (!NOISE_enable) { NOISE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; } + } + + void calculate_bias_gain_1() + { + if ((AUD_CTRL_sq1_R_en | AUD_CTRL_sq1_L_en) && ((Audio_Regs[NR12] & 0xF8) > 0)) + { + SQ1_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; + } + else + { + SQ1_bias_gain = 0; + } + + if (!SQ1_enable) { SQ1_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } + } + + void calculate_bias_gain_2() + { + if ((AUD_CTRL_sq2_R_en | AUD_CTRL_sq2_L_en) && ((Audio_Regs[NR22] & 0xF8) > 0)) + { + SQ2_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; + } + else + { + SQ2_bias_gain = 0; + } + + if (!SQ2_enable) { SQ2_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } + } + + void calculate_bias_gain_w() + { + if ((AUD_CTRL_wave_R_en | AUD_CTRL_wave_L_en) && WAVE_DAC_pow) + { + WAVE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; + } + else + { + WAVE_bias_gain = 0; + } + + if (!WAVE_enable) { WAVE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; } + } + + void calculate_bias_gain_n() + { + if ((AUD_CTRL_noise_R_en | AUD_CTRL_noise_L_en) && ((Audio_Regs[NR42] & 0xF8) > 0)) + { + NOISE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3; + } + else + { + NOISE_bias_gain = 0; + } + + if (!NOISE_enable) { NOISE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; } + } + + uint8_t Read_NR52() + { + return (uint8_t)( + ((AUD_CTRL_power ? 1 : 0) << 7) | + (SQ1_enable ? 1 : 0) | + ((SQ2_enable ? 1 : 0) << 1) | + ((WAVE_enable ? 1 : 0) << 2) | + ((NOISE_enable ? 1 : 0) << 3)); + } + + #pragma endregion + + + #pragma region State Save / Load + + uint8_t* SaveState(uint8_t* saver) + { + for (int i = 0; i < 21; i++) + { + saver = byte_saver(Audio_Regs[i], saver); + } + + for (int i = 0; i < 16; i++) + { + saver = byte_saver(Wave_RAM[i], saver); + } + + saver = bool_saver(SQ1_vol_done, saver); + saver = bool_saver(SQ1_calc_done, saver); + saver = bool_saver(SQ1_swp_enable, saver); + saver = bool_saver(SQ1_enable, saver); + saver = byte_saver(SQ1_vol_state, saver); + saver = byte_saver(SQ1_duty_cntr, saver); + saver = int_saver(SQ1_frq_shadow, saver); + saver = int_saver(SQ1_intl_cntr, saver); + saver = int_saver(SQ1_vol_per, saver); + saver = int_saver(SQ1_intl_swp_cnt, saver); + saver = int_saver(SQ1_len_cntr, saver); + saver = bool_saver(SQ1_negate, saver); + saver = bool_saver(SQ1_trigger, saver); + saver = bool_saver(SQ1_len_en, saver); + saver = bool_saver(SQ1_env_add, saver); + saver = byte_saver(SQ1_shift, saver); + saver = byte_saver(SQ1_duty, saver); + saver = byte_saver(SQ1_st_vol, saver); + saver = byte_saver(SQ1_per, saver); + saver = byte_saver(SQ1_swp_prd, saver); + saver = int_saver(SQ1_frq, saver); + saver = int_saver(SQ1_length, saver); + saver = int_saver(SQ1_output, saver); + + saver = bool_saver(SQ2_vol_done, saver); + saver = bool_saver(SQ2_enable, saver); + saver = byte_saver(SQ2_vol_state, saver); + saver = byte_saver(SQ2_duty_cntr, saver); + saver = int_saver(SQ2_intl_cntr, saver); + saver = int_saver(SQ2_vol_per, saver); + saver = int_saver(SQ2_len_cntr, saver); + saver = bool_saver(SQ2_trigger, saver); + saver = bool_saver(SQ2_len_en, saver); + saver = bool_saver(SQ2_env_add, saver); + saver = byte_saver(SQ2_duty, saver); + saver = byte_saver(SQ2_st_vol, saver); + saver = byte_saver(SQ2_per, saver); + saver = int_saver(SQ2_frq, saver); + saver = int_saver(SQ2_length, saver); + saver = int_saver(SQ2_output, saver); + + saver = bool_saver(WAVE_can_get, saver); + saver = bool_saver(WAVE_enable, saver); + saver = byte_saver(WAVE_wave_cntr, saver); + saver = int_saver(WAVE_intl_cntr, saver); + saver = int_saver(WAVE_len_cntr, saver); + saver = bool_saver(WAVE_DAC_pow, saver); + saver = bool_saver(WAVE_trigger, saver); + saver = bool_saver(WAVE_len_en, saver); + saver = byte_saver(WAVE_vol_code, saver); + saver = int_saver(WAVE_frq, saver); + saver = int_saver(WAVE_length, saver); + saver = int_saver(WAVE_output, saver); + + saver = bool_saver(NOISE_vol_done, saver); + saver = bool_saver(NOISE_enable, saver); + saver = byte_saver(NOISE_vol_state, saver); + saver = int_saver(NOISE_intl_cntr, saver); + saver = int_saver(NOISE_vol_per, saver); + saver = int_saver(NOISE_LFSR, saver); + saver = int_saver(NOISE_len_cntr, saver); + saver = bool_saver(NOISE_wdth_md, saver); + saver = bool_saver(NOISE_trigger, saver); + saver = bool_saver(NOISE_len_en, saver); + saver = bool_saver(NOISE_env_add, saver); + saver = byte_saver(NOISE_clk_shft, saver); + saver = byte_saver(NOISE_div_code, saver); + saver = byte_saver(NOISE_st_vol, saver); + saver = byte_saver(NOISE_per, saver); + saver = int_saver(NOISE_length, saver); + saver = int_saver(NOISE_output, saver); + + saver = int_saver(sequencer_len, saver); + saver = int_saver(sequencer_vol, saver); + saver = int_saver(sequencer_swp, saver); + saver = bool_saver(timer_bit_old, saver); + + saver = int_saver(master_audio_clock, saver); + + saver = byte_saver(sample, saver); + saver = int_saver(latched_sample_L, saver); + saver = int_saver(latched_sample_R, saver); + saver = int_saver(num_samples_L, saver); + saver = int_saver(num_samples_R, saver); + + saver = bool_saver(is_GBC, saver); + saver = bool_saver(double_speed, saver); + saver = int_saver(timer_div_reg, saver); + + saver = bool_saver(AUD_CTRL_vin_L_en, saver); + saver = bool_saver(AUD_CTRL_vin_R_en, saver); + saver = bool_saver(AUD_CTRL_sq1_L_en, saver); + saver = bool_saver(AUD_CTRL_sq2_L_en, saver); + saver = bool_saver(AUD_CTRL_wave_L_en, saver); + saver = bool_saver(AUD_CTRL_noise_L_en, saver); + saver = bool_saver(AUD_CTRL_sq1_R_en, saver); + saver = bool_saver(AUD_CTRL_sq2_R_en, saver); + saver = bool_saver(AUD_CTRL_wave_R_en, saver); + saver = bool_saver(AUD_CTRL_noise_R_en, saver); + saver = bool_saver(AUD_CTRL_power, saver); + saver = byte_saver(AUD_CTRL_vol_L, saver); + saver = byte_saver(AUD_CTRL_vol_R, saver); + + saver = int_saver(SQ1_bias_gain, saver); + saver = int_saver(SQ2_bias_gain, saver); + saver = int_saver(WAVE_bias_gain, saver); + saver = int_saver(NOISE_bias_gain, saver); + return saver; + } + + uint8_t* LoadState(uint8_t* loader) + { + for (int i = 0; i < 21; i++) + { + loader = byte_loader(&Audio_Regs[i], loader); + } + + for (int i = 0; i < 16; i++) + { + loader = byte_loader(&Wave_RAM[i], loader); + } + + loader = bool_loader(&SQ1_vol_done, loader); + loader = bool_loader(&SQ1_calc_done, loader); + loader = bool_loader(&SQ1_swp_enable, loader); + loader = bool_loader(&SQ1_enable, loader); + loader = byte_loader(&SQ1_vol_state, loader); + loader = byte_loader(&SQ1_duty_cntr, loader); + loader = int_loader(&SQ1_frq_shadow, loader); + loader = int_loader(&SQ1_intl_cntr, loader); + loader = int_loader(&SQ1_vol_per, loader); + loader = int_loader(&SQ1_intl_swp_cnt, loader); + loader = int_loader(&SQ1_len_cntr, loader); + loader = bool_loader(&SQ1_negate, loader); + loader = bool_loader(&SQ1_trigger, loader); + loader = bool_loader(&SQ1_len_en, loader); + loader = bool_loader(&SQ1_env_add, loader); + loader = byte_loader(&SQ1_shift, loader); + loader = byte_loader(&SQ1_duty, loader); + loader = byte_loader(&SQ1_st_vol, loader); + loader = byte_loader(&SQ1_per, loader); + loader = byte_loader(&SQ1_swp_prd, loader); + loader = int_loader(&SQ1_frq, loader); + loader = int_loader(&SQ1_length, loader); + loader = int_loader(&SQ1_output, loader); + + loader = bool_loader(&SQ2_vol_done, loader); + loader = bool_loader(&SQ2_enable, loader); + loader = byte_loader(&SQ2_vol_state, loader); + loader = byte_loader(&SQ2_duty_cntr, loader); + loader = int_loader(&SQ2_intl_cntr, loader); + loader = int_loader(&SQ2_vol_per, loader); + loader = int_loader(&SQ2_len_cntr, loader); + loader = bool_loader(&SQ2_trigger, loader); + loader = bool_loader(&SQ2_len_en, loader); + loader = bool_loader(&SQ2_env_add, loader); + loader = byte_loader(&SQ2_duty, loader); + loader = byte_loader(&SQ2_st_vol, loader); + loader = byte_loader(&SQ2_per, loader); + loader = int_loader(&SQ2_frq, loader); + loader = int_loader(&SQ2_length, loader); + loader = int_loader(&SQ2_output, loader); + + loader = bool_loader(&WAVE_can_get, loader); + loader = bool_loader(&WAVE_enable, loader); + loader = byte_loader(&WAVE_wave_cntr, loader); + loader = int_loader(&WAVE_intl_cntr, loader); + loader = int_loader(&WAVE_len_cntr, loader); + loader = bool_loader(&WAVE_DAC_pow, loader); + loader = bool_loader(&WAVE_trigger, loader); + loader = bool_loader(&WAVE_len_en, loader); + loader = byte_loader(&WAVE_vol_code, loader); + loader = int_loader(&WAVE_frq, loader); + loader = int_loader(&WAVE_length, loader); + loader = int_loader(&WAVE_output, loader); + + loader = bool_loader(&NOISE_vol_done, loader); + loader = bool_loader(&NOISE_enable, loader); + loader = byte_loader(&NOISE_vol_state, loader); + loader = int_loader(&NOISE_intl_cntr, loader); + loader = int_loader(&NOISE_vol_per, loader); + loader = int_loader(&NOISE_LFSR, loader); + loader = int_loader(&NOISE_len_cntr, loader); + loader = bool_loader(&NOISE_wdth_md, loader); + loader = bool_loader(&NOISE_trigger, loader); + loader = bool_loader(&NOISE_len_en, loader); + loader = bool_loader(&NOISE_env_add, loader); + loader = byte_loader(&NOISE_clk_shft, loader); + loader = byte_loader(&NOISE_div_code, loader); + loader = byte_loader(&NOISE_st_vol, loader); + loader = byte_loader(&NOISE_per, loader); + loader = int_loader(&NOISE_length, loader); + loader = int_loader(&NOISE_output, loader); + + loader = int_loader(&sequencer_len, loader); + loader = int_loader(&sequencer_vol, loader); + loader = int_loader(&sequencer_swp, loader); + loader = bool_loader(&timer_bit_old, loader); + + loader = int_loader(&master_audio_clock, loader); + + loader = byte_loader(&sample, loader); + loader = int_loader(&latched_sample_L, loader); + loader = int_loader(&latched_sample_R, loader); + loader = int_loader(&num_samples_L, loader); + loader = int_loader(&num_samples_R, loader); + + loader = bool_loader(&is_GBC, loader); + loader = bool_loader(&double_speed, loader); + loader = int_loader(&timer_div_reg, loader); + + loader = bool_loader(&AUD_CTRL_vin_L_en, loader); + loader = bool_loader(&AUD_CTRL_vin_R_en, loader); + loader = bool_loader(&AUD_CTRL_sq1_L_en, loader); + loader = bool_loader(&AUD_CTRL_sq2_L_en, loader); + loader = bool_loader(&AUD_CTRL_wave_L_en, loader); + loader = bool_loader(&AUD_CTRL_noise_L_en, loader); + loader = bool_loader(&AUD_CTRL_sq1_R_en, loader); + loader = bool_loader(&AUD_CTRL_sq2_R_en, loader); + loader = bool_loader(&AUD_CTRL_wave_R_en, loader); + loader = bool_loader(&AUD_CTRL_noise_R_en, loader); + loader = bool_loader(&AUD_CTRL_power, loader); + loader = byte_loader(&AUD_CTRL_vol_L, loader); + loader = byte_loader(&AUD_CTRL_vol_R, loader); + + loader = int_loader(&SQ1_bias_gain, loader); + loader = int_loader(&SQ2_bias_gain, loader); + loader = int_loader(&WAVE_bias_gain, loader); + loader = int_loader(&NOISE_bias_gain, loader); + return loader; + } + + #pragma endregion + + uint8_t* bool_saver(bool to_save, uint8_t* saver) + { + *saver = (uint8_t)(to_save ? 1 : 0); saver++; + + return saver; + } + + uint8_t* byte_saver(uint8_t to_save, uint8_t* saver) + { + *saver = to_save; saver++; + + return saver; + } + + uint8_t* int_saver(uint32_t to_save, uint8_t* saver) + { + *saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++; + *saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++; + + return saver; + } + + uint8_t* bool_loader(bool* to_load, uint8_t* loader) + { + to_load[0] = *to_load == 1; loader++; + + return loader; + } + + uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader) + { + to_load[0] = *loader; loader++; + + return loader; + } + + uint8_t* int_loader(uint32_t* to_load, uint8_t* loader) + { + to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++; + to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++; + + return loader; + } + }; +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/GBHawk.cpp b/libHawk/GBHawk/GBHawk/GBHawk.cpp index cbdc64dbb7..8c02c37456 100644 --- a/libHawk/GBHawk/GBHawk/GBHawk.cpp +++ b/libHawk/GBHawk/GBHawk/GBHawk.cpp @@ -53,9 +53,9 @@ GBHawk_EXPORT void GB_get_video(GBCore* p, uint32_t* dest) } // send audio data to external audio provider -GBHawk_EXPORT uint32_t GB_get_audio(GBCore* p, int32_t* dest, int32_t* n_samp) +GBHawk_EXPORT uint32_t GB_get_audio(GBCore* p, int32_t* dest_L, int32_t* n_samp_L, int32_t* dest_R, int32_t* n_samp_R) { - return p->GetAudio(dest, n_samp); + return p->GetAudio(dest_L, n_samp_L, dest_R, n_samp_R); } #pragma region State Save / Load diff --git a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj index 547228280b..ede8ced20b 100644 --- a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj +++ b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj @@ -151,7 +151,7 @@ - + diff --git a/libHawk/GBHawk/GBHawk/LR35902.cpp b/libHawk/GBHawk/GBHawk/LR35902.cpp index d264e78980..0cb691e652 100644 --- a/libHawk/GBHawk/GBHawk/LR35902.cpp +++ b/libHawk/GBHawk/GBHawk/LR35902.cpp @@ -11,10 +11,7 @@ namespace GBHawk { void LR35902::WriteMemory(uint32_t addr, uint8_t value) { - if ((addr & 0xFFFF) >= 0xFFFC) - { - mem_ctrl->MemoryWrite(addr, value); - } + mem_ctrl->MemoryWrite(addr, value); } uint8_t LR35902::ReadMemory(uint32_t addr) @@ -22,6 +19,11 @@ namespace GBHawk return mem_ctrl->HardwareRead(addr); } + uint8_t LR35902::PeekMemory(uint32_t addr) + { + return mem_ctrl->HardwareRead(addr); + } + uint8_t LR35902::SpeedFunc(uint32_t addr) { return mem_ctrl->HardwareRead(addr); diff --git a/libHawk/GBHawk/GBHawk/LR35902.h b/libHawk/GBHawk/GBHawk/LR35902.h index 0f350d9b49..b409984b99 100644 --- a/libHawk/GBHawk/GBHawk/LR35902.h +++ b/libHawk/GBHawk/GBHawk/LR35902.h @@ -18,74 +18,42 @@ namespace GBHawk // pointer to controlling memory manager goes here // this will be iplementation dependent MemoryManager* mem_ctrl; - - // Memory is usually mostly static, so it is efficient to access it with a pointer and write mask - // the size of the pointer matrix and masks is system dependent. - // This also assumes a simple relationship between bank and write mask - // some systems might require more detailed mask, maybe even the same size as read - const uint32_t low_mask = 0x3FF; - const uint32_t high_mask = 0x3F; - const uint32_t bank_shift = 10; - - // these are not savestated as they are automatically adjusted from the memory map upon load - uint32_t bank_num; - uint32_t bank_offset; - uint8_t* MemoryMap[64]; - uint8_t MemoryMapMask[64]; void WriteMemory(uint32_t, uint8_t); uint8_t ReadMemory(uint32_t); + uint8_t PeekMemory(uint32_t); uint8_t SpeedFunc(uint32_t); // State variables - uint64_t TotalExecutedCycles; - - uint32_t EI_pending; bool interrupts_enabled; - - // variables for executing instructions - int instr_pntr = 0; - int opcode; bool CB_prefix; bool halted; bool stopped; bool jammed; - int LY; - - // unsaved variables - bool checker; - uint8_t Regs[14] = {}; - bool was_FlagI, FlagI; + uint8_t Regs[14] = {}; + uint8_t EI_pending; + uint8_t LY; + uint8_t opcode; - uint32_t PRE_SRC; - // variables for executing instructions - uint32_t stepper = 0; uint32_t instr_pntr = 0; - uint32_t bus_pntr = 0; - uint32_t mem_pntr = 0; - uint32_t irq_pntr = 0; - uint32_t IRQS; - uint32_t Ztemp2_saver = 0; - uint32_t IRQS_cond_offset; uint64_t TotalExecutedCycles; - - uint32_t* cur_instr_ofst = nullptr; - uint32_t* cur_bus_ofst = nullptr; - uint32_t* cur_mem_ofst = nullptr; - uint32_t* cur_irqs_ofst = nullptr; - + // non-state variables bool checker; - - - uint32_t Ztemp1, Ztemp2, Ztemp3, Ztemp4; - uint32_t Reg16_d, Reg16_s, ans, temp, carry; + bool temp2; uint32_t cur_instr[60] = {}; // only used for building uint32_t instr_table[256 * 2 * 60 + 60 * 8] = {}; // compiled instruction table + // local variables for operations, not stated + bool imm; + uint8_t a_d; + uint32_t Reg16_d, Reg16_s, c; + uint32_t ans, ans_l, ans_h, temp; + uint32_t bit_check; + #pragma endregion #pragma region Constant Declarations @@ -171,19 +139,19 @@ namespace GBHawk #pragma region LR35902 functions inline bool FlagCget() { return (Regs[5] & 0x10) != 0; }; - inline void FlagCset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } + inline void FlagCset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } inline bool FlagHget() { return (Regs[5] & 0x20) != 0; }; - inline void FlagHset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } + inline void FlagHset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } inline bool FlagNget() { return (Regs[5] & 0x40) != 0; }; - inline void FlagNset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } + inline void FlagNset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } inline bool FlagZget() { return (Regs[5] & 0x80) != 0; }; - inline void FlagZset(bool value) { Regs[5] = (uint32_t)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } + inline void FlagZset(bool value) { Regs[5] = (uint8_t)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } inline uint32_t RegPCget() { return (uint32_t)(Regs[0] | (Regs[1] << 8)); } - inline void RegPCset(uint32_t value) { Regs[0] = (uint32_t)(value & 0xFF); Regs[1] = (uint32_t)((value >> 8) & 0xFF); } + inline void RegPCset(uint32_t value) { Regs[0] = (uint8_t)(value & 0xFF); Regs[1] = (uint8_t)((value >> 8) & 0xFF); } LR35902() { @@ -211,7 +179,7 @@ namespace GBHawk CB_prefix = false; } - inline void FetchInstruction(uint32_t op) + inline void FetchInstruction(uint8_t op) { opcode = op; @@ -368,15 +336,15 @@ namespace GBHawk case HALT: halted = true; - bool temp = false; + temp2 = false; if (instr_table[instr_pntr++] == 1) { - temp = FlagI; + temp2 = FlagI; } else { - temp = I_use; + temp2 = I_use; } if (EI_pending > 0 && !CB_prefix) @@ -389,7 +357,7 @@ namespace GBHawk } // if the I flag is asserted at the time of halt, don't halt - if (temp && interrupts_enabled && !CB_prefix && !jammed) + if (temp2 && interrupts_enabled && !CB_prefix && !jammed) { interrupts_enabled = false; @@ -418,7 +386,7 @@ namespace GBHawk Halt_bug_3 = false; } } - else if (temp) + else if (temp2) { // even if interrupt servicing is disabled, any interrupt flag raised still resumes execution if (TraceCallback) { TraceCallback(1); } @@ -560,7 +528,8 @@ namespace GBHawk // check if any interrupts got cancelled along the way // interrupt src = 5 sets the PC to zero as observed // also the triggering interrupt seems like it is held low (i.e. cannot trigger I flag) until the interrupt is serviced - uint32_t bit_check = instr_table[instr_pntr++]; + bit_check = instr_table[instr_pntr]; + instr_pntr++; //Console.WriteLine(interrupt_src + " " + interrupt_enable + " " + TotalExecutedCycles); if (((interrupt_src[0] & (1 << bit_check)) > 0) && ((interrupt_enable & (1 << bit_check)) > 0)) { int_src = bit_check; int_clear = (uint8_t)(1 << bit_check); } @@ -572,7 +541,8 @@ namespace GBHawk else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; int_clear = 16; } else { int_src = 5; int_clear = 0; } */ - Regs[instr_table[instr_pntr++]] = INT_vectors[int_src]; + Regs[instr_table[instr_pntr]] = INT_vectors[int_src]; + instr_pntr++; break; case HALT_CHK: I_use = FlagI; @@ -587,7 +557,7 @@ namespace GBHawk Halt_bug_2 = false; break; case IRQ_CLEAR: - if ((interrupt_src[0] & (1 << int_src)) > 0) { interrupt_src -= int_clear; } + if ((interrupt_src[0] & (1 << int_src)) > 0) { interrupt_src[0] -= int_clear; } if ((interrupt_src[0] & interrupt_enable) == 0) { FlagI = false; } @@ -2164,13 +2134,6 @@ namespace GBHawk #pragma region Operations - // local variables for operations, not stated - uint32_t Reg16_d, Reg16_s, c; - uint32_t ans, ans_l, ans_h, temp; - uint8_t a_d; - bool imm; - - void Read_Func(uint32_t dest, uint32_t src_l, uint32_t src_h) { uint32_t addr = (uint32_t)(Regs[src_l] | (Regs[src_h]) << 8); @@ -2185,14 +2148,14 @@ namespace GBHawk // special read for POP AF that always clears the lower 4 bits of F void Read_Func_F(uint32_t dest, uint32_t src_l, uint32_t src_h) { - Regs[dest] = (uint32_t)(ReadMemory((uint32_t)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0); + Regs[dest] = (ReadMemory((uint32_t)(Regs[src_l] | (Regs[src_h]) << 8)) & 0xF0); } void Write_Func(uint32_t dest_l, uint32_t dest_h, uint32_t src) { uint32_t addr = (uint32_t)(Regs[dest_l] | (Regs[dest_h]) << 8); //CDLCallback ? .Invoke(addr, eCDLogMemFlags.Write | eCDLogMemFlags.Data); - WriteMemory(addr, (uint8_t)Regs[src]); + WriteMemory(addr, Regs[src]); } void TR_Func(uint32_t dest, uint32_t src) @@ -2221,8 +2184,8 @@ namespace GBHawk FlagHset((Reg16_d & 0x1000) > 0); FlagNset(false); - Regs[dest_l] = ans_l; - Regs[dest_h] = ans_h; + Regs[dest_l] = (uint8_t)ans_l; + Regs[dest_h] = (uint8_t)ans_h; } void ADD8_Func(uint32_t dest, uint32_t src) @@ -2243,7 +2206,7 @@ namespace GBHawk FlagNset(false); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void SUB8_Func(uint32_t dest, uint32_t src) @@ -2263,35 +2226,35 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void BIT_Func(uint32_t bit, uint32_t src) { - FlagZset(!Regs[src].Bit(bit)); + FlagZset(!((Regs[src] & (1 << bit)) > 0)); FlagHset(true); FlagNset(false); } void SET_Func(uint32_t bit, uint32_t src) { - Regs[src] |= (uint32_t)(1 << bit); + Regs[src] |= (uint8_t)(1 << bit); } void RES_Func(uint32_t bit, uint32_t src) { - Regs[src] &= (uint32_t)(0xFF - (1 << bit)); + Regs[src] &= (uint8_t)(0xFF - (1 << bit)); } void ASGN_Func(uint32_t src, uint32_t val) { - Regs[src] = val; + Regs[src] = (uint8_t)val; } void SWAP_Func(uint32_t src) { temp = (uint32_t)((Regs[src] << 4) & 0xF0); - Regs[src] = (uint32_t)(temp | (Regs[src] >> 4)); + Regs[src] = (uint8_t)(temp | (Regs[src] >> 4)); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2301,9 +2264,9 @@ namespace GBHawk void SLA_Func(uint32_t src) { - FlagCset(Regs[src].Bit(7)); + FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (uint32_t)((Regs[src] << 1) & 0xFF); + Regs[src] = (uint8_t)((Regs[src] << 1) & 0xFF); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2312,11 +2275,11 @@ namespace GBHawk void SRA_Func(uint32_t src) { - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); temp = (uint32_t)(Regs[src] & 0x80); // MSB doesn't change in this operation - Regs[src] = (uint32_t)((Regs[src] >> 1) | temp); + Regs[src] = (uint8_t)((Regs[src] >> 1) | temp); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2325,9 +2288,9 @@ namespace GBHawk void SRL_Func(uint32_t src) { - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); - Regs[src] = (uint32_t)(Regs[src] >> 1); + Regs[src] = (uint8_t)(Regs[src] >> 1); FlagZset(Regs[src] == 0); FlagHset(false); @@ -2336,7 +2299,7 @@ namespace GBHawk void CPL_Func(uint32_t src) { - Regs[src] = (uint32_t)((~Regs[src]) & 0xFF); + Regs[src] = (uint8_t)((~Regs[src]) & 0xFF); FlagHset(true); FlagNset(true); @@ -2358,7 +2321,7 @@ namespace GBHawk void AND8_Func(uint32_t dest, uint32_t src) { - Regs[dest] = (uint32_t)(Regs[dest] & Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] & Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -2368,7 +2331,7 @@ namespace GBHawk void OR8_Func(uint32_t dest, uint32_t src) { - Regs[dest] = (uint32_t)(Regs[dest] | Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] | Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -2378,7 +2341,7 @@ namespace GBHawk void XOR8_Func(uint32_t dest, uint32_t src) { - Regs[dest] = (uint32_t)(Regs[dest] ^ Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] ^ Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -2408,9 +2371,9 @@ namespace GBHawk imm = src == Aim; if (imm) { src = A; } - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); - Regs[src] = (uint32_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); + Regs[src] = (uint8_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2424,9 +2387,9 @@ namespace GBHawk c = FlagCget() ? 0x80 : 0; - FlagCset(Regs[src].Bit(0)); + FlagCset((Regs[src] & 1) > 0); - Regs[src] = (uint32_t)(c | (Regs[src] >> 1)); + Regs[src] = (uint8_t)(c | (Regs[src] >> 1)); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2438,10 +2401,10 @@ namespace GBHawk imm = src == Aim; if (imm) { src = A; } - c = Regs[src].Bit(7) ? 1 : 0; - FlagCset(Regs[src].Bit(7)); + c = (Regs[src] & 0x80) > 0 ? 1 : 0; + FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (uint32_t)(((Regs[src] << 1) & 0xFF) | c); + Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | c); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2454,9 +2417,9 @@ namespace GBHawk if (imm) { src = A; } c = FlagCget() ? 1 : 0; - FlagCset(Regs[src].Bit(7)); + FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (uint32_t)(((Regs[src] << 1) & 0xFF) | c); + Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | c); FlagZset(imm ? false : (Regs[src] == 0)); FlagHset(false); @@ -2479,7 +2442,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(false); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; } void DEC8_Func(uint32_t src) @@ -2498,7 +2461,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; } void INC16_Func(uint32_t src_l, uint32_t src_h) @@ -2507,8 +2470,8 @@ namespace GBHawk Reg16_d += 1; - Regs[src_l] = (uint32_t)(Reg16_d & 0xFF); - Regs[src_h] = (uint32_t)((Reg16_d & 0xFF00) >> 8); + Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); } void DEC16_Func(uint32_t src_l, uint32_t src_h) @@ -2517,8 +2480,8 @@ namespace GBHawk Reg16_d -= 1; - Regs[src_l] = (uint32_t)(Reg16_d & 0xFF); - Regs[src_h] = (uint32_t)((Reg16_d & 0xFF00) >> 8); + Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); } void ADC8_Func(uint32_t dest, uint32_t src) @@ -2540,7 +2503,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(false); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void SBC8_Func(uint32_t dest, uint32_t src) @@ -2562,7 +2525,7 @@ namespace GBHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } // DA code courtesy of AWJ: http://forums.nesdev.com/viewtopic.php?f=20&t=15944 @@ -2583,7 +2546,7 @@ namespace GBHawk a_d &= 0xFF; - Regs[src] = a_d; + Regs[src] = (uint8_t)a_d; FlagZset(a_d == 0); FlagHset(false); @@ -2632,9 +2595,9 @@ namespace GBHawk FlagZset(false); } - Regs[dest_l] = ans_l; - Regs[dest_h] += temp; - Regs[dest_h] &= 0xFF; + Regs[dest_l] = (uint8_t)ans_l; + Regs[dest_h] += (uint8_t)temp; + Regs[dest_h] &= (uint8_t)0xFF; } @@ -2646,7 +2609,7 @@ namespace GBHawk const char* TraceHeader = "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; const char* Un_halt_event = " ==Un-halted== "; const char* IRQ_event = " ====IRQ==== "; - const char* Un_halt_event = " ==Un-stopped== "; + const char* Un_stop_event = " ==Un-stopped== "; const char* No_Reg = " "; const char* Reg_template = "AF:AAFF BC:BBCC DE:DDEE HL:HHLL Ix:IxIx Iy:IyIy SP:SPSP Cy:FEDCBA9876543210 CNP3H5ZSE"; const char* Disasm_template = "PCPC: AA BB CC DD Di Di, XXXXX "; @@ -2689,7 +2652,7 @@ namespace GBHawk reg_state.append(val_char_1, 4); reg_state.append(" Cy:"); - reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", (uint64_t)TotalExecutedCycles)); + reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", (unsigned long)TotalExecutedCycles)); reg_state.append(" "); reg_state.append(FlagCget() ? "C" : "c"); @@ -2719,12 +2682,8 @@ namespace GBHawk for (i = 0; i < bytes_read; i++) { - bank_num = bank_offset = (RegPCget() + i) & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - char* val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%02X", PeekMemory((RegPCget() + i) & 0xFFFF)); string val1(val_char_1, 2); byte_code.append(val1); @@ -2759,23 +2718,15 @@ namespace GBHawk { size_t str_loc = format.find("nn"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift) & high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 2); - - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; addr[0]++; val_char_2 = replacer; - sprintf_s(val_char_2, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_2, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); string val2(val_char_2, 2); + addr[0]++; format.erase(str_loc, 2); format.insert(str_loc, val1); @@ -2786,14 +2737,10 @@ namespace GBHawk { size_t str_loc = format.find("n"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%02X", MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%02X", PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 2); + addr[0]++; format.erase(str_loc, 1); format.insert(str_loc, val1); @@ -2803,14 +2750,10 @@ namespace GBHawk { size_t str_loc = format.find("+d"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%+04d", (int8_t)MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%+04d", (int8_t)PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 4); + addr[0]++; format.erase(str_loc, 2); format.insert(str_loc, val1); @@ -2819,14 +2762,10 @@ namespace GBHawk { size_t str_loc = format.find("d"); - bank_num = bank_offset = addr[0] & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift)& high_mask; - addr[0]++; - val_char_1 = replacer; - sprintf_s(val_char_1, 5, "%+04d", (int8_t)MemoryMap[bank_num][bank_offset]); + sprintf_s(val_char_1, 5, "%+04d", (int8_t)PeekMemory(addr[0] & 0xFFFF)); string val1(val_char_1, 4); + addr[0]++; format.erase(str_loc, 1); format.insert(str_loc, val1); @@ -2840,22 +2779,14 @@ namespace GBHawk uint32_t start_addr = addr; uint32_t extra_inc = 0; - bank_num = bank_offset = addr & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift) & high_mask; + uint32_t A = PeekMemory(addr & 0xFFFF); addr++; - - uint32_t A = MemoryMap[bank_num][bank_offset]; string format; switch (A) { case 0xCB: - bank_num = bank_offset = addr & 0xFFFF; - bank_offset &= low_mask; - bank_num = (bank_num >> bank_shift) & high_mask; + A = PeekMemory(addr & 0xFFFF); addr++; - - A = MemoryMap[bank_num][bank_offset]; format = mnemonics[A + 256]; break; @@ -2920,262 +2851,38 @@ namespace GBHawk "LDH A,(a8)", "POP AF", "LD A,(C)", "DI", "???", "PUSH AF", "OR d8", "RST 30H", // F0 "LD HL,SP+r8", "LD SP,HL", "LD A,(a16)", "EI ", "???", "???", "CP d8", "RST 38H", // F8 - "RLC B", // 00 - "RLC C", // 01 - "RLC D", // 02 - "RLC E", // 03 - "RLC H", // 04 - "RLC L", // 05 - "RLC (HL)", // 06 - "RLC A", // 07 - "RRC B", // 08 - "RRC C", // 09 - "RRC D", // 0a - "RRC E", // 0b - "RRC H", // 0c - "RRC L", // 0d - "RRC (HL)", // 0e - "RRC A", // 0f - "RL B", // 10 - "RL C", // 11 - "RL D", // 12 - "RL E", // 13 - "RL H", // 14 - "RL L", // 15 - "RL (HL)", // 16 - "RL A", // 17 - "RR B", // 18 - "RR C", // 19 - "RR D", // 1a - "RR E", // 1b - "RR H", // 1c - "RR L", // 1d - "RR (HL)", // 1e - "RR A", // 1f - "SLA B", // 20 - "SLA C", // 21 - "SLA D", // 22 - "SLA E", // 23 - "SLA H", // 24 - "SLA L", // 25 - "SLA (HL)", // 26 - "SLA A", // 27 - "SRA B", // 28 - "SRA C", // 29 - "SRA D", // 2a - "SRA E", // 2b - "SRA H", // 2c - "SRA L", // 2d - "SRA (HL)", // 2e - "SRA A", // 2f - "SWAP B", // 30 - "SWAP C", // 31 - "SWAP D", // 32 - "SWAP E", // 33 - "SWAP H", // 34 - "SWAP L", // 35 - "SWAP (HL)", // 36 - "SWAP A", // 37 - "SRL B", // 38 - "SRL C", // 39 - "SRL D", // 3a - "SRL E", // 3b - "SRL H", // 3c - "SRL L", // 3d - "SRL (HL)", // 3e - "SRL A", // 3f - "BIT 0,B", // 40 - "BIT 0,C", // 41 - "BIT 0,D", // 42 - "BIT 0,E", // 43 - "BIT 0,H", // 44 - "BIT 0,L", // 45 - "BIT 0,(HL)", // 46 - "BIT 0,A", // 47 - "BIT 1,B", // 48 - "BIT 1,C", // 49 - "BIT 1,D", // 4a - "BIT 1,E", // 4b - "BIT 1,H", // 4c - "BIT 1,L", // 4d - "BIT 1,(HL)", // 4e - "BIT 1,A", // 4f - "BIT 2,B", // 50 - "BIT 2,C", // 51 - "BIT 2,D", // 52 - "BIT 2,E", // 53 - "BIT 2,H", // 54 - "BIT 2,L", // 55 - "BIT 2,(HL)", // 56 - "BIT 2,A", // 57 - "BIT 3,B", // 58 - "BIT 3,C", // 59 - "BIT 3,D", // 5a - "BIT 3,E", // 5b - "BIT 3,H", // 5c - "BIT 3,L", // 5d - "BIT 3,(HL)", // 5e - "BIT 3,A", // 5f - "BIT 4,B", // 60 - "BIT 4,C", // 61 - "BIT 4,D", // 62 - "BIT 4,E", // 63 - "BIT 4,H", // 64 - "BIT 4,L", // 65 - "BIT 4,(HL)", // 66 - "BIT 4,A", // 67 - "BIT 5,B", // 68 - "BIT 5,C", // 69 - "BIT 5,D", // 6a - "BIT 5,E", // 6b - "BIT 5,H", // 6c - "BIT 5,L", // 6d - "BIT 5,(HL)", // 6e - "BIT 5,A", // 6f - "BIT 6,B", // 70 - "BIT 6,C", // 71 - "BIT 6,D", // 72 - "BIT 6,E", // 73 - "BIT 6,H", // 74 - "BIT 6,L", // 75 - "BIT 6,(HL)", // 76 - "BIT 6,A", // 77 - "BIT 7,B", // 78 - "BIT 7,C", // 79 - "BIT 7,D", // 7a - "BIT 7,E", // 7b - "BIT 7,H", // 7c - "BIT 7,L", // 7d - "BIT 7,(HL)", // 7e - "BIT 7,A", // 7f - "RES 0,B", // 80 - "RES 0,C", // 81 - "RES 0,D", // 82 - "RES 0,E", // 83 - "RES 0,H", // 84 - "RES 0,L", // 85 - "RES 0,(HL)", // 86 - "RES 0,A", // 87 - "RES 1,B", // 88 - "RES 1,C", // 89 - "RES 1,D", // 8a - "RES 1,E", // 8b - "RES 1,H", // 8c - "RES 1,L", // 8d - "RES 1,(HL)", // 8e - "RES 1,A", // 8f - "RES 2,B", // 90 - "RES 2,C", // 91 - "RES 2,D", // 92 - "RES 2,E", // 93 - "RES 2,H", // 94 - "RES 2,L", // 95 - "RES 2,(HL)", // 96 - "RES 2,A", // 97 - "RES 3,B", // 98 - "RES 3,C", // 99 - "RES 3,D", // 9a - "RES 3,E", // 9b - "RES 3,H", // 9c - "RES 3,L", // 9d - "RES 3,(HL)", // 9e - "RES 3,A", // 9f - "RES 4,B", // a0 - "RES 4,C", // a1 - "RES 4,D", // a2 - "RES 4,E", // a3 - "RES 4,H", // a4 - "RES 4,L", // a5 - "RES 4,(HL)", // a6 - "RES 4,A", // a7 - "RES 5,B", // a8 - "RES 5,C", // a9 - "RES 5,D", // aa - "RES 5,E", // ab - "RES 5,H", // ac - "RES 5,L", // ad - "RES 5,(HL)", // ae - "RES 5,A", // af - "RES 6,B", // b0 - "RES 6,C", // b1 - "RES 6,D", // b2 - "RES 6,E", // b3 - "RES 6,H", // b4 - "RES 6,L", // b5 - "RES 6,(HL)", // b6 - "RES 6,A", // b7 - "RES 7,B", // b8 - "RES 7,C", // b9 - "RES 7,D", // ba - "RES 7,E", // bb - "RES 7,H", // bc - "RES 7,L", // bd - "RES 7,(HL)", // be - "RES 7,A", // bf - "SET 0,B", // c0 - "SET 0,C", // c1 - "SET 0,D", // c2 - "SET 0,E", // c3 - "SET 0,H", // c4 - "SET 0,L", // c5 - "SET 0,(HL)", // c6 - "SET 0,A", // c7 - "SET 1,B", // c8 - "SET 1,C", // c9 - "SET 1,D", // ca - "SET 1,E", // cb - "SET 1,H", // cc - "SET 1,L", // cd - "SET 1,(HL)", // ce - "SET 1,A", // cf - "SET 2,B", // d0 - "SET 2,C", // d1 - "SET 2,D", // d2 - "SET 2,E", // d3 - "SET 2,H", // d4 - "SET 2,L", // d5 - "SET 2,(HL)", // d6 - "SET 2,A", // d7 - "SET 3,B", // d8 - "SET 3,C", // d9 - "SET 3,D", // da - "SET 3,E", // db - "SET 3,H", // dc - "SET 3,L", // dd - "SET 3,(HL)", // de - "SET 3,A", // df - "SET 4,B", // e0 - "SET 4,C", // e1 - "SET 4,D", // e2 - "SET 4,E", // e3 - "SET 4,H", // e4 - "SET 4,L", // e5 - "SET 4,(HL)", // e6 - "SET 4,A", // e7 - "SET 5,B", // e8 - "SET 5,C", // e9 - "SET 5,D", // ea - "SET 5,E", // eb - "SET 5,H", // ec - "SET 5,L", // ed - "SET 5,(HL)", // ee - "SET 5,A", // ef - "SET 6,B", // f0 - "SET 6,C", // f1 - "SET 6,D", // f2 - "SET 6,E", // f3 - "SET 6,H", // f4 - "SET 6,L", // f5 - "SET 6,(HL)", // f6 - "SET 6,A", // f7 - "SET 7,B", // f8 - "SET 7,C", // f9 - "SET 7,D", // fa - "SET 7,E", // fb - "SET 7,H", // fc - "SET 7,L", // fd - "SET 7,(HL)", // fe - "SET 7,A", // ff + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", // 00 + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", // 08 + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", // 10 + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", // 18 + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", // 20 + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", // 28 + "SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", // 30 + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", // 38 + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", // 40 + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", // 48 + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", // 50 + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", // 58 + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", // 60 + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", // 68 + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", // 70 + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", // 78 + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", // 80 + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", // 88 + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", // 90 + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", // 98 + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", // A0 + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", // A8 + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", // B0 + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", // B8 + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", // C0 + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", // C8 + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", // D0 + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", // d8 + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", // e0 + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", // E8 + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", // F0 + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A", // F8 }; #pragma endregion @@ -3184,57 +2891,25 @@ namespace GBHawk uint8_t* SaveState(uint8_t* saver) { - *saver = (uint8_t)(NO_prefix ? 1 : 0); saver++; + + *saver = (uint8_t)(interrupts_enabled ? 1 : 0); saver++; *saver = (uint8_t)(CB_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IX_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(EXTD_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IY_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IXCB_prefix ? 1 : 0); saver++; - *saver = (uint8_t)(IYCB_prefix ? 1 : 0); saver++; *saver = (uint8_t)(halted ? 1 : 0); saver++; - *saver = (uint8_t)(I_skip ? 1 : 0); saver++; + *saver = (uint8_t)(stopped ? 1 : 0); saver++; + *saver = (uint8_t)(jammed ? 1 : 0); saver++; + *saver = (uint8_t)(was_FlagI ? 1 : 0); saver++; *saver = (uint8_t)(FlagI ? 1 : 0); saver++; - *saver = (uint8_t)(FlagW ? 1 : 0); saver++; - *saver = (uint8_t)(IFF1 ? 1 : 0); saver++; - *saver = (uint8_t)(IFF2 ? 1 : 0); saver++; - *saver = (uint8_t)(nonMaskableInterrupt ? 1 : 0); saver++; - *saver = (uint8_t)(nonMaskableInterruptPending ? 1 : 0); saver++; - *saver = (uint8_t)(jp_cond_chk ? 1 : 0); saver++; - *saver = (uint8_t)(cond_chk_fail ? 1 : 0); saver++; + *saver = (uint8_t)(halted ? 1 : 0); saver++; *saver = opcode; saver++; - *saver = temp_R; saver++; + *saver = LY; saver++; *saver = EI_pending; saver++; - *saver = interruptMode; saver++; - *saver = ExternalDB; saver++; - *saver = instr_bank; saver++; - for (int i = 0; i < 36; i++) { *saver = Regs[i]; saver++; } - - *saver = (uint8_t)(PRE_SRC & 0xFF); saver++; *saver = (uint8_t)((PRE_SRC >> 8) & 0xFF); saver++; - *saver = (uint8_t)((PRE_SRC >> 16) & 0xFF); saver++; *saver = (uint8_t)((PRE_SRC >> 24) & 0xFF); saver++; + for (int i = 0; i < 14; i++) { *saver = Regs[i]; saver++; } *saver = (uint8_t)(instr_pntr & 0xFF); saver++; *saver = (uint8_t)((instr_pntr >> 8) & 0xFF); saver++; *saver = (uint8_t)((instr_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((instr_pntr >> 24) & 0xFF); saver++; - *saver = (uint8_t)(bus_pntr & 0xFF); saver++; *saver = (uint8_t)((bus_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((bus_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((bus_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(mem_pntr & 0xFF); saver++; *saver = (uint8_t)((mem_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((mem_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((mem_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(irq_pntr & 0xFF); saver++; *saver = (uint8_t)((irq_pntr >> 8) & 0xFF); saver++; - *saver = (uint8_t)((irq_pntr >> 16) & 0xFF); saver++; *saver = (uint8_t)((irq_pntr >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(IRQS & 0xFF); saver++; *saver = (uint8_t)((IRQS >> 8) & 0xFF); saver++; - *saver = (uint8_t)((IRQS >> 16) & 0xFF); saver++; *saver = (uint8_t)((IRQS >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(Ztemp2_saver & 0xFF); saver++; *saver = (uint8_t)((Ztemp2_saver >> 8) & 0xFF); saver++; - *saver = (uint8_t)((Ztemp2_saver >> 16) & 0xFF); saver++; *saver = (uint8_t)((Ztemp2_saver >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(IRQS_cond_offset & 0xFF); saver++; *saver = (uint8_t)((IRQS_cond_offset >> 8) & 0xFF); saver++; - *saver = (uint8_t)((IRQS_cond_offset >> 16) & 0xFF); saver++; *saver = (uint8_t)((IRQS_cond_offset >> 24) & 0xFF); saver++; - *saver = (uint8_t)(TotalExecutedCycles & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 8) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 16) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 24) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 16) & 0x32); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 40) & 0xFF); saver++; @@ -3245,179 +2920,23 @@ namespace GBHawk uint8_t* LoadState(uint8_t* loader) { - NO_prefix = *loader == 1; loader++; + interrupts_enabled = *loader == 1; loader++; CB_prefix = *loader == 1; loader++; - IX_prefix = *loader == 1; loader++; - EXTD_prefix = *loader == 1; loader++; - IY_prefix = *loader == 1; loader++; - IXCB_prefix = *loader == 1; loader++; - IYCB_prefix = *loader == 1; loader++; halted = *loader == 1; loader++; - I_skip = *loader == 1; loader++; + stopped = *loader == 1; loader++; + jammed = *loader == 1; loader++; + was_FlagI = *loader == 1; loader++; FlagI = *loader == 1; loader++; - FlagW = *loader == 1; loader++; - IFF1 = *loader == 1; loader++; - IFF2 = *loader == 1; loader++; - nonMaskableInterrupt = *loader == 1; loader++; - nonMaskableInterruptPending = *loader == 1; loader++; - jp_cond_chk = *loader == 1; loader++; - cond_chk_fail = *loader == 1; loader++; opcode = *loader; loader++; - temp_R = *loader; loader++; + LY = *loader; loader++; EI_pending = *loader; loader++; - interruptMode = *loader; loader++; - ExternalDB = *loader; loader++; - instr_bank = *loader; loader++; - for (int i = 0; i < 36; i++) { Regs[i] = *loader; loader++; } - - PRE_SRC = *loader; loader++; PRE_SRC |= (*loader << 8); loader++; - PRE_SRC |= (*loader << 16); loader++; PRE_SRC |= (*loader << 24); loader++; + for (int i = 0; i < 14; i++) { Regs[i] = *loader; loader++; } instr_pntr = *loader; loader++; instr_pntr |= (*loader << 8); loader++; instr_pntr |= (*loader << 16); loader++; instr_pntr |= (*loader << 24); loader++; - bus_pntr = *loader; loader++; bus_pntr |= (*loader << 8); loader++; - bus_pntr |= (*loader << 16); loader++; bus_pntr |= (*loader << 24); loader++; - - mem_pntr = *loader; loader++; mem_pntr |= (*loader << 8); loader++; - mem_pntr |= (*loader << 16); loader++; mem_pntr |= (*loader << 24); loader++; - - irq_pntr = *loader; loader++; irq_pntr |= (*loader << 8); loader++; - irq_pntr |= (*loader << 16); loader++; irq_pntr |= (*loader << 24); loader++; - - IRQS = *loader; loader++; IRQS |= (*loader << 8); loader++; - IRQS |= (*loader << 16); loader++; IRQS |= (*loader << 24); loader++; - - Ztemp2_saver = *loader; loader++; Ztemp2_saver |= (*loader << 8); loader++; - Ztemp2_saver |= (*loader << 16); loader++; Ztemp2_saver |= (*loader << 24); loader++; - - IRQS_cond_offset = *loader; loader++; IRQS_cond_offset |= (*loader << 8); loader++; - IRQS_cond_offset |= (*loader << 16); loader++; IRQS_cond_offset |= (*loader << 24); loader++; - - // load instruction pointers based on state - if (instr_bank == 0) - { - cur_instr_ofst = &NoIndex[opcode * 38]; - cur_bus_ofst = &NoIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &NoIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &NoIndexIRQS[opcode]; - } - else if (instr_bank == 1) - { - cur_instr_ofst = &CBIndex[opcode * 38]; - cur_bus_ofst = &CBIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &CBIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &CBIndexIRQS[opcode]; - } - else if (instr_bank == 2) - { - cur_instr_ofst = &EXTIndex[opcode * 38]; - cur_bus_ofst = &EXTIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &EXTIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &EXTIndexIRQS[opcode]; - } - else if (instr_bank == 3) - { - cur_instr_ofst = &IXIndex[opcode * 38]; - cur_bus_ofst = &IXIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &IXIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &IXIndexIRQS[opcode]; - } - else if (instr_bank == 4) - { - cur_instr_ofst = &IYIndex[opcode * 38]; - cur_bus_ofst = &IYIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &IYIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &IYIndexIRQS[opcode]; - } - else if (instr_bank == 5) - { - cur_instr_ofst = &IXYCBIndex[opcode * 38]; - cur_bus_ofst = &IXYCBIndexBUSRQ[opcode * 19]; - cur_mem_ofst = &IXYCBIndexMEMRQ[opcode * 19]; - cur_irqs_ofst = &IXYCBIndexIRQS[opcode]; - } - else if (instr_bank == 6) - { - cur_instr_ofst = &Reset_CPU[0]; - cur_bus_ofst = &Reset_BUSRQ[0]; - cur_mem_ofst = &Reset_MEMRQ[0]; - cur_irqs_ofst = &Reset_IRQS; - } - else if (instr_bank == 7) - { - cur_instr_ofst = &LD_OP_R_INST[0]; - cur_instr_ofst[14] = Ztemp2_saver; - cur_bus_ofst = &LD_OP_R_BUSRQ[0]; - cur_mem_ofst = &LD_OP_R_MEMRQ[0]; - cur_irqs_ofst = &LD_OP_R_IRQS; - } - else if (instr_bank == 8) - { - cur_instr_ofst = &LD_CP_R_INST[0]; - cur_instr_ofst[14] = Ztemp2_saver; - cur_bus_ofst = &LD_CP_R_BUSRQ[0]; - cur_mem_ofst = &LD_CP_R_MEMRQ[0]; - cur_irqs_ofst = &LD_CP_R_IRQS; - } - else if (instr_bank == 9) - { - cur_instr_ofst = &REP_OP_I_INST[0]; - cur_instr_ofst[8] = Ztemp2_saver; - cur_bus_ofst = &REP_OP_I_BUSRQ[0]; - cur_mem_ofst = &REP_OP_I_MEMRQ[0]; - cur_irqs_ofst = &REP_OP_I_IRQS; - } - else if (instr_bank == 10) - { - cur_instr_ofst = &REP_OP_O_INST[0]; - cur_bus_ofst = &REP_OP_O_BUSRQ[0]; - cur_mem_ofst = &REP_OP_O_MEMRQ[0]; - cur_irqs_ofst = &REP_OP_O_IRQS; - } - else if (instr_bank == 11) - { - cur_instr_ofst = &NO_HALT_INST[0]; - cur_bus_ofst = &NO_HALT_BUSRQ[0]; - cur_mem_ofst = &NO_HALT_MEMRQ[0]; - cur_irqs_ofst = &NO_HALT_IRQS; - } - else if (instr_bank == 12) - { - cur_instr_ofst = &NMI_INST[0]; - cur_bus_ofst = &NMI_BUSRQ[0]; - cur_mem_ofst = &NMI_MEMRQ[0]; - cur_irqs_ofst = &NMI_IRQS; - } - else if (instr_bank == 13) - { - cur_instr_ofst = &IRQ0_INST[0]; - cur_bus_ofst = &IRQ0_BUSRQ[0]; - cur_mem_ofst = &IRQ0_MEMRQ[0]; - cur_irqs_ofst = &IRQ0_IRQS; - } - else if (instr_bank == 14) - { - cur_instr_ofst = &IRQ1_INST[0]; - cur_bus_ofst = &IRQ1_BUSRQ[0]; - cur_mem_ofst = &IRQ1_MEMRQ[0]; - cur_irqs_ofst = &IRQ1_IRQS; - } - else if (instr_bank == 15) - { - cur_instr_ofst = &IRQ2_INST[0]; - cur_bus_ofst = &IRQ2_BUSRQ[0]; - cur_mem_ofst = &IRQ2_MEMRQ[0]; - cur_irqs_ofst = &IRQ2_IRQS; - } - - if (cond_chk_fail) - { - cur_irqs_ofst = &False_IRQS[IRQS_cond_offset]; - } - TotalExecutedCycles = *loader; loader++; TotalExecutedCycles |= ((uint64_t)*loader << 8); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 16); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 24); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 32); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 40); loader++; diff --git a/libHawk/GBHawk/GBHawk/Memory.cpp b/libHawk/GBHawk/GBHawk/Memory.cpp index bec2e266d1..3d1e499956 100644 --- a/libHawk/GBHawk/GBHawk/Memory.cpp +++ b/libHawk/GBHawk/GBHawk/Memory.cpp @@ -6,7 +6,7 @@ #include "Memory.h" #include "LR35902.h" #include "TMS9918A.h" -#include "AY_3_8910.h" +#include "GBAudio.h" using namespace std; @@ -14,216 +14,12 @@ namespace GBHawk { uint8_t MemoryManager::HardwareRead(uint32_t port) { - port &= 0xFF; - if (port == 0x98) // VDP - { - return vdp_pntr->ReadData(); - } - else if (port == 0x99) // VDP - { - return vdp_pntr->ReadVdpStatus(); - } - else if (port == 0xA2) - { - if (psg_pntr->port_sel == 0xE) { lagged = false; } - return psg_pntr->ReadReg(); - } - else if (port == 0xA8) - { - return PortA8; - } - else if (port == 0xA9) - { - lagged = false; - return ~kb_rows[kb_rows_sel]; - } - else if (port == 0xAA) - { - // TODO: casette, caps lamp, keyboard sound click - return kb_rows_sel; - } - return 0xFF; } void MemoryManager::HardwareWrite(uint32_t port, uint8_t value) { - port &= 0xFF; - if (port == 0x98) // VDP - { - vdp_pntr->WriteVdpData(value); - } - else if(port == 0x99) // VDP - { - vdp_pntr->WriteVdpControl(value); - } - else if (port == 0xA0) - { - psg_pntr->port_sel = (value & 0xF); - } - else if (port == 0xA1) - { - psg_pntr->WriteReg(value); - - // update controller port data if port F is written to - if (psg_pntr->port_sel == 0xF) - { - if ((psg_pntr->Register[0xF] & 0x40) > 0) - { - psg_pntr->Register[0xE] = controller_byte_2; - } - else - { - psg_pntr->Register[0xE] = controller_byte_1; - } - } - } - else if (port == 0xA8) - { - PortA8 = value; - remap(); - } - else if (port == 0xAA) - { - kb_rows_sel = value & 0xF; - remap(); - } - } - - void MemoryManager::remap() - { - if ((PortA8 & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &bios_rom[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0; - } - } - else if ((PortA8 & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &rom_1[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0; - } - } - else if ((PortA8 & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &rom_2[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0; - } - } - else if ((PortA8 & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i] = &ram[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i] = 0xFF; - } - } - - if (((PortA8 >> 2) & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &basic_rom[(0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0; - } - } - else if (((PortA8 >> 2) & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &rom_1[0x4000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0; - } - } - else if (((PortA8 >> 2) & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &rom_2[0x4000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0; - } - } - else if (((PortA8 >> 2) & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 16] = &ram[0x4000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 16] = 0xFF; - } - } - - if (((PortA8 >> 4) & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &unmapped[0]; - cpu_pntr->MemoryMapMask[i + 32] = 0; - } - } - else if (((PortA8 >> 4) & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &rom_1[0x8000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 32] = 0; - } - } - else if (((PortA8 >> 4) & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &rom_2[0x8000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 32] = 0; - } - } - else if (((PortA8 >> 4) & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 32] = &ram[0x8000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 32] = 0xFF; - } - } - - if (((PortA8 >> 6) & 3) == 0) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &unmapped[0]; - cpu_pntr->MemoryMapMask[i + 48] = 0; - } - } - else if (((PortA8 >> 6) & 3) == 1) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &rom_1[0xC000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 48] = 0; - } - } - else if (((PortA8 >> 6) & 3) == 2) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &rom_2[0xC000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 48] = 0; - } - } - else if (((PortA8 >> 6) & 3) == 3) - { - for (uint32_t i = 0; i < 16; i++) - { - cpu_pntr->MemoryMap[i + 48] = &ram[0xC000 + (0x400 * i)]; - cpu_pntr->MemoryMapMask[i + 48] = 0xFF; - } - } } } \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Memory.h b/libHawk/GBHawk/GBHawk/Memory.h index 23021c9938..f58035703a 100644 --- a/libHawk/GBHawk/GBHawk/Memory.h +++ b/libHawk/GBHawk/GBHawk/Memory.h @@ -7,17 +7,17 @@ using namespace std; namespace GBHawk { - class Z80A; + class LR35902; class TMS9918A; - class AY_3_8910; + class GBAudio; class MemoryManager { public: TMS9918A* vdp_pntr = nullptr; - AY_3_8910* psg_pntr = nullptr; - Z80A* cpu_pntr = nullptr; + GBAudio* psg_pntr = nullptr; + LR35902* cpu_pntr = nullptr; uint8_t* rom_1 = nullptr; uint8_t* rom_2 = nullptr; uint8_t* bios_rom = nullptr; @@ -54,8 +54,6 @@ namespace GBHawk void HardwareWrite(uint32_t addr, uint8_t value); - void remap(); - // NOTE: only called from source when both are available and of correct size (0x4000) void Load_BIOS(uint8_t* bios, uint8_t* basic) { @@ -82,8 +80,6 @@ namespace GBHawk // default memory map setup PortA8 = 0; - - remap(); } void MemoryWrite(uint32_t addr, uint8_t value) @@ -128,8 +124,6 @@ namespace GBHawk std::memcpy(&ram, loader, 0x10000); loader += 0x10000; std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000; - remap(); - return loader; }