forked from sin365/AxibugEmuOnline
Compare commits
3 Commits
a6cbe6df74
...
ba8b656914
Author | SHA1 | Date | |
---|---|---|---|
|
ba8b656914 | ||
4e78287c69 | |||
715e8160e8 |
@ -502,6 +502,35 @@ namespace VirtualNes.Core
|
||||
Debuger.LogError("exqueue overflow.");
|
||||
}
|
||||
}
|
||||
|
||||
internal byte ExRead(ushort addr)
|
||||
{
|
||||
byte data = 0;
|
||||
|
||||
if ((exsound_select & 0x10) != 0)
|
||||
{
|
||||
if (addr == 0x4800)
|
||||
{
|
||||
SetExQueue(nes.cpu.GetTotalCycles(), 0, 0);
|
||||
}
|
||||
}
|
||||
if ((exsound_select & 0x04) != 0)
|
||||
{
|
||||
if (addr >= 0x4040 && addr < 0x4100)
|
||||
{
|
||||
data = fds.SyncRead(addr);
|
||||
}
|
||||
}
|
||||
if ((exsound_select & 0x08) != 0)
|
||||
{
|
||||
if (addr >= 0x5000 && addr <= 0x5015)
|
||||
{
|
||||
data = mmc5.SyncRead(addr);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public struct QUEUEDATA
|
||||
|
@ -38,9 +38,62 @@ namespace VirtualNes.Core
|
||||
//todo : 实现
|
||||
}
|
||||
|
||||
internal byte SyncRead(ushort addr)
|
||||
{
|
||||
byte data = (byte)(addr >> 8);
|
||||
|
||||
if (addr >= 0x4040 && addr <= 0x407F)
|
||||
{
|
||||
data = (byte)(fds_sync.main_wavetable[addr & 0x3F] | 0x40);
|
||||
}
|
||||
else
|
||||
if (addr == 0x4090)
|
||||
{
|
||||
data = (byte)((fds_sync.volenv_gain & 0x3F) | 0x40);
|
||||
}
|
||||
else
|
||||
if (addr == 0x4092)
|
||||
{
|
||||
data = (byte)((fds_sync.swpenv_gain & 0x3F) | 0x40);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private class FDSSOUND
|
||||
{
|
||||
//todo : 实现
|
||||
public byte[] reg = new byte[0x80];
|
||||
public byte volenv_mode; // Volume Envelope
|
||||
public byte volenv_gain;
|
||||
public byte volenv_decay;
|
||||
public double volenv_phaseacc;
|
||||
public byte swpenv_mode; // Sweep Envelope
|
||||
public byte swpenv_gain;
|
||||
public byte swpenv_decay;
|
||||
public double swpenv_phaseacc;
|
||||
// For envelope unit
|
||||
public byte envelope_enable; // $4083 bit6
|
||||
public byte envelope_speed; // $408A
|
||||
// For $4089
|
||||
public byte wave_setup; // bit7
|
||||
public int master_volume; // bit1-0
|
||||
// For Main unit
|
||||
public int[] main_wavetable = new int[64];
|
||||
public byte main_enable;
|
||||
public int main_frequency;
|
||||
public int main_addr;
|
||||
// For Effector(LFO) unit
|
||||
public byte[] lfo_wavetable = new byte[64];
|
||||
public byte lfo_enable; // 0:Enable 1:Wavetable setup
|
||||
public int lfo_frequency;
|
||||
public int lfo_addr;
|
||||
public double lfo_phaseacc;
|
||||
// For Sweep unit
|
||||
public int sweep_bias;
|
||||
// Misc
|
||||
public int now_volume;
|
||||
public int now_freq;
|
||||
public int output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ namespace VirtualNes.Core
|
||||
{
|
||||
public class APU_MMC5 : APU_INTERFACE
|
||||
{
|
||||
SYNCRECTANGLE sch0 = new SYNCRECTANGLE();
|
||||
SYNCRECTANGLE sch1 = new SYNCRECTANGLE();
|
||||
|
||||
public override void Reset(float fClock, int nRate)
|
||||
{
|
||||
//todo : 实现
|
||||
@ -29,5 +32,28 @@ namespace VirtualNes.Core
|
||||
{
|
||||
//todo : 实现
|
||||
}
|
||||
|
||||
internal byte SyncRead(ushort addr)
|
||||
{
|
||||
byte data = 0;
|
||||
|
||||
if (addr == 0x5015)
|
||||
{
|
||||
if ((sch0.enable != 0) && sch0.vbl_length > 0) data |= (1 << 0);
|
||||
if ((sch1.enable != 0) && sch1.vbl_length > 0) data |= (1 << 1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public class SYNCRECTANGLE
|
||||
{
|
||||
// For sync
|
||||
public byte[] reg = new byte[4];
|
||||
public byte enable;
|
||||
public byte holdnote;
|
||||
public byte[] dummy = new byte[2];
|
||||
public int vbl_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace VirtualNes.Core
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class ByteArrayRef
|
||||
{
|
||||
@ -22,6 +24,9 @@
|
||||
SetArray(array, offset, length);
|
||||
}
|
||||
|
||||
public ByteArrayRef(byte[] array) : this(array, 0, array.Length) { }
|
||||
public ByteArrayRef(byte[] array, int offset) : this(array, offset, array.Length - offset) { }
|
||||
|
||||
public void SetArray(byte[] array, int offset, int length)
|
||||
{
|
||||
m_rawArray = array;
|
||||
@ -40,5 +45,15 @@
|
||||
m_rawArray[(m_offset + index)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator ByteArrayRef(byte[] array)
|
||||
{
|
||||
return new ByteArrayRef(array);
|
||||
}
|
||||
|
||||
public static implicit operator Span<byte>(ByteArrayRef array)
|
||||
{
|
||||
return new Span<byte>(array.m_rawArray, array.Offset, array.m_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
455
AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/EEPROM.cs
Normal file
455
AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/EEPROM.cs
Normal file
@ -0,0 +1,455 @@
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
|
||||
|
||||
public class X24C01
|
||||
{
|
||||
public const int X24C01_IDLE = 0; // Idle
|
||||
public const int X24C01_ADDRESS = 1; // Address set
|
||||
public const int X24C01_READ = 2; // Read
|
||||
public const int X24C01_WRITE = 3; // Write
|
||||
public const int X24C01_ACK = 4; // Acknowledge
|
||||
public const int X24C01_ACK_WAIT = 5; // Acknowledge wait
|
||||
|
||||
int now_state, next_state;
|
||||
int bitcnt;
|
||||
byte addr, data;
|
||||
byte sda;
|
||||
byte scl_old, sda_old;
|
||||
|
||||
ByteArrayRef pEEPDATA;
|
||||
|
||||
public X24C01()
|
||||
{
|
||||
now_state = X24C01_IDLE;
|
||||
next_state = X24C01_IDLE;
|
||||
addr = 0;
|
||||
data = 0;
|
||||
sda = 0xFF;
|
||||
scl_old = 0;
|
||||
sda_old = 0;
|
||||
|
||||
pEEPDATA = null;
|
||||
}
|
||||
|
||||
public void Reset(ByteArrayRef ptr)
|
||||
{
|
||||
now_state = X24C01_IDLE;
|
||||
next_state = X24C01_IDLE;
|
||||
addr = 0;
|
||||
data = 0;
|
||||
sda = 0xFF;
|
||||
scl_old = 0;
|
||||
sda_old = 0;
|
||||
|
||||
pEEPDATA = ptr;
|
||||
}
|
||||
|
||||
public void Write(byte scl_in, byte sda_in)
|
||||
{
|
||||
// Clock line
|
||||
byte scl_rise = (byte)(~scl_old & scl_in);
|
||||
byte scl_fall = (byte)(scl_old & ~scl_in);
|
||||
// Data line
|
||||
byte sda_rise = (byte)(~sda_old & sda_in);
|
||||
byte sda_fall = (byte)(sda_old & ~sda_in);
|
||||
|
||||
byte scl_old_temp = scl_old;
|
||||
byte sda_old_temp = sda_old;
|
||||
|
||||
scl_old = scl_in;
|
||||
sda_old = sda_in;
|
||||
|
||||
// Start condition?
|
||||
if (scl_old_temp != 0 && sda_fall != 0)
|
||||
{
|
||||
now_state = X24C01_ADDRESS;
|
||||
bitcnt = 0;
|
||||
addr = 0;
|
||||
sda = 0xFF;
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop condition?
|
||||
if (scl_old_temp != 0 && sda_rise != 0)
|
||||
{
|
||||
now_state = X24C01_IDLE;
|
||||
sda = 0xFF;
|
||||
return;
|
||||
}
|
||||
|
||||
// SCL ____---- RISE
|
||||
if (scl_rise != 0)
|
||||
{
|
||||
switch (now_state)
|
||||
{
|
||||
case X24C01_ADDRESS:
|
||||
if (bitcnt < 7)
|
||||
{
|
||||
// 本来はMSB->LSB
|
||||
addr = (byte)(addr & (~(1 << bitcnt)));
|
||||
addr = (byte)(addr | ((sda_in != 0 ? 1 : 0) << bitcnt));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sda_in != 0)
|
||||
{
|
||||
next_state = X24C01_READ;
|
||||
data = pEEPDATA[addr & 0x7F];
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = X24C01_WRITE;
|
||||
}
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
case X24C01_ACK:
|
||||
sda = 0; // ACK
|
||||
break;
|
||||
case X24C01_READ:
|
||||
if (bitcnt < 8)
|
||||
{
|
||||
// 本来はMSB->LSB
|
||||
sda = (byte)((data & (1 << bitcnt)) != 0 ? 1 : 0);
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
case X24C01_WRITE:
|
||||
if (bitcnt < 8)
|
||||
{
|
||||
// 本来はMSB->LSB
|
||||
data = (byte)(data & (~(1 << bitcnt)));
|
||||
data = (byte)(data | ((sda_in != 0 ? 1 : 0) << bitcnt));
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
|
||||
case X24C01_ACK_WAIT:
|
||||
if (sda_in == 0)
|
||||
{
|
||||
next_state = X24C01_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SCL ----____ FALL
|
||||
if (scl_fall != 0)
|
||||
{
|
||||
switch (now_state)
|
||||
{
|
||||
case X24C01_ADDRESS:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
now_state = X24C01_ACK;
|
||||
sda = 0xFF;
|
||||
}
|
||||
break;
|
||||
case X24C01_ACK:
|
||||
now_state = next_state;
|
||||
bitcnt = 0;
|
||||
sda = 0xFF;
|
||||
break;
|
||||
case X24C01_READ:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
now_state = X24C01_ACK_WAIT;
|
||||
addr = (byte)((addr + 1) & 0x7F);
|
||||
}
|
||||
break;
|
||||
case X24C01_WRITE:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
now_state = X24C01_ACK;
|
||||
next_state = X24C01_IDLE;
|
||||
pEEPDATA[addr & 0x7F] = data;
|
||||
addr = (byte)((addr + 1) & 0x7F);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte Read()
|
||||
{
|
||||
return sda;
|
||||
}
|
||||
|
||||
public void Load(byte[] p)
|
||||
{
|
||||
//now_state = *((INT*)&p[0]);
|
||||
//next_state = *((INT*)&p[4]);
|
||||
//bitcnt = *((INT*)&p[8]);
|
||||
//addr = p[12];
|
||||
//data = p[13];
|
||||
//sda = p[14];
|
||||
//scl_old = p[15];
|
||||
//sda_old = p[16];
|
||||
}
|
||||
|
||||
public void Save(byte[] p)
|
||||
{
|
||||
//*((INT*)&p[0]) = now_state;
|
||||
//*((INT*)&p[4]) = next_state;
|
||||
//*((INT*)&p[8]) = bitcnt;
|
||||
//p[12] = addr;
|
||||
//p[13] = data;
|
||||
//p[14] = sda;
|
||||
//p[15] = scl_old;
|
||||
//p[16] = sda_old;
|
||||
}
|
||||
}
|
||||
|
||||
public class X24C02
|
||||
{
|
||||
public const int X24C02_IDLE = 0; // Idle
|
||||
public const int X24C02_DEVADDR = 1; // Device address set
|
||||
public const int X24C02_ADDRESS = 2; // Address set
|
||||
public const int X24C02_READ = 3; // Read
|
||||
public const int X24C02_WRITE = 4; // Write
|
||||
public const int X24C02_ACK = 5; // Acknowledge
|
||||
public const int X24C02_NAK = 6; // Not Acknowledge
|
||||
public const int X24C02_ACK_WAIT = 7; // Acknowledge wait
|
||||
|
||||
int now_state, next_state;
|
||||
int bitcnt;
|
||||
byte addr, data, rw;
|
||||
byte sda;
|
||||
byte scl_old, sda_old;
|
||||
|
||||
ByteArrayRef pEEPDATA;
|
||||
|
||||
public X24C02()
|
||||
{
|
||||
now_state = X24C02_IDLE;
|
||||
next_state = X24C02_IDLE;
|
||||
addr = 0;
|
||||
data = 0;
|
||||
rw = 0;
|
||||
sda = 0xFF;
|
||||
scl_old = 0;
|
||||
sda_old = 0;
|
||||
|
||||
pEEPDATA = null;
|
||||
}
|
||||
|
||||
public void Reset(ByteArrayRef ptr)
|
||||
{
|
||||
now_state = X24C02_IDLE;
|
||||
next_state = X24C02_IDLE;
|
||||
addr = 0;
|
||||
data = 0;
|
||||
rw = 0;
|
||||
sda = 0xFF;
|
||||
scl_old = 0;
|
||||
sda_old = 0;
|
||||
|
||||
pEEPDATA = ptr;
|
||||
}
|
||||
|
||||
public void Write(byte scl_in, byte sda_in)
|
||||
{
|
||||
// Clock line
|
||||
byte scl_rise = (byte)(~scl_old & scl_in);
|
||||
byte scl_fall = (byte)(scl_old & ~scl_in);
|
||||
// Data line
|
||||
byte sda_rise = (byte)(~sda_old & sda_in);
|
||||
byte sda_fall = (byte)(sda_old & ~sda_in);
|
||||
|
||||
byte scl_old_temp = scl_old;
|
||||
byte sda_old_temp = sda_old;
|
||||
|
||||
scl_old = scl_in;
|
||||
sda_old = sda_in;
|
||||
|
||||
// Start condition?
|
||||
if (scl_old_temp != 0 && sda_fall != 0)
|
||||
{
|
||||
now_state = X24C02_DEVADDR;
|
||||
bitcnt = 0;
|
||||
sda = 0xFF;
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop condition?
|
||||
if (scl_old_temp != 0 && sda_rise != 0)
|
||||
{
|
||||
now_state = X24C02_IDLE;
|
||||
sda = 0xFF;
|
||||
return;
|
||||
}
|
||||
|
||||
// SCL ____---- RISE
|
||||
if (scl_rise != 0)
|
||||
{
|
||||
switch (now_state)
|
||||
{
|
||||
case X24C02_DEVADDR:
|
||||
if (bitcnt < 8)
|
||||
{
|
||||
data = (byte)(data & (~(1 << (7 - bitcnt))));
|
||||
data = (byte)(data | ((sda_in != 0 ? 1 : 0) << (7 - bitcnt)));
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
case X24C02_ADDRESS:
|
||||
if (bitcnt < 8)
|
||||
{
|
||||
addr = (byte)(addr & (~(1 << (7 - bitcnt))));
|
||||
addr = (byte)(addr | ((sda_in != 0 ? 1 : 0) << (7 - bitcnt)));
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
case X24C02_READ:
|
||||
if (bitcnt < 8)
|
||||
{
|
||||
sda = (byte)((data & (1 << (7 - bitcnt))) != 0 ? 1 : 0);
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
case X24C02_WRITE:
|
||||
if (bitcnt < 8)
|
||||
{
|
||||
data = (byte)(data & (~(1 << (7 - bitcnt))));
|
||||
data = (byte)(data | ((sda_in != 0 ? 1 : 0) << (7 - bitcnt)));
|
||||
}
|
||||
bitcnt++;
|
||||
break;
|
||||
case X24C02_NAK:
|
||||
sda = 0xFF; // NAK
|
||||
break;
|
||||
case X24C02_ACK:
|
||||
sda = 0; // ACK
|
||||
break;
|
||||
case X24C02_ACK_WAIT:
|
||||
if (sda_in == 0)
|
||||
{
|
||||
next_state = X24C02_READ;
|
||||
data = pEEPDATA[addr];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SCL ----____ FALL
|
||||
if (scl_fall != 0)
|
||||
{
|
||||
switch (now_state)
|
||||
{
|
||||
case X24C02_DEVADDR:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
if ((data & 0xA0) == 0xA0)
|
||||
{
|
||||
now_state = X24C02_ACK;
|
||||
rw = (byte)(data & 0x01);
|
||||
sda = 0xFF;
|
||||
if (rw != 0)
|
||||
{
|
||||
// Now address read
|
||||
next_state = X24C02_READ;
|
||||
data = pEEPDATA[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = X24C02_ADDRESS;
|
||||
}
|
||||
bitcnt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
now_state = X24C02_NAK;
|
||||
next_state = X24C02_IDLE;
|
||||
sda = 0xFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case X24C02_ADDRESS:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
now_state = X24C02_ACK;
|
||||
sda = 0xFF;
|
||||
if (rw != 0)
|
||||
{
|
||||
// Readでは絶対来ないが念の為
|
||||
next_state = X24C02_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// to Data Write
|
||||
next_state = X24C02_WRITE;
|
||||
}
|
||||
bitcnt = 0;
|
||||
}
|
||||
break;
|
||||
case X24C02_READ:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
now_state = X24C02_ACK_WAIT;
|
||||
addr = (byte)((addr + 1) & 0xFF);
|
||||
}
|
||||
break;
|
||||
case X24C02_WRITE:
|
||||
if (bitcnt >= 8)
|
||||
{
|
||||
pEEPDATA[addr] = data;
|
||||
now_state = X24C02_ACK;
|
||||
next_state = X24C02_WRITE;
|
||||
addr = (byte)((addr + 1) & 0xFF);
|
||||
bitcnt = 0;
|
||||
}
|
||||
break;
|
||||
case X24C02_NAK:
|
||||
now_state = X24C02_IDLE;
|
||||
bitcnt = 0;
|
||||
sda = 0xFF;
|
||||
break;
|
||||
case X24C02_ACK:
|
||||
now_state = next_state;
|
||||
bitcnt = 0;
|
||||
sda = 0xFF;
|
||||
break;
|
||||
case X24C02_ACK_WAIT:
|
||||
now_state = next_state;
|
||||
bitcnt = 0;
|
||||
sda = 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte Read()
|
||||
{
|
||||
return sda;
|
||||
}
|
||||
|
||||
public void Load(byte[] p)
|
||||
{
|
||||
//now_state = *((INT*)&p[0]);
|
||||
//next_state = *((INT*)&p[4]);
|
||||
//bitcnt = *((INT*)&p[8]);
|
||||
//addr = p[12];
|
||||
//data = p[13];
|
||||
//rw = p[14];
|
||||
//sda = p[15];
|
||||
//scl_old = p[16];
|
||||
//sda_old = p[17];
|
||||
}
|
||||
|
||||
public void Save(byte[] p)
|
||||
{
|
||||
//*((INT*)&p[0]) = now_state;
|
||||
//*((INT*)&p[4]) = next_state;
|
||||
//*((INT*)&p[8]) = bitcnt;
|
||||
//p[12] = addr;
|
||||
//p[13] = data;
|
||||
//p[14] = rw;
|
||||
//p[15] = sda;
|
||||
//p[16] = scl_old;
|
||||
//p[17] = sda_old;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ddf7290610bea74593ad83b43909036
|
||||
guid: be5901dc72f4b6045a7c33edba28145f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
@ -82,8 +82,149 @@ namespace VirtualNes.Core
|
||||
//todo : 实现加载mapper
|
||||
switch (no)
|
||||
{
|
||||
case 4:
|
||||
return new Mapper004(parent);
|
||||
case 4: return new Mapper004(parent);
|
||||
case 16: return new Mapper016(parent);
|
||||
case 17: return new Mapper017(parent);
|
||||
case 18: return new Mapper018(parent);
|
||||
case 19: return new Mapper019(parent);
|
||||
case 21: return new Mapper021(parent);
|
||||
case 22: return new Mapper022(parent);
|
||||
case 23: return new Mapper023(parent);
|
||||
case 24: return new Mapper024(parent);
|
||||
case 25: return new Mapper025(parent);
|
||||
case 26: return new Mapper026(parent);
|
||||
case 27: return new Mapper027(parent);
|
||||
case 32: return new Mapper032(parent);
|
||||
case 33: return new Mapper033(parent);
|
||||
case 34: return new Mapper034(parent);
|
||||
case 35: return new Mapper035(parent);
|
||||
case 40: return new Mapper040(parent);
|
||||
case 41: return new Mapper041(parent);
|
||||
case 42: return new Mapper042(parent);
|
||||
case 43: return new Mapper043(parent);
|
||||
case 44: return new Mapper044(parent);
|
||||
case 45: return new Mapper045(parent);
|
||||
case 46: return new Mapper046(parent);
|
||||
case 47: return new Mapper047(parent);
|
||||
case 48: return new Mapper048(parent);
|
||||
case 50: return new Mapper050(parent);
|
||||
case 51: return new Mapper051(parent);
|
||||
case 57: return new Mapper057(parent);
|
||||
case 58: return new Mapper058(parent);
|
||||
case 60: return new Mapper060(parent);
|
||||
case 61: return new Mapper061(parent);
|
||||
case 62: return new Mapper062(parent);
|
||||
case 64: return new Mapper064(parent);
|
||||
case 65: return new Mapper065(parent);
|
||||
case 66: return new Mapper066(parent);
|
||||
case 67: return new Mapper067(parent);
|
||||
case 68: return new Mapper068(parent);
|
||||
case 69: return new Mapper069(parent);
|
||||
case 70: return new Mapper070(parent);
|
||||
case 71: return new Mapper071(parent);
|
||||
case 72: return new Mapper072(parent);
|
||||
case 73: return new Mapper073(parent);
|
||||
case 74: return new Mapper074(parent);
|
||||
case 75: return new Mapper075(parent);
|
||||
case 76: return new Mapper076(parent);
|
||||
case 77: return new Mapper077(parent);
|
||||
case 78: return new Mapper078(parent);
|
||||
case 79: return new Mapper079(parent);
|
||||
case 80: return new Mapper080(parent);
|
||||
case 82: return new Mapper082(parent);
|
||||
case 83: return new Mapper083(parent);
|
||||
case 85: return new Mapper085(parent);
|
||||
case 86: return new Mapper086(parent);
|
||||
case 87: return new Mapper087(parent);
|
||||
case 88: return new Mapper088(parent);
|
||||
case 89: return new Mapper089(parent);
|
||||
case 90: return new Mapper090(parent);
|
||||
case 91: return new Mapper091(parent);
|
||||
case 92: return new Mapper092(parent);
|
||||
case 93: return new Mapper093(parent);
|
||||
case 94: return new Mapper094(parent);
|
||||
case 95: return new Mapper095(parent);
|
||||
case 96: return new Mapper096(parent);
|
||||
case 97: return new Mapper097(parent);
|
||||
case 99: return new Mapper099(parent);
|
||||
case 100: return new Mapper100(parent);
|
||||
case 101: return new Mapper101(parent);
|
||||
case 105: return new Mapper105(parent);
|
||||
case 108: return new Mapper108(parent);
|
||||
case 109: return new Mapper109(parent);
|
||||
case 110: return new Mapper110(parent);
|
||||
case 111: return new Mapper111(parent);
|
||||
case 112: return new Mapper112(parent);
|
||||
case 113: return new Mapper113(parent);
|
||||
case 114: return new Mapper114(parent);
|
||||
case 115: return new Mapper115(parent);
|
||||
case 116: return new Mapper116(parent);
|
||||
case 117: return new Mapper117(parent);
|
||||
case 118: return new Mapper118(parent);
|
||||
case 119: return new Mapper119(parent);
|
||||
case 122: return new Mapper122(parent);
|
||||
case 133: return new Mapper133(parent);
|
||||
case 134: return new Mapper134(parent);
|
||||
case 135: return new Mapper135(parent);
|
||||
case 140: return new Mapper140(parent);
|
||||
case 142: return new Mapper142(parent);
|
||||
case 151: return new Mapper151(parent);
|
||||
case 160: return new Mapper160(parent);
|
||||
case 162: return new Mapper162(parent);
|
||||
case 163: return new Mapper163(parent);
|
||||
case 164: return new Mapper164(parent);
|
||||
case 165: return new Mapper165(parent);
|
||||
case 167: return new Mapper167(parent);
|
||||
case 175: return new Mapper175(parent);
|
||||
case 176: return new Mapper176(parent);
|
||||
case 178: return new Mapper178(parent);
|
||||
case 180: return new Mapper180(parent);
|
||||
case 181: return new Mapper181(parent);
|
||||
case 182: return new Mapper182(parent);
|
||||
case 183: return new Mapper183(parent);
|
||||
case 185: return new Mapper185(parent);
|
||||
case 187: return new Mapper187(parent);
|
||||
case 188: return new Mapper188(parent);
|
||||
case 189: return new Mapper189(parent);
|
||||
case 190: return new Mapper190(parent);
|
||||
case 191: return new Mapper191(parent);
|
||||
case 192: return new Mapper192(parent);
|
||||
case 193: return new Mapper193(parent);
|
||||
case 194: return new Mapper194(parent);
|
||||
case 195: return new Mapper195(parent);
|
||||
case 198: return new Mapper198(parent);
|
||||
case 199: return new Mapper199(parent);
|
||||
case 200: return new Mapper200(parent);
|
||||
case 201: return new Mapper201(parent);
|
||||
case 202: return new Mapper202(parent);
|
||||
case 216: return new Mapper216(parent);
|
||||
case 222: return new Mapper222(parent);
|
||||
case 225: return new Mapper225(parent);
|
||||
case 226: return new Mapper226(parent);
|
||||
case 227: return new Mapper227(parent);
|
||||
case 228: return new Mapper228(parent);
|
||||
case 229: return new Mapper229(parent);
|
||||
case 230: return new Mapper230(parent);
|
||||
case 231: return new Mapper231(parent);
|
||||
case 232: return new Mapper232(parent);
|
||||
case 233: return new Mapper233(parent);
|
||||
case 234: return new Mapper234(parent);
|
||||
case 235: return new Mapper235(parent);
|
||||
case 236: return new Mapper236(parent);
|
||||
case 240: return new Mapper240(parent);
|
||||
case 241: return new Mapper241(parent);
|
||||
case 242: return new Mapper242(parent);
|
||||
case 243: return new Mapper243(parent);
|
||||
case 244: return new Mapper244(parent);
|
||||
case 245: return new Mapper245(parent);
|
||||
case 246: return new Mapper246(parent);
|
||||
case 248: return new Mapper248(parent);
|
||||
case 249: return new Mapper249(parent);
|
||||
case 251: return new Mapper251(parent);
|
||||
case 252: return new Mapper252(parent);
|
||||
case 254: return new Mapper254(parent);
|
||||
case 255: return new Mapper255(parent);
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Mapper#{no:000} is not Impl");
|
||||
}
|
||||
|
@ -1,430 +1,429 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper016 Bandai Standard //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using static VirtualNes.MMU;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
using INT = System.Int32;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper016 : Mapper
|
||||
{
|
||||
BYTE patch; // For Famicom Jump 2
|
||||
BYTE eeprom_type; // EEPROM type
|
||||
|
||||
BYTE[] reg = new byte[3];
|
||||
|
||||
BYTE irq_enable;
|
||||
INT irq_counter;
|
||||
INT irq_latch;
|
||||
BYTE irq_type;
|
||||
|
||||
X24C01 x24c01;
|
||||
X24C02 x24c02;
|
||||
public Mapper016(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
patch = 0;
|
||||
|
||||
reg[0] = reg[1] = reg[2] = 0;
|
||||
irq_enable = 0;
|
||||
irq_counter = 0;
|
||||
irq_latch = 0;
|
||||
|
||||
irq_type = 0;
|
||||
nes.SetIrqType( NES.IRQMETHOD.IRQ_CLOCK);
|
||||
|
||||
eeprom_type = 0;
|
||||
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0x3f15d20d // Famicom Jump 2(J)
|
||||
|| crc == 0xf76aa523)
|
||||
{ // Famicom Jump 2(J)(alt)
|
||||
patch = 1;
|
||||
eeprom_type = 0xFF;
|
||||
|
||||
WRAM[0x0BBC] = 0xFF; // SRAM対策
|
||||
}
|
||||
|
||||
if (crc == 0x1d6f27f7)
|
||||
{ // Dragon Ball Z 2(Korean Hack)
|
||||
nes.SetIrqType( NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x6f7247c8)
|
||||
{ // Dragon Ball Z 3(Korean Hack)
|
||||
nes.SetIrqType( NES.IRQMETHOD.IRQ_CLOCK);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
|
||||
if (crc == 0x7fb799fd)
|
||||
{ // Dragon Ball 2 - Dai Maou Fukkatsu(J)
|
||||
}
|
||||
if (crc == 0x6c6c2feb // Dragon Ball 3 - Gokuu Den(J)
|
||||
|| crc == 0x8edeb257)
|
||||
{ // Dragon Ball 3 - Gokuu Den(J)(Alt)
|
||||
}
|
||||
if (crc == 0x31cd9903)
|
||||
{ // Dragon Ball Z - Kyoushuu! Saiya Jin(J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
}
|
||||
if (crc == 0xe49fc53e // Dragon Ball Z 2 - Gekishin Freeza!!(J)
|
||||
|| crc == 0x1582fee0)
|
||||
{ // Dragon Ball Z 2 - Gekishin Freeza!!(J) [alt]
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x09499f4d)
|
||||
{ // Dragon Ball Z 3 - Ressen Jinzou Ningen(J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x2e991109)
|
||||
{ // Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x146fb9c3)
|
||||
{ // SD Gundam Gaiden - Knight Gundam Monogatari(J)
|
||||
}
|
||||
|
||||
if (crc == 0x73ac76db // SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi(J)
|
||||
|| crc == 0x81a15eb8)
|
||||
{ // SD Gundam Gaiden - Knight Gundam Monogatari 3 - Densetsu no Kishi Dan(J)
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x170250de)
|
||||
{ // Rokudenashi Blues(J)
|
||||
nes.SetRenderMethod( EnumRenderMethod.POST_ALL_RENDER);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
|
||||
// DATACH系
|
||||
if (crc == 0x0be0a328 // Datach - SD Gundam - Gundam Wars(J)
|
||||
|| crc == 0x19e81461 // Datach - Dragon Ball Z - Gekitou Tenkaichi Budou Kai(J)
|
||||
|| crc == 0x5b457641 // Datach - Ultraman Club - Supokon Fight!(J)
|
||||
|| crc == 0x894efdbc // Datach - Crayon Shin Chan - Ora to Poi Poi(J)
|
||||
|| crc == 0x983d8175 // Datach - Battle Rush - Build Up Robot Tournament(J)
|
||||
|| crc == 0xbe06853f)
|
||||
{ // Datach - J League Super Top Players(J)
|
||||
eeprom_type = 2;
|
||||
}
|
||||
if (crc == 0xf51a7f46)
|
||||
{ // Datach - Yuu Yuu Hakusho - Bakutou Ankoku Bujutsu Kai(J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 2;
|
||||
}
|
||||
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(128);
|
||||
x24c01.Reset(WRAM);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(256);
|
||||
x24c02.Reset(WRAM);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(384);
|
||||
x24c02.Reset(WRAM);
|
||||
x24c01.Reset(WRAM + 256);
|
||||
}
|
||||
}
|
||||
|
||||
//BYTE Mapper016::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
if (patch!=0)
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((addr & 0x00FF) == 0x0000)
|
||||
{
|
||||
BYTE ret = 0;
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
ret = x24c01.Read();
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
ret = x24c02.Read();
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
ret = x24c02.Read() & x24c01.Read();
|
||||
}
|
||||
return (ret ? 0x10 : 0) | (nes.GetBarcodeStatus());
|
||||
}
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
//void Mapper016::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (patch == 0)
|
||||
{
|
||||
WriteSubA(addr, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mapper::WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper016::Write(WORD addr, BYTE data)
|
||||
{
|
||||
if (!patch)
|
||||
{
|
||||
WriteSubA(addr, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteSubB(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE eeprom_addinc;
|
||||
|
||||
// Normal mapper #16
|
||||
void Mapper016::WriteSubA(WORD addr, BYTE data)
|
||||
{
|
||||
switch (addr & 0x000F)
|
||||
{
|
||||
case 0x0000:
|
||||
case 0x0001:
|
||||
case 0x0002:
|
||||
case 0x0003:
|
||||
case 0x0004:
|
||||
case 0x0005:
|
||||
case 0x0006:
|
||||
case 0x0007:
|
||||
if (VROM_1K_SIZE)
|
||||
{
|
||||
SetVROM_1K_Bank(addr & 0x0007, data);
|
||||
}
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
reg[0] = data;
|
||||
x24c01.Write((data & 0x08) ? 0xFF : 0, (reg[1] & 0x40) ? 0xFF : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0008:
|
||||
SetPROM_16K_Bank(4, data);
|
||||
break;
|
||||
|
||||
case 0x0009:
|
||||
data &= 0x03;
|
||||
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
break;
|
||||
|
||||
case 0x000A:
|
||||
irq_enable = data & 0x01;
|
||||
irq_counter = irq_latch;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x000B:
|
||||
irq_latch = (irq_latch & 0xFF00) | data;
|
||||
irq_counter = (irq_counter & 0xFF00) | data;
|
||||
break;
|
||||
case 0x000C:
|
||||
irq_latch = ((INT)data << 8) | (irq_latch & 0x00FF);
|
||||
irq_counter = ((INT)data << 8) | (irq_counter & 0x00FF);
|
||||
break;
|
||||
|
||||
case 0x000D:
|
||||
// EEPTYPE0(DragonBallZ)
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
x24c01.Write((data & 0x20) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0);
|
||||
}
|
||||
// EEPTYPE1(DragonBallZ2,Z3,Z Gaiden)
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
x24c02.Write((data & 0x20) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0);
|
||||
}
|
||||
// EEPTYPE2(DATACH)
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
reg[1] = data;
|
||||
x24c02.Write((data & 0x20) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0);
|
||||
x24c01.Write((reg[0] & 0x08) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Famicom Jump 2
|
||||
void Mapper016::WriteSubB(WORD addr, BYTE data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x8000:
|
||||
case 0x8001:
|
||||
case 0x8002:
|
||||
case 0x8003:
|
||||
reg[0] = data & 0x01;
|
||||
SetPROM_8K_Bank(4, reg[0] * 0x20 + reg[2] * 2 + 0);
|
||||
SetPROM_8K_Bank(5, reg[0] * 0x20 + reg[2] * 2 + 1);
|
||||
break;
|
||||
case 0x8004:
|
||||
case 0x8005:
|
||||
case 0x8006:
|
||||
case 0x8007:
|
||||
reg[1] = data & 0x01;
|
||||
SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E);
|
||||
SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F);
|
||||
break;
|
||||
case 0x8008:
|
||||
reg[2] = data;
|
||||
SetPROM_8K_Bank(4, reg[0] * 0x20 + reg[2] * 2 + 0);
|
||||
SetPROM_8K_Bank(5, reg[0] * 0x20 + reg[2] * 2 + 1);
|
||||
SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E);
|
||||
SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F);
|
||||
break;
|
||||
|
||||
case 0x8009:
|
||||
data &= 0x03;
|
||||
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
break;
|
||||
|
||||
case 0x800A:
|
||||
irq_enable = data & 0x01;
|
||||
irq_counter = irq_latch;
|
||||
|
||||
// if( !irq_enable ) {
|
||||
// nes.cpu.ClrIRQ( IRQ_MAPPER );
|
||||
// }
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x800B:
|
||||
irq_latch = (irq_latch & 0xFF00) | data;
|
||||
break;
|
||||
case 0x800C:
|
||||
irq_latch = ((INT)data << 8) | (irq_latch & 0x00FF);
|
||||
break;
|
||||
|
||||
case 0x800D:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper016::HSync(INT scanline)
|
||||
{
|
||||
if (irq_enable && (nes.GetIrqType() == NES.IRQMETHOD.IRQ_HSYNC))
|
||||
{
|
||||
if (irq_counter <= 113)
|
||||
{
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
// nes.cpu.IRQ();
|
||||
//// nes.cpu.IRQ_NotPending();
|
||||
// irq_enable = 0;
|
||||
// irq_counter = 0;
|
||||
irq_counter &= 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_counter -= 113;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper016::Clock(INT cycles)
|
||||
{
|
||||
if (irq_enable && (nes.GetIrqType() == NES::IRQ_CLOCK))
|
||||
{
|
||||
if ((irq_counter -= cycles) <= 0)
|
||||
{
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
// nes.cpu.IRQ();
|
||||
//// nes.cpu.IRQ_NotPending();
|
||||
// irq_enable = 0;
|
||||
// irq_counter = 0;
|
||||
irq_counter &= 0xFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper016::SaveState(LPBYTE p)
|
||||
{
|
||||
p[0] = reg[0];
|
||||
p[1] = reg[1];
|
||||
p[2] = reg[2];
|
||||
p[3] = irq_enable;
|
||||
*(INT*)&p[4] = irq_counter;
|
||||
*(INT*)&p[8] = irq_latch;
|
||||
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
x24c01.Save(&p[16]);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
x24c02.Save(&p[16]);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
x24c02.Save(&p[16]);
|
||||
x24c01.Save(&p[48]);
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper016::LoadState(LPBYTE p)
|
||||
{
|
||||
reg[0] = p[0];
|
||||
reg[1] = p[1];
|
||||
reg[2] = p[2];
|
||||
irq_enable = p[3];
|
||||
irq_counter = *(INT*)&p[4];
|
||||
irq_latch = *(INT*)&p[8];
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
x24c01.Load(&p[16]);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
x24c02.Load(&p[16]);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
x24c02.Load(&p[16]);
|
||||
x24c01.Load(&p[48]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
public class Mapper016 : Mapper
|
||||
{
|
||||
BYTE patch; // For Famicom Jump 2
|
||||
BYTE eeprom_type; // EEPROM type
|
||||
|
||||
BYTE[] reg = new byte[3];
|
||||
|
||||
BYTE irq_enable;
|
||||
INT irq_counter;
|
||||
INT irq_latch;
|
||||
BYTE irq_type;
|
||||
|
||||
X24C01 x24c01;
|
||||
X24C02 x24c02;
|
||||
public Mapper016(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
patch = 0;
|
||||
|
||||
reg[0] = reg[1] = reg[2] = 0;
|
||||
irq_enable = 0;
|
||||
irq_counter = 0;
|
||||
irq_latch = 0;
|
||||
|
||||
irq_type = 0;
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_CLOCK);
|
||||
|
||||
eeprom_type = 0;
|
||||
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0x3f15d20d // Famicom Jump 2(J)
|
||||
|| crc == 0xf76aa523)
|
||||
{ // Famicom Jump 2(J)(alt)
|
||||
patch = 1;
|
||||
eeprom_type = 0xFF;
|
||||
|
||||
WRAM[0x0BBC] = 0xFF; // SRAM対策
|
||||
}
|
||||
|
||||
if (crc == 0x1d6f27f7)
|
||||
{ // Dragon Ball Z 2(Korean Hack)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x6f7247c8)
|
||||
{ // Dragon Ball Z 3(Korean Hack)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_CLOCK);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
|
||||
if (crc == 0x7fb799fd)
|
||||
{ // Dragon Ball 2 - Dai Maou Fukkatsu(J)
|
||||
}
|
||||
if (crc == 0x6c6c2feb // Dragon Ball 3 - Gokuu Den(J)
|
||||
|| crc == 0x8edeb257)
|
||||
{ // Dragon Ball 3 - Gokuu Den(J)(Alt)
|
||||
}
|
||||
if (crc == 0x31cd9903)
|
||||
{ // Dragon Ball Z - Kyoushuu! Saiya Jin(J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
}
|
||||
if (crc == 0xe49fc53e // Dragon Ball Z 2 - Gekishin Freeza!!(J)
|
||||
|| crc == 0x1582fee0)
|
||||
{ // Dragon Ball Z 2 - Gekishin Freeza!!(J) [alt]
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x09499f4d)
|
||||
{ // Dragon Ball Z 3 - Ressen Jinzou Ningen(J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x2e991109)
|
||||
{ // Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x146fb9c3)
|
||||
{ // SD Gundam Gaiden - Knight Gundam Monogatari(J)
|
||||
}
|
||||
|
||||
if (crc == 0x73ac76db // SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi(J)
|
||||
|| crc == 0x81a15eb8)
|
||||
{ // SD Gundam Gaiden - Knight Gundam Monogatari 3 - Densetsu no Kishi Dan(J)
|
||||
eeprom_type = 1;
|
||||
}
|
||||
if (crc == 0x170250de)
|
||||
{ // Rokudenashi Blues(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
eeprom_type = 1;
|
||||
}
|
||||
|
||||
// DATACH系
|
||||
if (crc == 0x0be0a328 // Datach - SD Gundam - Gundam Wars(J)
|
||||
|| crc == 0x19e81461 // Datach - Dragon Ball Z - Gekitou Tenkaichi Budou Kai(J)
|
||||
|| crc == 0x5b457641 // Datach - Ultraman Club - Supokon Fight!(J)
|
||||
|| crc == 0x894efdbc // Datach - Crayon Shin Chan - Ora to Poi Poi(J)
|
||||
|| crc == 0x983d8175 // Datach - Battle Rush - Build Up Robot Tournament(J)
|
||||
|| crc == 0xbe06853f)
|
||||
{ // Datach - J League Super Top Players(J)
|
||||
eeprom_type = 2;
|
||||
}
|
||||
if (crc == 0xf51a7f46)
|
||||
{ // Datach - Yuu Yuu Hakusho - Bakutou Ankoku Bujutsu Kai(J)
|
||||
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
|
||||
eeprom_type = 2;
|
||||
}
|
||||
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(128);
|
||||
x24c01.Reset(WRAM);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(256);
|
||||
x24c02.Reset(WRAM);
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(384);
|
||||
x24c02.Reset(WRAM);
|
||||
x24c01.Reset(new ByteArrayRef(WRAM, 256));
|
||||
}
|
||||
}
|
||||
|
||||
//BYTE Mapper016::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
if (patch != 0)
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((addr & 0x00FF) == 0x0000)
|
||||
{
|
||||
BYTE ret = 0;
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
ret = x24c01.Read();
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
ret = x24c02.Read();
|
||||
}
|
||||
else
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
ret = (byte)(x24c02.Read() & x24c01.Read());
|
||||
}
|
||||
return (byte)((ret != 0 ? 0x10 : 0) | (nes.GetBarcodeStatus()));
|
||||
}
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
//void Mapper016::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (patch == 0)
|
||||
{
|
||||
WriteSubA(addr, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
if (patch == 0)
|
||||
{
|
||||
WriteSubA(addr, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteSubB(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE eeprom_addinc;
|
||||
|
||||
// Normal mapper #16
|
||||
void WriteSubA(ushort addr, BYTE data)
|
||||
{
|
||||
switch (addr & 0x000F)
|
||||
{
|
||||
case 0x0000:
|
||||
case 0x0001:
|
||||
case 0x0002:
|
||||
case 0x0003:
|
||||
case 0x0004:
|
||||
case 0x0005:
|
||||
case 0x0006:
|
||||
case 0x0007:
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
SetVROM_1K_Bank((byte)(addr & 0x0007), data);
|
||||
}
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
reg[0] = data;
|
||||
x24c01.Write((byte)((data & 0x08) != 0 ? 0xFF : 0), (byte)((reg[1] & 0x40) != 0 ? 0xFF : 0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0008:
|
||||
SetPROM_16K_Bank(4, data);
|
||||
break;
|
||||
|
||||
case 0x0009:
|
||||
data &= 0x03;
|
||||
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
break;
|
||||
|
||||
case 0x000A:
|
||||
irq_enable = (byte)(data & 0x01);
|
||||
irq_counter = irq_latch;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x000B:
|
||||
irq_latch = (irq_latch & 0xFF00) | data;
|
||||
irq_counter = (irq_counter & 0xFF00) | data;
|
||||
break;
|
||||
case 0x000C:
|
||||
irq_latch = (data << 8) | (irq_latch & 0x00FF);
|
||||
irq_counter = (data << 8) | (irq_counter & 0x00FF);
|
||||
break;
|
||||
|
||||
case 0x000D:
|
||||
// EEPTYPE0(DragonBallZ)
|
||||
if (eeprom_type == 0)
|
||||
{
|
||||
x24c01.Write((byte)((data & 0x20) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
|
||||
}
|
||||
// EEPTYPE1(DragonBallZ2,Z3,Z Gaiden)
|
||||
if (eeprom_type == 1)
|
||||
{
|
||||
x24c02.Write((byte)((data & 0x20) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
|
||||
}
|
||||
// EEPTYPE2(DATACH)
|
||||
if (eeprom_type == 2)
|
||||
{
|
||||
reg[1] = data;
|
||||
x24c02.Write((byte)((data & 0x20) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
|
||||
x24c01.Write((byte)((reg[0] & 0x08) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Famicom Jump 2
|
||||
void WriteSubB(ushort addr, BYTE data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x8000:
|
||||
case 0x8001:
|
||||
case 0x8002:
|
||||
case 0x8003:
|
||||
reg[0] = (byte)(data & 0x01);
|
||||
SetPROM_8K_Bank(4, reg[0] * 0x20 + reg[2] * 2 + 0);
|
||||
SetPROM_8K_Bank(5, reg[0] * 0x20 + reg[2] * 2 + 1);
|
||||
break;
|
||||
case 0x8004:
|
||||
case 0x8005:
|
||||
case 0x8006:
|
||||
case 0x8007:
|
||||
reg[1] = (byte)(data & 0x01);
|
||||
SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E);
|
||||
SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F);
|
||||
break;
|
||||
case 0x8008:
|
||||
reg[2] = data;
|
||||
SetPROM_8K_Bank(4, reg[0] * 0x20 + reg[2] * 2 + 0);
|
||||
SetPROM_8K_Bank(5, reg[0] * 0x20 + reg[2] * 2 + 1);
|
||||
SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E);
|
||||
SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F);
|
||||
break;
|
||||
|
||||
case 0x8009:
|
||||
data &= 0x03;
|
||||
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
break;
|
||||
|
||||
case 0x800A:
|
||||
irq_enable = (byte)(data & 0x01);
|
||||
irq_counter = irq_latch;
|
||||
|
||||
// if( !irq_enable ) {
|
||||
// nes.cpu.ClrIRQ( IRQ_MAPPER );
|
||||
// }
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x800B:
|
||||
irq_latch = (irq_latch & 0xFF00) | data;
|
||||
break;
|
||||
case 0x800C:
|
||||
irq_latch = (data << 8) | (irq_latch & 0x00FF);
|
||||
break;
|
||||
|
||||
case 0x800D:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if (irq_enable != 0 && (nes.GetIrqType() == (int)NES.IRQMETHOD.IRQ_HSYNC))
|
||||
{
|
||||
if (irq_counter <= 113)
|
||||
{
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
// nes.cpu.IRQ();
|
||||
//// nes.cpu.IRQ_NotPending();
|
||||
// irq_enable = 0;
|
||||
// irq_counter = 0;
|
||||
irq_counter &= 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_counter -= 113;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clock(int cycles)
|
||||
{
|
||||
if (irq_enable != 0 && (nes.GetIrqType() == (int)NES.IRQMETHOD.IRQ_CLOCK))
|
||||
{
|
||||
if ((irq_counter -= cycles) <= 0)
|
||||
{
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
// nes.cpu.IRQ();
|
||||
//// nes.cpu.IRQ_NotPending();
|
||||
// irq_enable = 0;
|
||||
// irq_counter = 0;
|
||||
irq_counter &= 0xFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
//p[0] = reg[0];
|
||||
//p[1] = reg[1];
|
||||
//p[2] = reg[2];
|
||||
//p[3] = irq_enable;
|
||||
//*(INT*)&p[4] = irq_counter;
|
||||
//*(INT*)&p[8] = irq_latch;
|
||||
|
||||
//if (eeprom_type == 0)
|
||||
//{
|
||||
// x24c01.Save(&p[16]);
|
||||
//}
|
||||
//else
|
||||
//if (eeprom_type == 1)
|
||||
//{
|
||||
// x24c02.Save(&p[16]);
|
||||
//}
|
||||
//else
|
||||
//if (eeprom_type == 2)
|
||||
//{
|
||||
// x24c02.Save(&p[16]);
|
||||
// x24c01.Save(&p[48]);
|
||||
//}
|
||||
}
|
||||
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
//reg[0] = p[0];
|
||||
//reg[1] = p[1];
|
||||
//reg[2] = p[2];
|
||||
//irq_enable = p[3];
|
||||
//irq_counter = *(INT*)&p[4];
|
||||
//irq_latch = *(INT*)&p[8];
|
||||
//if (eeprom_type == 0)
|
||||
//{
|
||||
// x24c01.Load(&p[16]);
|
||||
//}
|
||||
//else
|
||||
//if (eeprom_type == 1)
|
||||
//{
|
||||
// x24c02.Load(&p[16]);
|
||||
//}
|
||||
//else
|
||||
//if (eeprom_type == 2)
|
||||
//{
|
||||
// x24c02.Load(&p[16]);
|
||||
// x24c01.Load(&p[48]);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -8,409 +8,410 @@ using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper019 : Mapper
|
||||
{
|
||||
BYTE patch;
|
||||
BYTE exsound_enable;
|
||||
|
||||
BYTE[] reg = new byte[3];
|
||||
BYTE[] exram = new byte[128];
|
||||
|
||||
BYTE irq_enable;
|
||||
ushort irq_counter;
|
||||
public Mapper019(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
patch = 0;
|
||||
|
||||
reg[0] = reg[1] = reg[2] = 0;
|
||||
|
||||
::memset(exram, 0, sizeof(exram));
|
||||
|
||||
irq_enable = 0;
|
||||
irq_counter = 0;
|
||||
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
if (VROM_1K_SIZE >= 8)
|
||||
{
|
||||
SetVROM_8K_Bank(VROM_8K_SIZE - 1);
|
||||
}
|
||||
|
||||
exsound_enable = 0xFF;
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0xb62a7b71)
|
||||
{ // Family Circuit '91(J)
|
||||
patch = 1;
|
||||
}
|
||||
|
||||
if (crc == 0x02738c68)
|
||||
{ // Wagan Land 2(J)
|
||||
patch = 3;
|
||||
}
|
||||
if (crc == 0x14942c06)
|
||||
{ // Wagan Land 3(J)
|
||||
patch = 2;
|
||||
}
|
||||
|
||||
if (crc == 0x968dcf09)
|
||||
{ // Final Lap(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER);
|
||||
}
|
||||
if (crc == 0x3deac303)
|
||||
{ // Rolling Thunder(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0xb1b9e187)
|
||||
{ // For Kaijuu Monogatari(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0x6901346e)
|
||||
{ // For Sangokushi 2 - Haou no Tairiku(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
}
|
||||
|
||||
// if( crc == 0xdd454208 ) { // Hydlide 3(J)
|
||||
// nes.SetRenderMethod( NES::PRE_ALL_RENDER );
|
||||
// }
|
||||
|
||||
if (crc == 0xaf15338f // For Mindseeker(J)
|
||||
|| crc == 0xb1b9e187 // For Kaijuu Monogatari(J)
|
||||
|| crc == 0x96533999 // Dokuganryuu Masamune(J)
|
||||
// || crc == 0x2b825ce1 // Namco Classic(J)
|
||||
// || crc == 0x9a2b0641 // Namco Classic 2(J)
|
||||
|| crc == 0x3296ff7a // Battle Fleet(J)
|
||||
|| crc == 0xdd454208)
|
||||
{ // Hydlide 3(J)
|
||||
exsound_enable = 0;
|
||||
}
|
||||
|
||||
if (crc == 0x429fd177)
|
||||
{ // Famista '90(J)
|
||||
exsound_enable = 0;
|
||||
}
|
||||
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.SelectExSound(0x10);
|
||||
}
|
||||
}
|
||||
|
||||
//BYTE Mapper019::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
BYTE data = 0;
|
||||
|
||||
switch (addr & 0xF800)
|
||||
{
|
||||
case 0x4800:
|
||||
if (addr == 0x4800)
|
||||
{
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.ExRead(addr);
|
||||
data = exram[reg[2] & 0x7F];
|
||||
}
|
||||
else
|
||||
{
|
||||
data = WRAM[reg[2] & 0x7F];
|
||||
}
|
||||
if ((reg[2] & 0x80) != 0)
|
||||
reg[2] = (byte)((reg[2] + 1) | 0x80);
|
||||
return data;
|
||||
}
|
||||
break;
|
||||
case 0x5000:
|
||||
return (byte)((BYTE)irq_counter & 0x00FF);
|
||||
case 0x5800:
|
||||
return (BYTE)((irq_counter >> 8) & 0x7F);
|
||||
case 0x6000:
|
||||
case 0x6800:
|
||||
case 0x7000:
|
||||
case 0x7800:
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
|
||||
return (BYTE)(addr >> 8);
|
||||
}
|
||||
|
||||
//void Mapper019::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
switch (addr & 0xF800)
|
||||
{
|
||||
case 0x4800:
|
||||
if (addr == 0x4800)
|
||||
{
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.ExWrite(addr, data);
|
||||
exram[reg[2] & 0x7F] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRAM[reg[2] & 0x7F] = data;
|
||||
}
|
||||
if ((reg[2] & 0x80) != 0)
|
||||
reg[2] = (byte)((reg[2] + 1) | 0x80);
|
||||
}
|
||||
break;
|
||||
case 0x5000:
|
||||
irq_counter = (byte)((irq_counter & 0xFF00) | (ushort)data);
|
||||
// if( irq_enable ) {
|
||||
// irq_counter++;
|
||||
// }
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x5800:
|
||||
irq_counter = (byte)((irq_counter & 0x00FF) | ((ushort)(data & 0x7F) << 8));
|
||||
irq_enable = (byte)(data & 0x80);
|
||||
// if( irq_enable ) {
|
||||
// irq_counter++;
|
||||
// }
|
||||
// if( !irq_enable ) {
|
||||
// nes.cpu.ClrIRQ( IRQ_MAPPER );
|
||||
// }
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x6000:
|
||||
case 0x6800:
|
||||
case 0x7000:
|
||||
case 0x7800:
|
||||
base.WriteLow(addr, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper019::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//if( addr >= 0xC000 ) {
|
||||
//DEBUGOUT( "W %04X %02X L:%3d\n", addr, data, nes.GetScanline() );
|
||||
//}
|
||||
switch (addr & 0xF800)
|
||||
{
|
||||
case 0x8000:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(0, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(0, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0x8800:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(1, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(1, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0x9000:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(2, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(2, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0x9800:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(3, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(3, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(4, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(4, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xA800:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(5, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(5, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xB000:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(6, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(6, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xB800:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(7, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(7, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xC000:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(8, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(8, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xC800:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(9, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(9, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xD000:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(10, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(10, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xD800:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(11, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(11, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE000:
|
||||
SetPROM_8K_Bank(4, data & 0x3F);
|
||||
if (patch == 2)
|
||||
{
|
||||
if ((data & 0x40) != 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
if (patch == 3)
|
||||
{
|
||||
if ((data & 0x80) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
break;
|
||||
case 0xE800:
|
||||
reg[0] = (byte)(data & 0x40);
|
||||
reg[1] = (byte)(data & 0x80);
|
||||
SetPROM_8K_Bank(5, data & 0x3F);
|
||||
break;
|
||||
case 0xF000:
|
||||
SetPROM_8K_Bank(6, data & 0x3F);
|
||||
break;
|
||||
case 0xF800:
|
||||
if (addr == 0xF800)
|
||||
{
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.ExWrite(addr, data);
|
||||
}
|
||||
reg[2] = data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper019::Clock(INT cycles)
|
||||
public override void Clock(int cycles)
|
||||
{
|
||||
if (irq_enable != 0)
|
||||
{
|
||||
if ((irq_counter += cycles) >= 0x7FFF)
|
||||
{
|
||||
// irq_counter = 0x7FFF;
|
||||
// nes.cpu.IRQ_NotPending();
|
||||
|
||||
irq_enable = 0;
|
||||
// irq_counter &= 0x7FFF;
|
||||
irq_counter = 0x7FFF;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper019::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
// p[0] = reg[0];
|
||||
// p[1] = reg[1];
|
||||
// p[2] = reg[2];
|
||||
// p[3] = irq_enable;
|
||||
// *(WORD*)&p[4] = irq_counter;
|
||||
|
||||
//::memcpy(&p[8], exram, sizeof(exram));
|
||||
}
|
||||
|
||||
//void Mapper019::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
// reg[0] = p[0];
|
||||
// reg[1] = p[1];
|
||||
// reg[2] = p[2];
|
||||
// irq_enable = p[3];
|
||||
// irq_counter = *(WORD*)&p[4];
|
||||
|
||||
//::memcpy(exram, &p[8], sizeof(exram));
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{
|
||||
public class Mapper019 : Mapper
|
||||
{
|
||||
BYTE patch;
|
||||
BYTE exsound_enable;
|
||||
|
||||
BYTE[] reg = new byte[3];
|
||||
BYTE[] exram = new byte[128];
|
||||
|
||||
BYTE irq_enable;
|
||||
ushort irq_counter;
|
||||
public Mapper019(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
patch = 0;
|
||||
|
||||
reg[0] = reg[1] = reg[2] = 0;
|
||||
|
||||
MemoryUtility.ZEROMEMORY(exram, exram.Length);
|
||||
|
||||
irq_enable = 0;
|
||||
irq_counter = 0;
|
||||
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
if (VROM_1K_SIZE >= 8)
|
||||
{
|
||||
SetVROM_8K_Bank(VROM_8K_SIZE - 1);
|
||||
}
|
||||
|
||||
exsound_enable = 0xFF;
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0xb62a7b71)
|
||||
{ // Family Circuit '91(J)
|
||||
patch = 1;
|
||||
}
|
||||
|
||||
if (crc == 0x02738c68)
|
||||
{ // Wagan Land 2(J)
|
||||
patch = 3;
|
||||
}
|
||||
if (crc == 0x14942c06)
|
||||
{ // Wagan Land 3(J)
|
||||
patch = 2;
|
||||
}
|
||||
|
||||
if (crc == 0x968dcf09)
|
||||
{ // Final Lap(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER);
|
||||
}
|
||||
if (crc == 0x3deac303)
|
||||
{ // Rolling Thunder(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0xb1b9e187)
|
||||
{ // For Kaijuu Monogatari(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0x6901346e)
|
||||
{ // For Sangokushi 2 - Haou no Tairiku(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
}
|
||||
|
||||
// if( crc == 0xdd454208 ) { // Hydlide 3(J)
|
||||
// nes.SetRenderMethod( NES::PRE_ALL_RENDER );
|
||||
// }
|
||||
|
||||
if (crc == 0xaf15338f // For Mindseeker(J)
|
||||
|| crc == 0xb1b9e187 // For Kaijuu Monogatari(J)
|
||||
|| crc == 0x96533999 // Dokuganryuu Masamune(J)
|
||||
// || crc == 0x2b825ce1 // Namco Classic(J)
|
||||
// || crc == 0x9a2b0641 // Namco Classic 2(J)
|
||||
|| crc == 0x3296ff7a // Battle Fleet(J)
|
||||
|| crc == 0xdd454208)
|
||||
{ // Hydlide 3(J)
|
||||
exsound_enable = 0;
|
||||
}
|
||||
|
||||
if (crc == 0x429fd177)
|
||||
{ // Famista '90(J)
|
||||
exsound_enable = 0;
|
||||
}
|
||||
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.SelectExSound(0x10);
|
||||
}
|
||||
}
|
||||
|
||||
//BYTE Mapper019::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
BYTE data = 0;
|
||||
|
||||
switch (addr & 0xF800)
|
||||
{
|
||||
case 0x4800:
|
||||
if (addr == 0x4800)
|
||||
{
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.ExRead(addr);
|
||||
data = exram[reg[2] & 0x7F];
|
||||
}
|
||||
else
|
||||
{
|
||||
data = WRAM[reg[2] & 0x7F];
|
||||
}
|
||||
if ((reg[2] & 0x80) != 0)
|
||||
reg[2] = (byte)((reg[2] + 1) | 0x80);
|
||||
return data;
|
||||
}
|
||||
break;
|
||||
case 0x5000:
|
||||
return (byte)((BYTE)irq_counter & 0x00FF);
|
||||
case 0x5800:
|
||||
return (BYTE)((irq_counter >> 8) & 0x7F);
|
||||
case 0x6000:
|
||||
case 0x6800:
|
||||
case 0x7000:
|
||||
case 0x7800:
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
|
||||
return (BYTE)(addr >> 8);
|
||||
}
|
||||
|
||||
//void Mapper019::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
switch (addr & 0xF800)
|
||||
{
|
||||
case 0x4800:
|
||||
if (addr == 0x4800)
|
||||
{
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.ExWrite(addr, data);
|
||||
exram[reg[2] & 0x7F] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRAM[reg[2] & 0x7F] = data;
|
||||
}
|
||||
if ((reg[2] & 0x80) != 0)
|
||||
reg[2] = (byte)((reg[2] + 1) | 0x80);
|
||||
}
|
||||
break;
|
||||
case 0x5000:
|
||||
irq_counter = (byte)((irq_counter & 0xFF00) | (ushort)data);
|
||||
// if( irq_enable ) {
|
||||
// irq_counter++;
|
||||
// }
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x5800:
|
||||
irq_counter = (byte)((irq_counter & 0x00FF) | ((ushort)(data & 0x7F) << 8));
|
||||
irq_enable = (byte)(data & 0x80);
|
||||
// if( irq_enable ) {
|
||||
// irq_counter++;
|
||||
// }
|
||||
// if( !irq_enable ) {
|
||||
// nes.cpu.ClrIRQ( IRQ_MAPPER );
|
||||
// }
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x6000:
|
||||
case 0x6800:
|
||||
case 0x7000:
|
||||
case 0x7800:
|
||||
base.WriteLow(addr, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper019::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//if( addr >= 0xC000 ) {
|
||||
//DEBUGOUT( "W %04X %02X L:%3d\n", addr, data, nes.GetScanline() );
|
||||
//}
|
||||
switch (addr & 0xF800)
|
||||
{
|
||||
case 0x8000:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(0, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(0, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0x8800:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(1, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(1, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0x9000:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(2, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(2, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0x9800:
|
||||
if ((data < 0xE0) || (reg[0] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(3, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(3, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(4, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(4, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xA800:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(5, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(5, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xB000:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(6, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(6, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xB800:
|
||||
if ((data < 0xE0) || (reg[1] != 0))
|
||||
{
|
||||
SetVROM_1K_Bank(7, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(7, data & 0x1F);
|
||||
}
|
||||
break;
|
||||
case 0xC000:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(8, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(8, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xC800:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(9, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(9, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xD000:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(10, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(10, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xD800:
|
||||
if (patch == 0)
|
||||
{
|
||||
if (data <= 0xDF)
|
||||
{
|
||||
SetVROM_1K_Bank(11, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_1K_Bank(11, data & 0x01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE000:
|
||||
SetPROM_8K_Bank(4, data & 0x3F);
|
||||
if (patch == 2)
|
||||
{
|
||||
if ((data & 0x40) != 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
if (patch == 3)
|
||||
{
|
||||
if ((data & 0x80) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
break;
|
||||
case 0xE800:
|
||||
reg[0] = (byte)(data & 0x40);
|
||||
reg[1] = (byte)(data & 0x80);
|
||||
SetPROM_8K_Bank(5, data & 0x3F);
|
||||
break;
|
||||
case 0xF000:
|
||||
SetPROM_8K_Bank(6, data & 0x3F);
|
||||
break;
|
||||
case 0xF800:
|
||||
if (addr == 0xF800)
|
||||
{
|
||||
if (exsound_enable != 0)
|
||||
{
|
||||
nes.apu.ExWrite(addr, data);
|
||||
}
|
||||
reg[2] = data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper019::Clock(INT cycles)
|
||||
public override void Clock(int cycles)
|
||||
{
|
||||
if (irq_enable != 0)
|
||||
{
|
||||
irq_counter = (ushort)(irq_counter + cycles);
|
||||
if (irq_counter >= 0x7FFF)
|
||||
{
|
||||
// irq_counter = 0x7FFF;
|
||||
// nes.cpu.IRQ_NotPending();
|
||||
|
||||
irq_enable = 0;
|
||||
// irq_counter &= 0x7FFF;
|
||||
irq_counter = 0x7FFF;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper019::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
// p[0] = reg[0];
|
||||
// p[1] = reg[1];
|
||||
// p[2] = reg[2];
|
||||
// p[3] = irq_enable;
|
||||
// *(WORD*)&p[4] = irq_counter;
|
||||
|
||||
//::memcpy(&p[8], exram, sizeof(exram));
|
||||
}
|
||||
|
||||
//void Mapper019::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
// reg[0] = p[0];
|
||||
// reg[1] = p[1];
|
||||
// reg[2] = p[2];
|
||||
// irq_enable = p[3];
|
||||
// irq_counter = *(WORD*)&p[4];
|
||||
|
||||
//::memcpy(exram, &p[8], sizeof(exram));
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace VirtualNes.Core
|
||||
{
|
||||
addrmask = 0xFFFF;
|
||||
|
||||
for (INT i = 0; i < 8; i++)
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
reg[i] = i;
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper035 //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper035 : Mapper
|
||||
{
|
||||
|
||||
BYTE[] reg = new byte[8];
|
||||
BYTE[] chr = new byte[8];
|
||||
ushort IRQCount, IRQa;
|
||||
public Mapper035(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
reg[i] = chr[i] = 0;
|
||||
|
||||
IRQCount = IRQa = 0;
|
||||
|
||||
//SetPROM_32K_Bank( 0, 1, PROM_8K_SIZE-2, PROM_8K_SIZE-1 );
|
||||
|
||||
Sync();
|
||||
//setprg8r(0x10,0x6000,0);
|
||||
SetPROM_8K_Bank(7, PROM_8K_SIZE - 1);
|
||||
}
|
||||
|
||||
void Sync()
|
||||
{
|
||||
int i;
|
||||
SetPROM_8K_Bank(4, reg[0]);
|
||||
SetPROM_8K_Bank(5, reg[1]);
|
||||
SetPROM_8K_Bank(6, reg[2]);
|
||||
for (i = 0; i < 8; i++)
|
||||
SetVROM_1K_Bank((byte)i, chr[i]);
|
||||
SetVRAM_Mirror(reg[3] ^ 1);
|
||||
}
|
||||
|
||||
//void Mapper035::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr >= 0x6000 && addr <= 0x7FFF)
|
||||
{
|
||||
XRAM[addr - 0x6000] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
//BYTE Mapper035::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
if (addr >= 0x6000 && addr <= 0x7FFF)
|
||||
{
|
||||
return XRAM[addr - 0x6000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper035::Write(WORD A, BYTE V)
|
||||
public override void Write(ushort A, byte V)
|
||||
{
|
||||
switch (A)
|
||||
{
|
||||
case 0x8000: reg[0] = V; break;
|
||||
case 0x8001: reg[1] = V; break;
|
||||
case 0x8002: reg[2] = V; break;
|
||||
case 0x9000: chr[0] = V; break;
|
||||
case 0x9001: chr[1] = V; break;
|
||||
case 0x9002: chr[2] = V; break;
|
||||
case 0x9003: chr[3] = V; break;
|
||||
case 0x9004: chr[4] = V; break;
|
||||
case 0x9005: chr[5] = V; break;
|
||||
case 0x9006: chr[6] = V; break;
|
||||
case 0x9007: chr[7] = V; break;
|
||||
case 0xC002:
|
||||
IRQa = 0;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER); break;
|
||||
case 0xC005: IRQCount = V; break;
|
||||
case 0xC003: IRQa = 1; break;
|
||||
case 0xD001: reg[3] = V; break;
|
||||
}
|
||||
Sync();
|
||||
}
|
||||
|
||||
//void Mapper035::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((scanline >= 0 && scanline <= 239))
|
||||
{
|
||||
if (nes.ppu.IsDispON())
|
||||
{
|
||||
if (IRQa!=0)
|
||||
{
|
||||
IRQCount--;
|
||||
if (IRQCount == 0)
|
||||
{
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
IRQa = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a56d9f749be056e4b9ccf087899369ad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -7,53 +7,54 @@ using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
using VirtualNes.Core.Debug;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper072 : Mapper
|
||||
{
|
||||
public Mapper072(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
if (VROM_8K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper072::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
if (data & 0x80)
|
||||
{
|
||||
SetPROM_16K_Bank(4, data & 0x0F);
|
||||
}
|
||||
else if (data & 0x40)
|
||||
{
|
||||
SetVROM_8K_Bank(data & 0x0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addr >= 0xC100 && addr <= 0xC11F && data == 0x20)
|
||||
{
|
||||
//DEBUGOUT( "ADDR:%04X DATA:%02X\n", addr, data );
|
||||
DEBUGOUT("SOUND CODE:%02X\n", addr & 0x1F);
|
||||
|
||||
// OSDにするべきか…
|
||||
if (Config.sound.bExtraSoundEnable)
|
||||
{
|
||||
DirectSound.EsfAllStop();
|
||||
DirectSound.EsfPlay(ESF_MOETENNIS_00 + (addr & 0x1F));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
{
|
||||
public class Mapper072 : Mapper
|
||||
{
|
||||
public Mapper072(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
if (VROM_8K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper072::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
SetPROM_16K_Bank(4, data & 0x0F);
|
||||
}
|
||||
else if ((data & 0x40) != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(data & 0x0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addr >= 0xC100 && addr <= 0xC11F && data == 0x20)
|
||||
{
|
||||
Debuger.Log($"SOUND CODE:{addr & 0x1F:X2}");
|
||||
|
||||
// OSDにするべきか…
|
||||
if (Supporter.Config.sound.bExtraSoundEnable)
|
||||
{
|
||||
//TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
|
||||
//DirectSound.EsfAllStop();
|
||||
//DirectSound.EsfPlay(ESF_MOETENNIS_00 + (addr & 0x1F));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,62 +10,63 @@ using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper086 : Mapper
|
||||
{
|
||||
BYTE reg, cnt;
|
||||
public Mapper086(NES parent) : base(parent)
|
||||
public class Mapper086 : Mapper
|
||||
{
|
||||
BYTE reg, cnt;
|
||||
public Mapper086(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 2, 3);
|
||||
SetVROM_8K_Bank(0);
|
||||
reg = 0xFF;
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
//void Mapper086::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr == 0x6000)
|
||||
{
|
||||
SetPROM_32K_Bank((data & 0x30) >> 4);
|
||||
|
||||
SetVROM_8K_Bank((data & 0x03) | ((data & 0x40) >> 4));
|
||||
}
|
||||
if (addr == 0x7000)
|
||||
{
|
||||
if ((reg & 0x10) == 0 && ((data & 0x10) != 0) && cnt==0)
|
||||
{
|
||||
//DEBUGOUT( "WR:$%02X\n", data );
|
||||
if ((data & 0x0F) == 0 // Strike
|
||||
|| (data & 0x0F) == 5)
|
||||
{ // Foul
|
||||
cnt = 60; // 次の発声を1秒程禁止する
|
||||
}
|
||||
|
||||
// OSDにするべきか…
|
||||
if (Config.sound.bExtraSoundEnable)
|
||||
{
|
||||
DirectSound.EsfAllStop();
|
||||
DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + (data & 0x0F));
|
||||
}
|
||||
}
|
||||
reg = data;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper086::VSync()
|
||||
public override void VSync()
|
||||
{
|
||||
if (cnt!=0)
|
||||
{
|
||||
cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 2, 3);
|
||||
SetVROM_8K_Bank(0);
|
||||
reg = 0xFF;
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
//void Mapper086::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr == 0x6000)
|
||||
{
|
||||
SetPROM_32K_Bank((data & 0x30) >> 4);
|
||||
|
||||
SetVROM_8K_Bank((data & 0x03) | ((data & 0x40) >> 4));
|
||||
}
|
||||
if (addr == 0x7000)
|
||||
{
|
||||
if ((reg & 0x10) == 0 && ((data & 0x10) != 0) && cnt == 0)
|
||||
{
|
||||
//DEBUGOUT( "WR:$%02X\n", data );
|
||||
if ((data & 0x0F) == 0 // Strike
|
||||
|| (data & 0x0F) == 5)
|
||||
{ // Foul
|
||||
cnt = 60; // 次の発声を1秒程禁止する
|
||||
}
|
||||
|
||||
// OSDにするべきか…
|
||||
if (Supporter.Config.sound.bExtraSoundEnable)
|
||||
{
|
||||
//TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
|
||||
//DirectSound.EsfAllStop();
|
||||
//DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + (data & 0x0F));
|
||||
}
|
||||
}
|
||||
reg = data;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper086::VSync()
|
||||
public override void VSync()
|
||||
{
|
||||
if (cnt != 0)
|
||||
{
|
||||
cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,476 +7,477 @@ using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
using VirtualNes.Core.Debug;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper090 : Mapper
|
||||
{
|
||||
BYTE patch;
|
||||
|
||||
BYTE[] prg_reg = new byte[4];
|
||||
BYTE[] nth_reg = new byte[4];
|
||||
BYTE[] ntl_reg = new byte[4];
|
||||
BYTE[] chh_reg = new byte[8];
|
||||
BYTE[] chl_reg = new byte[8];
|
||||
|
||||
BYTE irq_enable;
|
||||
BYTE irq_counter;
|
||||
BYTE irq_latch;
|
||||
BYTE irq_occur;
|
||||
BYTE irq_preset;
|
||||
BYTE irq_offset;
|
||||
|
||||
BYTE prg_6000, prg_E000;
|
||||
BYTE prg_size, chr_size;
|
||||
BYTE mir_mode, mir_type;
|
||||
|
||||
BYTE key_val;
|
||||
BYTE mul_val1, mul_val2;
|
||||
BYTE sw_val;
|
||||
public Mapper090(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
SetVROM_8K_Bank(0);
|
||||
patch = 0;
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0x2a268152)
|
||||
{
|
||||
patch = 1;
|
||||
}
|
||||
if (crc == 0x2224b882)
|
||||
{
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
}
|
||||
|
||||
irq_enable = 0; // Disable
|
||||
irq_counter = 0;
|
||||
irq_latch = 0;
|
||||
irq_occur = 0;
|
||||
irq_preset = 0;
|
||||
irq_offset = 0;
|
||||
|
||||
prg_6000 = 0;
|
||||
prg_E000 = 0;
|
||||
prg_size = 0;
|
||||
chr_size = 0;
|
||||
mir_mode = 0;
|
||||
mir_type = 0;
|
||||
|
||||
key_val = 0;
|
||||
mul_val1 = mul_val2 = 0;
|
||||
|
||||
for (INT i = 0; i < 4; i++)
|
||||
{
|
||||
prg_reg[i] = (byte)(PROM_8K_SIZE - 4 + i);
|
||||
ntl_reg[i] = 0;
|
||||
nth_reg[i] = 0;
|
||||
chl_reg[i] = i;
|
||||
chh_reg[i] = 0;
|
||||
chl_reg[i + 4] = (byte)(i + 4);
|
||||
chh_reg[i + 4] = 0;
|
||||
}
|
||||
|
||||
if (sw_val != 0)
|
||||
sw_val = 0x00;
|
||||
else
|
||||
sw_val = 0xFF;
|
||||
|
||||
// nes.SetRenderMethod( NES::PRE_ALL_RENDER );
|
||||
}
|
||||
|
||||
//BYTE Mapper090::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
DEBUGOUT("RD:%04X\n", addr);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x5000:
|
||||
return (byte)((sw_val != 0) ? 0x00 : 0xFF);
|
||||
case 0x5800:
|
||||
return (BYTE)(mul_val1 * mul_val2);
|
||||
case 0x5801:
|
||||
return (BYTE)((mul_val1 * mul_val2) >> 8);
|
||||
case 0x5803:
|
||||
return key_val;
|
||||
}
|
||||
|
||||
if (addr >= 0x6000)
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
|
||||
// return sw_val?0x00:0xFF;
|
||||
return (BYTE)(addr >> 8);
|
||||
}
|
||||
|
||||
//void Mapper090::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
DEBUGOUT("WR:%04X %02X\n", addr, data);
|
||||
|
||||
if (addr == 0x5800)
|
||||
{
|
||||
mul_val1 = data;
|
||||
}
|
||||
else
|
||||
if (addr == 0x5801)
|
||||
{
|
||||
mul_val2 = data;
|
||||
}
|
||||
else
|
||||
if (addr == 0x5803)
|
||||
{
|
||||
key_val = data;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
switch (addr & 0xF007)
|
||||
{
|
||||
case 0x8000:
|
||||
case 0x8001:
|
||||
case 0x8002:
|
||||
case 0x8003:
|
||||
prg_reg[addr & 3] = data;
|
||||
SetBank_CPU();
|
||||
break;
|
||||
|
||||
case 0x9000:
|
||||
case 0x9001:
|
||||
case 0x9002:
|
||||
case 0x9003:
|
||||
case 0x9004:
|
||||
case 0x9005:
|
||||
case 0x9006:
|
||||
case 0x9007:
|
||||
chl_reg[addr & 7] = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
|
||||
case 0xA000:
|
||||
case 0xA001:
|
||||
case 0xA002:
|
||||
case 0xA003:
|
||||
case 0xA004:
|
||||
case 0xA005:
|
||||
case 0xA006:
|
||||
case 0xA007:
|
||||
chh_reg[addr & 7] = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
|
||||
case 0xB000:
|
||||
case 0xB001:
|
||||
case 0xB002:
|
||||
case 0xB003:
|
||||
ntl_reg[addr & 3] = data;
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xB004:
|
||||
case 0xB005:
|
||||
case 0xB006:
|
||||
case 0xB007:
|
||||
nth_reg[addr & 3] = data;
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xC002:
|
||||
irq_enable = 0;
|
||||
irq_occur = 0;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0xC003:
|
||||
irq_enable = 0xFF;
|
||||
irq_preset = 0xFF;
|
||||
break;
|
||||
case 0xC004:
|
||||
break;
|
||||
case 0xC005:
|
||||
if ((irq_offset & 0x80) != 0)
|
||||
{
|
||||
irq_latch = (byte)(data ^ (irq_offset | 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_latch = (byte)(data | (irq_offset & 0x27));
|
||||
}
|
||||
irq_preset = 0xFF;
|
||||
break;
|
||||
case 0xC006:
|
||||
if (patch != 0)
|
||||
{
|
||||
irq_offset = data;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD000:
|
||||
prg_6000 = (byte)(data & 0x80);
|
||||
prg_E000 = (byte)(data & 0x04);
|
||||
prg_size = (byte)(data & 0x03);
|
||||
chr_size = (byte)((data & 0x18) >> 3);
|
||||
mir_mode = (byte)(data & 0x20);
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xD001:
|
||||
mir_type = (byte)(data & 0x03);
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xD003:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((scanline >= 0 && scanline <= 239))
|
||||
{
|
||||
if (nes.ppu.IsDispON())
|
||||
{
|
||||
if (irq_preset != 0)
|
||||
{
|
||||
irq_counter = irq_latch;
|
||||
irq_preset = 0;
|
||||
}
|
||||
if (irq_counter != 0)
|
||||
{
|
||||
irq_counter--;
|
||||
}
|
||||
if (irq_counter == 0)
|
||||
{
|
||||
if (irq_enable != 0)
|
||||
{
|
||||
// irq_occur = 0xFF;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::Clock(INT cycles)
|
||||
public override void Clock(int cycles)
|
||||
{
|
||||
// if( irq_occur ) {
|
||||
// nes.cpu.IRQ_NotPending();
|
||||
// }
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
if (prg_size == 0)
|
||||
{
|
||||
SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
if (prg_size == 1)
|
||||
{
|
||||
SetPROM_32K_Bank(prg_reg[1] * 2, prg_reg[1] * 2 + 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
if (prg_size == 2)
|
||||
{
|
||||
if (prg_E000 != 0)
|
||||
{
|
||||
SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], prg_reg[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prg_6000 != 0)
|
||||
{
|
||||
SetPROM_8K_Bank(3, prg_reg[3]);
|
||||
}
|
||||
SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], PROM_8K_SIZE - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_32K_Bank(prg_reg[3], prg_reg[2], prg_reg[1], prg_reg[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
INT[] bank = new int[8];
|
||||
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
bank[i] = ((INT)chh_reg[i] << 8) | ((INT)chl_reg[i]);
|
||||
}
|
||||
|
||||
if (chr_size == 0)
|
||||
{
|
||||
SetVROM_8K_Bank(bank[0]);
|
||||
}
|
||||
else
|
||||
if (chr_size == 1)
|
||||
{
|
||||
SetVROM_4K_Bank(0, bank[0]);
|
||||
SetVROM_4K_Bank(4, bank[4]);
|
||||
}
|
||||
else
|
||||
if (chr_size == 2)
|
||||
{
|
||||
SetVROM_2K_Bank(0, bank[0]);
|
||||
SetVROM_2K_Bank(2, bank[2]);
|
||||
SetVROM_2K_Bank(4, bank[4]);
|
||||
SetVROM_2K_Bank(6, bank[6]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVROM_8K_Bank(bank[0], bank[1], bank[2], bank[3], bank[4], bank[5], bank[6], bank[7]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_VRAM()
|
||||
{
|
||||
INT[] bank = new int[4];
|
||||
|
||||
for (INT i = 0; i < 4; i++)
|
||||
{
|
||||
bank[i] = ((INT)nth_reg[i] << 8) | ((INT)ntl_reg[i]);
|
||||
}
|
||||
|
||||
if (patch == 0 && mir_mode != 0)
|
||||
{
|
||||
for (INT i = 0; i < 4; i++)
|
||||
{
|
||||
if (nth_reg[i] == 0 && (ntl_reg[i] == (BYTE)i))
|
||||
{
|
||||
mir_mode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mir_mode != 0)
|
||||
{
|
||||
SetVROM_1K_Bank(8, bank[0]);
|
||||
SetVROM_1K_Bank(9, bank[1]);
|
||||
SetVROM_1K_Bank(10, bank[2]);
|
||||
SetVROM_1K_Bank(11, bank[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mir_type == 0)
|
||||
{
|
||||
SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
else
|
||||
if (mir_type == 1)
|
||||
{
|
||||
SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
INT i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p[i] = prg_reg[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
p[i + 4] = chh_reg[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
p[i + 12] = chl_reg[i];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p[i + 20] = nth_reg[i];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p[i + 24] = ntl_reg[i];
|
||||
}
|
||||
p[28] = irq_enable;
|
||||
p[29] = irq_counter;
|
||||
p[30] = irq_latch;
|
||||
p[31] = prg_6000;
|
||||
p[32] = prg_E000;
|
||||
p[33] = prg_size;
|
||||
p[34] = chr_size;
|
||||
p[35] = mir_mode;
|
||||
p[36] = mir_type;
|
||||
p[37] = mul_val1;
|
||||
p[38] = mul_val2;
|
||||
p[39] = key_val;
|
||||
p[40] = irq_occur;
|
||||
p[41] = irq_preset;
|
||||
p[42] = irq_offset;
|
||||
}
|
||||
|
||||
//void Mapper090::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
INT i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
prg_reg[i] = p[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chh_reg[i] = p[i + 4];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chl_reg[i] = p[i + 12];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
nth_reg[i] = p[i + 20];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
ntl_reg[i] = p[i + 24];
|
||||
}
|
||||
irq_enable = p[28];
|
||||
irq_counter = p[29];
|
||||
irq_latch = p[30];
|
||||
prg_6000 = p[31];
|
||||
prg_E000 = p[32];
|
||||
prg_size = p[33];
|
||||
chr_size = p[34];
|
||||
mir_mode = p[35];
|
||||
mir_type = p[36];
|
||||
mul_val1 = p[37];
|
||||
mul_val2 = p[38];
|
||||
key_val = p[39];
|
||||
irq_occur = p[40];
|
||||
irq_preset = p[41];
|
||||
irq_offset = p[42];
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
public class Mapper090 : Mapper
|
||||
{
|
||||
BYTE patch;
|
||||
|
||||
BYTE[] prg_reg = new byte[4];
|
||||
BYTE[] nth_reg = new byte[4];
|
||||
BYTE[] ntl_reg = new byte[4];
|
||||
BYTE[] chh_reg = new byte[8];
|
||||
BYTE[] chl_reg = new byte[8];
|
||||
|
||||
BYTE irq_enable;
|
||||
BYTE irq_counter;
|
||||
BYTE irq_latch;
|
||||
BYTE irq_occur;
|
||||
BYTE irq_preset;
|
||||
BYTE irq_offset;
|
||||
|
||||
BYTE prg_6000, prg_E000;
|
||||
BYTE prg_size, chr_size;
|
||||
BYTE mir_mode, mir_type;
|
||||
|
||||
BYTE key_val;
|
||||
BYTE mul_val1, mul_val2;
|
||||
BYTE sw_val;
|
||||
public Mapper090(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
SetVROM_8K_Bank(0);
|
||||
patch = 0;
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0x2a268152)
|
||||
{
|
||||
patch = 1;
|
||||
}
|
||||
if (crc == 0x2224b882)
|
||||
{
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
}
|
||||
|
||||
irq_enable = 0; // Disable
|
||||
irq_counter = 0;
|
||||
irq_latch = 0;
|
||||
irq_occur = 0;
|
||||
irq_preset = 0;
|
||||
irq_offset = 0;
|
||||
|
||||
prg_6000 = 0;
|
||||
prg_E000 = 0;
|
||||
prg_size = 0;
|
||||
chr_size = 0;
|
||||
mir_mode = 0;
|
||||
mir_type = 0;
|
||||
|
||||
key_val = 0;
|
||||
mul_val1 = mul_val2 = 0;
|
||||
|
||||
for (byte i = 0; i < 4; i++)
|
||||
{
|
||||
prg_reg[i] = (byte)(PROM_8K_SIZE - 4 + i);
|
||||
ntl_reg[i] = 0;
|
||||
nth_reg[i] = 0;
|
||||
chl_reg[i] = i;
|
||||
chh_reg[i] = 0;
|
||||
chl_reg[i + 4] = (byte)(i + 4);
|
||||
chh_reg[i + 4] = 0;
|
||||
}
|
||||
|
||||
if (sw_val != 0)
|
||||
sw_val = 0x00;
|
||||
else
|
||||
sw_val = 0xFF;
|
||||
|
||||
// nes.SetRenderMethod( NES::PRE_ALL_RENDER );
|
||||
}
|
||||
|
||||
//BYTE Mapper090::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
Debuger.Log($"RD:{addr:X4}");
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x5000:
|
||||
return (byte)((sw_val != 0) ? 0x00 : 0xFF);
|
||||
case 0x5800:
|
||||
return (BYTE)(mul_val1 * mul_val2);
|
||||
case 0x5801:
|
||||
return (BYTE)((mul_val1 * mul_val2) >> 8);
|
||||
case 0x5803:
|
||||
return key_val;
|
||||
}
|
||||
|
||||
if (addr >= 0x6000)
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
|
||||
// return sw_val?0x00:0xFF;
|
||||
return (BYTE)(addr >> 8);
|
||||
}
|
||||
|
||||
//void Mapper090::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
Debuger.Log($"WR:{addr:X4} {data:X2}");
|
||||
|
||||
if (addr == 0x5800)
|
||||
{
|
||||
mul_val1 = data;
|
||||
}
|
||||
else
|
||||
if (addr == 0x5801)
|
||||
{
|
||||
mul_val2 = data;
|
||||
}
|
||||
else
|
||||
if (addr == 0x5803)
|
||||
{
|
||||
key_val = data;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
switch (addr & 0xF007)
|
||||
{
|
||||
case 0x8000:
|
||||
case 0x8001:
|
||||
case 0x8002:
|
||||
case 0x8003:
|
||||
prg_reg[addr & 3] = data;
|
||||
SetBank_CPU();
|
||||
break;
|
||||
|
||||
case 0x9000:
|
||||
case 0x9001:
|
||||
case 0x9002:
|
||||
case 0x9003:
|
||||
case 0x9004:
|
||||
case 0x9005:
|
||||
case 0x9006:
|
||||
case 0x9007:
|
||||
chl_reg[addr & 7] = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
|
||||
case 0xA000:
|
||||
case 0xA001:
|
||||
case 0xA002:
|
||||
case 0xA003:
|
||||
case 0xA004:
|
||||
case 0xA005:
|
||||
case 0xA006:
|
||||
case 0xA007:
|
||||
chh_reg[addr & 7] = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
|
||||
case 0xB000:
|
||||
case 0xB001:
|
||||
case 0xB002:
|
||||
case 0xB003:
|
||||
ntl_reg[addr & 3] = data;
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xB004:
|
||||
case 0xB005:
|
||||
case 0xB006:
|
||||
case 0xB007:
|
||||
nth_reg[addr & 3] = data;
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xC002:
|
||||
irq_enable = 0;
|
||||
irq_occur = 0;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0xC003:
|
||||
irq_enable = 0xFF;
|
||||
irq_preset = 0xFF;
|
||||
break;
|
||||
case 0xC004:
|
||||
break;
|
||||
case 0xC005:
|
||||
if ((irq_offset & 0x80) != 0)
|
||||
{
|
||||
irq_latch = (byte)(data ^ (irq_offset | 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_latch = (byte)(data | (irq_offset & 0x27));
|
||||
}
|
||||
irq_preset = 0xFF;
|
||||
break;
|
||||
case 0xC006:
|
||||
if (patch != 0)
|
||||
{
|
||||
irq_offset = data;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD000:
|
||||
prg_6000 = (byte)(data & 0x80);
|
||||
prg_E000 = (byte)(data & 0x04);
|
||||
prg_size = (byte)(data & 0x03);
|
||||
chr_size = (byte)((data & 0x18) >> 3);
|
||||
mir_mode = (byte)(data & 0x20);
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xD001:
|
||||
mir_type = (byte)(data & 0x03);
|
||||
SetBank_VRAM();
|
||||
break;
|
||||
|
||||
case 0xD003:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((scanline >= 0 && scanline <= 239))
|
||||
{
|
||||
if (nes.ppu.IsDispON())
|
||||
{
|
||||
if (irq_preset != 0)
|
||||
{
|
||||
irq_counter = irq_latch;
|
||||
irq_preset = 0;
|
||||
}
|
||||
if (irq_counter != 0)
|
||||
{
|
||||
irq_counter--;
|
||||
}
|
||||
if (irq_counter == 0)
|
||||
{
|
||||
if (irq_enable != 0)
|
||||
{
|
||||
// irq_occur = 0xFF;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::Clock(INT cycles)
|
||||
public override void Clock(int cycles)
|
||||
{
|
||||
// if( irq_occur ) {
|
||||
// nes.cpu.IRQ_NotPending();
|
||||
// }
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
if (prg_size == 0)
|
||||
{
|
||||
SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
if (prg_size == 1)
|
||||
{
|
||||
SetPROM_32K_Bank(prg_reg[1] * 2, prg_reg[1] * 2 + 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
if (prg_size == 2)
|
||||
{
|
||||
if (prg_E000 != 0)
|
||||
{
|
||||
SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], prg_reg[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prg_6000 != 0)
|
||||
{
|
||||
SetPROM_8K_Bank(3, prg_reg[3]);
|
||||
}
|
||||
SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], PROM_8K_SIZE - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_32K_Bank(prg_reg[3], prg_reg[2], prg_reg[1], prg_reg[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
INT[] bank = new int[8];
|
||||
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
bank[i] = ((INT)chh_reg[i] << 8) | ((INT)chl_reg[i]);
|
||||
}
|
||||
|
||||
if (chr_size == 0)
|
||||
{
|
||||
SetVROM_8K_Bank(bank[0]);
|
||||
}
|
||||
else
|
||||
if (chr_size == 1)
|
||||
{
|
||||
SetVROM_4K_Bank(0, bank[0]);
|
||||
SetVROM_4K_Bank(4, bank[4]);
|
||||
}
|
||||
else
|
||||
if (chr_size == 2)
|
||||
{
|
||||
SetVROM_2K_Bank(0, bank[0]);
|
||||
SetVROM_2K_Bank(2, bank[2]);
|
||||
SetVROM_2K_Bank(4, bank[4]);
|
||||
SetVROM_2K_Bank(6, bank[6]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVROM_8K_Bank(bank[0], bank[1], bank[2], bank[3], bank[4], bank[5], bank[6], bank[7]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_VRAM()
|
||||
{
|
||||
INT[] bank = new int[4];
|
||||
|
||||
for (INT i = 0; i < 4; i++)
|
||||
{
|
||||
bank[i] = ((INT)nth_reg[i] << 8) | ((INT)ntl_reg[i]);
|
||||
}
|
||||
|
||||
if (patch == 0 && mir_mode != 0)
|
||||
{
|
||||
for (INT i = 0; i < 4; i++)
|
||||
{
|
||||
if (nth_reg[i] == 0 && (ntl_reg[i] == (BYTE)i))
|
||||
{
|
||||
mir_mode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mir_mode != 0)
|
||||
{
|
||||
SetVROM_1K_Bank(8, bank[0]);
|
||||
SetVROM_1K_Bank(9, bank[1]);
|
||||
SetVROM_1K_Bank(10, bank[2]);
|
||||
SetVROM_1K_Bank(11, bank[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mir_type == 0)
|
||||
{
|
||||
SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
else
|
||||
if (mir_type == 1)
|
||||
{
|
||||
SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper090::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
INT i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p[i] = prg_reg[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
p[i + 4] = chh_reg[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
p[i + 12] = chl_reg[i];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p[i + 20] = nth_reg[i];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p[i + 24] = ntl_reg[i];
|
||||
}
|
||||
p[28] = irq_enable;
|
||||
p[29] = irq_counter;
|
||||
p[30] = irq_latch;
|
||||
p[31] = prg_6000;
|
||||
p[32] = prg_E000;
|
||||
p[33] = prg_size;
|
||||
p[34] = chr_size;
|
||||
p[35] = mir_mode;
|
||||
p[36] = mir_type;
|
||||
p[37] = mul_val1;
|
||||
p[38] = mul_val2;
|
||||
p[39] = key_val;
|
||||
p[40] = irq_occur;
|
||||
p[41] = irq_preset;
|
||||
p[42] = irq_offset;
|
||||
}
|
||||
|
||||
//void Mapper090::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
INT i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
prg_reg[i] = p[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chh_reg[i] = p[i + 4];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chl_reg[i] = p[i + 12];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
nth_reg[i] = p[i + 20];
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
ntl_reg[i] = p[i + 24];
|
||||
}
|
||||
irq_enable = p[28];
|
||||
irq_counter = p[29];
|
||||
irq_latch = p[30];
|
||||
prg_6000 = p[31];
|
||||
prg_E000 = p[32];
|
||||
prg_size = p[33];
|
||||
chr_size = p[34];
|
||||
mir_mode = p[35];
|
||||
mir_type = p[36];
|
||||
mul_val1 = p[37];
|
||||
mul_val2 = p[38];
|
||||
key_val = p[39];
|
||||
irq_occur = p[40];
|
||||
irq_preset = p[41];
|
||||
irq_offset = p[42];
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,68 +7,70 @@ using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
using VirtualNes.Core.Debug;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper092 : Mapper
|
||||
{
|
||||
public Mapper092(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
if (VROM_8K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper092::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//DEBUGOUT( "A:%04X D:%02X\n", addr, data );
|
||||
|
||||
data = (byte)(addr & 0xFF);
|
||||
|
||||
if (addr >= 0x9000)
|
||||
{
|
||||
if ((data & 0xF0) == 0xD0)
|
||||
{
|
||||
SetPROM_16K_Bank(6, data & 0x0F);
|
||||
}
|
||||
else if ((data & 0xF0) == 0xE0)
|
||||
{
|
||||
SetVROM_8K_Bank(data & 0x0F);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((data & 0xF0) == 0xB0)
|
||||
{
|
||||
SetPROM_16K_Bank(6, data & 0x0F);
|
||||
}
|
||||
else if ((data & 0xF0) == 0x70)
|
||||
{
|
||||
SetVROM_8K_Bank(data & 0x0F);
|
||||
}
|
||||
else if ((data & 0xF0) == 0xC0)
|
||||
{
|
||||
INT[] tbl = new int[]{ 3, 4, 5, 6, 0, 1, 2, 7,
|
||||
9,10, 8,11,13,12,14,15 };
|
||||
|
||||
// OSDにするべきか…
|
||||
if (Config.sound.bExtraSoundEnable)
|
||||
{
|
||||
DEBUGOUT("CODE %02X\n", data);
|
||||
DirectSound.EsfAllStop();
|
||||
DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + tbl[data & 0x0F]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
public class Mapper092 : Mapper
|
||||
{
|
||||
public Mapper092(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
if (VROM_8K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper092::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//DEBUGOUT( "A:%04X D:%02X\n", addr, data );
|
||||
|
||||
data = (byte)(addr & 0xFF);
|
||||
|
||||
if (addr >= 0x9000)
|
||||
{
|
||||
if ((data & 0xF0) == 0xD0)
|
||||
{
|
||||
SetPROM_16K_Bank(6, data & 0x0F);
|
||||
}
|
||||
else if ((data & 0xF0) == 0xE0)
|
||||
{
|
||||
SetVROM_8K_Bank(data & 0x0F);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((data & 0xF0) == 0xB0)
|
||||
{
|
||||
SetPROM_16K_Bank(6, data & 0x0F);
|
||||
}
|
||||
else if ((data & 0xF0) == 0x70)
|
||||
{
|
||||
SetVROM_8K_Bank(data & 0x0F);
|
||||
}
|
||||
else if ((data & 0xF0) == 0xC0)
|
||||
{
|
||||
INT[] tbl = new int[]{ 3, 4, 5, 6, 0, 1, 2, 7,
|
||||
9,10, 8,11,13,12,14,15 };
|
||||
|
||||
// OSDにするべきか…
|
||||
if (Supporter.Config.sound.bExtraSoundEnable)
|
||||
{
|
||||
//TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
|
||||
Debuger.Log($"CODE {data:X2}");
|
||||
//DirectSound.EsfAllStop();
|
||||
//DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + tbl[data & 0x0F]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class _MapName : Mapper
|
||||
public class Mapper107 : Mapper
|
||||
{
|
||||
public _MapName(NES parent) : base(parent)
|
||||
public Mapper107(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,291 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper111 Nintendo MMC1 Hack //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper111 : Mapper
|
||||
{
|
||||
|
||||
ushort last_addr;
|
||||
|
||||
BYTE patch;
|
||||
BYTE wram_patch;
|
||||
BYTE wram_bank;
|
||||
BYTE wram_count;
|
||||
|
||||
BYTE[] reg = new byte[4];
|
||||
BYTE shift, regbuf;
|
||||
|
||||
public Mapper111(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
reg[0] = 0x0C; // D3=1,D2=1
|
||||
reg[1] = reg[2] = reg[3] = 0;
|
||||
shift = regbuf = 0;
|
||||
|
||||
patch = 0;
|
||||
wram_patch = 0;
|
||||
|
||||
if (PROM_16K_SIZE < 32)
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For 512K/1M byte Cartridge
|
||||
SetPROM_16K_Bank(4, 0);
|
||||
SetPROM_16K_Bank(6, 16 - 1);
|
||||
|
||||
patch = 1;
|
||||
}
|
||||
|
||||
if (VROM_8K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
|
||||
// Ninja Ryukenden(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
|
||||
//void Mapper111::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
// DEBUGOUT( "MMC1 %04X=%02X\n", addr&0xFFFF,data&0xFF );
|
||||
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
shift = regbuf = 0;
|
||||
reg[0] |= 0x0C; // D3=1,D2=1 残りはリセットされない
|
||||
return;
|
||||
}
|
||||
|
||||
addr = (ushort)((addr & 0x7FFF) >> 13);
|
||||
reg[addr] = data;
|
||||
|
||||
// DEBUGOUT( "MMC1 %d=%02X\n", addr&0xFFFF,regbuf&0xFF );
|
||||
|
||||
if (patch != 1)
|
||||
{
|
||||
// For Normal Cartridge
|
||||
switch (addr)
|
||||
{
|
||||
case 0:
|
||||
if ((reg[0] & 0x02) != 0)
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Register #1
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank lower($0000-$0FFF)
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
// CHR 4K bank higher($1000-$1FFF)
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHR 8K bank($0000-$1FFF)
|
||||
SetVROM_8K_Bank(reg[1] >> 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Register #2
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank lower($0000-$0FFF)
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
// CHR 4K bank higher($1000-$1FFF)
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHR 8K bank($0000-$1FFF)
|
||||
SetVROM_8K_Bank(reg[1] >> 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ((reg[0] & 0x08) == 0)
|
||||
{
|
||||
// PRG 32K bank ($8000-$FFFF)
|
||||
SetPROM_32K_Bank(reg[3] >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x04) != 0)
|
||||
{
|
||||
// PRG 16K bank ($8000-$BFFF)
|
||||
SetPROM_16K_Bank(4, reg[3]);
|
||||
SetPROM_16K_Bank(6, PROM_16K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PRG 16K bank ($C000-$FFFF)
|
||||
SetPROM_16K_Bank(6, reg[3]);
|
||||
SetPROM_16K_Bank(4, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For 512K/1M byte Cartridge
|
||||
INT PROM_BASE = 0;
|
||||
if (PROM_16K_SIZE >= 32)
|
||||
{
|
||||
PROM_BASE = reg[1] & 0x10;
|
||||
}
|
||||
|
||||
// Register #0
|
||||
if (addr == 0)
|
||||
{
|
||||
if ((reg[0] & 0x02) != 0)
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
}
|
||||
// Register #1
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank lower($0000-$0FFF)
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHR 8K bank($0000-$1FFF)
|
||||
SetVROM_8K_Bank(reg[1] >> 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
}
|
||||
// Register #2
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank higher($1000-$1FFF)
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
}
|
||||
// Register #3
|
||||
if ((reg[0] & 0x08) == 0)
|
||||
{
|
||||
// PRG 32K bank ($8000-$FFFF)
|
||||
SetPROM_32K_Bank((reg[3] & (0xF + PROM_BASE)) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x04) != 0)
|
||||
{
|
||||
// PRG 16K bank ($8000-$BFFF)
|
||||
SetPROM_16K_Bank(4, PROM_BASE + (reg[3] & 0x0F));
|
||||
if (PROM_16K_SIZE >= 32) SetPROM_16K_Bank(6, PROM_BASE + 16 - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PRG 16K bank ($C000-$FFFF)
|
||||
SetPROM_16K_Bank(6, PROM_BASE + (reg[3] & 0x0F));
|
||||
if (PROM_16K_SIZE >= 32) SetPROM_16K_Bank(4, PROM_BASE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper111::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = reg[0];
|
||||
p[1] = reg[1];
|
||||
p[2] = reg[2];
|
||||
p[3] = reg[3];
|
||||
p[4] = shift;
|
||||
p[5] = regbuf;
|
||||
|
||||
p[6] = wram_bank;
|
||||
p[7] = wram_count;
|
||||
}
|
||||
|
||||
//void Mapper111::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
reg[0] = p[0];
|
||||
reg[1] = p[1];
|
||||
reg[2] = p[2];
|
||||
reg[3] = p[3];
|
||||
shift = p[4];
|
||||
regbuf = p[5];
|
||||
|
||||
wram_bank = p[6];
|
||||
wram_count = p[7];
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 554591bf0683358478fb48fe49a84697
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -7,6 +7,7 @@ using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
using VirtualNes.Core.Debug;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
@ -73,7 +74,7 @@ namespace VirtualNes.Core
|
||||
//void Mapper116::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
DEBUGOUT("MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr & 0xFFFF, data & 0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles());
|
||||
Debuger.Log($"MPRWR A={addr & 0xFFFF:X4} D={data & 0xFF:X2} L={nes.GetScanline(),3} CYC={nes.cpu.GetTotalCycles()}");
|
||||
if ((addr & 0x4100) == 0x4100)
|
||||
{
|
||||
ExChrSwitch = data;
|
||||
@ -84,7 +85,7 @@ namespace VirtualNes.Core
|
||||
//void Mapper116::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
DEBUGOUT("MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr & 0xFFFF, data & 0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles());
|
||||
Debuger.Log($"MPRWR A={addr & 0xFFFF:X4} D={data & 0xFF:X2} L={nes.GetScanline(),3} CYC={nes.cpu.GetTotalCycles()}");
|
||||
|
||||
switch (addr & 0xE001)
|
||||
{
|
||||
|
@ -7,125 +7,126 @@ using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
using VirtualNes.Core.Debug;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper162 : Mapper
|
||||
{
|
||||
BYTE reg5000;
|
||||
BYTE reg5100;
|
||||
BYTE reg5200;
|
||||
BYTE reg5300;
|
||||
public Mapper162(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
reg5000 = 0;
|
||||
reg5100 = 0;
|
||||
reg5200 = 0;
|
||||
reg5300 = 7;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
|
||||
//void Mapper162::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr == 0x5000)
|
||||
{
|
||||
reg5000 = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
else if (addr == 0x5100)
|
||||
{
|
||||
reg5100 = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
else if (addr == 0x5200)
|
||||
{
|
||||
reg5200 = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
else if (addr == 0x5300)
|
||||
{
|
||||
reg5300 = data;
|
||||
}
|
||||
else if (addr >= 0x6000)
|
||||
{
|
||||
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGOUT("write to %04x:%02x\n", addr, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
BYTE bank = 0;
|
||||
switch (reg5300)
|
||||
{
|
||||
case 4:
|
||||
bank = (byte)((((reg5000 & 0xF) + ((reg5100 & 3) >> 1)) | ((reg5200 & 1) << 4)));
|
||||
break;
|
||||
case 7:
|
||||
bank = (byte)(((reg5000 & 0xF) | ((reg5200 & 1) << 4)));
|
||||
break;
|
||||
}
|
||||
SetPROM_32K_Bank((byte)bank);
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
SetCRAM_8K_Bank(0);
|
||||
}
|
||||
|
||||
//void Mapper162::HSync(int scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((reg5000 & 0x80) != 0 && nes.ppu.IsDispON())
|
||||
{
|
||||
if (scanline < 127)
|
||||
{
|
||||
// SetCRAM_4K_Bank(0, 0);
|
||||
SetCRAM_4K_Bank(4, 0);
|
||||
}
|
||||
else if (scanline < 240)
|
||||
{
|
||||
// SetCRAM_4K_Bank(0, 1);
|
||||
SetCRAM_4K_Bank(4, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//void Mapper162::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = reg5000;
|
||||
p[1] = reg5100;
|
||||
p[2] = reg5200;
|
||||
p[3] = reg5300;
|
||||
}
|
||||
|
||||
//void Mapper162::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
reg5000 = p[0];
|
||||
reg5100 = p[1];
|
||||
reg5200 = p[2];
|
||||
reg5300 = p[3];
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{
|
||||
public class Mapper162 : Mapper
|
||||
{
|
||||
BYTE reg5000;
|
||||
BYTE reg5100;
|
||||
BYTE reg5200;
|
||||
BYTE reg5300;
|
||||
public Mapper162(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
reg5000 = 0;
|
||||
reg5100 = 0;
|
||||
reg5200 = 0;
|
||||
reg5300 = 7;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
|
||||
//void Mapper162::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr == 0x5000)
|
||||
{
|
||||
reg5000 = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
else if (addr == 0x5100)
|
||||
{
|
||||
reg5100 = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
else if (addr == 0x5200)
|
||||
{
|
||||
reg5200 = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
}
|
||||
else if (addr == 0x5300)
|
||||
{
|
||||
reg5300 = data;
|
||||
}
|
||||
else if (addr >= 0x6000)
|
||||
{
|
||||
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debuger.Log($"write to {addr:X4}:{data:X2}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
BYTE bank = 0;
|
||||
switch (reg5300)
|
||||
{
|
||||
case 4:
|
||||
bank = (byte)((((reg5000 & 0xF) + ((reg5100 & 3) >> 1)) | ((reg5200 & 1) << 4)));
|
||||
break;
|
||||
case 7:
|
||||
bank = (byte)(((reg5000 & 0xF) | ((reg5200 & 1) << 4)));
|
||||
break;
|
||||
}
|
||||
SetPROM_32K_Bank((byte)bank);
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
SetCRAM_8K_Bank(0);
|
||||
}
|
||||
|
||||
//void Mapper162::HSync(int scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((reg5000 & 0x80) != 0 && nes.ppu.IsDispON())
|
||||
{
|
||||
if (scanline < 127)
|
||||
{
|
||||
// SetCRAM_4K_Bank(0, 0);
|
||||
SetCRAM_4K_Bank(4, 0);
|
||||
}
|
||||
else if (scanline < 240)
|
||||
{
|
||||
// SetCRAM_4K_Bank(0, 1);
|
||||
SetCRAM_4K_Bank(4, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//void Mapper162::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = reg5000;
|
||||
p[1] = reg5100;
|
||||
p[2] = reg5200;
|
||||
p[3] = reg5300;
|
||||
}
|
||||
|
||||
//void Mapper162::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
reg5000 = p[0];
|
||||
reg5100 = p[1];
|
||||
reg5200 = p[2];
|
||||
reg5300 = p[3];
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace VirtualNes.Core
|
||||
BYTE laststrobe, trigger;
|
||||
BYTE[] reg = new byte[8];
|
||||
public Mapper163(NES parent) : base(parent)
|
||||
{
|
||||
{
|
||||
/*
|
||||
reg[1] = 0xFF;
|
||||
strobe = 1;
|
||||
@ -36,8 +36,9 @@ namespace VirtualNes.Core
|
||||
if( crc == 0xf52468e7 ) { // San Guo Wu Shuang - Meng Jiang Zhuan (NJ047) (Ch) [dump]
|
||||
rom_type = 1;
|
||||
}
|
||||
*/
|
||||
memset(reg, 0, 8);
|
||||
*/
|
||||
|
||||
MemoryUtility.ZEROMEMORY(reg, reg.Length);
|
||||
laststrobe = 1;
|
||||
SetPROM_32K_Bank((reg[0] << 4) | (reg[1] & 0xF));
|
||||
//SetPROM_32K_Bank(0);
|
||||
|
@ -7,6 +7,7 @@ using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
using Codice.CM.Client.Differences;
|
||||
using VirtualNes.Core.Debug;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
@ -20,13 +21,12 @@ namespace VirtualNes.Core
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
|
||||
{
|
||||
reg5000 = 0;
|
||||
reg5100 = 0;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
nes.ppu.SetExtLatchMode(TRUE);
|
||||
nes.ppu.SetExtLatchMode(true);
|
||||
}
|
||||
|
||||
//void Mapper164::WriteLow(WORD addr, BYTE data)
|
||||
@ -51,7 +51,7 @@ namespace VirtualNes.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGOUT("write to %04x:%02x\n", addr, data);
|
||||
Debuger.Log($"write to {addr:X4}:{data:X2}");
|
||||
}
|
||||
|
||||
}
|
||||
@ -74,11 +74,11 @@ namespace VirtualNes.Core
|
||||
bank += (reg5000 & 0x20) >> 1;
|
||||
SetPROM_16K_Bank(4, bank + @base);
|
||||
SetPROM_16K_Bank(6, @base + 0x1f);
|
||||
DEBUGOUT("-- normal mode: mode=%d, bank=%d --\n", mode, bank);
|
||||
Debuger.Log($"-- normal mode: mode={mode}, bank={bank} --");
|
||||
break;
|
||||
case 1:
|
||||
case 3: /* REG MODE */
|
||||
DEBUGOUT("-- reg mode --\n");
|
||||
Debuger.Log("-- reg mode --");
|
||||
break;
|
||||
case 5: /* 32K MODE */
|
||||
bank = (reg5000 & 0x0f);
|
||||
@ -91,7 +91,7 @@ namespace VirtualNes.Core
|
||||
SetPROM_16K_Bank(4, bank + @base);
|
||||
bank = (bank & 0x10) + 0x0f;
|
||||
SetPROM_16K_Bank(6, @base + 0x1f);
|
||||
DEBUGOUT("-- half mode --\n");
|
||||
Debuger.Log("-- half mode --");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -116,18 +116,19 @@ namespace VirtualNes.Core
|
||||
{
|
||||
INT loopy_v = nes.ppu.GetPPUADDR();
|
||||
INT loopy_y = nes.ppu.GetTILEY();
|
||||
INT tileofs = (PPUREG[0] & PPU_BGTBL_BIT) << 8;
|
||||
INT tileofs = (PPUREG[0] & PPU.PPU_BGTBL_BIT) << 8;
|
||||
INT attradr = 0x23C0 + (loopy_v & 0x0C00) + ((loopy_v & 0x0380) >> 4);
|
||||
INT attrsft = (ntbladr & 0x0040) >> 4;
|
||||
LPBYTE pNTBL = PPU_MEM_BANK[ntbladr >> 10];
|
||||
Span<byte> pNTBL = PPU_MEM_BANK[ntbladr >> 10];
|
||||
|
||||
INT ntbl_x = ntbladr & 0x001F;
|
||||
INT tileadr;
|
||||
|
||||
attradr &= 0x3FF;
|
||||
attr = ((pNTBL[attradr + (ntbl_x >> 2)] >> ((ntbl_x & 2) + attrsft)) & 3) << 2;
|
||||
attr = (byte)(((pNTBL[attradr + (ntbl_x >> 2)] >> ((ntbl_x & 2) + attrsft)) & 3) << 2);
|
||||
tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y;
|
||||
|
||||
if (p_mode)
|
||||
if (p_mode != 0)
|
||||
{
|
||||
tileadr = (tileadr & 0xfff7) | a3;
|
||||
chr_l = chr_h = PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
|
||||
|
@ -41,7 +41,7 @@ namespace VirtualNes.Core
|
||||
|
||||
we_sram = 0; // Disable
|
||||
|
||||
nes->ppu->SetChrLatchMode(TRUE);
|
||||
nes.ppu.SetChrLatchMode(true);
|
||||
}
|
||||
|
||||
//void Mapper165::Write(WORD addr, BYTE data)
|
||||
|
@ -7,52 +7,52 @@ using Codice.CM.Client.Differences;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper176 : Mapper
|
||||
{
|
||||
BYTE prg, chr;
|
||||
public Mapper176(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
//prg = ~0;
|
||||
prg = (~0);
|
||||
chr = 0;
|
||||
Sync();
|
||||
}
|
||||
|
||||
void Sync()
|
||||
{
|
||||
//setprg8r(0x10,0x6000,0);
|
||||
SetPROM_32K_Bank(prg >> 1);
|
||||
SetVROM_8K_Bank(chr);
|
||||
}
|
||||
|
||||
//void Mapper176::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x5ff1:
|
||||
prg = data; Sync();
|
||||
break;
|
||||
case 0x5ff2:
|
||||
chr = data; Sync();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (addr >= 0x6000)
|
||||
{
|
||||
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{
|
||||
public class Mapper176 : Mapper
|
||||
{
|
||||
BYTE prg, chr;
|
||||
public Mapper176(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
//prg = ~0;
|
||||
prg = unchecked((byte)(~0));
|
||||
chr = 0;
|
||||
Sync();
|
||||
}
|
||||
|
||||
void Sync()
|
||||
{
|
||||
//setprg8r(0x10,0x6000,0);
|
||||
SetPROM_32K_Bank(prg >> 1);
|
||||
SetVROM_8K_Bank(chr);
|
||||
}
|
||||
|
||||
//void Mapper176::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x5ff1:
|
||||
prg = data; Sync();
|
||||
break;
|
||||
case 0x5ff2:
|
||||
chr = data; Sync();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (addr >= 0x6000)
|
||||
{
|
||||
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,236 +11,236 @@ using Codice.CM.Client.Differences;
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper199 : Mapper
|
||||
{
|
||||
BYTE[] reg = new byte[8];
|
||||
BYTE[] prg = new byte[4];
|
||||
BYTE[] chr = new byte[8];
|
||||
BYTE we_sram;
|
||||
|
||||
BYTE irq_type;
|
||||
BYTE irq_enable;
|
||||
BYTE irq_counter;
|
||||
BYTE irq_latch;
|
||||
BYTE irq_request;
|
||||
public Mapper199(NES parent) : base(parent)
|
||||
{
|
||||
BYTE[] reg = new byte[8];
|
||||
BYTE[] prg = new byte[4];
|
||||
BYTE[] chr = new byte[8];
|
||||
BYTE we_sram;
|
||||
|
||||
BYTE irq_type;
|
||||
BYTE irq_enable;
|
||||
BYTE irq_counter;
|
||||
BYTE irq_latch;
|
||||
BYTE irq_request;
|
||||
public Mapper199(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
reg[i] = 0x00;
|
||||
chr[i] = (byte)i;
|
||||
}
|
||||
prg[0] = 0x00;
|
||||
prg[1] = 0x01;
|
||||
prg[2] = 0x3e;
|
||||
prg[3] = 0x3f;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
|
||||
we_sram = 0;
|
||||
irq_enable = irq_counter = irq_latch = irq_request = 0;
|
||||
|
||||
|
||||
uint crcP = nes.rom.GetPROM_CRC();
|
||||
uint crcV = nes.rom.GetVROM_CRC();
|
||||
|
||||
if ((crcP == 0xE80D8741) || (crcV == 0x3846520D))
|
||||
{//ÍâÐÇ°ÔÍõµÄ´ó½
|
||||
nes.SetRenderMethod( EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//BYTE Mapper199::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
if (addr >= 0x5000 && addr <= 0x5FFF)
|
||||
{
|
||||
return XRAM[addr - 0x4000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper199::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr >= 0x5000 && addr <= 0x5FFF)
|
||||
{
|
||||
XRAM[addr - 0x4000] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper199::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles() );
|
||||
|
||||
switch (addr & 0xE001)
|
||||
{
|
||||
case 0x8000:
|
||||
reg[0] = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x8001:
|
||||
reg[1] = data;
|
||||
|
||||
switch (reg[0] & 0x0f)
|
||||
{
|
||||
case 0x00: chr[0] = data; SetBank_PPU(); break;
|
||||
case 0x01: chr[2] = data; SetBank_PPU(); break;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05: chr[(reg[0] & 0x07) + 2] = data; SetBank_PPU(); break;
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x08:
|
||||
case 0x09: prg[(reg[0] & 0x0f) - 6] = data; SetBank_CPU(); break;
|
||||
case 0x0A: chr[1] = data; SetBank_PPU(); break;
|
||||
case 0x0B: chr[3] = data; SetBank_PPU(); break;
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
reg[2] = data;
|
||||
//if( !nes.rom.Is4SCREEN() )
|
||||
{
|
||||
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
}
|
||||
break;
|
||||
case 0xA001:
|
||||
reg[3] = data;
|
||||
break;
|
||||
case 0xC000:
|
||||
reg[4] = data;
|
||||
irq_counter = data;
|
||||
irq_request = 0;
|
||||
break;
|
||||
case 0xC001:
|
||||
reg[5] = data;
|
||||
irq_latch = data;
|
||||
irq_request = 0;
|
||||
break;
|
||||
case 0xE000:
|
||||
reg[6] = data;
|
||||
irq_enable = 0;
|
||||
irq_request = 0;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0xE001:
|
||||
reg[7] = data;
|
||||
irq_enable = 1;
|
||||
irq_request = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//void Mapper199::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((scanline >= 0 && scanline <= 239))
|
||||
{
|
||||
if (nes.ppu.IsDispON())
|
||||
{
|
||||
if (irq_enable != 0 && irq_request == 0)
|
||||
{
|
||||
if (scanline == 0)
|
||||
{
|
||||
if (irq_counter != 0)
|
||||
{
|
||||
irq_counter--;
|
||||
}
|
||||
}
|
||||
if ((irq_counter--) == 0)
|
||||
{
|
||||
irq_request = 0xFF;
|
||||
irq_counter = irq_latch;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
SetPROM_8K_Bank(4, prg[0 ^ (reg[0] >> 5 & ~(0 << 1) & 2)]);
|
||||
SetPROM_8K_Bank(5, prg[1 ^ (reg[0] >> 5 & ~(1 << 1) & 2)]);
|
||||
SetPROM_8K_Bank(6, prg[2 ^ (reg[0] >> 5 & ~(2 << 1) & 2)]);
|
||||
SetPROM_8K_Bank(7, prg[3 ^ (reg[0] >> 5 & ~(3 << 1) & 2)]);
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
//unsigned int bank = (reg[0] & 0x80) >> 5;
|
||||
int bank = (reg[0] & 0x80) >> 5;
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
if (chr[x] <= 7)
|
||||
{
|
||||
SetCRAM_1K_Bank((byte)(x ^ bank), chr[x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVROM_1K_Bank((byte)(x ^ bank), chr[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper199::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
p[i] = reg[i];
|
||||
p[10 + i] = chr[i];
|
||||
}
|
||||
|
||||
p[8] = prg[0];
|
||||
p[9] = prg[1];
|
||||
p[18] = irq_enable;
|
||||
p[19] = irq_counter;
|
||||
p[20] = irq_latch;
|
||||
p[21] = irq_request;
|
||||
p[22] = prg[2];
|
||||
p[23] = prg[3];
|
||||
}
|
||||
|
||||
//void Mapper199::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
reg[i] = p[i];
|
||||
chr[i] = p[10 + i];
|
||||
}
|
||||
prg[0] = p[8];
|
||||
prg[1] = p[9];
|
||||
irq_enable = p[18];
|
||||
irq_counter = p[19];
|
||||
irq_latch = p[20];
|
||||
irq_request = p[21];
|
||||
prg[2] = p[22];
|
||||
prg[3] = p[23];
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override void Reset()
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
reg[i] = 0x00;
|
||||
chr[i] = (byte)i;
|
||||
}
|
||||
prg[0] = 0x00;
|
||||
prg[1] = 0x01;
|
||||
prg[2] = 0x3e;
|
||||
prg[3] = 0x3f;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
|
||||
we_sram = 0;
|
||||
irq_enable = irq_counter = irq_latch = irq_request = 0;
|
||||
|
||||
|
||||
uint crcP = nes.rom.GetPROM_CRC();
|
||||
uint crcV = nes.rom.GetVROM_CRC();
|
||||
|
||||
if ((crcP == 0xE80D8741) || (crcV == 0x3846520D))
|
||||
{//ÍâÐÇ°ÔÍõµÄ´ó½
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//BYTE Mapper199::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
if (addr >= 0x5000 && addr <= 0x5FFF)
|
||||
{
|
||||
return XRAM[addr - 0x4000];
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.ReadLow(addr);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper199::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr >= 0x5000 && addr <= 0x5FFF)
|
||||
{
|
||||
XRAM[addr - 0x4000] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper199::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles() );
|
||||
|
||||
switch (addr & 0xE001)
|
||||
{
|
||||
case 0x8000:
|
||||
reg[0] = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x8001:
|
||||
reg[1] = data;
|
||||
|
||||
switch (reg[0] & 0x0f)
|
||||
{
|
||||
case 0x00: chr[0] = data; SetBank_PPU(); break;
|
||||
case 0x01: chr[2] = data; SetBank_PPU(); break;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05: chr[(reg[0] & 0x07) + 2] = data; SetBank_PPU(); break;
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x08:
|
||||
case 0x09: prg[(reg[0] & 0x0f) - 6] = data; SetBank_CPU(); break;
|
||||
case 0x0A: chr[1] = data; SetBank_PPU(); break;
|
||||
case 0x0B: chr[3] = data; SetBank_PPU(); break;
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
reg[2] = data;
|
||||
//if( !nes.rom.Is4SCREEN() )
|
||||
{
|
||||
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
}
|
||||
break;
|
||||
case 0xA001:
|
||||
reg[3] = data;
|
||||
break;
|
||||
case 0xC000:
|
||||
reg[4] = data;
|
||||
irq_counter = data;
|
||||
irq_request = 0;
|
||||
break;
|
||||
case 0xC001:
|
||||
reg[5] = data;
|
||||
irq_latch = data;
|
||||
irq_request = 0;
|
||||
break;
|
||||
case 0xE000:
|
||||
reg[6] = data;
|
||||
irq_enable = 0;
|
||||
irq_request = 0;
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0xE001:
|
||||
reg[7] = data;
|
||||
irq_enable = 1;
|
||||
irq_request = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//void Mapper199::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((scanline >= 0 && scanline <= 239))
|
||||
{
|
||||
if (nes.ppu.IsDispON())
|
||||
{
|
||||
if (irq_enable != 0 && irq_request == 0)
|
||||
{
|
||||
if (scanline == 0)
|
||||
{
|
||||
if (irq_counter != 0)
|
||||
{
|
||||
irq_counter--;
|
||||
}
|
||||
}
|
||||
if ((irq_counter--) == 0)
|
||||
{
|
||||
irq_request = 0xFF;
|
||||
irq_counter = irq_latch;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
SetPROM_8K_Bank(4, prg[0 ^ (reg[0] >> 5 & ~(0 << 1) & 2)]);
|
||||
SetPROM_8K_Bank(5, prg[1 ^ (reg[0] >> 5 & ~(1 << 1) & 2)]);
|
||||
SetPROM_8K_Bank(6, prg[2 ^ (reg[0] >> 5 & ~(2 << 1) & 2)]);
|
||||
SetPROM_8K_Bank(7, prg[3 ^ (reg[0] >> 5 & ~(3 << 1) & 2)]);
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
//unsigned int bank = (reg[0] & 0x80) >> 5;
|
||||
int bank = (reg[0] & 0x80) >> 5;
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
if (chr[x] <= 7)
|
||||
{
|
||||
SetCRAM_1K_Bank((byte)(x ^ bank), chr[x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVROM_1K_Bank((byte)(x ^ bank), chr[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper199::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
p[i] = reg[i];
|
||||
p[10 + i] = chr[i];
|
||||
}
|
||||
|
||||
p[8] = prg[0];
|
||||
p[9] = prg[1];
|
||||
p[18] = irq_enable;
|
||||
p[19] = irq_counter;
|
||||
p[20] = irq_latch;
|
||||
p[21] = irq_request;
|
||||
p[22] = prg[2];
|
||||
p[23] = prg[3];
|
||||
}
|
||||
|
||||
//void Mapper199::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
reg[i] = p[i];
|
||||
chr[i] = p[10 + i];
|
||||
}
|
||||
prg[0] = p[8];
|
||||
prg[1] = p[9];
|
||||
irq_enable = p[18];
|
||||
irq_counter = p[19];
|
||||
irq_latch = p[20];
|
||||
irq_request = p[21];
|
||||
prg[2] = p[22];
|
||||
prg[3] = p[23];
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace VirtualNes.Core
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 2, 3);
|
||||
|
||||
if (VROM_1K_SIZE)
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class _MapName : Mapper
|
||||
{
|
||||
public _MapName(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -2,19 +2,17 @@
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class _Mapper : Mapper
|
||||
{
|
||||
public _Mapper(NES parent) : base(parent)
|
||||
{
|
||||
}
|
||||
public class _Mapper : Mapper
|
||||
{
|
||||
|
||||
public _Mapper(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
public override void Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a56d9f749be056e4b9ccf087899369ad
|
||||
guid: 5886971893af9a84581da5bc1ff575e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
@ -324,7 +324,7 @@ namespace VirtualNes.Core
|
||||
}
|
||||
}
|
||||
|
||||
private int GetIrqType()
|
||||
internal int GetIrqType()
|
||||
{
|
||||
return nIRQtype;
|
||||
}
|
||||
@ -1668,6 +1668,16 @@ namespace VirtualNes.Core
|
||||
return NES_scanline;
|
||||
}
|
||||
|
||||
internal void SetSAVERAM_SIZE(int size)
|
||||
{
|
||||
SAVERAM_SIZE = size;
|
||||
}
|
||||
|
||||
internal byte GetBarcodeStatus()
|
||||
{
|
||||
return m_BarcodeOut;
|
||||
}
|
||||
|
||||
public enum IRQMETHOD
|
||||
{
|
||||
IRQ_HSYNC = 0, IRQ_CLOCK = 1
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace VirtualNes.Core
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class PPU
|
||||
{
|
||||
@ -1125,6 +1127,26 @@
|
||||
return (MMU.PPUREG[1] & (PPU_BGDISP_BIT | PPU_SPDISP_BIT)) != 0;
|
||||
}
|
||||
|
||||
internal void SetExtLatchMode(bool bMode)
|
||||
{
|
||||
bExtLatch = bMode;
|
||||
}
|
||||
|
||||
internal ushort GetPPUADDR()
|
||||
{
|
||||
return MMU.loopy_v;
|
||||
}
|
||||
|
||||
internal ushort GetTILEY()
|
||||
{
|
||||
return loopy_y;
|
||||
}
|
||||
|
||||
internal void SetChrLatchMode(bool bMode)
|
||||
{
|
||||
bChrLatch = bMode;
|
||||
}
|
||||
|
||||
public struct Sprite
|
||||
{
|
||||
public byte y
|
||||
|
@ -401,6 +401,11 @@ namespace VirtualNes.Core
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
internal uint GetVROM_CRC()
|
||||
{
|
||||
return crcvrom;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user