871 lines
22 KiB
C#
871 lines
22 KiB
C#
using System;
|
|
using System.IO;
|
|
|
|
namespace MyNes.Core
|
|
{
|
|
[BoardInfo("MMC5", 5, 8, 16)]
|
|
[WithExternalSound]
|
|
[HassIssues]
|
|
internal class Mapper005 : Board
|
|
{
|
|
private int ram_protectA;
|
|
|
|
private int ram_protectB;
|
|
|
|
private int ExRAM_mode;
|
|
|
|
private int[] CHROffset_spr;
|
|
|
|
private int[] CHROffsetEX;
|
|
|
|
private int[] CHROffsetSP;
|
|
|
|
private int[] chrRegA;
|
|
|
|
private int[] chrRegB;
|
|
|
|
private int[] prgReg;
|
|
|
|
private bool useSRAMmirroring;
|
|
|
|
private int chr_high;
|
|
|
|
private int chr_mode;
|
|
|
|
private int prg_mode;
|
|
|
|
private bool chr_setB_last;
|
|
|
|
private byte temp_val;
|
|
|
|
private byte temp_fill;
|
|
|
|
private int lastAccessVRAM;
|
|
|
|
private int paletteNo;
|
|
|
|
private int shift;
|
|
|
|
private int EXtilenumber;
|
|
|
|
private byte multiplicand;
|
|
|
|
private byte multiplier;
|
|
|
|
private ushort product;
|
|
|
|
private bool split_enable;
|
|
|
|
private bool split_right;
|
|
|
|
private int split_tile;
|
|
|
|
private int split_yscroll;
|
|
|
|
private bool split_doit;
|
|
|
|
private int split_watch_tile;
|
|
|
|
private byte irq_line;
|
|
|
|
private byte irq_enable;
|
|
|
|
private int irq_pending;
|
|
|
|
private int irq_current_counter;
|
|
|
|
private int irq_current_inframe;
|
|
|
|
private MMC5Sqr snd_1;
|
|
|
|
private MMC5Sqr snd_2;
|
|
|
|
private MMC5Pcm snd_3;
|
|
|
|
private double[] audio_pulse_table;
|
|
|
|
private double[] audio_tnd_table;
|
|
|
|
internal override string Issues => MNInterfaceLanguage.IssueMapper5;
|
|
|
|
internal override void Initialize(IRom rom)
|
|
{
|
|
base.Initialize(rom);
|
|
snd_1 = new MMC5Sqr();
|
|
snd_2 = new MMC5Sqr();
|
|
snd_3 = new MMC5Pcm();
|
|
audio_pulse_table = new double[32];
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
audio_pulse_table[i] = 95.52 / (8128.0 / (double)i + 100.0);
|
|
}
|
|
audio_tnd_table = new double[204];
|
|
for (int j = 0; j < 204; j++)
|
|
{
|
|
audio_tnd_table[j] = 163.67 / (24329.0 / (double)j + 100.0);
|
|
}
|
|
}
|
|
|
|
internal override void HardReset()
|
|
{
|
|
base.HardReset();
|
|
switch (SHA1.ToUpper())
|
|
{
|
|
case "37267833C984F176DB4B0BC9D45DABA0FFF45304":
|
|
useSRAMmirroring = true;
|
|
break;
|
|
case "800AEFE756E85A0A78CCB4DAE68EBBA5DF24BF41":
|
|
useSRAMmirroring = true;
|
|
break;
|
|
}
|
|
Console.WriteLine("MMC5: using PRG RAM mirroring = " + useSRAMmirroring);
|
|
CHROffset_spr = new int[8];
|
|
CHROffsetEX = new int[8];
|
|
CHROffsetSP = new int[8];
|
|
chrRegA = new int[8];
|
|
chrRegB = new int[4];
|
|
prgReg = new int[4];
|
|
prgReg[3] = PRG_ROM_08KB_Mask;
|
|
prg_mode = 3;
|
|
Switch08KPRG(PRG_ROM_08KB_Mask, PRGArea.Area8000);
|
|
Switch08KPRG(PRG_ROM_08KB_Mask, PRGArea.AreaA000);
|
|
Switch08KPRG(PRG_ROM_08KB_Mask, PRGArea.AreaC000);
|
|
Switch08KPRG(PRG_ROM_08KB_Mask, PRGArea.AreaE000);
|
|
Switch04kCHREX(0, 0);
|
|
Switch04kCHRSP(0, 0);
|
|
Switch08kCHR_spr(0);
|
|
TogglePRGRAMWritableEnable(enable: true);
|
|
TogglePRGRAMEnable(enable: true);
|
|
APUApplyChannelsSettings();
|
|
snd_1.HardReset();
|
|
snd_2.HardReset();
|
|
snd_3.HardReset();
|
|
}
|
|
|
|
internal override void SoftReset()
|
|
{
|
|
base.SoftReset();
|
|
snd_1.SoftReset();
|
|
snd_2.SoftReset();
|
|
snd_3.SoftReset();
|
|
}
|
|
|
|
internal override void WriteEX(ref ushort address, ref byte value)
|
|
{
|
|
if (address >= 23552)
|
|
{
|
|
if (ExRAM_mode == 2)
|
|
{
|
|
NMT_RAM[2][address & 0x3FF] = value;
|
|
}
|
|
else if (ExRAM_mode < 2)
|
|
{
|
|
if (irq_current_inframe == 64)
|
|
{
|
|
NMT_RAM[2][address & 0x3FF] = value;
|
|
}
|
|
else
|
|
{
|
|
NMT_RAM[2][address & 0x3FF] = 0;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
switch (address)
|
|
{
|
|
case 20480:
|
|
snd_1.Write0(ref value);
|
|
break;
|
|
case 20482:
|
|
snd_1.Write2(ref value);
|
|
break;
|
|
case 20483:
|
|
snd_1.Write3(ref value);
|
|
break;
|
|
case 20484:
|
|
snd_2.Write0(ref value);
|
|
break;
|
|
case 20486:
|
|
snd_2.Write2(ref value);
|
|
break;
|
|
case 20487:
|
|
snd_2.Write3(ref value);
|
|
break;
|
|
case 20496:
|
|
snd_3.Write5010(value);
|
|
break;
|
|
case 20497:
|
|
snd_3.Write5011(value);
|
|
break;
|
|
case 20501:
|
|
snd_1.WriteEnabled((value & 1) != 0);
|
|
snd_2.WriteEnabled((value & 2) != 0);
|
|
break;
|
|
case 20736:
|
|
prg_mode = value & 3;
|
|
break;
|
|
case 20737:
|
|
chr_mode = value & 3;
|
|
break;
|
|
case 20738:
|
|
ram_protectA = value & 3;
|
|
UpdateRamProtect();
|
|
break;
|
|
case 20739:
|
|
ram_protectB = value & 3;
|
|
UpdateRamProtect();
|
|
break;
|
|
case 20740:
|
|
ExRAM_mode = value & 3;
|
|
break;
|
|
case 20741:
|
|
Switch01KNMT(value);
|
|
break;
|
|
case 20755:
|
|
if (!useSRAMmirroring)
|
|
{
|
|
Switch08KPRG(value & 7, PRGArea.Area6000);
|
|
}
|
|
else
|
|
{
|
|
Switch08KPRG((value >> 2) & 1, PRGArea.Area6000);
|
|
}
|
|
break;
|
|
case 20756:
|
|
if (prg_mode == 3)
|
|
{
|
|
Toggle08KPRG_RAM((value & 0x80) == 0, PRGArea.Area8000);
|
|
Switch08KPRG(value & 0x7F, PRGArea.Area8000);
|
|
}
|
|
break;
|
|
case 20757:
|
|
switch (prg_mode)
|
|
{
|
|
case 1:
|
|
Toggle16KPRG_RAM((value & 0x80) == 0, PRGArea.Area8000);
|
|
Switch16KPRG((value & 0x7F) >> 1, PRGArea.Area8000);
|
|
break;
|
|
case 2:
|
|
Toggle16KPRG_RAM((value & 0x80) == 0, PRGArea.Area8000);
|
|
Switch16KPRG((value & 0x7F) >> 1, PRGArea.Area8000);
|
|
break;
|
|
case 3:
|
|
Toggle08KPRG_RAM((value & 0x80) == 0, PRGArea.AreaA000);
|
|
Switch08KPRG(value & 0x7F, PRGArea.AreaA000);
|
|
break;
|
|
}
|
|
break;
|
|
case 20758:
|
|
{
|
|
int num = prg_mode;
|
|
if ((uint)(num - 2) <= 1u)
|
|
{
|
|
Toggle08KPRG_RAM((value & 0x80) == 0, PRGArea.AreaC000);
|
|
Switch08KPRG(value & 0x7F, PRGArea.AreaC000);
|
|
}
|
|
break;
|
|
}
|
|
case 20759:
|
|
switch (prg_mode)
|
|
{
|
|
case 0:
|
|
Switch32KPRG((value & 0x7C) >> 2, PRGArea.Area8000);
|
|
break;
|
|
case 1:
|
|
Switch16KPRG((value & 0x7F) >> 1, PRGArea.AreaC000);
|
|
break;
|
|
case 2:
|
|
Switch08KPRG(value & 0x7F, PRGArea.AreaE000);
|
|
break;
|
|
case 3:
|
|
Switch08KPRG(value & 0x7F, PRGArea.AreaE000);
|
|
break;
|
|
}
|
|
break;
|
|
case 20768:
|
|
chr_setB_last = false;
|
|
if (chr_mode == 3)
|
|
{
|
|
Switch01kCHR_spr(value | chr_high, 0);
|
|
}
|
|
break;
|
|
case 20769:
|
|
chr_setB_last = false;
|
|
switch (chr_mode)
|
|
{
|
|
case 2:
|
|
Switch02kCHR_spr(value | chr_high, 0);
|
|
break;
|
|
case 3:
|
|
Switch01kCHR_spr(value | chr_high, 1024);
|
|
break;
|
|
}
|
|
break;
|
|
case 20770:
|
|
chr_setB_last = false;
|
|
if (chr_mode == 3)
|
|
{
|
|
Switch01kCHR_spr(value | chr_high, 2048);
|
|
}
|
|
break;
|
|
case 20771:
|
|
chr_setB_last = false;
|
|
switch (chr_mode)
|
|
{
|
|
case 1:
|
|
Switch04kCHR_spr(value | chr_high, 0);
|
|
break;
|
|
case 2:
|
|
Switch02kCHR_spr(value | chr_high, 2048);
|
|
break;
|
|
case 3:
|
|
Switch01kCHR_spr(value | chr_high, 3072);
|
|
break;
|
|
}
|
|
break;
|
|
case 20772:
|
|
chr_setB_last = false;
|
|
if (chr_mode == 3)
|
|
{
|
|
Switch01kCHR_spr(value | chr_high, 4096);
|
|
}
|
|
break;
|
|
case 20773:
|
|
chr_setB_last = false;
|
|
switch (chr_mode)
|
|
{
|
|
case 2:
|
|
Switch02kCHR_spr(value | chr_high, 4096);
|
|
break;
|
|
case 3:
|
|
Switch01kCHR_spr(value | chr_high, 5120);
|
|
break;
|
|
}
|
|
break;
|
|
case 20774:
|
|
chr_setB_last = false;
|
|
if (chr_mode == 3)
|
|
{
|
|
Switch01kCHR_spr(value | chr_high, 6144);
|
|
}
|
|
break;
|
|
case 20775:
|
|
chr_setB_last = false;
|
|
switch (chr_mode)
|
|
{
|
|
case 0:
|
|
Switch08kCHR_spr(value | chr_high);
|
|
break;
|
|
case 1:
|
|
Switch04kCHR_spr(value | chr_high, 4096);
|
|
break;
|
|
case 2:
|
|
Switch02kCHR_spr(value | chr_high, 6144);
|
|
break;
|
|
case 3:
|
|
Switch01kCHR_spr(value | chr_high, 7168);
|
|
break;
|
|
}
|
|
break;
|
|
case 20776:
|
|
chr_setB_last = true;
|
|
if (chr_mode == 3)
|
|
{
|
|
Switch01KCHR(value | chr_high, CHRArea.Area0000);
|
|
Switch01KCHR(value | chr_high, CHRArea.Area1000);
|
|
}
|
|
break;
|
|
case 20777:
|
|
chr_setB_last = true;
|
|
switch (chr_mode)
|
|
{
|
|
case 2:
|
|
Switch02KCHR(value | chr_high, CHRArea.Area0000);
|
|
Switch02KCHR(value | chr_high, CHRArea.Area1000);
|
|
break;
|
|
case 3:
|
|
Switch01KCHR(value | chr_high, CHRArea.Area0400);
|
|
Switch01KCHR(value | chr_high, CHRArea.Area1400);
|
|
break;
|
|
}
|
|
break;
|
|
case 20778:
|
|
chr_setB_last = true;
|
|
if (chr_mode == 3)
|
|
{
|
|
Switch01KCHR(value | chr_high, CHRArea.Area0800);
|
|
Switch01KCHR(value | chr_high, CHRArea.Area1800);
|
|
}
|
|
break;
|
|
case 20779:
|
|
chr_setB_last = true;
|
|
switch (chr_mode)
|
|
{
|
|
case 0:
|
|
Switch04kCHR_bkg(value | chr_high, 0);
|
|
Switch04kCHR_bkg(value | chr_high, 4096);
|
|
break;
|
|
case 1:
|
|
Switch04KCHR(value | chr_high, CHRArea.Area0000);
|
|
Switch04KCHR(value | chr_high, CHRArea.Area1000);
|
|
break;
|
|
case 2:
|
|
Switch02KCHR(value | chr_high, CHRArea.Area0800);
|
|
Switch02KCHR(value | chr_high, CHRArea.Area1800);
|
|
break;
|
|
case 3:
|
|
Switch01KCHR(value | chr_high, CHRArea.Area0C00);
|
|
Switch01KCHR(value | chr_high, CHRArea.Area1C00);
|
|
break;
|
|
}
|
|
break;
|
|
case 20784:
|
|
chr_high = (value & 3) << 8;
|
|
break;
|
|
case 20742:
|
|
{
|
|
for (int j = 0; j < 960; j++)
|
|
{
|
|
NMT_RAM[3][j] = value;
|
|
}
|
|
break;
|
|
}
|
|
case 20743:
|
|
{
|
|
for (int i = 960; i < 1024; i++)
|
|
{
|
|
temp_fill = (byte)((uint)(2 << (value & 3)) | (value & 3u));
|
|
temp_fill |= (byte)((temp_fill & 0xF) << 4);
|
|
NMT_RAM[3][i] = temp_fill;
|
|
}
|
|
break;
|
|
}
|
|
case 20992:
|
|
split_tile = value & 0x1F;
|
|
split_enable = (value & 0x80) == 128;
|
|
split_right = (value & 0x40) == 64;
|
|
break;
|
|
case 20993:
|
|
split_yscroll = value;
|
|
break;
|
|
case 20994:
|
|
Switch04kCHRSP(value, address & 0);
|
|
Switch04kCHRSP(value, address & 0x1000);
|
|
break;
|
|
case 20995:
|
|
irq_line = value;
|
|
break;
|
|
case 20996:
|
|
irq_enable = value;
|
|
break;
|
|
case 20997:
|
|
multiplicand = value;
|
|
product = (ushort)(multiplicand * multiplier);
|
|
break;
|
|
case 20998:
|
|
multiplier = value;
|
|
product = (ushort)(multiplicand * multiplier);
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal override void ReadEX(ref ushort address, out byte data)
|
|
{
|
|
if (address >= 23552 && ExRAM_mode >= 2)
|
|
{
|
|
data = NMT_RAM[2][address & 0x3FF];
|
|
return;
|
|
}
|
|
switch (address)
|
|
{
|
|
case 20496:
|
|
data = snd_3.Read5010();
|
|
break;
|
|
case 20996:
|
|
data = (byte)(irq_current_inframe | irq_pending);
|
|
irq_pending = 0;
|
|
NesEmu.IRQFlags &= -9;
|
|
break;
|
|
case 20997:
|
|
data = (byte)(product & 0xFFu);
|
|
break;
|
|
case 20998:
|
|
data = (byte)((product & 0xFF00) >> 8);
|
|
break;
|
|
case 20501:
|
|
data = (byte)((snd_1.ReadEnable() ? 1u : 0u) | (snd_2.ReadEnable() ? 2u : 0u));
|
|
data = 0;
|
|
break;
|
|
default:
|
|
data = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal override void ReadCHR(ref ushort address, out byte data)
|
|
{
|
|
if (!NesEmu.ppu_is_sprfetch && split_enable && ExRAM_mode < 2)
|
|
{
|
|
split_watch_tile = address & 0x3F;
|
|
if (!split_right)
|
|
{
|
|
split_doit = split_watch_tile < split_tile;
|
|
}
|
|
else
|
|
{
|
|
split_doit = split_watch_tile >= split_tile;
|
|
}
|
|
_ = split_doit;
|
|
}
|
|
if (ExRAM_mode == 1)
|
|
{
|
|
if (!NesEmu.ppu_is_sprfetch)
|
|
{
|
|
EXtilenumber = NMT_RAM[2][lastAccessVRAM] & 0x3F;
|
|
Switch04kCHREX(EXtilenumber | chr_high, address & 0x1000);
|
|
data = CHR_ROM[CHROffsetEX[(address >> 10) & 7]][address & 0x3FF];
|
|
}
|
|
else
|
|
{
|
|
data = CHR_ROM[CHROffset_spr[(address >> 10) & 7]][address & 0x3FF];
|
|
}
|
|
}
|
|
else if (NesEmu.ppu_reg_2000_Sprite_size == 16)
|
|
{
|
|
if (!NesEmu.ppu_is_sprfetch)
|
|
{
|
|
data = CHR_ROM[CHR_AREA_BLK_INDEX[(address >> 10) & 7]][address & 0x3FF];
|
|
}
|
|
else
|
|
{
|
|
data = CHR_ROM[CHROffset_spr[(address >> 10) & 7]][address & 0x3FF];
|
|
}
|
|
}
|
|
else if (chr_setB_last)
|
|
{
|
|
data = CHR_ROM[CHR_AREA_BLK_INDEX[(address >> 10) & 7]][address & 0x3FF];
|
|
}
|
|
else
|
|
{
|
|
data = CHR_ROM[CHROffset_spr[(address >> 10) & 7]][address & 0x3FF];
|
|
}
|
|
}
|
|
|
|
internal override void ReadNMT(ref ushort address, out byte data)
|
|
{
|
|
_ = split_doit;
|
|
if (ExRAM_mode == 1)
|
|
{
|
|
if ((address & 0x3FF) <= 959)
|
|
{
|
|
lastAccessVRAM = address & 0x3FF;
|
|
}
|
|
else
|
|
{
|
|
paletteNo = NMT_RAM[2][lastAccessVRAM] & 0xC0;
|
|
shift = ((lastAccessVRAM >> 4) & 4) | (lastAccessVRAM & 2);
|
|
switch (shift)
|
|
{
|
|
case 0:
|
|
data = (byte)(paletteNo >> 6);
|
|
return;
|
|
case 2:
|
|
data = (byte)(paletteNo >> 4);
|
|
return;
|
|
case 4:
|
|
data = (byte)(paletteNo >> 2);
|
|
return;
|
|
case 6:
|
|
data = (byte)paletteNo;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
data = NMT_RAM[NMT_AREA_BLK_INDEX[(address >> 10) & 3]][address & 0x3FF];
|
|
}
|
|
|
|
internal override void WriteNMT(ref ushort address, ref byte value)
|
|
{
|
|
if (ExRAM_mode == 1 && (address & 0x3FF) <= 959)
|
|
{
|
|
lastAccessVRAM = address & 0x3FF;
|
|
}
|
|
NMT_RAM[NMT_AREA_BLK_INDEX[(address >> 10) & 3]][address & 0x3FF] = value;
|
|
}
|
|
|
|
private void UpdateRamProtect()
|
|
{
|
|
TogglePRGRAMWritableEnable(ram_protectA == 2 && ram_protectB == 1);
|
|
}
|
|
|
|
private void Switch04kCHR_bkg(int index, int where)
|
|
{
|
|
int num = (where >> 10) & 7;
|
|
index <<= 2;
|
|
CHR_AREA_BLK_INDEX[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHR_AREA_BLK_INDEX[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHR_AREA_BLK_INDEX[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHR_AREA_BLK_INDEX[num] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
private void Switch01kCHR_spr(int index, int where)
|
|
{
|
|
CHROffset_spr[(where >> 10) & 7] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
private void Switch02kCHR_spr(int index, int where)
|
|
{
|
|
int num = (where >> 10) & 7;
|
|
index <<= 1;
|
|
CHROffset_spr[num] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[num + 1] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
private void Switch04kCHR_spr(int index, int where)
|
|
{
|
|
int num = (where >> 10) & 7;
|
|
index <<= 2;
|
|
CHROffset_spr[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffset_spr[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffset_spr[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffset_spr[num] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
private void Switch08kCHR_spr(int index)
|
|
{
|
|
index <<= 3;
|
|
CHROffset_spr[0] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[1] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[2] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[3] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[4] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[5] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[6] = index & CHR_ROM_01KB_Mask;
|
|
index++;
|
|
CHROffset_spr[7] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
private void Switch04kCHREX(int index, int where)
|
|
{
|
|
int num = (where >> 10) & 7;
|
|
index <<= 2;
|
|
CHROffsetEX[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffsetEX[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffsetEX[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffsetEX[num] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
private void Switch04kCHRSP(int index, int where)
|
|
{
|
|
int num = (where >> 10) & 7;
|
|
index <<= 2;
|
|
CHROffsetSP[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffsetSP[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffsetSP[num] = index & CHR_ROM_01KB_Mask;
|
|
num++;
|
|
index++;
|
|
CHROffsetSP[num] = index & CHR_ROM_01KB_Mask;
|
|
}
|
|
|
|
internal override void OnPPUScanlineTick()
|
|
{
|
|
irq_current_inframe = ((NesEmu.IsInRender() && NesEmu.IsRenderingOn()) ? 64 : 0);
|
|
if (irq_current_inframe == 0)
|
|
{
|
|
irq_current_inframe = 64;
|
|
irq_current_counter = 0;
|
|
irq_pending = 0;
|
|
NesEmu.IRQFlags &= -9;
|
|
return;
|
|
}
|
|
irq_current_counter++;
|
|
if (irq_current_counter == irq_line)
|
|
{
|
|
irq_pending = 128;
|
|
if (irq_enable == 128)
|
|
{
|
|
NesEmu.IRQFlags |= 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override void OnAPUClock()
|
|
{
|
|
base.OnAPUClock();
|
|
snd_1.Clock();
|
|
snd_2.Clock();
|
|
}
|
|
|
|
internal override void OnAPUClockEnvelope()
|
|
{
|
|
base.OnAPUClockEnvelope();
|
|
snd_1.ClockLength();
|
|
snd_2.ClockLength();
|
|
snd_1.ClockEnvelope();
|
|
snd_2.ClockEnvelope();
|
|
}
|
|
|
|
internal override double APUGetSample()
|
|
{
|
|
return audio_pulse_table[snd_1.output + snd_2.output] + audio_tnd_table[snd_3.output];
|
|
}
|
|
|
|
internal override void APUApplyChannelsSettings()
|
|
{
|
|
base.APUApplyChannelsSettings();
|
|
snd_1.Outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_MMC5_SQ1;
|
|
snd_2.Outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_MMC5_SQ2;
|
|
snd_3.Outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_MMC5_PCM;
|
|
}
|
|
|
|
internal override void WriteStateData(ref BinaryWriter stream)
|
|
{
|
|
base.WriteStateData(ref stream);
|
|
stream.Write(ram_protectA);
|
|
stream.Write(ram_protectB);
|
|
stream.Write(ExRAM_mode);
|
|
for (int i = 0; i < CHROffset_spr.Length; i++)
|
|
{
|
|
stream.Write(CHROffset_spr[i]);
|
|
}
|
|
for (int j = 0; j < CHROffsetEX.Length; j++)
|
|
{
|
|
stream.Write(CHROffsetEX[j]);
|
|
}
|
|
for (int k = 0; k < CHROffsetSP.Length; k++)
|
|
{
|
|
stream.Write(CHROffsetSP[k]);
|
|
}
|
|
for (int l = 0; l < chrRegA.Length; l++)
|
|
{
|
|
stream.Write(chrRegA[l]);
|
|
}
|
|
for (int m = 0; m < chrRegB.Length; m++)
|
|
{
|
|
stream.Write(chrRegB[m]);
|
|
}
|
|
for (int n = 0; n < prgReg.Length; n++)
|
|
{
|
|
stream.Write(prgReg[n]);
|
|
}
|
|
stream.Write(useSRAMmirroring);
|
|
stream.Write(chr_high);
|
|
stream.Write(chr_mode);
|
|
stream.Write(prg_mode);
|
|
stream.Write(chr_setB_last);
|
|
stream.Write(temp_val);
|
|
stream.Write(temp_fill);
|
|
stream.Write(lastAccessVRAM);
|
|
stream.Write(paletteNo);
|
|
stream.Write(shift);
|
|
stream.Write(EXtilenumber);
|
|
stream.Write(multiplicand);
|
|
stream.Write(multiplier);
|
|
stream.Write(product);
|
|
stream.Write(split_enable);
|
|
stream.Write(split_right);
|
|
stream.Write(split_tile);
|
|
stream.Write(split_yscroll);
|
|
stream.Write(split_doit);
|
|
stream.Write(split_watch_tile);
|
|
stream.Write(irq_line);
|
|
stream.Write(irq_enable);
|
|
stream.Write(irq_pending);
|
|
stream.Write(irq_current_counter);
|
|
stream.Write(irq_current_inframe);
|
|
snd_1.WriteStateData(ref stream);
|
|
snd_2.WriteStateData(ref stream);
|
|
snd_3.SaveState(ref stream);
|
|
}
|
|
|
|
internal override void ReadStateData(ref BinaryReader stream)
|
|
{
|
|
base.ReadStateData(ref stream);
|
|
ram_protectA = stream.ReadInt32();
|
|
ram_protectB = stream.ReadInt32();
|
|
ExRAM_mode = stream.ReadInt32();
|
|
for (int i = 0; i < CHROffset_spr.Length; i++)
|
|
{
|
|
CHROffset_spr[i] = stream.ReadInt32();
|
|
}
|
|
for (int j = 0; j < CHROffsetEX.Length; j++)
|
|
{
|
|
CHROffsetEX[j] = stream.ReadInt32();
|
|
}
|
|
for (int k = 0; k < CHROffsetSP.Length; k++)
|
|
{
|
|
CHROffsetSP[k] = stream.ReadInt32();
|
|
}
|
|
for (int l = 0; l < chrRegA.Length; l++)
|
|
{
|
|
chrRegA[l] = stream.ReadInt32();
|
|
}
|
|
for (int m = 0; m < chrRegB.Length; m++)
|
|
{
|
|
chrRegB[m] = stream.ReadInt32();
|
|
}
|
|
for (int n = 0; n < prgReg.Length; n++)
|
|
{
|
|
prgReg[n] = stream.ReadInt32();
|
|
}
|
|
useSRAMmirroring = stream.ReadBoolean();
|
|
chr_high = stream.ReadInt32();
|
|
chr_mode = stream.ReadInt32();
|
|
prg_mode = stream.ReadInt32();
|
|
chr_setB_last = stream.ReadBoolean();
|
|
temp_val = stream.ReadByte();
|
|
temp_fill = stream.ReadByte();
|
|
lastAccessVRAM = stream.ReadInt32();
|
|
paletteNo = stream.ReadInt32();
|
|
shift = stream.ReadInt32();
|
|
EXtilenumber = stream.ReadInt32();
|
|
multiplicand = stream.ReadByte();
|
|
multiplier = stream.ReadByte();
|
|
product = stream.ReadUInt16();
|
|
split_enable = stream.ReadBoolean();
|
|
split_right = stream.ReadBoolean();
|
|
split_tile = stream.ReadInt32();
|
|
split_yscroll = stream.ReadInt32();
|
|
split_doit = stream.ReadBoolean();
|
|
split_watch_tile = stream.ReadInt32();
|
|
irq_line = stream.ReadByte();
|
|
irq_enable = stream.ReadByte();
|
|
irq_pending = stream.ReadInt32();
|
|
irq_current_counter = stream.ReadInt32();
|
|
irq_current_inframe = stream.ReadInt32();
|
|
snd_1.ReadStateData(ref stream);
|
|
snd_2.ReadStateData(ref stream);
|
|
snd_3.LoadState(ref stream);
|
|
}
|
|
}
|
|
}
|