AxibugEmuOnline/AxibugEmuOnline.Client/Assets/MyNes.Core/Namcot106.cs
2024-07-03 18:22:22 +08:00

554 lines
15 KiB
C#

using System.IO;
namespace MyNes.Core
{
[WithExternalSound]
internal abstract class Namcot106 : Board
{
private int irq_counter;
private bool irq_enable;
private bool disables_chr_ram_A;
private bool disables_chr_ram_B;
private bool enable_mirroring_switch;
private bool enable_N106_sound;
private int temp_nmt;
private Namcot106Chnl[] sound_channels;
private byte soundReg;
public int enabledChannels;
private int enabledChannels1;
private int channelIndex;
private byte temp_val;
private byte temp_i;
public byte[] EXRAM;
private bool[] sound_channels_enable;
private double soundOut;
private int sound_out_div;
internal override void HardReset()
{
base.HardReset();
EXRAM = new byte[128];
Switch08KPRG(PRG_ROM_08KB_Mask, PRGArea.AreaE000);
enable_mirroring_switch = (enable_N106_sound = base.MapperNumber == 19);
switch (SHA1.ToUpper())
{
case "97E7E61EECB73CB1EA0C15AE51E65EA56301A685":
case "3D554F55411AB2DDD1A87E7583E643970DB784F3":
case "7FA51058307DB50825C2D3A3A98C0DA554BC3C92":
case "1C476C795CFC17E987C22FFD6F09BAF1396ED2C9":
enable_mirroring_switch = false;
enable_N106_sound = false;
break;
}
if (enable_N106_sound)
{
sound_channels = new Namcot106Chnl[8];
sound_channels_enable = new bool[8];
for (int i = 0; i < 8; i++)
{
sound_channels[i] = new Namcot106Chnl(this);
sound_channels[i].HardReset();
}
soundReg = 0;
enabledChannels = 0;
channelIndex = 0;
APUApplyChannelsSettings();
}
}
internal override void WriteEX(ref ushort address, ref byte data)
{
switch (address & 0xF800)
{
case 18432:
if (soundReg >= 64)
{
switch (soundReg & 0x7F)
{
case 64:
sound_channels[0].WriteA(ref data);
break;
case 66:
sound_channels[0].WriteB(ref data);
break;
case 68:
sound_channels[0].WriteC(ref data);
break;
case 70:
sound_channels[0].WriteD(ref data);
break;
case 71:
sound_channels[0].WriteE(ref data);
break;
case 72:
sound_channels[1].WriteA(ref data);
break;
case 74:
sound_channels[1].WriteB(ref data);
break;
case 76:
sound_channels[1].WriteC(ref data);
break;
case 78:
sound_channels[1].WriteD(ref data);
break;
case 79:
sound_channels[1].WriteE(ref data);
break;
case 80:
sound_channels[2].WriteA(ref data);
break;
case 82:
sound_channels[2].WriteB(ref data);
break;
case 84:
sound_channels[2].WriteC(ref data);
break;
case 86:
sound_channels[2].WriteD(ref data);
break;
case 87:
sound_channels[2].WriteE(ref data);
break;
case 88:
sound_channels[3].WriteA(ref data);
break;
case 90:
sound_channels[3].WriteB(ref data);
break;
case 92:
sound_channels[3].WriteC(ref data);
break;
case 94:
sound_channels[3].WriteD(ref data);
break;
case 95:
sound_channels[3].WriteE(ref data);
break;
case 96:
sound_channels[4].WriteA(ref data);
break;
case 98:
sound_channels[4].WriteB(ref data);
break;
case 100:
sound_channels[4].WriteC(ref data);
break;
case 102:
sound_channels[4].WriteD(ref data);
break;
case 103:
sound_channels[4].WriteE(ref data);
break;
case 104:
sound_channels[5].WriteA(ref data);
break;
case 106:
sound_channels[5].WriteB(ref data);
break;
case 108:
sound_channels[5].WriteC(ref data);
break;
case 110:
sound_channels[5].WriteD(ref data);
break;
case 111:
sound_channels[5].WriteE(ref data);
break;
case 112:
sound_channels[6].WriteA(ref data);
break;
case 114:
sound_channels[6].WriteB(ref data);
break;
case 116:
sound_channels[6].WriteC(ref data);
break;
case 118:
sound_channels[6].WriteD(ref data);
break;
case 119:
sound_channels[6].WriteE(ref data);
break;
case 120:
sound_channels[7].WriteA(ref data);
break;
case 122:
sound_channels[7].WriteB(ref data);
break;
case 124:
sound_channels[7].WriteC(ref data);
break;
case 126:
sound_channels[7].WriteD(ref data);
break;
case 127:
sound_channels[7].WriteE(ref data);
enabledChannels = (data & 0x70) >> 4;
channelIndex = 0;
enabledChannels1 = enabledChannels + 1;
temp_i = 7;
while (temp_i >= 0 && enabledChannels1 > 0)
{
sound_channels[temp_i].Enabled = true;
enabledChannels1--;
temp_i--;
}
break;
}
}
EXRAM[soundReg & 0x7F] = data;
if ((soundReg & 0x80) == 128)
{
soundReg = (byte)(((uint)(soundReg + 1) & 0x7Fu) | 0x80u);
}
break;
case 20480:
NesEmu.IRQFlags &= -9;
irq_counter = (irq_counter & 0x7F00) | data;
break;
case 22528:
NesEmu.IRQFlags &= -9;
irq_counter = (irq_counter & 0xFF) | ((data & 0x7F) << 8);
irq_enable = (data & 0x80) == 128;
break;
}
}
internal override void ReadEX(ref ushort address, out byte value)
{
switch (address & 0xF800)
{
case 18432:
value = EXRAM[soundReg & 0x7F];
if ((soundReg & 0x80) == 128)
{
soundReg = (byte)(((uint)(soundReg + 1) & 0x7Fu) | 0x80u);
}
break;
case 20480:
NesEmu.IRQFlags &= -9;
value = (byte)((uint)irq_counter & 0xFFu);
break;
case 22528:
NesEmu.IRQFlags &= -9;
value = (byte)((irq_enable ? 128u : 0u) | (uint)((irq_counter & 0x7F00) >> 8));
break;
default:
value = 0;
break;
}
}
internal override void WritePRG(ref ushort address, ref byte data)
{
switch (address & 0xF800)
{
case 32768:
if (!disables_chr_ram_A)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area0000);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area0000);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area0000);
Switch01KCHR(data, CHRArea.Area0000);
}
break;
case 34816:
if (!disables_chr_ram_A)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area0400);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area0400);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area0400);
Switch01KCHR(data, CHRArea.Area0400);
}
break;
case 36864:
if (!disables_chr_ram_A)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area0800);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area0800);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area0800);
Switch01KCHR(data, CHRArea.Area0800);
}
break;
case 38912:
if (!disables_chr_ram_A)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area0C00);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area0C00);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area0C00);
Switch01KCHR(data, CHRArea.Area0C00);
}
break;
case 40960:
if (!disables_chr_ram_B)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area1000);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area1000);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area1000);
Switch01KCHR(data, CHRArea.Area1000);
}
break;
case 43008:
if (!disables_chr_ram_B)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area1400);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area1400);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area1400);
Switch01KCHR(data, CHRArea.Area1400);
}
break;
case 45056:
if (!disables_chr_ram_B)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area1800);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area1800);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area1800);
Switch01KCHR(data, CHRArea.Area1800);
}
break;
case 47104:
if (!disables_chr_ram_B)
{
Toggle01KCHR_RAM(data >= 224, CHRArea.Area1C00);
Switch01KCHR((data >= 224) ? (data - 224) : data, CHRArea.Area1C00);
}
else
{
Toggle01KCHR_RAM(ram: false, CHRArea.Area1C00);
Switch01KCHR(data, CHRArea.Area1C00);
}
break;
case 49152:
if (enable_mirroring_switch)
{
NMT_AREA_BLK_INDEX[0] = data;
}
break;
case 51200:
if (enable_mirroring_switch)
{
NMT_AREA_BLK_INDEX[1] = data;
}
break;
case 53248:
if (enable_mirroring_switch)
{
NMT_AREA_BLK_INDEX[2] = data;
}
break;
case 55296:
if (enable_mirroring_switch)
{
NMT_AREA_BLK_INDEX[3] = data;
}
break;
case 57344:
Switch08KPRG(data & 0x3F, PRGArea.Area8000);
break;
case 59392:
Switch08KPRG(data & 0x3F, PRGArea.AreaA000);
disables_chr_ram_A = (data & 0x40) == 64;
disables_chr_ram_B = (data & 0x80) == 128;
break;
case 61440:
Switch08KPRG(data & 0x3F, PRGArea.AreaC000);
break;
case 63488:
soundReg = data;
break;
}
}
internal override void ReadNMT(ref ushort address, out byte data)
{
if (enable_mirroring_switch)
{
temp_nmt = NMT_AREA_BLK_INDEX[(address >> 10) & 3];
if (temp_nmt >= 224)
{
data = NMT_RAM[(temp_nmt - 224) & 1][address & 0x3FF];
}
else
{
data = CHR_ROM[temp_nmt][address & 0x3FF];
}
}
else
{
base.ReadNMT(ref address, out data);
}
}
internal override void WriteNMT(ref ushort address, ref byte data)
{
if (enable_mirroring_switch)
{
temp_nmt = NMT_AREA_BLK_INDEX[(address >> 10) & 3];
if (temp_nmt >= 224)
{
NMT_RAM[(temp_nmt - 224) & 1][address & 0x3FF] = data;
}
}
else
{
base.WriteNMT(ref address, ref data);
}
}
internal override void OnCPUClock()
{
if (irq_enable)
{
if (irq_counter == 32767)
{
NesEmu.IRQFlags |= 8;
irq_counter = 0;
}
else
{
irq_counter++;
}
}
}
internal override void OnAPUClockSingle()
{
if (sound_channels != null)
{
for (int i = 0; i < sound_channels.Length; i++)
{
sound_channels[i].ClockSingle();
}
}
}
internal override double APUGetSample()
{
soundOut = 0.0;
sound_out_div = 0;
if (enabledChannels > 0)
{
for (int i = 0; i < sound_channels.Length; i++)
{
if (sound_channels[i].Enabled && sound_channels_enable[i])
{
if (sound_channels[i].clocks > 0)
{
sound_channels[i].output = sound_channels[i].output_av / sound_channels[i].clocks;
}
sound_channels[i].clocks = (sound_channels[i].output_av = 0);
soundOut += sound_channels[i].output;
sound_out_div++;
}
}
soundOut = soundOut / 8.0 / 225.0;
}
return soundOut;
}
internal override void APUApplyChannelsSettings()
{
base.APUApplyChannelsSettings();
sound_channels_enable[0] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT1;
sound_channels_enable[1] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT2;
sound_channels_enable[2] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT3;
sound_channels_enable[3] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT4;
sound_channels_enable[4] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT5;
sound_channels_enable[5] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT6;
sound_channels_enable[6] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT7;
sound_channels_enable[7] = MyNesMain.RendererSettings.Audio_ChannelEnabled_NMT8;
}
internal override void WriteStateData(ref BinaryWriter stream)
{
base.WriteStateData(ref stream);
stream.Write(irq_counter);
stream.Write(irq_enable);
stream.Write(disables_chr_ram_A);
stream.Write(disables_chr_ram_B);
stream.Write(enable_mirroring_switch);
stream.Write(enable_N106_sound);
stream.Write(temp_nmt);
if (enable_N106_sound)
{
for (int i = 0; i < sound_channels.Length; i++)
{
sound_channels[i].SaveState(stream);
}
}
stream.Write(soundReg);
stream.Write(enabledChannels);
stream.Write(enabledChannels1);
stream.Write(channelIndex);
stream.Write(temp_val);
stream.Write(temp_i);
stream.Write(EXRAM);
}
internal override void ReadStateData(ref BinaryReader stream)
{
base.ReadStateData(ref stream);
irq_counter = stream.ReadInt32();
irq_enable = stream.ReadBoolean();
disables_chr_ram_A = stream.ReadBoolean();
disables_chr_ram_B = stream.ReadBoolean();
enable_mirroring_switch = stream.ReadBoolean();
enable_N106_sound = stream.ReadBoolean();
temp_nmt = stream.ReadInt32();
if (enable_N106_sound)
{
for (int i = 0; i < sound_channels.Length; i++)
{
sound_channels[i].LoadState(stream);
}
}
soundReg = stream.ReadByte();
enabledChannels = stream.ReadInt32();
enabledChannels1 = stream.ReadInt32();
channelIndex = stream.ReadInt32();
temp_val = stream.ReadByte();
temp_i = stream.ReadByte();
stream.Read(EXRAM, 0, EXRAM.Length);
}
}
}