From 263fdfebc31c2d5b1142fd568aebd5f31cacdf04 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 24 Jan 2020 19:47:16 -0500 Subject: [PATCH] MSXHawk: audio --- .../Computers/MSX/LibMSX.cs | 8 +- .../Computers/MSX/MSX.IEmulator.cs | 42 +- BizHawk.Emulation.Cores/Computers/MSX/MSX.cs | 3 +- .../Consoles/Coleco/AY_3_8910_SGM.cs | 2 +- .../Consoles/GCE/Vectrex/Audio.cs | 2 +- libHawk/MSXHawk/MSXHawk/AY_3_8910.h | 439 ++++++++++++++++++ libHawk/MSXHawk/MSXHawk/Core.h | 23 +- libHawk/MSXHawk/MSXHawk/MSXHawk.cpp | 4 +- libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj | 2 +- libHawk/MSXHawk/MSXHawk/Memory.cpp | 12 +- libHawk/MSXHawk/MSXHawk/Memory.h | 4 +- libHawk/MSXHawk/MSXHawk/PSG.h | 360 -------------- libHawk/MSXHawk/MSXHawk/TMS9918A.h | 128 ++--- 13 files changed, 553 insertions(+), 476 deletions(-) create mode 100644 libHawk/MSXHawk/MSXHawk/AY_3_8910.h delete mode 100644 libHawk/MSXHawk/MSXHawk/PSG.h diff --git a/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs b/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs index 648ddcc81d..333a3e0f21 100644 --- a/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs +++ b/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs @@ -67,12 +67,10 @@ namespace BizHawk.Emulation.Cores.Computers.MSX /// Get Video data /// /// opaque state pointer - /// where to send left audio to - /// where to send right audio to - /// number of left samples - /// number of right samples + /// where to send left audio to + /// number of left samples [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern uint MSX_get_audio(IntPtr core, uint[] aud_buf_L, uint[] aud_buf_R, ref uint n_samp_L, ref uint n_samp_R); + public static extern uint MSX_get_audio(IntPtr core, uint[] aud_buf, ref uint n_samp); #endregion diff --git a/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs index 2331e539aa..86924ea5f3 100644 --- a/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs @@ -70,27 +70,19 @@ namespace BizHawk.Emulation.Cores.Computers.MSX MSX_Pntr = IntPtr.Zero; } - if (blip_L != null) + if (blip != null) { - blip_L.Dispose(); - blip_L = null; - } - - if (blip_R != null) - { - blip_R.Dispose(); - blip_R = null; + blip.Dispose(); + blip = null; } } #region Audio - public BlipBuffer blip_L = new BlipBuffer(4500); - public BlipBuffer blip_R = new BlipBuffer(4500); + public BlipBuffer blip = new BlipBuffer(4500); - public uint[] Aud_L = new uint [9000]; - public uint[] Aud_R = new uint[9000]; - public uint num_samp_L, num_samp_R; + public uint[] Aud = new uint [9000]; + public uint num_samp; const int blipbuffsize = 4500; @@ -116,32 +108,24 @@ namespace BizHawk.Emulation.Cores.Computers.MSX public void GetSamplesSync(out short[] samples, out int nsamp) { - uint f_clock = LibMSX.MSX_get_audio(MSX_Pntr, Aud_L, Aud_R, ref num_samp_L, ref num_samp_R); + uint f_clock = LibMSX.MSX_get_audio(MSX_Pntr, Aud, ref num_samp); - for (int i = 0; i < num_samp_L;i++) + for (int i = 0; i < num_samp;i++) { - blip_L.AddDelta(Aud_L[i * 2], (int)Aud_L[i * 2 + 1]); + blip.AddDelta(Aud[i * 2], (int)Aud[i * 2 + 1]); } - for (int i = 0; i < num_samp_R; i++) - { - blip_R.AddDelta(Aud_R[i * 2], (int)Aud_R[i * 2 + 1]); - } + blip.EndFrame(f_clock); - blip_L.EndFrame(f_clock); - blip_R.EndFrame(f_clock); - - nsamp = Math.Max(Math.Max(blip_L.SamplesAvailable(), blip_R.SamplesAvailable()), 1); + nsamp = blip.SamplesAvailable(); samples = new short[nsamp * 2]; - blip_L.ReadSamplesLeft(samples, nsamp); - blip_R.ReadSamplesRight(samples, nsamp); + blip.ReadSamples(samples, nsamp, true); } public void DiscardSamples() { - blip_L.Clear(); - blip_R.Clear(); + blip.Clear(); } #endregion diff --git a/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs b/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs index e35a1a3af1..19e65498ef 100644 --- a/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs +++ b/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs @@ -43,8 +43,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX LibMSX.MSX_load_bios(MSX_Pntr, Bios, Basic); LibMSX.MSX_load(MSX_Pntr, RomData, (uint)RomData.Length, 0, RomData, (uint)RomData.Length, 0); - blip_L.SetRates(3579545, 44100); - blip_R.SetRates(3579545, 44100); + blip.SetRates(3579545, 44100); (ServiceProvider as BasicServiceProvider).Register(this); diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/AY_3_8910_SGM.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/AY_3_8910_SGM.cs index d1aef90365..cc21e6a0f7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/AY_3_8910_SGM.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/AY_3_8910_SGM.cs @@ -281,7 +281,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision } else { - v = (short)(sound_out_A ? VolumeTable[vol_A] : 0); + v = (short)(sound_out_A ? VolumeTable[env_E] : 0); } if (env_vol_B == 0) diff --git a/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/Audio.cs b/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/Audio.cs index 573cb89d41..ed414dea08 100644 --- a/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/Audio.cs +++ b/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/Audio.cs @@ -282,7 +282,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Vectrex } else { - v = (short)(sound_out_A ? VolumeTable[vol_A] : 0); + v = (short)(sound_out_A ? VolumeTable[env_E] : 0); } if (env_vol_B == 0) diff --git a/libHawk/MSXHawk/MSXHawk/AY_3_8910.h b/libHawk/MSXHawk/MSXHawk/AY_3_8910.h new file mode 100644 index 0000000000..77a36ad53e --- /dev/null +++ b/libHawk/MSXHawk/MSXHawk/AY_3_8910.h @@ -0,0 +1,439 @@ +#include +#include +#include +#include + +using namespace std; + +namespace MSXHawk +{ + 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; + + uint32_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; + + uint32_t current_sample; + uint32_t sampleclock; + uint32_t num_samples; + uint32_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; + + 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); + } + + 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/MSXHawk/MSXHawk/Core.h b/libHawk/MSXHawk/MSXHawk/Core.h index 013b7d49af..f933315b1f 100644 --- a/libHawk/MSXHawk/MSXHawk/Core.h +++ b/libHawk/MSXHawk/MSXHawk/Core.h @@ -4,7 +4,7 @@ #include #include "Z80A.h" -#include "PSG.h" +#include "AY_3_8910.h" #include "TMS9918A.h" #include "Memory.h" @@ -26,7 +26,7 @@ namespace MSXHawk TMS9918A vdp; Z80A cpu; - SN76489sms psg; + AY_3_8910 psg; MemoryManager MemMap; void Load_BIOS(uint8_t* bios, uint8_t* basic) @@ -49,8 +49,7 @@ namespace MSXHawk uint32_t scanlinesPerFrame = 262; vdp.SpriteLimit = true; - psg.num_samples_L = 0; - psg.num_samples_R = 0; + psg.num_samples = 0; psg.sampleclock = 0; for (uint32_t i = 0; i < scanlinesPerFrame; i++) @@ -90,19 +89,13 @@ namespace MSXHawk std::memcpy(dst, src, sizeof uint32_t * 256 * 192); } - uint32_t GetAudio(uint32_t* dest_L, uint32_t* dest_R, uint32_t* n_samp_L, uint32_t* n_samp_R) + uint32_t GetAudio(uint32_t* dest, uint32_t* n_samp) { - uint32_t* src_L = psg.samples_L; - uint32_t* dst_L = dest_L; + uint32_t* src = psg.samples; + uint32_t* dst = dest; - std::memcpy(dst_L, src_L, sizeof uint32_t * psg.num_samples_L * 2); - n_samp_L[0] = psg.num_samples_L; - - uint32_t* src_R = psg.samples_R; - uint32_t* dst_R = dest_R; - - std::memcpy(dst_R, src_R, sizeof uint32_t * psg.num_samples_R * 2); - n_samp_R[0] = psg.num_samples_R; + std::memcpy(dst, src, sizeof uint32_t * psg.num_samples * 2); + n_samp[0] = psg.num_samples; return psg.sampleclock; } diff --git a/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp b/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp index 7bb21252a5..a122e11a1b 100644 --- a/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp +++ b/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp @@ -54,9 +54,9 @@ MSXHawk_EXPORT void MSX_get_video(MSXCore* p, uint32_t* dest) } // send audio data to external audio provider -MSXHawk_EXPORT uint32_t MSX_get_audio(MSXCore* p, uint32_t* dest_L, uint32_t* dest_R, uint32_t* n_samp_L, uint32_t* n_samp_R) +MSXHawk_EXPORT uint32_t MSX_get_audio(MSXCore* p, uint32_t* dest, uint32_t* n_samp) { - return p->GetAudio(dest_L, dest_R, n_samp_L, n_samp_R); + return p->GetAudio(dest, n_samp); } #pragma region State Save / Load diff --git a/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj b/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj index b1dfcdac86..6176713181 100644 --- a/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj +++ b/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj @@ -161,7 +161,7 @@ - + diff --git a/libHawk/MSXHawk/MSXHawk/Memory.cpp b/libHawk/MSXHawk/MSXHawk/Memory.cpp index 8e1c17169e..f61c9eaea2 100644 --- a/libHawk/MSXHawk/MSXHawk/Memory.cpp +++ b/libHawk/MSXHawk/MSXHawk/Memory.cpp @@ -6,7 +6,7 @@ #include "Memory.h" #include "Z80A.h" #include "TMS9918A.h" -#include "PSG.h" +#include "AY_3_8910.h" using namespace std; @@ -24,9 +24,9 @@ namespace MSXHawk { return vdp_pntr->ReadVdpStatus(); } - else if (port == 0xA1) + else if (port == 0xA2) { - // not readable + return psg_pntr->ReadReg(); } else if (port == 0xA8) { @@ -47,7 +47,11 @@ namespace MSXHawk 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); diff --git a/libHawk/MSXHawk/MSXHawk/Memory.h b/libHawk/MSXHawk/MSXHawk/Memory.h index b34ac72e66..d9c60d36e4 100644 --- a/libHawk/MSXHawk/MSXHawk/Memory.h +++ b/libHawk/MSXHawk/MSXHawk/Memory.h @@ -9,14 +9,14 @@ namespace MSXHawk { class Z80A; class TMS9918A; - class SN76489sms; + class AY_3_8910; class MemoryManager { public: TMS9918A* vdp_pntr = nullptr; - SN76489sms* psg_pntr = nullptr; + AY_3_8910* psg_pntr = nullptr; Z80A* cpu_pntr = nullptr; uint8_t* rom_1 = nullptr; uint8_t* rom_2 = nullptr; diff --git a/libHawk/MSXHawk/MSXHawk/PSG.h b/libHawk/MSXHawk/MSXHawk/PSG.h deleted file mode 100644 index de535cd9bd..0000000000 --- a/libHawk/MSXHawk/MSXHawk/PSG.h +++ /dev/null @@ -1,360 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -namespace MSXHawk -{ - class SN76489sms - { - public: - - #pragma region PSG - - bool vol_tone; - bool noise_type; - bool noise_bit; - bool A_L, B_L, C_L, noise_L; - bool A_R, B_R, C_R, noise_R; - bool A_up, B_up, C_up; - - uint8_t Chan_vol[4]; - uint8_t stereo_panning; - uint8_t chan_sel; - uint8_t noise_rate; - - uint16_t Chan_tone[4]; - - uint32_t psg_clock; - uint32_t clock_A, clock_B, clock_C; - uint32_t noise_clock; - uint32_t noise; - - // only old_sample_L/R is savestated, this only works if savestates are only made at frame boundaries - // These would need to be included for subframe states - uint32_t old_sample_L; - uint32_t old_sample_R; - uint32_t current_sample_L; - uint32_t current_sample_R; - uint32_t sampleclock; - uint32_t num_samples_L; - uint32_t num_samples_R; - uint32_t samples_L[9000] = {}; - uint32_t samples_R[9000] = {}; - uint32_t Clock_Divider; - - const uint8_t LogScale[16] = { 255, 203, 161, 128, 102, 86, 64, 51, 40, 32, 26, 20, 16, 13, 10, 0 }; - - SN76489sms() - { - Reset(); - } - - void Reset() - { - clock_A = clock_B = clock_C = 0x1000; - noise_clock = 0x10; - chan_sel = 0; - - // reset the shift register - noise = 0x40000; - - Chan_vol[0] = 0xF; - Chan_vol[1] = 0xF; - Chan_vol[2] = 0xF; - Chan_vol[3] = 0xF; - - Set_Panning(0xFF); - } - - void Set_Panning(uint8_t value) - { - A_L = (value & 0x10) != 0; - A_R = (value & 0x01) != 0; - B_L = (value & 0x20) != 0; - B_R = (value & 0x02) != 0; - C_L = (value & 0x40) != 0; - C_R = (value & 0x04) != 0; - noise_L = (value & 0x80) != 0; - noise_R = (value & 0x08) != 0; - - stereo_panning = value; - } - - uint8_t ReadReg() - { - // not used, reading not allowed, just return 0xFF - return 0xFF; - } - - void WriteReg(uint8_t value) - { - // if bit 7 is set, change the latch, otherwise modify the currently latched register - if ((value & 0x80) > 0) - { - chan_sel = (value >> 5) & 3; - vol_tone = ((value & 0x10) > 0); - - if (vol_tone) - { - Chan_vol[chan_sel] = (uint8_t)(value & 0xF); - } - else - { - if (chan_sel < 3) - { - Chan_tone[chan_sel] &= 0x3F0; - Chan_tone[chan_sel] |= (uint16_t)(value & 0xF); - } - else - { - noise_type = ((value & 0x4) > 0); - noise_rate = value & 3; - - // reset the shift register - noise = 0x40000; - } - } - } - else - { - if (vol_tone) - { - Chan_vol[chan_sel] = (uint8_t)(value & 0xF); - } - else - { - if (chan_sel < 3) - { - Chan_tone[chan_sel] &= 0xF; - Chan_tone[chan_sel] |= (uint16_t)((value & 0x3F) << 4); - } - else - { - noise_type = ((value & 0x4) > 0); - noise_rate = value & 3; - - // reset the shift register - noise = 0x40000; - } - } - } - } - - void generate_sound() - { - clock_A--; - clock_B--; - clock_C--; - noise_clock--; - - // clock noise - if (noise_clock == 0) - { - noise_bit = ((noise & 1) > 0); - if (noise_type) - { - noise = (((noise & 1) ^ ((noise >> 1) & 1)) << 14) | (noise >> 1); - } - else - { - noise = ((noise & 1) << 14) | (noise >> 1); - } - - if (noise_rate == 0) - { - noise_clock = 0x10; - } - else if (noise_rate == 1) - { - noise_clock = 0x20; - } - else if (noise_rate == 2) - { - noise_clock = 0x40; - } - else - { - noise_clock = Chan_tone[2] + 1; - } - - noise_clock *= 2; - } - - if (clock_A == 0) - { - A_up = !A_up; - clock_A = Chan_tone[0] + 1; - } - - if (clock_B == 0) - { - B_up = !B_up; - clock_B = Chan_tone[1] + 1; - } - - if (clock_C == 0) - { - C_up = !C_up; - clock_C = Chan_tone[2] + 1; - } - - // now calculate the volume of each channel and add them together - current_sample_L = (A_L ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0); - - current_sample_L += (B_L ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0); - - current_sample_L += (C_L ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0); - - current_sample_L += (noise_L ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0); - - current_sample_R = (A_R ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0); - - current_sample_R += (B_R ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0); - - current_sample_R += (C_R ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0); - - current_sample_R += (noise_R ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0); - - if ((current_sample_L != old_sample_L) && (num_samples_L < 4500)) - { - samples_L[num_samples_L * 2] = sampleclock; - samples_L[num_samples_L * 2 + 1] = current_sample_L - old_sample_L; - num_samples_L++; - old_sample_L = current_sample_L; - } - - if ((current_sample_R != old_sample_R) && (num_samples_R < 4500)) - { - samples_R[num_samples_R * 2] = sampleclock; - samples_R[num_samples_R * 2 + 1] = current_sample_R - old_sample_R; - num_samples_R++; - old_sample_R = current_sample_R; - } - } - - #pragma endregion - - #pragma region State Save / Load - - uint8_t* SaveState(uint8_t* saver) - { - *saver = (uint8_t)(vol_tone ? 1 : 0); saver++; - *saver = (uint8_t)(noise_type ? 1 : 0); saver++; - *saver = (uint8_t)(noise_bit ? 1 : 0); saver++; - *saver = (uint8_t)(A_L ? 1 : 0); saver++; - *saver = (uint8_t)(B_L ? 1 : 0); saver++; - *saver = (uint8_t)(C_L ? 1 : 0); saver++; - *saver = (uint8_t)(noise_L ? 1 : 0); saver++; - *saver = (uint8_t)(A_R ? 1 : 0); saver++; - *saver = (uint8_t)(B_R ? 1 : 0); saver++; - *saver = (uint8_t)(C_R ? 1 : 0); saver++; - *saver = (uint8_t)(noise_R ? 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 = Chan_vol[0]; saver++; - *saver = Chan_vol[1]; saver++; - *saver = Chan_vol[2]; saver++; - *saver = Chan_vol[3]; saver++; - - *saver = stereo_panning; saver++; - *saver = chan_sel; saver++; - *saver = noise_rate; saver++; - - *saver = (uint8_t)(Chan_tone[0] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[0] >> 8) & 0xFF); saver++; - *saver = (uint8_t)(Chan_tone[1] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[1] >> 8) & 0xFF); saver++; - *saver = (uint8_t)(Chan_tone[2] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[2] >> 8) & 0xFF); saver++; - *saver = (uint8_t)(Chan_tone[3] & 0xFF); saver++; *saver = (uint8_t)((Chan_tone[3] >> 8) & 0xFF); 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)(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)(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 & 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_L & 0xFF); saver++; *saver = (uint8_t)((old_sample_L >> 8) & 0xFF); saver++; - *saver = (uint8_t)((old_sample_L >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_L >> 24) & 0xFF); saver++; - - *saver = (uint8_t)(old_sample_R & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 8) & 0xFF); saver++; - *saver = (uint8_t)((old_sample_R >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 24) & 0xFF); saver++; - - return saver; - } - - uint8_t* LoadState(uint8_t* loader) - { - vol_tone = *loader == 1; loader++; - noise_type = *loader == 1; loader++; - noise_bit = *loader == 1; loader++; - A_L = *loader == 1; loader++; - B_L = *loader == 1; loader++; - C_L = *loader == 1; loader++; - noise_L = *loader == 1; loader++; - A_R = *loader == 1; loader++; - B_R = *loader == 1; loader++; - C_R = *loader == 1; loader++; - noise_R = *loader == 1; loader++; - A_up = *loader == 1; loader++; - B_up = *loader == 1; loader++; - C_up = *loader == 1; loader++; - - Chan_vol[0] = *loader; loader++; - Chan_vol[1] = *loader; loader++; - Chan_vol[2] = *loader; loader++; - Chan_vol[3] = *loader; loader++; - - stereo_panning = *loader; loader++; - chan_sel = *loader; loader++; - noise_rate = *loader; loader++; - - Chan_tone[0] = *loader; loader++; Chan_tone[0] |= (*loader << 8); loader++; - Chan_tone[1] = *loader; loader++; Chan_tone[1] |= (*loader << 8); loader++; - Chan_tone[2] = *loader; loader++; Chan_tone[2] |= (*loader << 8); loader++; - Chan_tone[3] = *loader; loader++; Chan_tone[3] |= (*loader << 8); loader++; - - psg_clock = *loader; loader++; psg_clock |= (*loader << 8); loader++; - psg_clock |= (*loader << 16); loader++; psg_clock |= (*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++; - - noise_clock = *loader; loader++; noise_clock |= (*loader << 8); loader++; - noise_clock |= (*loader << 16); loader++; noise_clock |= (*loader << 24); loader++; - - noise = *loader; loader++; noise |= (*loader << 8); loader++; - noise |= (*loader << 16); loader++; noise |= (*loader << 24); loader++; - - old_sample_L = *loader; loader++; old_sample_L |= (*loader << 8); loader++; - old_sample_L |= (*loader << 16); loader++; old_sample_L |= (*loader << 24); loader++; - - old_sample_R = *loader; loader++; old_sample_R |= (*loader << 8); loader++; - old_sample_R |= (*loader << 16); loader++; old_sample_R |= (*loader << 24); loader++; - - return loader; - } - - #pragma endregion - }; -} \ No newline at end of file diff --git a/libHawk/MSXHawk/MSXHawk/TMS9918A.h b/libHawk/MSXHawk/MSXHawk/TMS9918A.h index c07c2676af..298a0c4428 100644 --- a/libHawk/MSXHawk/MSXHawk/TMS9918A.h +++ b/libHawk/MSXHawk/MSXHawk/TMS9918A.h @@ -45,11 +45,35 @@ namespace MSXHawk uint32_t TmsSpriteAttributeBase; uint32_t FrameBuffer[192 * 256] = {}; + uint8_t ScanlinePriorityBuffer[256] = {}; + uint8_t SpriteCollisionBuffer[256] = {}; // constants after load, not stated uint32_t BackgroundColor = 0; uint32_t IPeriod = 228; + // temporary variables not stated if on frame boundary + bool is_top; + uint32_t yc; + uint32_t yofs; + uint32_t FrameBufferOffset; + uint32_t PatternNameOffset; + uint32_t ScreenBGColor; + uint32_t yrow; + uint32_t PatternGeneratorOffset; + uint32_t ColorOffset; + uint32_t pn; + uint32_t pv; + uint32_t colorEntry; + uint32_t fgIndex; + uint32_t bgIndex; + uint32_t fgColor; + uint32_t bgColor; + uint32_t lColorIndex; + uint32_t rColorIndex; + uint32_t lColor; + uint32_t rColor; + uint32_t PaletteTMS9918[16] = { 0xFF000000, @@ -105,8 +129,7 @@ namespace MSXHawk case 0x40: // write VRAM break; case 0x80: // VDP register write - uint32_t reg = value & 0x0F; - WriteRegister(reg, VdpLatch); + WriteRegister(value & 0x0F, VdpLatch); break; } } @@ -218,21 +241,21 @@ namespace MSXHawk return; } - uint32_t yc = scanLine / 8; - uint32_t yofs = scanLine % 8; - uint32_t FrameBufferOffset = scanLine * 256; - uint32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 32); - uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + yc = scanLine / 8; + yofs = scanLine % 8; + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yc * 32); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; for (uint32_t xc = 0; xc < 32; xc++) { - uint32_t pn = VRAM[PatternNameOffset++]; - uint32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; - uint32_t colorEntry = VRAM[ColorTableBase + (pn / 8)]; - uint32_t fgIndex = (colorEntry >> 4) & 0x0F; - uint32_t bgIndex = colorEntry & 0x0F; - uint32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; - uint32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + pn = VRAM[PatternNameOffset++]; + pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; + colorEntry = VRAM[ColorTableBase + (pn / 8)]; + fgIndex = (colorEntry >> 4) & 0x0F; + bgIndex = colorEntry & 0x0F; + fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor; FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor; @@ -253,21 +276,21 @@ namespace MSXHawk return; } - uint32_t yc = scanLine / 8; - uint32_t yofs = scanLine % 8; - uint32_t FrameBufferOffset = scanLine * 256; - uint32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 40); - uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + yc = scanLine / 8; + yofs = scanLine % 8; + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yc * 40); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; for (uint32_t xc = 0; xc < 40; xc++) { - uint32_t pn = VRAM[PatternNameOffset++]; - uint32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; - uint32_t colorEntry = Registers[7]; - uint32_t fgIndex = (colorEntry >> 4) & 0x0F; - uint32_t bgIndex = colorEntry & 0x0F; - uint32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; - uint32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + pn = VRAM[PatternNameOffset++]; + pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; + colorEntry = Registers[7]; + fgIndex = (colorEntry >> 4) & 0x0F; + bgIndex = colorEntry & 0x0F; + fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor; FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor; @@ -286,23 +309,23 @@ namespace MSXHawk return; } - uint32_t yrow = scanLine / 8; - uint32_t yofs = scanLine % 8; - uint32_t FrameBufferOffset = scanLine * 256; - uint32_t PatternNameOffset = TmsPatternNameTableBase + (yrow * 32); - uint32_t PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000); - uint32_t ColorOffset = (ColorTableBase & 0x2000); - uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + yrow = scanLine / 8; + yofs = scanLine % 8; + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yrow * 32); + PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000); + ColorOffset = (ColorTableBase & 0x2000); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; for (uint32_t xc = 0; xc < 32; xc++) { - uint32_t pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100); - uint32_t pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs]; - uint32_t colorEntry = VRAM[ColorOffset + (pn * 8) + yofs]; - uint32_t fgIndex = (colorEntry >> 4) & 0x0F; - uint32_t bgIndex = colorEntry & 0x0F; - uint32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; - uint32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100); + pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs]; + colorEntry = VRAM[ColorOffset + (pn * 8) + yofs]; + fgIndex = (colorEntry >> 4) & 0x0F; + bgIndex = colorEntry & 0x0F; + fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor; FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor; @@ -323,21 +346,21 @@ namespace MSXHawk return; } - uint32_t yc = scanLine / 8; - bool top = (scanLine & 4) == 0; // am I in the top 4 pixels of an 8-pixel character? - uint32_t FrameBufferOffset = scanLine * 256; - uint32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 32); - uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + yc = scanLine / 8; + is_top = (scanLine & 4) == 0; // am I in the top 4 pixels of an 8-pixel character? + FrameBufferOffset = scanLine * 256; + PatternNameOffset = TmsPatternNameTableBase + (yc * 32); + ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; for (uint32_t xc = 0; xc < 32; xc++) { - uint32_t pn = VRAM[PatternNameOffset++]; - uint32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + ((yc & 3) * 2) + (top ? 0 : 1)]; + pn = VRAM[PatternNameOffset++]; + pv = VRAM[PatternGeneratorBase + (pn * 8) + ((yc & 3) * 2) + (is_top ? 0 : 1)]; - uint32_t lColorIndex = pv & 0xF; - uint32_t rColorIndex = pv >> 4; - uint32_t lColor = lColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[lColorIndex]; - uint32_t rColor = rColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[rColorIndex]; + lColorIndex = pv & 0xF; + rColorIndex = pv >> 4; + lColor = lColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[lColorIndex]; + rColor = rColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[rColorIndex]; FrameBuffer[FrameBufferOffset++] = lColor; FrameBuffer[FrameBufferOffset++] = lColor; @@ -350,9 +373,6 @@ namespace MSXHawk } } - uint8_t ScanlinePriorityBuffer[256] = {}; - uint8_t SpriteCollisionBuffer[256] = {}; - void RenderTmsSprites(int32_t scanLine) { if (EnableDoubledSprites() == false)