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