Mapper补全 #21

Merged
sin365 merged 1 commits from Alienjack/AxibugEmuOnline:dev_4VirtualNes into dev_4VirtualNes 2024-08-05 11:55:09 +08:00
26 changed files with 2516 additions and 1881 deletions
Showing only changes of commit ba8b656914 - Show all commits

View File

@ -502,6 +502,35 @@ namespace VirtualNes.Core
Debuger.LogError("exqueue overflow."); 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 public struct QUEUEDATA

View File

@ -38,9 +38,62 @@ namespace VirtualNes.Core
//todo : 实现 //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 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;
} }
} }
} }

View File

@ -4,6 +4,9 @@ namespace VirtualNes.Core
{ {
public class APU_MMC5 : APU_INTERFACE public class APU_MMC5 : APU_INTERFACE
{ {
SYNCRECTANGLE sch0 = new SYNCRECTANGLE();
SYNCRECTANGLE sch1 = new SYNCRECTANGLE();
public override void Reset(float fClock, int nRate) public override void Reset(float fClock, int nRate)
{ {
//todo : 实现 //todo : 实现
@ -29,5 +32,28 @@ namespace VirtualNes.Core
{ {
//todo : 实现 //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;
}
} }
} }

View File

@ -1,4 +1,6 @@
namespace VirtualNes.Core using System;
namespace VirtualNes.Core
{ {
public class ByteArrayRef public class ByteArrayRef
{ {
@ -22,6 +24,9 @@
SetArray(array, offset, length); 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) public void SetArray(byte[] array, int offset, int length)
{ {
m_rawArray = array; m_rawArray = array;
@ -40,5 +45,15 @@
m_rawArray[(m_offset + index)] = value; 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);
}
} }
} }

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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be5901dc72f4b6045a7c33edba28145f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,430 +1,429 @@
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Mapper016 Bandai Standard // // Mapper016 Bandai Standard //
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
using static VirtualNes.MMU;
using static VirtualNes.Core.CPU; using static VirtualNes.Core.CPU;
using INT = System.Int32; using static VirtualNes.MMU;
using BYTE = System.Byte; using BYTE = System.Byte;
using Codice.CM.Client.Differences; using INT = System.Int32;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper016 : Mapper public class Mapper016 : Mapper
{ {
BYTE patch; // For Famicom Jump 2 BYTE patch; // For Famicom Jump 2
BYTE eeprom_type; // EEPROM type BYTE eeprom_type; // EEPROM type
BYTE[] reg = new byte[3]; BYTE[] reg = new byte[3];
BYTE irq_enable; BYTE irq_enable;
INT irq_counter; INT irq_counter;
INT irq_latch; INT irq_latch;
BYTE irq_type; BYTE irq_type;
X24C01 x24c01; X24C01 x24c01;
X24C02 x24c02; X24C02 x24c02;
public Mapper016(NES parent) : base(parent) public Mapper016(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
patch = 0; patch = 0;
reg[0] = reg[1] = reg[2] = 0; reg[0] = reg[1] = reg[2] = 0;
irq_enable = 0; irq_enable = 0;
irq_counter = 0; irq_counter = 0;
irq_latch = 0; irq_latch = 0;
irq_type = 0; irq_type = 0;
nes.SetIrqType( NES.IRQMETHOD.IRQ_CLOCK); nes.SetIrqType(NES.IRQMETHOD.IRQ_CLOCK);
eeprom_type = 0; eeprom_type = 0;
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
uint crc = nes.rom.GetPROM_CRC(); uint crc = nes.rom.GetPROM_CRC();
if (crc == 0x3f15d20d // Famicom Jump 2(J) if (crc == 0x3f15d20d // Famicom Jump 2(J)
|| crc == 0xf76aa523) || crc == 0xf76aa523)
{ // Famicom Jump 2(J)(alt) { // Famicom Jump 2(J)(alt)
patch = 1; patch = 1;
eeprom_type = 0xFF; eeprom_type = 0xFF;
WRAM[0x0BBC] = 0xFF; // SRAM対策 WRAM[0x0BBC] = 0xFF; // SRAM対策
} }
if (crc == 0x1d6f27f7) if (crc == 0x1d6f27f7)
{ // Dragon Ball Z 2(Korean Hack) { // Dragon Ball Z 2(Korean Hack)
nes.SetIrqType( NES.IRQMETHOD.IRQ_HSYNC); nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
eeprom_type = 1; eeprom_type = 1;
} }
if (crc == 0x6f7247c8) if (crc == 0x6f7247c8)
{ // Dragon Ball Z 3(Korean Hack) { // Dragon Ball Z 3(Korean Hack)
nes.SetIrqType( NES.IRQMETHOD.IRQ_CLOCK); nes.SetIrqType(NES.IRQMETHOD.IRQ_CLOCK);
eeprom_type = 1; eeprom_type = 1;
} }
if (crc == 0x7fb799fd) if (crc == 0x7fb799fd)
{ // Dragon Ball 2 - Dai Maou Fukkatsu(J) { // Dragon Ball 2 - Dai Maou Fukkatsu(J)
} }
if (crc == 0x6c6c2feb // Dragon Ball 3 - Gokuu Den(J) if (crc == 0x6c6c2feb // Dragon Ball 3 - Gokuu Den(J)
|| crc == 0x8edeb257) || crc == 0x8edeb257)
{ // Dragon Ball 3 - Gokuu Den(J)(Alt) { // Dragon Ball 3 - Gokuu Den(J)(Alt)
} }
if (crc == 0x31cd9903) if (crc == 0x31cd9903)
{ // Dragon Ball Z - Kyoushuu! Saiya Jin(J) { // Dragon Ball Z - Kyoushuu! Saiya Jin(J)
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC); nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
} }
if (crc == 0xe49fc53e // Dragon Ball Z 2 - Gekishin Freeza!!(J) if (crc == 0xe49fc53e // Dragon Ball Z 2 - Gekishin Freeza!!(J)
|| crc == 0x1582fee0) || crc == 0x1582fee0)
{ // Dragon Ball Z 2 - Gekishin Freeza!!(J) [alt] { // Dragon Ball Z 2 - Gekishin Freeza!!(J) [alt]
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC); nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
eeprom_type = 1; eeprom_type = 1;
} }
if (crc == 0x09499f4d) if (crc == 0x09499f4d)
{ // Dragon Ball Z 3 - Ressen Jinzou Ningen(J) { // Dragon Ball Z 3 - Ressen Jinzou Ningen(J)
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC); nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
eeprom_type = 1; eeprom_type = 1;
} }
if (crc == 0x2e991109) if (crc == 0x2e991109)
{ // Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (J) { // Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (J)
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC); nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
eeprom_type = 1; eeprom_type = 1;
} }
if (crc == 0x146fb9c3) if (crc == 0x146fb9c3)
{ // SD Gundam Gaiden - Knight Gundam Monogatari(J) { // SD Gundam Gaiden - Knight Gundam Monogatari(J)
} }
if (crc == 0x73ac76db // SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi(J) if (crc == 0x73ac76db // SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi(J)
|| crc == 0x81a15eb8) || crc == 0x81a15eb8)
{ // SD Gundam Gaiden - Knight Gundam Monogatari 3 - Densetsu no Kishi Dan(J) { // SD Gundam Gaiden - Knight Gundam Monogatari 3 - Densetsu no Kishi Dan(J)
eeprom_type = 1; eeprom_type = 1;
} }
if (crc == 0x170250de) if (crc == 0x170250de)
{ // Rokudenashi Blues(J) { // Rokudenashi Blues(J)
nes.SetRenderMethod( EnumRenderMethod.POST_ALL_RENDER); nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
eeprom_type = 1; eeprom_type = 1;
} }
// DATACH系 // DATACH系
if (crc == 0x0be0a328 // Datach - SD Gundam - Gundam Wars(J) if (crc == 0x0be0a328 // Datach - SD Gundam - Gundam Wars(J)
|| crc == 0x19e81461 // Datach - Dragon Ball Z - Gekitou Tenkaichi Budou Kai(J) || crc == 0x19e81461 // Datach - Dragon Ball Z - Gekitou Tenkaichi Budou Kai(J)
|| crc == 0x5b457641 // Datach - Ultraman Club - Supokon Fight!(J) || crc == 0x5b457641 // Datach - Ultraman Club - Supokon Fight!(J)
|| crc == 0x894efdbc // Datach - Crayon Shin Chan - Ora to Poi Poi(J) || crc == 0x894efdbc // Datach - Crayon Shin Chan - Ora to Poi Poi(J)
|| crc == 0x983d8175 // Datach - Battle Rush - Build Up Robot Tournament(J) || crc == 0x983d8175 // Datach - Battle Rush - Build Up Robot Tournament(J)
|| crc == 0xbe06853f) || crc == 0xbe06853f)
{ // Datach - J League Super Top Players(J) { // Datach - J League Super Top Players(J)
eeprom_type = 2; eeprom_type = 2;
} }
if (crc == 0xf51a7f46) if (crc == 0xf51a7f46)
{ // Datach - Yuu Yuu Hakusho - Bakutou Ankoku Bujutsu Kai(J) { // Datach - Yuu Yuu Hakusho - Bakutou Ankoku Bujutsu Kai(J)
nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC); nes.SetIrqType(NES.IRQMETHOD.IRQ_HSYNC);
eeprom_type = 2; eeprom_type = 2;
} }
if (eeprom_type == 0) if (eeprom_type == 0)
{ {
nes.SetSAVERAM_SIZE(128); nes.SetSAVERAM_SIZE(128);
x24c01.Reset(WRAM); x24c01.Reset(WRAM);
} }
else else
if (eeprom_type == 1) if (eeprom_type == 1)
{ {
nes.SetSAVERAM_SIZE(256); nes.SetSAVERAM_SIZE(256);
x24c02.Reset(WRAM); x24c02.Reset(WRAM);
} }
else else
if (eeprom_type == 2) if (eeprom_type == 2)
{ {
nes.SetSAVERAM_SIZE(384); nes.SetSAVERAM_SIZE(384);
x24c02.Reset(WRAM); x24c02.Reset(WRAM);
x24c01.Reset(WRAM + 256); x24c01.Reset(new ByteArrayRef(WRAM, 256));
} }
} }
//BYTE Mapper016::ReadLow(WORD addr) //BYTE Mapper016::ReadLow(WORD addr)
public override byte ReadLow(ushort addr) public override byte ReadLow(ushort addr)
{ {
if (patch!=0) if (patch != 0)
{ {
return base.ReadLow(addr); return base.ReadLow(addr);
} }
else else
{ {
if ((addr & 0x00FF) == 0x0000) if ((addr & 0x00FF) == 0x0000)
{ {
BYTE ret = 0; BYTE ret = 0;
if (eeprom_type == 0) if (eeprom_type == 0)
{ {
ret = x24c01.Read(); ret = x24c01.Read();
} }
else else
if (eeprom_type == 1) if (eeprom_type == 1)
{ {
ret = x24c02.Read(); ret = x24c02.Read();
} }
else else
if (eeprom_type == 2) if (eeprom_type == 2)
{ {
ret = x24c02.Read() & x24c01.Read(); ret = (byte)(x24c02.Read() & x24c01.Read());
} }
return (ret ? 0x10 : 0) | (nes.GetBarcodeStatus()); return (byte)((ret != 0 ? 0x10 : 0) | (nes.GetBarcodeStatus()));
} }
} }
return 0x00; return 0x00;
} }
//void Mapper016::WriteLow(WORD addr, BYTE data) //void Mapper016::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
if (patch == 0) if (patch == 0)
{ {
WriteSubA(addr, data); WriteSubA(addr, data);
} }
else else
{ {
Mapper::WriteLow(addr, data); base.WriteLow(addr, data);
} }
} }
void Mapper016::Write(WORD addr, BYTE data) public override void Write(ushort addr, byte data)
{ {
if (!patch) if (patch == 0)
{ {
WriteSubA(addr, data); WriteSubA(addr, data);
} }
else else
{ {
WriteSubB(addr, data); WriteSubB(addr, data);
} }
} }
static BYTE eeprom_addinc; static BYTE eeprom_addinc;
// Normal mapper #16 // Normal mapper #16
void Mapper016::WriteSubA(WORD addr, BYTE data) void WriteSubA(ushort addr, BYTE data)
{ {
switch (addr & 0x000F) switch (addr & 0x000F)
{ {
case 0x0000: case 0x0000:
case 0x0001: case 0x0001:
case 0x0002: case 0x0002:
case 0x0003: case 0x0003:
case 0x0004: case 0x0004:
case 0x0005: case 0x0005:
case 0x0006: case 0x0006:
case 0x0007: case 0x0007:
if (VROM_1K_SIZE) if (VROM_1K_SIZE != 0)
{ {
SetVROM_1K_Bank(addr & 0x0007, data); SetVROM_1K_Bank((byte)(addr & 0x0007), data);
} }
if (eeprom_type == 2) if (eeprom_type == 2)
{ {
reg[0] = data; reg[0] = data;
x24c01.Write((data & 0x08) ? 0xFF : 0, (reg[1] & 0x40) ? 0xFF : 0); x24c01.Write((byte)((data & 0x08) != 0 ? 0xFF : 0), (byte)((reg[1] & 0x40) != 0 ? 0xFF : 0));
} }
break; break;
case 0x0008: case 0x0008:
SetPROM_16K_Bank(4, data); SetPROM_16K_Bank(4, data);
break; break;
case 0x0009: case 0x0009:
data &= 0x03; data &= 0x03;
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR); if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR); else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L); else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
else SetVRAM_Mirror(VRAM_MIRROR4H); else SetVRAM_Mirror(VRAM_MIRROR4H);
break; break;
case 0x000A: case 0x000A:
irq_enable = data & 0x01; irq_enable = (byte)(data & 0x01);
irq_counter = irq_latch; irq_counter = irq_latch;
nes.cpu.ClrIRQ(IRQ_MAPPER); nes.cpu.ClrIRQ(IRQ_MAPPER);
break; break;
case 0x000B: case 0x000B:
irq_latch = (irq_latch & 0xFF00) | data; irq_latch = (irq_latch & 0xFF00) | data;
irq_counter = (irq_counter & 0xFF00) | data; irq_counter = (irq_counter & 0xFF00) | data;
break; break;
case 0x000C: case 0x000C:
irq_latch = ((INT)data << 8) | (irq_latch & 0x00FF); irq_latch = (data << 8) | (irq_latch & 0x00FF);
irq_counter = ((INT)data << 8) | (irq_counter & 0x00FF); irq_counter = (data << 8) | (irq_counter & 0x00FF);
break; break;
case 0x000D: case 0x000D:
// EEPTYPE0(DragonBallZ) // EEPTYPE0(DragonBallZ)
if (eeprom_type == 0) if (eeprom_type == 0)
{ {
x24c01.Write((data & 0x20) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0); x24c01.Write((byte)((data & 0x20) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
} }
// EEPTYPE1(DragonBallZ2,Z3,Z Gaiden) // EEPTYPE1(DragonBallZ2,Z3,Z Gaiden)
if (eeprom_type == 1) if (eeprom_type == 1)
{ {
x24c02.Write((data & 0x20) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0); x24c02.Write((byte)((data & 0x20) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
} }
// EEPTYPE2(DATACH) // EEPTYPE2(DATACH)
if (eeprom_type == 2) if (eeprom_type == 2)
{ {
reg[1] = data; reg[1] = data;
x24c02.Write((data & 0x20) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0); x24c02.Write((byte)((data & 0x20) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
x24c01.Write((reg[0] & 0x08) ? 0xFF : 0, (data & 0x40) ? 0xFF : 0); x24c01.Write((byte)((reg[0] & 0x08) != 0 ? 0xFF : 0), (byte)((data & 0x40) != 0 ? 0xFF : 0));
} }
break; break;
} }
} }
// Famicom Jump 2 // Famicom Jump 2
void Mapper016::WriteSubB(WORD addr, BYTE data) void WriteSubB(ushort addr, BYTE data)
{ {
switch (addr) switch (addr)
{ {
case 0x8000: case 0x8000:
case 0x8001: case 0x8001:
case 0x8002: case 0x8002:
case 0x8003: case 0x8003:
reg[0] = data & 0x01; reg[0] = (byte)(data & 0x01);
SetPROM_8K_Bank(4, reg[0] * 0x20 + reg[2] * 2 + 0); 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(5, reg[0] * 0x20 + reg[2] * 2 + 1);
break; break;
case 0x8004: case 0x8004:
case 0x8005: case 0x8005:
case 0x8006: case 0x8006:
case 0x8007: case 0x8007:
reg[1] = data & 0x01; reg[1] = (byte)(data & 0x01);
SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E); SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E);
SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F); SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F);
break; break;
case 0x8008: case 0x8008:
reg[2] = data; reg[2] = data;
SetPROM_8K_Bank(4, reg[0] * 0x20 + reg[2] * 2 + 0); 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(5, reg[0] * 0x20 + reg[2] * 2 + 1);
SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E); SetPROM_8K_Bank(6, reg[1] * 0x20 + 0x1E);
SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F); SetPROM_8K_Bank(7, reg[1] * 0x20 + 0x1F);
break; break;
case 0x8009: case 0x8009:
data &= 0x03; data &= 0x03;
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR); if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR); else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L); else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
else SetVRAM_Mirror(VRAM_MIRROR4H); else SetVRAM_Mirror(VRAM_MIRROR4H);
break; break;
case 0x800A: case 0x800A:
irq_enable = data & 0x01; irq_enable = (byte)(data & 0x01);
irq_counter = irq_latch; irq_counter = irq_latch;
// if( !irq_enable ) { // if( !irq_enable ) {
// nes.cpu.ClrIRQ( IRQ_MAPPER ); // nes.cpu.ClrIRQ( IRQ_MAPPER );
// } // }
nes.cpu.ClrIRQ(IRQ_MAPPER); nes.cpu.ClrIRQ(IRQ_MAPPER);
break; break;
case 0x800B: case 0x800B:
irq_latch = (irq_latch & 0xFF00) | data; irq_latch = (irq_latch & 0xFF00) | data;
break; break;
case 0x800C: case 0x800C:
irq_latch = ((INT)data << 8) | (irq_latch & 0x00FF); irq_latch = (data << 8) | (irq_latch & 0x00FF);
break; break;
case 0x800D: case 0x800D:
break; break;
} }
} }
void Mapper016::HSync(INT scanline) public override void HSync(int scanline)
{ {
if (irq_enable && (nes.GetIrqType() == NES.IRQMETHOD.IRQ_HSYNC)) if (irq_enable != 0 && (nes.GetIrqType() == (int)NES.IRQMETHOD.IRQ_HSYNC))
{ {
if (irq_counter <= 113) if (irq_counter <= 113)
{ {
nes.cpu.SetIRQ(IRQ_MAPPER); nes.cpu.SetIRQ(IRQ_MAPPER);
// nes.cpu.IRQ(); // nes.cpu.IRQ();
//// nes.cpu.IRQ_NotPending(); //// nes.cpu.IRQ_NotPending();
// irq_enable = 0; // irq_enable = 0;
// irq_counter = 0; // irq_counter = 0;
irq_counter &= 0xFFFF; irq_counter &= 0xFFFF;
} }
else else
{ {
irq_counter -= 113; irq_counter -= 113;
} }
} }
} }
void Mapper016::Clock(INT cycles) public override void Clock(int cycles)
{ {
if (irq_enable && (nes.GetIrqType() == NES::IRQ_CLOCK)) if (irq_enable != 0 && (nes.GetIrqType() == (int)NES.IRQMETHOD.IRQ_CLOCK))
{ {
if ((irq_counter -= cycles) <= 0) if ((irq_counter -= cycles) <= 0)
{ {
nes.cpu.SetIRQ(IRQ_MAPPER); nes.cpu.SetIRQ(IRQ_MAPPER);
// nes.cpu.IRQ(); // nes.cpu.IRQ();
//// nes.cpu.IRQ_NotPending(); //// nes.cpu.IRQ_NotPending();
// irq_enable = 0; // irq_enable = 0;
// irq_counter = 0; // irq_counter = 0;
irq_counter &= 0xFFFF; irq_counter &= 0xFFFF;
} }
} }
} }
void Mapper016::SaveState(LPBYTE p) public override void SaveState(byte[] p)
{ {
p[0] = reg[0]; //p[0] = reg[0];
p[1] = reg[1]; //p[1] = reg[1];
p[2] = reg[2]; //p[2] = reg[2];
p[3] = irq_enable; //p[3] = irq_enable;
*(INT*)&p[4] = irq_counter; //*(INT*)&p[4] = irq_counter;
*(INT*)&p[8] = irq_latch; //*(INT*)&p[8] = irq_latch;
if (eeprom_type == 0) //if (eeprom_type == 0)
{ //{
x24c01.Save(&p[16]); // x24c01.Save(&p[16]);
} //}
else //else
if (eeprom_type == 1) //if (eeprom_type == 1)
{ //{
x24c02.Save(&p[16]); // x24c02.Save(&p[16]);
} //}
else //else
if (eeprom_type == 2) //if (eeprom_type == 2)
{ //{
x24c02.Save(&p[16]); // x24c02.Save(&p[16]);
x24c01.Save(&p[48]); // x24c01.Save(&p[48]);
} //}
} }
void Mapper016::LoadState(LPBYTE p) public override void LoadState(byte[] p)
{ {
reg[0] = p[0]; //reg[0] = p[0];
reg[1] = p[1]; //reg[1] = p[1];
reg[2] = p[2]; //reg[2] = p[2];
irq_enable = p[3]; //irq_enable = p[3];
irq_counter = *(INT*)&p[4]; //irq_counter = *(INT*)&p[4];
irq_latch = *(INT*)&p[8]; //irq_latch = *(INT*)&p[8];
if (eeprom_type == 0) //if (eeprom_type == 0)
{ //{
x24c01.Load(&p[16]); // x24c01.Load(&p[16]);
} //}
else //else
if (eeprom_type == 1) //if (eeprom_type == 1)
{ //{
x24c02.Load(&p[16]); // x24c02.Load(&p[16]);
} //}
else //else
if (eeprom_type == 2) //if (eeprom_type == 2)
{ //{
x24c02.Load(&p[16]); // x24c02.Load(&p[16]);
x24c01.Load(&p[48]); // x24c01.Load(&p[48]);
} //}
} }
public override bool IsStateSave() public override bool IsStateSave()
{ {
return true; return true;
} }
} }
} }

View File

@ -8,409 +8,410 @@ using BYTE = System.Byte;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper019 : Mapper public class Mapper019 : Mapper
{ {
BYTE patch; BYTE patch;
BYTE exsound_enable; BYTE exsound_enable;
BYTE[] reg = new byte[3]; BYTE[] reg = new byte[3];
BYTE[] exram = new byte[128]; BYTE[] exram = new byte[128];
BYTE irq_enable; BYTE irq_enable;
ushort irq_counter; ushort irq_counter;
public Mapper019(NES parent) : base(parent) public Mapper019(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
patch = 0; patch = 0;
reg[0] = reg[1] = reg[2] = 0; reg[0] = reg[1] = reg[2] = 0;
::memset(exram, 0, sizeof(exram)); MemoryUtility.ZEROMEMORY(exram, exram.Length);
irq_enable = 0; irq_enable = 0;
irq_counter = 0; irq_counter = 0;
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
if (VROM_1K_SIZE >= 8) if (VROM_1K_SIZE >= 8)
{ {
SetVROM_8K_Bank(VROM_8K_SIZE - 1); SetVROM_8K_Bank(VROM_8K_SIZE - 1);
} }
exsound_enable = 0xFF; exsound_enable = 0xFF;
uint crc = nes.rom.GetPROM_CRC(); uint crc = nes.rom.GetPROM_CRC();
if (crc == 0xb62a7b71) if (crc == 0xb62a7b71)
{ // Family Circuit '91(J) { // Family Circuit '91(J)
patch = 1; patch = 1;
} }
if (crc == 0x02738c68) if (crc == 0x02738c68)
{ // Wagan Land 2(J) { // Wagan Land 2(J)
patch = 3; patch = 3;
} }
if (crc == 0x14942c06) if (crc == 0x14942c06)
{ // Wagan Land 3(J) { // Wagan Land 3(J)
patch = 2; patch = 2;
} }
if (crc == 0x968dcf09) if (crc == 0x968dcf09)
{ // Final Lap(J) { // Final Lap(J)
nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER); nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER);
} }
if (crc == 0x3deac303) if (crc == 0x3deac303)
{ // Rolling Thunder(J) { // Rolling Thunder(J)
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER); nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
} }
if (crc == 0xb1b9e187) if (crc == 0xb1b9e187)
{ // For Kaijuu Monogatari(J) { // For Kaijuu Monogatari(J)
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER); nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
} }
if (crc == 0x6901346e) if (crc == 0x6901346e)
{ // For Sangokushi 2 - Haou no Tairiku(J) { // For Sangokushi 2 - Haou no Tairiku(J)
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER); nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
} }
// if( crc == 0xdd454208 ) { // Hydlide 3(J) // if( crc == 0xdd454208 ) { // Hydlide 3(J)
// nes.SetRenderMethod( NES::PRE_ALL_RENDER ); // nes.SetRenderMethod( NES::PRE_ALL_RENDER );
// } // }
if (crc == 0xaf15338f // For Mindseeker(J) if (crc == 0xaf15338f // For Mindseeker(J)
|| crc == 0xb1b9e187 // For Kaijuu Monogatari(J) || crc == 0xb1b9e187 // For Kaijuu Monogatari(J)
|| crc == 0x96533999 // Dokuganryuu Masamune(J) || crc == 0x96533999 // Dokuganryuu Masamune(J)
// || crc == 0x2b825ce1 // Namco Classic(J) // || crc == 0x2b825ce1 // Namco Classic(J)
// || crc == 0x9a2b0641 // Namco Classic 2(J) // || crc == 0x9a2b0641 // Namco Classic 2(J)
|| crc == 0x3296ff7a // Battle Fleet(J) || crc == 0x3296ff7a // Battle Fleet(J)
|| crc == 0xdd454208) || crc == 0xdd454208)
{ // Hydlide 3(J) { // Hydlide 3(J)
exsound_enable = 0; exsound_enable = 0;
} }
if (crc == 0x429fd177) if (crc == 0x429fd177)
{ // Famista '90(J) { // Famista '90(J)
exsound_enable = 0; exsound_enable = 0;
} }
if (exsound_enable != 0) if (exsound_enable != 0)
{ {
nes.apu.SelectExSound(0x10); nes.apu.SelectExSound(0x10);
} }
} }
//BYTE Mapper019::ReadLow(WORD addr) //BYTE Mapper019::ReadLow(WORD addr)
public override byte ReadLow(ushort addr) public override byte ReadLow(ushort addr)
{ {
BYTE data = 0; BYTE data = 0;
switch (addr & 0xF800) switch (addr & 0xF800)
{ {
case 0x4800: case 0x4800:
if (addr == 0x4800) if (addr == 0x4800)
{ {
if (exsound_enable != 0) if (exsound_enable != 0)
{ {
nes.apu.ExRead(addr); nes.apu.ExRead(addr);
data = exram[reg[2] & 0x7F]; data = exram[reg[2] & 0x7F];
} }
else else
{ {
data = WRAM[reg[2] & 0x7F]; data = WRAM[reg[2] & 0x7F];
} }
if ((reg[2] & 0x80) != 0) if ((reg[2] & 0x80) != 0)
reg[2] = (byte)((reg[2] + 1) | 0x80); reg[2] = (byte)((reg[2] + 1) | 0x80);
return data; return data;
} }
break; break;
case 0x5000: case 0x5000:
return (byte)((BYTE)irq_counter & 0x00FF); return (byte)((BYTE)irq_counter & 0x00FF);
case 0x5800: case 0x5800:
return (BYTE)((irq_counter >> 8) & 0x7F); return (BYTE)((irq_counter >> 8) & 0x7F);
case 0x6000: case 0x6000:
case 0x6800: case 0x6800:
case 0x7000: case 0x7000:
case 0x7800: case 0x7800:
return base.ReadLow(addr); return base.ReadLow(addr);
} }
return (BYTE)(addr >> 8); return (BYTE)(addr >> 8);
} }
//void Mapper019::WriteLow(WORD addr, BYTE data) //void Mapper019::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
switch (addr & 0xF800) switch (addr & 0xF800)
{ {
case 0x4800: case 0x4800:
if (addr == 0x4800) if (addr == 0x4800)
{ {
if (exsound_enable != 0) if (exsound_enable != 0)
{ {
nes.apu.ExWrite(addr, data); nes.apu.ExWrite(addr, data);
exram[reg[2] & 0x7F] = data; exram[reg[2] & 0x7F] = data;
} }
else else
{ {
WRAM[reg[2] & 0x7F] = data; WRAM[reg[2] & 0x7F] = data;
} }
if ((reg[2] & 0x80) != 0) if ((reg[2] & 0x80) != 0)
reg[2] = (byte)((reg[2] + 1) | 0x80); reg[2] = (byte)((reg[2] + 1) | 0x80);
} }
break; break;
case 0x5000: case 0x5000:
irq_counter = (byte)((irq_counter & 0xFF00) | (ushort)data); irq_counter = (byte)((irq_counter & 0xFF00) | (ushort)data);
// if( irq_enable ) { // if( irq_enable ) {
// irq_counter++; // irq_counter++;
// } // }
nes.cpu.ClrIRQ(IRQ_MAPPER); nes.cpu.ClrIRQ(IRQ_MAPPER);
break; break;
case 0x5800: case 0x5800:
irq_counter = (byte)((irq_counter & 0x00FF) | ((ushort)(data & 0x7F) << 8)); irq_counter = (byte)((irq_counter & 0x00FF) | ((ushort)(data & 0x7F) << 8));
irq_enable = (byte)(data & 0x80); irq_enable = (byte)(data & 0x80);
// if( irq_enable ) { // if( irq_enable ) {
// irq_counter++; // irq_counter++;
// } // }
// if( !irq_enable ) { // if( !irq_enable ) {
// nes.cpu.ClrIRQ( IRQ_MAPPER ); // nes.cpu.ClrIRQ( IRQ_MAPPER );
// } // }
nes.cpu.ClrIRQ(IRQ_MAPPER); nes.cpu.ClrIRQ(IRQ_MAPPER);
break; break;
case 0x6000: case 0x6000:
case 0x6800: case 0x6800:
case 0x7000: case 0x7000:
case 0x7800: case 0x7800:
base.WriteLow(addr, data); base.WriteLow(addr, data);
break; break;
} }
} }
//void Mapper019::Write(WORD addr, BYTE data) //void Mapper019::Write(WORD addr, BYTE data)
public override void Write(ushort addr, byte data) public override void Write(ushort addr, byte data)
{ {
//if( addr >= 0xC000 ) { //if( addr >= 0xC000 ) {
//DEBUGOUT( "W %04X %02X L:%3d\n", addr, data, nes.GetScanline() ); //DEBUGOUT( "W %04X %02X L:%3d\n", addr, data, nes.GetScanline() );
//} //}
switch (addr & 0xF800) switch (addr & 0xF800)
{ {
case 0x8000: case 0x8000:
if ((data < 0xE0) || (reg[0] != 0)) if ((data < 0xE0) || (reg[0] != 0))
{ {
SetVROM_1K_Bank(0, data); SetVROM_1K_Bank(0, data);
} }
else else
{ {
SetCRAM_1K_Bank(0, data & 0x1F); SetCRAM_1K_Bank(0, data & 0x1F);
} }
break; break;
case 0x8800: case 0x8800:
if ((data < 0xE0) || (reg[0] != 0)) if ((data < 0xE0) || (reg[0] != 0))
{ {
SetVROM_1K_Bank(1, data); SetVROM_1K_Bank(1, data);
} }
else else
{ {
SetCRAM_1K_Bank(1, data & 0x1F); SetCRAM_1K_Bank(1, data & 0x1F);
} }
break; break;
case 0x9000: case 0x9000:
if ((data < 0xE0) || (reg[0] != 0)) if ((data < 0xE0) || (reg[0] != 0))
{ {
SetVROM_1K_Bank(2, data); SetVROM_1K_Bank(2, data);
} }
else else
{ {
SetCRAM_1K_Bank(2, data & 0x1F); SetCRAM_1K_Bank(2, data & 0x1F);
} }
break; break;
case 0x9800: case 0x9800:
if ((data < 0xE0) || (reg[0] != 0)) if ((data < 0xE0) || (reg[0] != 0))
{ {
SetVROM_1K_Bank(3, data); SetVROM_1K_Bank(3, data);
} }
else else
{ {
SetCRAM_1K_Bank(3, data & 0x1F); SetCRAM_1K_Bank(3, data & 0x1F);
} }
break; break;
case 0xA000: case 0xA000:
if ((data < 0xE0) || (reg[1] != 0)) if ((data < 0xE0) || (reg[1] != 0))
{ {
SetVROM_1K_Bank(4, data); SetVROM_1K_Bank(4, data);
} }
else else
{ {
SetCRAM_1K_Bank(4, data & 0x1F); SetCRAM_1K_Bank(4, data & 0x1F);
} }
break; break;
case 0xA800: case 0xA800:
if ((data < 0xE0) || (reg[1] != 0)) if ((data < 0xE0) || (reg[1] != 0))
{ {
SetVROM_1K_Bank(5, data); SetVROM_1K_Bank(5, data);
} }
else else
{ {
SetCRAM_1K_Bank(5, data & 0x1F); SetCRAM_1K_Bank(5, data & 0x1F);
} }
break; break;
case 0xB000: case 0xB000:
if ((data < 0xE0) || (reg[1] != 0)) if ((data < 0xE0) || (reg[1] != 0))
{ {
SetVROM_1K_Bank(6, data); SetVROM_1K_Bank(6, data);
} }
else else
{ {
SetCRAM_1K_Bank(6, data & 0x1F); SetCRAM_1K_Bank(6, data & 0x1F);
} }
break; break;
case 0xB800: case 0xB800:
if ((data < 0xE0) || (reg[1] != 0)) if ((data < 0xE0) || (reg[1] != 0))
{ {
SetVROM_1K_Bank(7, data); SetVROM_1K_Bank(7, data);
} }
else else
{ {
SetCRAM_1K_Bank(7, data & 0x1F); SetCRAM_1K_Bank(7, data & 0x1F);
} }
break; break;
case 0xC000: case 0xC000:
if (patch == 0) if (patch == 0)
{ {
if (data <= 0xDF) if (data <= 0xDF)
{ {
SetVROM_1K_Bank(8, data); SetVROM_1K_Bank(8, data);
} }
else else
{ {
SetVRAM_1K_Bank(8, data & 0x01); SetVRAM_1K_Bank(8, data & 0x01);
} }
} }
break; break;
case 0xC800: case 0xC800:
if (patch == 0) if (patch == 0)
{ {
if (data <= 0xDF) if (data <= 0xDF)
{ {
SetVROM_1K_Bank(9, data); SetVROM_1K_Bank(9, data);
} }
else else
{ {
SetVRAM_1K_Bank(9, data & 0x01); SetVRAM_1K_Bank(9, data & 0x01);
} }
} }
break; break;
case 0xD000: case 0xD000:
if (patch == 0) if (patch == 0)
{ {
if (data <= 0xDF) if (data <= 0xDF)
{ {
SetVROM_1K_Bank(10, data); SetVROM_1K_Bank(10, data);
} }
else else
{ {
SetVRAM_1K_Bank(10, data & 0x01); SetVRAM_1K_Bank(10, data & 0x01);
} }
} }
break; break;
case 0xD800: case 0xD800:
if (patch == 0) if (patch == 0)
{ {
if (data <= 0xDF) if (data <= 0xDF)
{ {
SetVROM_1K_Bank(11, data); SetVROM_1K_Bank(11, data);
} }
else else
{ {
SetVRAM_1K_Bank(11, data & 0x01); SetVRAM_1K_Bank(11, data & 0x01);
} }
} }
break; break;
case 0xE000: case 0xE000:
SetPROM_8K_Bank(4, data & 0x3F); SetPROM_8K_Bank(4, data & 0x3F);
if (patch == 2) if (patch == 2)
{ {
if ((data & 0x40) != 0) SetVRAM_Mirror(VRAM_VMIRROR); if ((data & 0x40) != 0) SetVRAM_Mirror(VRAM_VMIRROR);
else SetVRAM_Mirror(VRAM_MIRROR4L); else SetVRAM_Mirror(VRAM_MIRROR4L);
} }
if (patch == 3) if (patch == 3)
{ {
if ((data & 0x80) != 0) SetVRAM_Mirror(VRAM_HMIRROR); if ((data & 0x80) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
else SetVRAM_Mirror(VRAM_VMIRROR); else SetVRAM_Mirror(VRAM_VMIRROR);
} }
break; break;
case 0xE800: case 0xE800:
reg[0] = (byte)(data & 0x40); reg[0] = (byte)(data & 0x40);
reg[1] = (byte)(data & 0x80); reg[1] = (byte)(data & 0x80);
SetPROM_8K_Bank(5, data & 0x3F); SetPROM_8K_Bank(5, data & 0x3F);
break; break;
case 0xF000: case 0xF000:
SetPROM_8K_Bank(6, data & 0x3F); SetPROM_8K_Bank(6, data & 0x3F);
break; break;
case 0xF800: case 0xF800:
if (addr == 0xF800) if (addr == 0xF800)
{ {
if (exsound_enable != 0) if (exsound_enable != 0)
{ {
nes.apu.ExWrite(addr, data); nes.apu.ExWrite(addr, data);
} }
reg[2] = data; reg[2] = data;
} }
break; break;
} }
} }
//void Mapper019::Clock(INT cycles) //void Mapper019::Clock(INT cycles)
public override void Clock(int cycles) public override void Clock(int cycles)
{ {
if (irq_enable != 0) if (irq_enable != 0)
{ {
if ((irq_counter += cycles) >= 0x7FFF) irq_counter = (ushort)(irq_counter + cycles);
{ if (irq_counter >= 0x7FFF)
// irq_counter = 0x7FFF; {
// nes.cpu.IRQ_NotPending(); // irq_counter = 0x7FFF;
// nes.cpu.IRQ_NotPending();
irq_enable = 0;
// irq_counter &= 0x7FFF; irq_enable = 0;
irq_counter = 0x7FFF; // irq_counter &= 0x7FFF;
nes.cpu.SetIRQ(IRQ_MAPPER); irq_counter = 0x7FFF;
} nes.cpu.SetIRQ(IRQ_MAPPER);
} }
} }
}
//void Mapper019::SaveState(LPBYTE p)
public override void SaveState(byte[] p) //void Mapper019::SaveState(LPBYTE p)
{ public override void SaveState(byte[] p)
// p[0] = reg[0]; {
// p[1] = reg[1]; // p[0] = reg[0];
// p[2] = reg[2]; // p[1] = reg[1];
// p[3] = irq_enable; // p[2] = reg[2];
// *(WORD*)&p[4] = irq_counter; // p[3] = irq_enable;
// *(WORD*)&p[4] = irq_counter;
//::memcpy(&p[8], exram, sizeof(exram));
} //::memcpy(&p[8], exram, sizeof(exram));
}
//void Mapper019::LoadState(LPBYTE p)
public override void LoadState(byte[] p) //void Mapper019::LoadState(LPBYTE p)
{ public override void LoadState(byte[] p)
// reg[0] = p[0]; {
// reg[1] = p[1]; // reg[0] = p[0];
// reg[2] = p[2]; // reg[1] = p[1];
// irq_enable = p[3]; // reg[2] = p[2];
// irq_counter = *(WORD*)&p[4]; // irq_enable = p[3];
// irq_counter = *(WORD*)&p[4];
//::memcpy(exram, &p[8], sizeof(exram));
} //::memcpy(exram, &p[8], sizeof(exram));
}
public override bool IsStateSave()
{ public override bool IsStateSave()
return true; {
} return true;
} }
}
} }

View File

@ -28,7 +28,7 @@ namespace VirtualNes.Core
{ {
addrmask = 0xFFFF; addrmask = 0xFFFF;
for (INT i = 0; i < 8; i++) for (byte i = 0; i < 8; i++)
{ {
reg[i] = i; reg[i] = i;
} }

View File

@ -7,53 +7,54 @@ using INT = System.Int32;
using BYTE = System.Byte; using BYTE = System.Byte;
using System; using System;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
using VirtualNes.Core.Debug;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper072 : Mapper public class Mapper072 : Mapper
{ {
public Mapper072(NES parent) : base(parent) public Mapper072(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
if (VROM_8K_SIZE != 0) if (VROM_8K_SIZE != 0)
{ {
SetVROM_8K_Bank(0); SetVROM_8K_Bank(0);
} }
} }
//void Mapper072::Write(WORD addr, BYTE data) //void Mapper072::Write(WORD addr, BYTE data)
public override void Write(ushort addr, byte data) public override void Write(ushort addr, byte data)
{ {
if (data & 0x80) if ((data & 0x80) != 0)
{ {
SetPROM_16K_Bank(4, data & 0x0F); SetPROM_16K_Bank(4, data & 0x0F);
} }
else if (data & 0x40) else if ((data & 0x40) != 0)
{ {
SetVROM_8K_Bank(data & 0x0F); SetVROM_8K_Bank(data & 0x0F);
} }
else else
{ {
if (addr >= 0xC100 && addr <= 0xC11F && data == 0x20) if (addr >= 0xC100 && addr <= 0xC11F && data == 0x20)
{ {
//DEBUGOUT( "ADDR:%04X DATA:%02X\n", addr, data ); Debuger.Log($"SOUND CODE:{addr & 0x1F:X2}");
DEBUGOUT("SOUND CODE:%02X\n", addr & 0x1F);
// OSDにするべきか…
// OSDにするべきか… if (Supporter.Config.sound.bExtraSoundEnable)
if (Config.sound.bExtraSoundEnable) {
{ //TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
DirectSound.EsfAllStop(); //DirectSound.EsfAllStop();
DirectSound.EsfPlay(ESF_MOETENNIS_00 + (addr & 0x1F)); //DirectSound.EsfPlay(ESF_MOETENNIS_00 + (addr & 0x1F));
} }
} }
} }
} }
} }
} }

View File

@ -10,62 +10,63 @@ using Codice.CM.Client.Differences;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper086 : Mapper public class Mapper086 : Mapper
{ {
BYTE reg, cnt; BYTE reg, cnt;
public Mapper086(NES parent) : base(parent) public Mapper086(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
SetPROM_32K_Bank(0, 1, 2, 3); SetPROM_32K_Bank(0, 1, 2, 3);
SetVROM_8K_Bank(0); SetVROM_8K_Bank(0);
reg = 0xFF; reg = 0xFF;
cnt = 0; cnt = 0;
} }
//void Mapper086::WriteLow(WORD addr, BYTE data) //void Mapper086::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
if (addr == 0x6000) if (addr == 0x6000)
{ {
SetPROM_32K_Bank((data & 0x30) >> 4); SetPROM_32K_Bank((data & 0x30) >> 4);
SetVROM_8K_Bank((data & 0x03) | ((data & 0x40) >> 4)); SetVROM_8K_Bank((data & 0x03) | ((data & 0x40) >> 4));
} }
if (addr == 0x7000) if (addr == 0x7000)
{ {
if ((reg & 0x10) == 0 && ((data & 0x10) != 0) && cnt==0) if ((reg & 0x10) == 0 && ((data & 0x10) != 0) && cnt == 0)
{ {
//DEBUGOUT( "WR:$%02X\n", data ); //DEBUGOUT( "WR:$%02X\n", data );
if ((data & 0x0F) == 0 // Strike if ((data & 0x0F) == 0 // Strike
|| (data & 0x0F) == 5) || (data & 0x0F) == 5)
{ // Foul { // Foul
cnt = 60; // 次の発声を1秒程禁止する cnt = 60; // 次の発声を1秒程禁止する
} }
// OSDにするべきか… // OSDにするべきか…
if (Config.sound.bExtraSoundEnable) if (Supporter.Config.sound.bExtraSoundEnable)
{ {
DirectSound.EsfAllStop(); //TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + (data & 0x0F)); //DirectSound.EsfAllStop();
} //DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + (data & 0x0F));
} }
reg = data; }
} reg = data;
} }
}
//void Mapper086::VSync()
public override void VSync() //void Mapper086::VSync()
{ public override void VSync()
if (cnt!=0) {
{ if (cnt != 0)
cnt--; {
} cnt--;
} }
}
}
}
} }

View File

@ -7,476 +7,477 @@ using INT = System.Int32;
using BYTE = System.Byte; using BYTE = System.Byte;
using System; using System;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
using VirtualNes.Core.Debug;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper090 : Mapper public class Mapper090 : Mapper
{ {
BYTE patch; BYTE patch;
BYTE[] prg_reg = new byte[4]; BYTE[] prg_reg = new byte[4];
BYTE[] nth_reg = new byte[4]; BYTE[] nth_reg = new byte[4];
BYTE[] ntl_reg = new byte[4]; BYTE[] ntl_reg = new byte[4];
BYTE[] chh_reg = new byte[8]; BYTE[] chh_reg = new byte[8];
BYTE[] chl_reg = new byte[8]; BYTE[] chl_reg = new byte[8];
BYTE irq_enable; BYTE irq_enable;
BYTE irq_counter; BYTE irq_counter;
BYTE irq_latch; BYTE irq_latch;
BYTE irq_occur; BYTE irq_occur;
BYTE irq_preset; BYTE irq_preset;
BYTE irq_offset; BYTE irq_offset;
BYTE prg_6000, prg_E000; BYTE prg_6000, prg_E000;
BYTE prg_size, chr_size; BYTE prg_size, chr_size;
BYTE mir_mode, mir_type; BYTE mir_mode, mir_type;
BYTE key_val; BYTE key_val;
BYTE mul_val1, mul_val2; BYTE mul_val1, mul_val2;
BYTE sw_val; BYTE sw_val;
public Mapper090(NES parent) : base(parent) public Mapper090(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
SetVROM_8K_Bank(0); SetVROM_8K_Bank(0);
patch = 0; patch = 0;
uint crc = nes.rom.GetPROM_CRC(); uint crc = nes.rom.GetPROM_CRC();
if (crc == 0x2a268152) if (crc == 0x2a268152)
{ {
patch = 1; patch = 1;
} }
if (crc == 0x2224b882) if (crc == 0x2224b882)
{ {
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER); nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
} }
irq_enable = 0; // Disable irq_enable = 0; // Disable
irq_counter = 0; irq_counter = 0;
irq_latch = 0; irq_latch = 0;
irq_occur = 0; irq_occur = 0;
irq_preset = 0; irq_preset = 0;
irq_offset = 0; irq_offset = 0;
prg_6000 = 0; prg_6000 = 0;
prg_E000 = 0; prg_E000 = 0;
prg_size = 0; prg_size = 0;
chr_size = 0; chr_size = 0;
mir_mode = 0; mir_mode = 0;
mir_type = 0; mir_type = 0;
key_val = 0; key_val = 0;
mul_val1 = mul_val2 = 0; mul_val1 = mul_val2 = 0;
for (INT i = 0; i < 4; i++) for (byte i = 0; i < 4; i++)
{ {
prg_reg[i] = (byte)(PROM_8K_SIZE - 4 + i); prg_reg[i] = (byte)(PROM_8K_SIZE - 4 + i);
ntl_reg[i] = 0; ntl_reg[i] = 0;
nth_reg[i] = 0; nth_reg[i] = 0;
chl_reg[i] = i; chl_reg[i] = i;
chh_reg[i] = 0; chh_reg[i] = 0;
chl_reg[i + 4] = (byte)(i + 4); chl_reg[i + 4] = (byte)(i + 4);
chh_reg[i + 4] = 0; chh_reg[i + 4] = 0;
} }
if (sw_val != 0) if (sw_val != 0)
sw_val = 0x00; sw_val = 0x00;
else else
sw_val = 0xFF; sw_val = 0xFF;
// nes.SetRenderMethod( NES::PRE_ALL_RENDER ); // nes.SetRenderMethod( NES::PRE_ALL_RENDER );
} }
//BYTE Mapper090::ReadLow(WORD addr) //BYTE Mapper090::ReadLow(WORD addr)
public override byte ReadLow(ushort addr) public override byte ReadLow(ushort addr)
{ {
DEBUGOUT("RD:%04X\n", addr); Debuger.Log($"RD:{addr:X4}");
switch (addr) switch (addr)
{ {
case 0x5000: case 0x5000:
return (byte)((sw_val != 0) ? 0x00 : 0xFF); return (byte)((sw_val != 0) ? 0x00 : 0xFF);
case 0x5800: case 0x5800:
return (BYTE)(mul_val1 * mul_val2); return (BYTE)(mul_val1 * mul_val2);
case 0x5801: case 0x5801:
return (BYTE)((mul_val1 * mul_val2) >> 8); return (BYTE)((mul_val1 * mul_val2) >> 8);
case 0x5803: case 0x5803:
return key_val; return key_val;
} }
if (addr >= 0x6000) if (addr >= 0x6000)
{ {
return base.ReadLow(addr); return base.ReadLow(addr);
} }
// return sw_val?0x00:0xFF; // return sw_val?0x00:0xFF;
return (BYTE)(addr >> 8); return (BYTE)(addr >> 8);
} }
//void Mapper090::WriteLow(WORD addr, BYTE data) //void Mapper090::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
DEBUGOUT("WR:%04X %02X\n", addr, data); Debuger.Log($"WR:{addr:X4} {data:X2}");
if (addr == 0x5800) if (addr == 0x5800)
{ {
mul_val1 = data; mul_val1 = data;
} }
else else
if (addr == 0x5801) if (addr == 0x5801)
{ {
mul_val2 = data; mul_val2 = data;
} }
else else
if (addr == 0x5803) if (addr == 0x5803)
{ {
key_val = data; key_val = data;
} }
} }
//void Mapper090::Write(WORD addr, BYTE data) //void Mapper090::Write(WORD addr, BYTE data)
public override void Write(ushort addr, byte data) public override void Write(ushort addr, byte data)
{ {
switch (addr & 0xF007) switch (addr & 0xF007)
{ {
case 0x8000: case 0x8000:
case 0x8001: case 0x8001:
case 0x8002: case 0x8002:
case 0x8003: case 0x8003:
prg_reg[addr & 3] = data; prg_reg[addr & 3] = data;
SetBank_CPU(); SetBank_CPU();
break; break;
case 0x9000: case 0x9000:
case 0x9001: case 0x9001:
case 0x9002: case 0x9002:
case 0x9003: case 0x9003:
case 0x9004: case 0x9004:
case 0x9005: case 0x9005:
case 0x9006: case 0x9006:
case 0x9007: case 0x9007:
chl_reg[addr & 7] = data; chl_reg[addr & 7] = data;
SetBank_PPU(); SetBank_PPU();
break; break;
case 0xA000: case 0xA000:
case 0xA001: case 0xA001:
case 0xA002: case 0xA002:
case 0xA003: case 0xA003:
case 0xA004: case 0xA004:
case 0xA005: case 0xA005:
case 0xA006: case 0xA006:
case 0xA007: case 0xA007:
chh_reg[addr & 7] = data; chh_reg[addr & 7] = data;
SetBank_PPU(); SetBank_PPU();
break; break;
case 0xB000: case 0xB000:
case 0xB001: case 0xB001:
case 0xB002: case 0xB002:
case 0xB003: case 0xB003:
ntl_reg[addr & 3] = data; ntl_reg[addr & 3] = data;
SetBank_VRAM(); SetBank_VRAM();
break; break;
case 0xB004: case 0xB004:
case 0xB005: case 0xB005:
case 0xB006: case 0xB006:
case 0xB007: case 0xB007:
nth_reg[addr & 3] = data; nth_reg[addr & 3] = data;
SetBank_VRAM(); SetBank_VRAM();
break; break;
case 0xC002: case 0xC002:
irq_enable = 0; irq_enable = 0;
irq_occur = 0; irq_occur = 0;
nes.cpu.ClrIRQ(IRQ_MAPPER); nes.cpu.ClrIRQ(IRQ_MAPPER);
break; break;
case 0xC003: case 0xC003:
irq_enable = 0xFF; irq_enable = 0xFF;
irq_preset = 0xFF; irq_preset = 0xFF;
break; break;
case 0xC004: case 0xC004:
break; break;
case 0xC005: case 0xC005:
if ((irq_offset & 0x80) != 0) if ((irq_offset & 0x80) != 0)
{ {
irq_latch = (byte)(data ^ (irq_offset | 1)); irq_latch = (byte)(data ^ (irq_offset | 1));
} }
else else
{ {
irq_latch = (byte)(data | (irq_offset & 0x27)); irq_latch = (byte)(data | (irq_offset & 0x27));
} }
irq_preset = 0xFF; irq_preset = 0xFF;
break; break;
case 0xC006: case 0xC006:
if (patch != 0) if (patch != 0)
{ {
irq_offset = data; irq_offset = data;
} }
break; break;
case 0xD000: case 0xD000:
prg_6000 = (byte)(data & 0x80); prg_6000 = (byte)(data & 0x80);
prg_E000 = (byte)(data & 0x04); prg_E000 = (byte)(data & 0x04);
prg_size = (byte)(data & 0x03); prg_size = (byte)(data & 0x03);
chr_size = (byte)((data & 0x18) >> 3); chr_size = (byte)((data & 0x18) >> 3);
mir_mode = (byte)(data & 0x20); mir_mode = (byte)(data & 0x20);
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
SetBank_VRAM(); SetBank_VRAM();
break; break;
case 0xD001: case 0xD001:
mir_type = (byte)(data & 0x03); mir_type = (byte)(data & 0x03);
SetBank_VRAM(); SetBank_VRAM();
break; break;
case 0xD003: case 0xD003:
break; break;
} }
} }
//void Mapper090::HSync(INT scanline) //void Mapper090::HSync(INT scanline)
public override void HSync(int scanline) public override void HSync(int scanline)
{ {
if ((scanline >= 0 && scanline <= 239)) if ((scanline >= 0 && scanline <= 239))
{ {
if (nes.ppu.IsDispON()) if (nes.ppu.IsDispON())
{ {
if (irq_preset != 0) if (irq_preset != 0)
{ {
irq_counter = irq_latch; irq_counter = irq_latch;
irq_preset = 0; irq_preset = 0;
} }
if (irq_counter != 0) if (irq_counter != 0)
{ {
irq_counter--; irq_counter--;
} }
if (irq_counter == 0) if (irq_counter == 0)
{ {
if (irq_enable != 0) if (irq_enable != 0)
{ {
// irq_occur = 0xFF; // irq_occur = 0xFF;
nes.cpu.SetIRQ(IRQ_MAPPER); nes.cpu.SetIRQ(IRQ_MAPPER);
} }
} }
} }
} }
} }
//void Mapper090::Clock(INT cycles) //void Mapper090::Clock(INT cycles)
public override void Clock(int cycles) public override void Clock(int cycles)
{ {
// if( irq_occur ) { // if( irq_occur ) {
// nes.cpu.IRQ_NotPending(); // nes.cpu.IRQ_NotPending();
// } // }
} }
void SetBank_CPU() void SetBank_CPU()
{ {
if (prg_size == 0) if (prg_size == 0)
{ {
SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(PROM_8K_SIZE - 4, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
} }
else else
if (prg_size == 1) if (prg_size == 1)
{ {
SetPROM_32K_Bank(prg_reg[1] * 2, prg_reg[1] * 2 + 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(prg_reg[1] * 2, prg_reg[1] * 2 + 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
} }
else else
if (prg_size == 2) if (prg_size == 2)
{ {
if (prg_E000 != 0) if (prg_E000 != 0)
{ {
SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], prg_reg[3]); SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], prg_reg[3]);
} }
else else
{ {
if (prg_6000 != 0) if (prg_6000 != 0)
{ {
SetPROM_8K_Bank(3, prg_reg[3]); SetPROM_8K_Bank(3, prg_reg[3]);
} }
SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], PROM_8K_SIZE - 1); SetPROM_32K_Bank(prg_reg[0], prg_reg[1], prg_reg[2], PROM_8K_SIZE - 1);
} }
} }
else else
{ {
SetPROM_32K_Bank(prg_reg[3], prg_reg[2], prg_reg[1], prg_reg[0]); SetPROM_32K_Bank(prg_reg[3], prg_reg[2], prg_reg[1], prg_reg[0]);
} }
} }
void SetBank_PPU() void SetBank_PPU()
{ {
INT[] bank = new int[8]; INT[] bank = new int[8];
for (INT i = 0; i < 8; i++) for (INT i = 0; i < 8; i++)
{ {
bank[i] = ((INT)chh_reg[i] << 8) | ((INT)chl_reg[i]); bank[i] = ((INT)chh_reg[i] << 8) | ((INT)chl_reg[i]);
} }
if (chr_size == 0) if (chr_size == 0)
{ {
SetVROM_8K_Bank(bank[0]); SetVROM_8K_Bank(bank[0]);
} }
else else
if (chr_size == 1) if (chr_size == 1)
{ {
SetVROM_4K_Bank(0, bank[0]); SetVROM_4K_Bank(0, bank[0]);
SetVROM_4K_Bank(4, bank[4]); SetVROM_4K_Bank(4, bank[4]);
} }
else else
if (chr_size == 2) if (chr_size == 2)
{ {
SetVROM_2K_Bank(0, bank[0]); SetVROM_2K_Bank(0, bank[0]);
SetVROM_2K_Bank(2, bank[2]); SetVROM_2K_Bank(2, bank[2]);
SetVROM_2K_Bank(4, bank[4]); SetVROM_2K_Bank(4, bank[4]);
SetVROM_2K_Bank(6, bank[6]); SetVROM_2K_Bank(6, bank[6]);
} }
else else
{ {
SetVROM_8K_Bank(bank[0], bank[1], bank[2], bank[3], bank[4], bank[5], bank[6], bank[7]); SetVROM_8K_Bank(bank[0], bank[1], bank[2], bank[3], bank[4], bank[5], bank[6], bank[7]);
} }
} }
void SetBank_VRAM() void SetBank_VRAM()
{ {
INT[] bank = new int[4]; INT[] bank = new int[4];
for (INT i = 0; i < 4; i++) for (INT i = 0; i < 4; i++)
{ {
bank[i] = ((INT)nth_reg[i] << 8) | ((INT)ntl_reg[i]); bank[i] = ((INT)nth_reg[i] << 8) | ((INT)ntl_reg[i]);
} }
if (patch == 0 && mir_mode != 0) if (patch == 0 && mir_mode != 0)
{ {
for (INT i = 0; i < 4; i++) for (INT i = 0; i < 4; i++)
{ {
if (nth_reg[i] == 0 && (ntl_reg[i] == (BYTE)i)) if (nth_reg[i] == 0 && (ntl_reg[i] == (BYTE)i))
{ {
mir_mode = 0; mir_mode = 0;
} }
} }
if (mir_mode != 0) if (mir_mode != 0)
{ {
SetVROM_1K_Bank(8, bank[0]); SetVROM_1K_Bank(8, bank[0]);
SetVROM_1K_Bank(9, bank[1]); SetVROM_1K_Bank(9, bank[1]);
SetVROM_1K_Bank(10, bank[2]); SetVROM_1K_Bank(10, bank[2]);
SetVROM_1K_Bank(11, bank[3]); SetVROM_1K_Bank(11, bank[3]);
} }
} }
else else
{ {
if (mir_type == 0) if (mir_type == 0)
{ {
SetVRAM_Mirror(VRAM_VMIRROR); SetVRAM_Mirror(VRAM_VMIRROR);
} }
else else
if (mir_type == 1) if (mir_type == 1)
{ {
SetVRAM_Mirror(VRAM_HMIRROR); SetVRAM_Mirror(VRAM_HMIRROR);
} }
else else
{ {
SetVRAM_Mirror(VRAM_MIRROR4L); SetVRAM_Mirror(VRAM_MIRROR4L);
} }
} }
} }
//void Mapper090::SaveState(LPBYTE p) //void Mapper090::SaveState(LPBYTE p)
public override void SaveState(byte[] p) public override void SaveState(byte[] p)
{ {
INT i; INT i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
p[i] = prg_reg[i]; p[i] = prg_reg[i];
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
{ {
p[i + 4] = chh_reg[i]; p[i + 4] = chh_reg[i];
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
{ {
p[i + 12] = chl_reg[i]; p[i + 12] = chl_reg[i];
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
p[i + 20] = nth_reg[i]; p[i + 20] = nth_reg[i];
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
p[i + 24] = ntl_reg[i]; p[i + 24] = ntl_reg[i];
} }
p[28] = irq_enable; p[28] = irq_enable;
p[29] = irq_counter; p[29] = irq_counter;
p[30] = irq_latch; p[30] = irq_latch;
p[31] = prg_6000; p[31] = prg_6000;
p[32] = prg_E000; p[32] = prg_E000;
p[33] = prg_size; p[33] = prg_size;
p[34] = chr_size; p[34] = chr_size;
p[35] = mir_mode; p[35] = mir_mode;
p[36] = mir_type; p[36] = mir_type;
p[37] = mul_val1; p[37] = mul_val1;
p[38] = mul_val2; p[38] = mul_val2;
p[39] = key_val; p[39] = key_val;
p[40] = irq_occur; p[40] = irq_occur;
p[41] = irq_preset; p[41] = irq_preset;
p[42] = irq_offset; p[42] = irq_offset;
} }
//void Mapper090::LoadState(LPBYTE p) //void Mapper090::LoadState(LPBYTE p)
public override void LoadState(byte[] p) public override void LoadState(byte[] p)
{ {
INT i; INT i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
prg_reg[i] = p[i]; prg_reg[i] = p[i];
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
{ {
chh_reg[i] = p[i + 4]; chh_reg[i] = p[i + 4];
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
{ {
chl_reg[i] = p[i + 12]; chl_reg[i] = p[i + 12];
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
nth_reg[i] = p[i + 20]; nth_reg[i] = p[i + 20];
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
ntl_reg[i] = p[i + 24]; ntl_reg[i] = p[i + 24];
} }
irq_enable = p[28]; irq_enable = p[28];
irq_counter = p[29]; irq_counter = p[29];
irq_latch = p[30]; irq_latch = p[30];
prg_6000 = p[31]; prg_6000 = p[31];
prg_E000 = p[32]; prg_E000 = p[32];
prg_size = p[33]; prg_size = p[33];
chr_size = p[34]; chr_size = p[34];
mir_mode = p[35]; mir_mode = p[35];
mir_type = p[36]; mir_type = p[36];
mul_val1 = p[37]; mul_val1 = p[37];
mul_val2 = p[38]; mul_val2 = p[38];
key_val = p[39]; key_val = p[39];
irq_occur = p[40]; irq_occur = p[40];
irq_preset = p[41]; irq_preset = p[41];
irq_offset = p[42]; irq_offset = p[42];
} }
public override bool IsStateSave() public override bool IsStateSave()
{ {
return true; return true;
} }
} }
} }

View File

@ -7,68 +7,70 @@ using INT = System.Int32;
using BYTE = System.Byte; using BYTE = System.Byte;
using System; using System;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
using VirtualNes.Core.Debug;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper092 : Mapper public class Mapper092 : Mapper
{ {
public Mapper092(NES parent) : base(parent) public Mapper092(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
if (VROM_8K_SIZE != 0) if (VROM_8K_SIZE != 0)
{ {
SetVROM_8K_Bank(0); SetVROM_8K_Bank(0);
} }
} }
//void Mapper092::Write(WORD addr, BYTE data) //void Mapper092::Write(WORD addr, BYTE data)
public override void Write(ushort addr, byte data) public override void Write(ushort addr, byte data)
{ {
//DEBUGOUT( "A:%04X D:%02X\n", addr, data ); //DEBUGOUT( "A:%04X D:%02X\n", addr, data );
data = (byte)(addr & 0xFF); data = (byte)(addr & 0xFF);
if (addr >= 0x9000) if (addr >= 0x9000)
{ {
if ((data & 0xF0) == 0xD0) if ((data & 0xF0) == 0xD0)
{ {
SetPROM_16K_Bank(6, data & 0x0F); SetPROM_16K_Bank(6, data & 0x0F);
} }
else if ((data & 0xF0) == 0xE0) else if ((data & 0xF0) == 0xE0)
{ {
SetVROM_8K_Bank(data & 0x0F); SetVROM_8K_Bank(data & 0x0F);
} }
} }
else else
{ {
if ((data & 0xF0) == 0xB0) if ((data & 0xF0) == 0xB0)
{ {
SetPROM_16K_Bank(6, data & 0x0F); SetPROM_16K_Bank(6, data & 0x0F);
} }
else if ((data & 0xF0) == 0x70) else if ((data & 0xF0) == 0x70)
{ {
SetVROM_8K_Bank(data & 0x0F); SetVROM_8K_Bank(data & 0x0F);
} }
else if ((data & 0xF0) == 0xC0) else if ((data & 0xF0) == 0xC0)
{ {
INT[] tbl = new int[]{ 3, 4, 5, 6, 0, 1, 2, 7, INT[] tbl = new int[]{ 3, 4, 5, 6, 0, 1, 2, 7,
9,10, 8,11,13,12,14,15 }; 9,10, 8,11,13,12,14,15 };
// OSDにするべきか… // OSDにするべきか…
if (Config.sound.bExtraSoundEnable) if (Supporter.Config.sound.bExtraSoundEnable)
{ {
DEBUGOUT("CODE %02X\n", data); //TODO : 似乎VirtuaNES有直接播放某个音频文件的功能
DirectSound.EsfAllStop(); Debuger.Log($"CODE {data:X2}");
DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + tbl[data & 0x0F]); //DirectSound.EsfAllStop();
} //DirectSound.EsfPlay(ESF_MOEPRO_STRIKE + tbl[data & 0x0F]);
} }
} }
} }
}
}
}
} }

View File

@ -9,9 +9,9 @@ using System;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class _MapName : Mapper public class Mapper107 : Mapper
{ {
public _MapName(NES parent) : base(parent) public Mapper107(NES parent) : base(parent)
{ {
} }

View File

@ -7,6 +7,7 @@ using INT = System.Int32;
using BYTE = System.Byte; using BYTE = System.Byte;
using System; using System;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
using VirtualNes.Core.Debug;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
@ -73,7 +74,7 @@ namespace VirtualNes.Core
//void Mapper116::WriteLow(WORD addr, BYTE data) //void Mapper116::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort 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) if ((addr & 0x4100) == 0x4100)
{ {
ExChrSwitch = data; ExChrSwitch = data;
@ -84,7 +85,7 @@ namespace VirtualNes.Core
//void Mapper116::Write(WORD addr, BYTE data) //void Mapper116::Write(WORD addr, BYTE data)
public override void Write(ushort 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) switch (addr & 0xE001)
{ {

View File

@ -7,125 +7,126 @@ using INT = System.Int32;
using BYTE = System.Byte; using BYTE = System.Byte;
using System; using System;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
using VirtualNes.Core.Debug;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper162 : Mapper public class Mapper162 : Mapper
{ {
BYTE reg5000; BYTE reg5000;
BYTE reg5100; BYTE reg5100;
BYTE reg5200; BYTE reg5200;
BYTE reg5300; BYTE reg5300;
public Mapper162(NES parent) : base(parent) public Mapper162(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
reg5000 = 0; reg5000 = 0;
reg5100 = 0; reg5100 = 0;
reg5200 = 0; reg5200 = 0;
reg5300 = 7; reg5300 = 7;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
} }
//void Mapper162::WriteLow(WORD addr, BYTE data) //void Mapper162::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
if (addr == 0x5000) if (addr == 0x5000)
{ {
reg5000 = data; reg5000 = data;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
} }
else if (addr == 0x5100) else if (addr == 0x5100)
{ {
reg5100 = data; reg5100 = data;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
} }
else if (addr == 0x5200) else if (addr == 0x5200)
{ {
reg5200 = data; reg5200 = data;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
} }
else if (addr == 0x5300) else if (addr == 0x5300)
{ {
reg5300 = data; reg5300 = data;
} }
else if (addr >= 0x6000) else if (addr >= 0x6000)
{ {
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data; CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
} }
else else
{ {
DEBUGOUT("write to %04x:%02x\n", addr, data); Debuger.Log($"write to {addr:X4}:{data:X2}");
} }
} }
void SetBank_CPU() void SetBank_CPU()
{ {
BYTE bank = 0; BYTE bank = 0;
switch (reg5300) switch (reg5300)
{ {
case 4: case 4:
bank = (byte)((((reg5000 & 0xF) + ((reg5100 & 3) >> 1)) | ((reg5200 & 1) << 4))); bank = (byte)((((reg5000 & 0xF) + ((reg5100 & 3) >> 1)) | ((reg5200 & 1) << 4)));
break; break;
case 7: case 7:
bank = (byte)(((reg5000 & 0xF) | ((reg5200 & 1) << 4))); bank = (byte)(((reg5000 & 0xF) | ((reg5200 & 1) << 4)));
break; break;
} }
SetPROM_32K_Bank((byte)bank); SetPROM_32K_Bank((byte)bank);
} }
void SetBank_PPU() void SetBank_PPU()
{ {
SetCRAM_8K_Bank(0); SetCRAM_8K_Bank(0);
} }
//void Mapper162::HSync(int scanline) //void Mapper162::HSync(int scanline)
public override void HSync(int scanline) public override void HSync(int scanline)
{ {
if ((reg5000 & 0x80) != 0 && nes.ppu.IsDispON()) if ((reg5000 & 0x80) != 0 && nes.ppu.IsDispON())
{ {
if (scanline < 127) if (scanline < 127)
{ {
// SetCRAM_4K_Bank(0, 0); // SetCRAM_4K_Bank(0, 0);
SetCRAM_4K_Bank(4, 0); SetCRAM_4K_Bank(4, 0);
} }
else if (scanline < 240) else if (scanline < 240)
{ {
// SetCRAM_4K_Bank(0, 1); // SetCRAM_4K_Bank(0, 1);
SetCRAM_4K_Bank(4, 1); SetCRAM_4K_Bank(4, 1);
} }
} }
} }
//void Mapper162::SaveState(LPBYTE p) //void Mapper162::SaveState(LPBYTE p)
public override void SaveState(byte[] p) public override void SaveState(byte[] p)
{ {
p[0] = reg5000; p[0] = reg5000;
p[1] = reg5100; p[1] = reg5100;
p[2] = reg5200; p[2] = reg5200;
p[3] = reg5300; p[3] = reg5300;
} }
//void Mapper162::LoadState(LPBYTE p) //void Mapper162::LoadState(LPBYTE p)
public override void LoadState(byte[] p) public override void LoadState(byte[] p)
{ {
reg5000 = p[0]; reg5000 = p[0];
reg5100 = p[1]; reg5100 = p[1];
reg5200 = p[2]; reg5200 = p[2];
reg5300 = p[3]; reg5300 = p[3];
} }
public override bool IsStateSave() public override bool IsStateSave()
{ {
return true; return true;
} }
} }
} }

View File

@ -21,7 +21,7 @@ namespace VirtualNes.Core
BYTE laststrobe, trigger; BYTE laststrobe, trigger;
BYTE[] reg = new byte[8]; BYTE[] reg = new byte[8];
public Mapper163(NES parent) : base(parent) public Mapper163(NES parent) : base(parent)
{ {
/* /*
reg[1] = 0xFF; reg[1] = 0xFF;
strobe = 1; strobe = 1;
@ -36,8 +36,9 @@ namespace VirtualNes.Core
if( crc == 0xf52468e7 ) { // San Guo Wu Shuang - Meng Jiang Zhuan (NJ047) (Ch) [dump] if( crc == 0xf52468e7 ) { // San Guo Wu Shuang - Meng Jiang Zhuan (NJ047) (Ch) [dump]
rom_type = 1; rom_type = 1;
} }
*/ */
memset(reg, 0, 8);
MemoryUtility.ZEROMEMORY(reg, reg.Length);
laststrobe = 1; laststrobe = 1;
SetPROM_32K_Bank((reg[0] << 4) | (reg[1] & 0xF)); SetPROM_32K_Bank((reg[0] << 4) | (reg[1] & 0xF));
//SetPROM_32K_Bank(0); //SetPROM_32K_Bank(0);

View File

@ -7,6 +7,7 @@ using INT = System.Int32;
using BYTE = System.Byte; using BYTE = System.Byte;
using System; using System;
using Codice.CM.Client.Differences; using Codice.CM.Client.Differences;
using VirtualNes.Core.Debug;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
@ -20,13 +21,12 @@ namespace VirtualNes.Core
} }
public override void Reset() public override void Reset()
{ {
reg5000 = 0; reg5000 = 0;
reg5100 = 0; reg5100 = 0;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
nes.ppu.SetExtLatchMode(TRUE); nes.ppu.SetExtLatchMode(true);
} }
//void Mapper164::WriteLow(WORD addr, BYTE data) //void Mapper164::WriteLow(WORD addr, BYTE data)
@ -51,7 +51,7 @@ namespace VirtualNes.Core
} }
else 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; bank += (reg5000 & 0x20) >> 1;
SetPROM_16K_Bank(4, bank + @base); SetPROM_16K_Bank(4, bank + @base);
SetPROM_16K_Bank(6, @base + 0x1f); 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; break;
case 1: case 1:
case 3: /* REG MODE */ case 3: /* REG MODE */
DEBUGOUT("-- reg mode --\n"); Debuger.Log("-- reg mode --");
break; break;
case 5: /* 32K MODE */ case 5: /* 32K MODE */
bank = (reg5000 & 0x0f); bank = (reg5000 & 0x0f);
@ -91,7 +91,7 @@ namespace VirtualNes.Core
SetPROM_16K_Bank(4, bank + @base); SetPROM_16K_Bank(4, bank + @base);
bank = (bank & 0x10) + 0x0f; bank = (bank & 0x10) + 0x0f;
SetPROM_16K_Bank(6, @base + 0x1f); SetPROM_16K_Bank(6, @base + 0x1f);
DEBUGOUT("-- half mode --\n"); Debuger.Log("-- half mode --");
break; break;
default: default:
break; break;
@ -116,18 +116,19 @@ namespace VirtualNes.Core
{ {
INT loopy_v = nes.ppu.GetPPUADDR(); INT loopy_v = nes.ppu.GetPPUADDR();
INT loopy_y = nes.ppu.GetTILEY(); 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 attradr = 0x23C0 + (loopy_v & 0x0C00) + ((loopy_v & 0x0380) >> 4);
INT attrsft = (ntbladr & 0x0040) >> 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 ntbl_x = ntbladr & 0x001F;
INT tileadr; INT tileadr;
attradr &= 0x3FF; 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; tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y;
if (p_mode) if (p_mode != 0)
{ {
tileadr = (tileadr & 0xfff7) | a3; tileadr = (tileadr & 0xfff7) | a3;
chr_l = chr_h = PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF]; chr_l = chr_h = PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];

View File

@ -41,7 +41,7 @@ namespace VirtualNes.Core
we_sram = 0; // Disable we_sram = 0; // Disable
nes->ppu->SetChrLatchMode(TRUE); nes.ppu.SetChrLatchMode(true);
} }
//void Mapper165::Write(WORD addr, BYTE data) //void Mapper165::Write(WORD addr, BYTE data)

View File

@ -7,52 +7,52 @@ using Codice.CM.Client.Differences;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper176 : Mapper public class Mapper176 : Mapper
{ {
BYTE prg, chr; BYTE prg, chr;
public Mapper176(NES parent) : base(parent) public Mapper176(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
//prg = ~0; //prg = ~0;
prg = (~0); prg = unchecked((byte)(~0));
chr = 0; chr = 0;
Sync(); Sync();
} }
void Sync() void Sync()
{ {
//setprg8r(0x10,0x6000,0); //setprg8r(0x10,0x6000,0);
SetPROM_32K_Bank(prg >> 1); SetPROM_32K_Bank(prg >> 1);
SetVROM_8K_Bank(chr); SetVROM_8K_Bank(chr);
} }
//void Mapper176::WriteLow(WORD addr, BYTE data) //void Mapper176::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
switch (addr) switch (addr)
{ {
case 0x5ff1: case 0x5ff1:
prg = data; Sync(); prg = data; Sync();
break; break;
case 0x5ff2: case 0x5ff2:
chr = data; Sync(); chr = data; Sync();
break; break;
default: default:
break; break;
} }
if (addr >= 0x6000) if (addr >= 0x6000)
{ {
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data; CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
} }
} }
public override bool IsStateSave() public override bool IsStateSave()
{ {
return true; return true;
} }
} }
} }

View File

@ -11,236 +11,236 @@ using Codice.CM.Client.Differences;
namespace VirtualNes.Core namespace VirtualNes.Core
{ {
public class Mapper199 : Mapper public class Mapper199 : Mapper
{ {
BYTE[] reg = new byte[8]; BYTE[] reg = new byte[8];
BYTE[] prg = new byte[4]; BYTE[] prg = new byte[4];
BYTE[] chr = new byte[8]; BYTE[] chr = new byte[8];
BYTE we_sram; BYTE we_sram;
BYTE irq_type; BYTE irq_type;
BYTE irq_enable; BYTE irq_enable;
BYTE irq_counter; BYTE irq_counter;
BYTE irq_latch; BYTE irq_latch;
BYTE irq_request; BYTE irq_request;
public Mapper199(NES parent) : base(parent) public Mapper199(NES parent) : base(parent)
{ {
} }
public override void Reset() public override void Reset()
{ {
for (INT i = 0; i < 8; i++) for (INT i = 0; i < 8; i++)
{ {
reg[i] = 0x00; reg[i] = 0x00;
chr[i] = (byte)i; chr[i] = (byte)i;
} }
prg[0] = 0x00; prg[0] = 0x00;
prg[1] = 0x01; prg[1] = 0x01;
prg[2] = 0x3e; prg[2] = 0x3e;
prg[3] = 0x3f; prg[3] = 0x3f;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
we_sram = 0; we_sram = 0;
irq_enable = irq_counter = irq_latch = irq_request = 0; irq_enable = irq_counter = irq_latch = irq_request = 0;
uint crcP = nes.rom.GetPROM_CRC(); uint crcP = nes.rom.GetPROM_CRC();
uint crcV = nes.rom.GetVROM_CRC(); uint crcV = nes.rom.GetVROM_CRC();
if ((crcP == 0xE80D8741) || (crcV == 0x3846520D)) if ((crcP == 0xE80D8741) || (crcV == 0x3846520D))
{//ÍâÐÇ°ÔÍõµÄ´ó½ {//ÍâÐÇ°ÔÍõµÄ´ó½
nes.SetRenderMethod( EnumRenderMethod.POST_ALL_RENDER); nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
} }
} }
//BYTE Mapper199::ReadLow(WORD addr) //BYTE Mapper199::ReadLow(WORD addr)
public override byte ReadLow(ushort addr) public override byte ReadLow(ushort addr)
{ {
if (addr >= 0x5000 && addr <= 0x5FFF) if (addr >= 0x5000 && addr <= 0x5FFF)
{ {
return XRAM[addr - 0x4000]; return XRAM[addr - 0x4000];
} }
else else
{ {
return base.ReadLow(addr); return base.ReadLow(addr);
} }
} }
//void Mapper199::WriteLow(WORD addr, BYTE data) //void Mapper199::WriteLow(WORD addr, BYTE data)
public override void WriteLow(ushort addr, byte data) public override void WriteLow(ushort addr, byte data)
{ {
if (addr >= 0x5000 && addr <= 0x5FFF) if (addr >= 0x5000 && addr <= 0x5FFF)
{ {
XRAM[addr - 0x4000] = data; XRAM[addr - 0x4000] = data;
} }
else else
{ {
base.WriteLow(addr, data); base.WriteLow(addr, data);
} }
} }
//void Mapper199::Write(WORD addr, BYTE data) //void Mapper199::Write(WORD addr, BYTE data)
public override void Write(ushort 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() ); //DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles() );
switch (addr & 0xE001) switch (addr & 0xE001)
{ {
case 0x8000: case 0x8000:
reg[0] = data; reg[0] = data;
SetBank_CPU(); SetBank_CPU();
SetBank_PPU(); SetBank_PPU();
break; break;
case 0x8001: case 0x8001:
reg[1] = data; reg[1] = data;
switch (reg[0] & 0x0f) switch (reg[0] & 0x0f)
{ {
case 0x00: chr[0] = data; SetBank_PPU(); break; case 0x00: chr[0] = data; SetBank_PPU(); break;
case 0x01: chr[2] = data; SetBank_PPU(); break; case 0x01: chr[2] = data; SetBank_PPU(); break;
case 0x02: case 0x02:
case 0x03: case 0x03:
case 0x04: case 0x04:
case 0x05: chr[(reg[0] & 0x07) + 2] = data; SetBank_PPU(); break; case 0x05: chr[(reg[0] & 0x07) + 2] = data; SetBank_PPU(); break;
case 0x06: case 0x06:
case 0x07: case 0x07:
case 0x08: case 0x08:
case 0x09: prg[(reg[0] & 0x0f) - 6] = data; SetBank_CPU(); break; case 0x09: prg[(reg[0] & 0x0f) - 6] = data; SetBank_CPU(); break;
case 0x0A: chr[1] = data; SetBank_PPU(); break; case 0x0A: chr[1] = data; SetBank_PPU(); break;
case 0x0B: chr[3] = data; SetBank_PPU(); break; case 0x0B: chr[3] = data; SetBank_PPU(); break;
} }
break; break;
case 0xA000: case 0xA000:
reg[2] = data; reg[2] = data;
//if( !nes.rom.Is4SCREEN() ) //if( !nes.rom.Is4SCREEN() )
{ {
if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR); if (data == 0) SetVRAM_Mirror(VRAM_VMIRROR);
else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR); else if (data == 1) SetVRAM_Mirror(VRAM_HMIRROR);
else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L); else if (data == 2) SetVRAM_Mirror(VRAM_MIRROR4L);
else SetVRAM_Mirror(VRAM_MIRROR4H); else SetVRAM_Mirror(VRAM_MIRROR4H);
} }
break; break;
case 0xA001: case 0xA001:
reg[3] = data; reg[3] = data;
break; break;
case 0xC000: case 0xC000:
reg[4] = data; reg[4] = data;
irq_counter = data; irq_counter = data;
irq_request = 0; irq_request = 0;
break; break;
case 0xC001: case 0xC001:
reg[5] = data; reg[5] = data;
irq_latch = data; irq_latch = data;
irq_request = 0; irq_request = 0;
break; break;
case 0xE000: case 0xE000:
reg[6] = data; reg[6] = data;
irq_enable = 0; irq_enable = 0;
irq_request = 0; irq_request = 0;
nes.cpu.ClrIRQ(IRQ_MAPPER); nes.cpu.ClrIRQ(IRQ_MAPPER);
break; break;
case 0xE001: case 0xE001:
reg[7] = data; reg[7] = data;
irq_enable = 1; irq_enable = 1;
irq_request = 0; irq_request = 0;
break; break;
} }
} }
//void Mapper199::HSync(INT scanline) //void Mapper199::HSync(INT scanline)
public override void HSync(int scanline) public override void HSync(int scanline)
{ {
if ((scanline >= 0 && scanline <= 239)) if ((scanline >= 0 && scanline <= 239))
{ {
if (nes.ppu.IsDispON()) if (nes.ppu.IsDispON())
{ {
if (irq_enable != 0 && irq_request == 0) if (irq_enable != 0 && irq_request == 0)
{ {
if (scanline == 0) if (scanline == 0)
{ {
if (irq_counter != 0) if (irq_counter != 0)
{ {
irq_counter--; irq_counter--;
} }
} }
if ((irq_counter--) == 0) if ((irq_counter--) == 0)
{ {
irq_request = 0xFF; irq_request = 0xFF;
irq_counter = irq_latch; irq_counter = irq_latch;
nes.cpu.SetIRQ(IRQ_MAPPER); nes.cpu.SetIRQ(IRQ_MAPPER);
} }
} }
} }
} }
} }
void SetBank_CPU() void SetBank_CPU()
{ {
SetPROM_8K_Bank(4, prg[0 ^ (reg[0] >> 5 & ~(0 << 1) & 2)]); 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(5, prg[1 ^ (reg[0] >> 5 & ~(1 << 1) & 2)]);
SetPROM_8K_Bank(6, prg[2 ^ (reg[0] >> 5 & ~(2 << 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)]); SetPROM_8K_Bank(7, prg[3 ^ (reg[0] >> 5 & ~(3 << 1) & 2)]);
} }
void SetBank_PPU() void SetBank_PPU()
{ {
//unsigned int bank = (reg[0] & 0x80) >> 5; //unsigned int bank = (reg[0] & 0x80) >> 5;
int bank = (reg[0] & 0x80) >> 5; int bank = (reg[0] & 0x80) >> 5;
for (int x = 0; x < 8; x++) for (int x = 0; x < 8; x++)
{ {
if (chr[x] <= 7) if (chr[x] <= 7)
{ {
SetCRAM_1K_Bank((byte)(x ^ bank), chr[x]); SetCRAM_1K_Bank((byte)(x ^ bank), chr[x]);
} }
else else
{ {
SetVROM_1K_Bank((byte)(x ^ bank), chr[x]); SetVROM_1K_Bank((byte)(x ^ bank), chr[x]);
} }
} }
} }
//void Mapper199::SaveState(LPBYTE p) //void Mapper199::SaveState(LPBYTE p)
public override void SaveState(byte[] p) public override void SaveState(byte[] p)
{ {
for (INT i = 0; i < 8; i++) for (INT i = 0; i < 8; i++)
{ {
p[i] = reg[i]; p[i] = reg[i];
p[10 + i] = chr[i]; p[10 + i] = chr[i];
} }
p[8] = prg[0]; p[8] = prg[0];
p[9] = prg[1]; p[9] = prg[1];
p[18] = irq_enable; p[18] = irq_enable;
p[19] = irq_counter; p[19] = irq_counter;
p[20] = irq_latch; p[20] = irq_latch;
p[21] = irq_request; p[21] = irq_request;
p[22] = prg[2]; p[22] = prg[2];
p[23] = prg[3]; p[23] = prg[3];
} }
//void Mapper199::LoadState(LPBYTE p) //void Mapper199::LoadState(LPBYTE p)
public override void LoadState(byte[] p) public override void LoadState(byte[] p)
{ {
for (INT i = 0; i < 8; i++) for (INT i = 0; i < 8; i++)
{ {
reg[i] = p[i]; reg[i] = p[i];
chr[i] = p[10 + i]; chr[i] = p[10 + i];
} }
prg[0] = p[8]; prg[0] = p[8];
prg[1] = p[9]; prg[1] = p[9];
irq_enable = p[18]; irq_enable = p[18];
irq_counter = p[19]; irq_counter = p[19];
irq_latch = p[20]; irq_latch = p[20];
irq_request = p[21]; irq_request = p[21];
prg[2] = p[22]; prg[2] = p[22];
prg[3] = p[23]; prg[3] = p[23];
} }
public override bool IsStateSave() public override bool IsStateSave()
{ {
return true; return true;
} }
} }
} }

View File

@ -20,7 +20,7 @@ namespace VirtualNes.Core
{ {
SetPROM_32K_Bank(0, 1, 2, 3); SetPROM_32K_Bank(0, 1, 2, 3);
if (VROM_1K_SIZE) if (VROM_1K_SIZE != 0)
{ {
SetVROM_8K_Bank(0); SetVROM_8K_Bank(0);
} }

View File

@ -324,7 +324,7 @@ namespace VirtualNes.Core
} }
} }
private int GetIrqType() internal int GetIrqType()
{ {
return nIRQtype; return nIRQtype;
} }
@ -1668,6 +1668,16 @@ namespace VirtualNes.Core
return NES_scanline; return NES_scanline;
} }
internal void SetSAVERAM_SIZE(int size)
{
SAVERAM_SIZE = size;
}
internal byte GetBarcodeStatus()
{
return m_BarcodeOut;
}
public enum IRQMETHOD public enum IRQMETHOD
{ {
IRQ_HSYNC = 0, IRQ_CLOCK = 1 IRQ_HSYNC = 0, IRQ_CLOCK = 1

View File

@ -1,4 +1,6 @@
namespace VirtualNes.Core using System;
namespace VirtualNes.Core
{ {
public class PPU public class PPU
{ {
@ -1125,6 +1127,26 @@
return (MMU.PPUREG[1] & (PPU_BGDISP_BIT | PPU_SPDISP_BIT)) != 0; 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 struct Sprite
{ {
public byte y public byte y

View File

@ -401,6 +401,11 @@ namespace VirtualNes.Core
{ {
return path; return path;
} }
internal uint GetVROM_CRC()
{
return crcvrom;
}
} }

Binary file not shown.