This commit is contained in:
ALIENJACK\alien 2024-07-26 17:52:33 +08:00
parent 88214310d7
commit 323e8c66a2
101 changed files with 4073 additions and 244 deletions

View File

@ -62,5 +62,7 @@ namespace AxibugEmuOnline.Client
romName = Path.GetFileNameWithoutExtension(romName);
File.WriteAllBytes($"{diskFileDirectoryPath}/{romName}.dsv", diskFileContent);
}
public EmulatorConfig Config { get; private set; } = new EmulatorConfig();
}
}

View File

@ -10,8 +10,7 @@ namespace AxibugEmuOnline.Client
private void Start()
{
//StartGame("Kirby.nes");
StartGame("Kirby.nes");
}
public void StartGame(string romName)

View File

@ -10,6 +10,12 @@ namespace VirtualNes.Core
private NES nes;
private byte exsound_select;
private APU_INTERNAL @internal = new APU_INTERNAL();
private APU_VRC6 vrc6 = new APU_VRC6();
private APU_VRC7 vrc7 = new APU_VRC7();
private APU_MMC5 mmc5 = new APU_MMC5();
private APU_FDS fds = new APU_FDS();
private APU_N106 n106 = new APU_N106();
private APU_FME7 fme7 = new APU_FME7();
private int last_data;
private int last_diff;
protected short[] m_SoundBuffer = new short[256];
@ -17,6 +23,7 @@ namespace VirtualNes.Core
protected QUEUE queue = new QUEUE();
protected QUEUE exqueue = new QUEUE();
protected bool[] m_bMute = new bool[16];
protected double elapsed_time;
public APU(NES parent)
{
@ -90,6 +97,81 @@ namespace VirtualNes.Core
}
return false;
}
public void SoundSetup()
{
float fClock = nes.nescfg.CpuClock;
int nRate = Supporter.Config.sound.nRate;
@internal.Setup(fClock, nRate);
vrc6.Setup(fClock, nRate);
vrc7.Setup(fClock, nRate);
mmc5.Setup(fClock, nRate);
fds.Setup(fClock, nRate);
n106.Setup(fClock, nRate);
fme7.Setup(fClock, nRate);
}
internal void SelectExSound(byte data)
{
exsound_select = data;
}
internal void Reset()
{
queue = new QUEUE();
exqueue = new QUEUE();
elapsed_time = 0;
float fClock = nes.nescfg.CpuClock;
int nRate = Supporter.Config.sound.nRate;
@internal.Reset(fClock, nRate);
vrc6.Reset(fClock, nRate);
vrc7.Reset(fClock, nRate);
mmc5.Reset(fClock, nRate);
fds.Reset(fClock, nRate);
n106.Reset(fClock, nRate);
fme7.Reset(fClock, nRate);
SoundSetup();
}
internal void ExWrite(ushort addr, byte data)
{
SetExQueue(nes.cpu.GetTotalCycles(), addr, data);
if ((exsound_select & 0x04) != 0)
{
if (addr >= 0x4040 && addr < 0x4100)
{
fds.SyncWrite(addr, data);
}
}
if ((exsound_select & 0x08) != 0)
{
if (addr >= 0x5000 && addr <= 0x5015)
{
mmc5.SyncWrite(addr, data);
}
}
}
private void SetExQueue(int writetime, ushort addr, byte data)
{
exqueue.data[exqueue.wrptr].time = writetime;
exqueue.data[exqueue.wrptr].addr = addr;
exqueue.data[exqueue.wrptr].data = data;
exqueue.wrptr++;
var temp = QUEUE_LENGTH - 1;
exqueue.wrptr = (int)(exqueue.wrptr & temp);
if (exqueue.wrptr == exqueue.rdptr)
{
Debuger.LogError("exqueue overflow.");
}
}
}
public struct QUEUEDATA

View File

@ -0,0 +1,45 @@
using System;
namespace VirtualNes.Core
{
public class APU_FDS : APU_INTERFACE
{
private FDSSOUND fds = new FDSSOUND();
private FDSSOUND fds_sync = new FDSSOUND();
public override void Reset(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Setup(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Write(ushort addr, byte data)
{
throw new System.NotImplementedException();
}
public override int Process(int channel)
{
throw new System.NotImplementedException();
}
internal void SyncWrite(ushort addr, byte data)
{
WriteSub(addr, data, fds_sync, 1789772.5d);
}
private void WriteSub(ushort addr, byte data, FDSSOUND ch, double rate)
{
throw new NotImplementedException();
}
private class FDSSOUND
{
//todo : 实现
}
}
}

View File

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

View File

@ -0,0 +1,27 @@
using System;
namespace VirtualNes.Core
{
public class APU_FME7 : APU_INTERFACE
{
public override void Reset(float fClock, int nRate)
{
throw new NotImplementedException();
}
public override void Setup(float fClock, int nRate)
{
throw new NotImplementedException();
}
public override void Write(ushort addr, byte data)
{
throw new NotImplementedException();
}
public override int Process(int channel)
{
throw new NotImplementedException();
}
}
}

View File

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

View File

@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualNes.Core
namespace VirtualNes.Core
{
public abstract class APU_INTERFACE
{
public const float APU_CLOCK = 1789772.5f;
public virtual void Dispose() { }
public abstract void Reset(float fClock, int nRate);
public abstract void Setup(float fClock, int nRate);
public abstract void Write(ushort addr, byte data);
@ -24,5 +22,15 @@ namespace VirtualNes.Core
public virtual int GetStateSize() { return 0; }
public virtual void SaveState(byte[] p) { }
public virtual void LoadState(byte[] p) { }
public static int INT2FIX(int x)
{
return x << 16;
}
public static int FIX2INT(int x)
{
return x >> 16;
}
}
}

View File

@ -1,5 +1,3 @@
using System;
namespace VirtualNes.Core
{
public class APU_INTERNAL : APU_INTERFACE
@ -63,8 +61,43 @@ namespace VirtualNes.Core
private bool SyncUpdateDPCM(int cycles)
{
//TODO : 实现
return false;
bool bIRQ = false;
if (ch4.sync_enable != 0)
{
ch4.sync_cycles -= cycles;
while (ch4.sync_cycles < 0)
{
ch4.sync_cycles += ch4.sync_cache_cycles;
if (ch4.sync_dmalength != 0)
{
// if( !(--ch4.sync_dmalength) ) {
if (--ch4.sync_dmalength < 2)
{
if (ch4.sync_looping != 0)
{
ch4.sync_dmalength = ch4.sync_cache_dmalength;
}
else
{
ch4.sync_dmalength = 0;
if (ch4.sync_irq_gen != 0)
{
ch4.sync_irq_enable = 0xFF;
nes.cpu.SetIRQ(CPU.IRQ_DPCM);
}
}
}
}
}
}
if (ch4.sync_irq_enable != 0)
{
bIRQ = true;
}
return bIRQ;
}
private void UpdateFrame()

View File

@ -0,0 +1,32 @@
using System;
namespace VirtualNes.Core
{
public class APU_MMC5 : APU_INTERFACE
{
public override void Reset(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Setup(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Write(ushort addr, byte data)
{
throw new System.NotImplementedException();
}
public override int Process(int channel)
{
throw new System.NotImplementedException();
}
internal void SyncWrite(ushort addr, byte data)
{
throw new NotImplementedException();
}
}
}

View File

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

View File

@ -0,0 +1,25 @@
namespace VirtualNes.Core
{
public class APU_N106 : APU_INTERFACE
{
public override void Reset(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Setup(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Write(ushort addr, byte data)
{
throw new System.NotImplementedException();
}
public override int Process(int channel)
{
throw new System.NotImplementedException();
}
}
}

View File

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

View File

@ -0,0 +1,310 @@
using System;
namespace VirtualNes.Core
{
public class APU_VRC6 : APU_INTERFACE
{
public const int RECTANGLE_VOL_SHIFT = 8;
public const int SAWTOOTH_VOL_SHIFT = 6;
private RECTANGLE ch0 = new RECTANGLE();
private RECTANGLE ch1 = new RECTANGLE();
private SAWTOOTH ch2 = new SAWTOOTH();
private int cycle_rate;
private float cpu_clock;
public APU_VRC6()
{
Reset(APU_CLOCK, 22050);
}
public override void Reset(float fClock, int nRate)
{
ch0.ZeroMemory();
ch1.ZeroMemory();
ch2.ZeroMemory();
Setup(fClock, nRate);
}
public override void Setup(float fClock, int nRate)
{
cpu_clock = fClock;
cycle_rate = (int)(fClock * 65536.0f / nRate);
}
public override void Write(ushort addr, byte data)
{
switch (addr)
{
// VRC6 CH0 rectangle
case 0x9000:
ch0.reg[0] = data;
ch0.gate = (byte)(data & 0x80);
ch0.volume = (byte)(data & 0x0F);
ch0.duty_pos = (byte)((data >> 4) & 0x07);
break;
case 0x9001:
ch0.reg[1] = data;
ch0.freq = INT2FIX((((ch0.reg[2] & 0x0F) << 8) | data) + 1);
break;
case 0x9002:
ch0.reg[2] = data;
ch0.enable = (byte)(data & 0x80);
ch0.freq = INT2FIX((((data & 0x0F) << 8) | ch0.reg[1]) + 1);
break;
// VRC6 CH1 rectangle
case 0xA000:
ch1.reg[0] = data;
ch1.gate = (byte)(data & 0x80);
ch1.volume = (byte)(data & 0x0F);
ch1.duty_pos = (byte)((data >> 4) & 0x07);
break;
case 0xA001:
ch1.reg[1] = data;
ch1.freq = INT2FIX((((ch1.reg[2] & 0x0F) << 8) | data) + 1);
break;
case 0xA002:
ch1.reg[2] = data;
ch1.enable = (byte)(data & 0x80);
ch1.freq = INT2FIX((((data & 0x0F) << 8) | ch1.reg[1]) + 1);
break;
// VRC6 CH2 sawtooth
case 0xB000:
ch2.reg[1] = data;
ch2.phaseaccum = (byte)(data & 0x3F);
break;
case 0xB001:
ch2.reg[1] = data;
ch2.freq = INT2FIX((((ch2.reg[2] & 0x0F) << 8) | data) + 1);
break;
case 0xB002:
ch2.reg[2] = data;
ch2.enable = (byte)(data & 0x80);
ch2.freq = INT2FIX((((data & 0x0F) << 8) | ch2.reg[1]) + 1);
// ch2.adder = 0; // 僋儕傾偡傞偲僲僀僘偺尨場偵側傞
// ch2.accum = 0; // 僋儕傾偡傞偲僲僀僘偺尨場偵側傞
break;
}
}
public override int Process(int channel)
{
switch (channel)
{
case 0:
return RectangleRender(ch0);
case 1:
return RectangleRender(ch1);
case 2:
return SawtoothRender(ch2);
}
return 0;
}
public override int GetFreq(int channel)
{
if (channel == 0 || channel == 1)
{
RECTANGLE ch = null;
if (channel == 0) ch = ch0;
else ch = ch1;
if (ch.enable == 0 || ch.gate != 0 || ch.volume == 0)
return 0;
if (ch.freq < INT2FIX(8))
return 0;
return (int)(256.0f * cpu_clock / (FIX2INT(ch.freq) * 16.0f));
}
if (channel == 2)
{
SAWTOOTH ch = ch2;
if (ch.enable == 0 || ch.phaseaccum == 0)
return 0;
if (ch.freq < INT2FIX(8))
return 0;
return (int)(256.0f * cpu_clock / (FIX2INT(ch.freq) * 14.0f));
}
return 0;
}
private int RectangleRender(RECTANGLE ch)
{
// Enable?
if (ch.enable == 0)
{
ch.output_vol = 0;
ch.adder = 0;
return ch.output_vol;
}
// Digitized output
if (ch.gate != 0)
{
ch.output_vol = ch.volume << RECTANGLE_VOL_SHIFT;
return ch.output_vol;
}
// 堦掕埲忋偺廃攇悢偼張棟偟側偄(柍懯)
if (ch.freq < INT2FIX(8))
{
ch.output_vol = 0;
return ch.output_vol;
}
ch.phaseacc -= cycle_rate;
if (ch.phaseacc >= 0)
return ch.output_vol;
int output = ch.volume << RECTANGLE_VOL_SHIFT;
if (ch.freq > cycle_rate)
{
// add 1 step
ch.phaseacc += ch.freq;
ch.adder = (byte)((ch.adder + 1) & 0x0F);
if (ch.adder <= ch.duty_pos)
ch.output_vol = output;
else
ch.output_vol = -output;
}
else
{
// average calculate
int num_times, total;
num_times = total = 0;
while (ch.phaseacc < 0)
{
ch.phaseacc += ch.freq;
ch.adder = (byte)((ch.adder + 1) & 0x0F);
if (ch.adder <= ch.duty_pos)
total += output;
else
total += -output;
num_times++;
}
ch.output_vol = total / num_times;
}
return ch.output_vol;
}
private int SawtoothRender(SAWTOOTH ch)
{
// Digitized output
if (ch.enable == 0)
{
ch.output_vol = 0;
return ch.output_vol;
}
// 堦掕埲忋偺廃攇悢偼張棟偟側偄(柍懯)
if (ch.freq < INT2FIX(9))
{
return ch.output_vol;
}
ch.phaseacc -= cycle_rate / 2;
if (ch.phaseacc >= 0)
return ch.output_vol;
if (ch.freq > cycle_rate / 2)
{
// add 1 step
ch.phaseacc += ch.freq;
if (++ch.adder >= 7)
{
ch.adder = 0;
ch.accum = 0;
}
ch.accum += ch.phaseaccum;
ch.output_vol = ch.accum << SAWTOOTH_VOL_SHIFT;
}
else
{
// average calculate
int num_times, total;
num_times = total = 0;
while (ch.phaseacc < 0)
{
ch.phaseacc += ch.freq;
if (++ch.adder >= 7)
{
ch.adder = 0;
ch.accum = 0;
}
ch.accum += ch.phaseaccum;
total += ch.accum << SAWTOOTH_VOL_SHIFT;
num_times++;
}
ch.output_vol = (total / num_times);
}
return ch.output_vol;
}
private class RECTANGLE
{
public byte[] reg = new byte[3];
public byte enable;
public byte gate;
public byte volume;
public int phaseacc;
public int freq;
public int output_vol;
public byte adder;
public byte duty_pos;
public void ZeroMemory()
{
Array.Clear(reg, 0, reg.Length);
enable = default;
gate = default;
volume = default;
phaseacc = default;
freq = default;
output_vol = default;
adder = default;
duty_pos = default;
}
}
private class SAWTOOTH
{
public byte[] reg = new byte[3];
public byte enable;
public byte volume;
public int phaseacc;
public int freq;
public int output_vol;
public byte adder;
public byte accum;
public byte phaseaccum;
public void ZeroMemory()
{
Array.Clear(reg, 0, reg.Length);
enable = default;
volume = default;
phaseacc = default;
freq = default;
output_vol = default;
adder = default;
accum = default;
phaseaccum = default;
}
}
}
}

View File

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

View File

@ -0,0 +1,25 @@
namespace VirtualNes.Core
{
public class APU_VRC7 : APU_INTERFACE
{
public override void Reset(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Setup(float fClock, int nRate)
{
throw new System.NotImplementedException();
}
public override void Write(ushort addr, byte data)
{
throw new System.NotImplementedException();
}
public override int Process(int channel)
{
throw new System.NotImplementedException();
}
}
}

View File

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

View File

@ -1,11 +1,4 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualNes.Core
namespace VirtualNes.Core
{
public class DPCM
{

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualNes.Core
namespace VirtualNes.Core
{
public class NOISE
{

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualNes.Core
{
@ -47,5 +43,43 @@ namespace VirtualNes.Core
public byte sync_holdnote;
public byte dummy2;
public int sync_len_count;
public void ZeroMemory()
{
Array.Clear(reg, 0, reg.Length);
enable = 0;
holdnote = 0;
volume = 0;
complement = 0;
phaseacc = 0;
freq = 0;
freqlimit = 0;
adder = 0;
duty = 0;
len_count = 0;
nowvolume = 0;
env_fixed = 0;
env_decay = 0;
env_count = 0;
dummy0 = 0;
env_vol = 0;
swp_on = 0;
swp_inc = 0;
swp_shift = 0;
swp_decay = 0;
swp_count = 0;
Array.Clear(dummy1, 0, dummy1.Length);
Array.Clear(sync_reg, 0, sync_reg.Length);
sync_output_enable = 0;
sync_enable = 0;
sync_holdnote = 0;
dummy2 = 0;
sync_len_count = 0;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
namespace VirtualNes.Core
{
public class CHEATCODE
{
public byte enable;
public byte type;
public byte length;
public ushort address;
public uint data;
public string comment;
}
class GENIECODE
{
public ushort address;
public byte data;
public byte cmp;
};
}

View File

@ -1,22 +1,17 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting.Antlr3.Runtime.Tree;
using UnityEngine;
namespace VirtualNes.Core
{
public static class CRC
{
const int CHAR_BIT = 8;
const ulong CRCPOLY1 = 0x04C11DB7UL;
const ulong CRCPOLY2 = 0xEDB88320UL;
const uint CRCPOLY1 = 0x04C11DB7U;
const uint CRCPOLY2 = 0xEDB88320U;
static bool m_Init;
static bool m_InitRev;
static ulong[] m_CrcTable = new ulong[byte.MaxValue + 1];
static ulong[] m_CrcTableRev = new ulong[byte.MaxValue + 1];
static uint[] m_CrcTable = new uint[byte.MaxValue + 1];
static uint[] m_CrcTableRev = new uint[byte.MaxValue + 1];
public static ulong Crc(int size, Span<byte> c)
{
@ -35,7 +30,7 @@ namespace VirtualNes.Core
}
return ~r & 0xFFFFFFFFUL;
}
public static ulong CrcRev(int size, Span<byte> c)
public static uint CrcRev(int size, Span<byte> c)
{
if (!m_InitRev)
{
@ -43,41 +38,41 @@ namespace VirtualNes.Core
m_InitRev = true;
}
ulong r = 0xFFFFFFFFUL;
uint r = 0xFFFFFFFFU;
int step = 0;
while (--size >= 0)
{
r = (r >> CHAR_BIT) ^ m_CrcTableRev[(byte)r ^ c[step]];
step++;
}
return r ^ 0xFFFFFFFFUL;
return r ^ 0xFFFFFFFFU;
}
static void MakeTable()
{
int i, j;
ulong r;
uint r;
for (i = 0; i <= byte.MaxValue; i++)
{
r = (ulong)i << (32 - CHAR_BIT);
r = (uint)i << (32 - CHAR_BIT);
for (j = 0; j < CHAR_BIT; j++)
{
if ((r & 0x80000000UL) > 0) r = (r << 1) ^ CRCPOLY1;
else r <<= 1;
}
m_CrcTable[i] = r & 0xFFFFFFFFUL;
m_CrcTable[i] = r & 0xFFFFFFFFU;
}
}
static void MakeTableRev()
{
int i, j;
ulong r;
uint r;
for (i = 0; i <= byte.MaxValue; i++)
{
r = (ulong)i;
r = (uint)i;
for (j = 0; j < CHAR_BIT; j++)
{
if ((r & 1) > 0) r = (r >> 1) ^ CRCPOLY2;

View File

@ -0,0 +1,145 @@
using System;
namespace VirtualNes.Core
{
public class OPLL_PATCH
{
public uint TL, FB, EG, ML, AR, DR, SL, RR, KR, KL, AM, PM, WF;
}
public class OPLL_SLOT
{
public OPLL_PATCH patch;
public int type; /* 0 : modulator 1 : carrier */
/* OUTPUT */
public Int32 feedback;
public Int32[] output = new Int32[5]; /* Output value of slot */
/* for Phase Generator (PG) */
public UInt32 sintbl; /* Wavetable */
public UInt32 phase; /* Phase */
public UInt32 dphase; /* Phase increment amount */
public UInt32 pgout; /* output */
/* for Envelope Generator (EG) */
public int fnum; /* F-Number */
public int block; /* Block */
public int volume; /* Current volume */
public int sustine; /* Sustine 1 = ON, 0 = OFF */
public UInt32 tll; /* Total Level + Key scale level*/
public UInt32 rks; /* Key scale offset (Rks) */
public int eg_mode; /* Current state */
public UInt32 eg_phase; /* Phase */
public UInt32 eg_dphase; /* Phase increment amount */
public UInt32 egout; /* output */
/* refer to opll-> */
public UInt32 plfo_pm;
public UInt32 plfo_am;
}
public class OPLL_CH
{
public int patch_number;
public int key_status;
public OPLL_SLOT mod;
public OPLL_SLOT car;
}
public class OPLL
{
public UInt32 adr;
public Int32[] output = new Int32[2];
/* Register */
public byte[] reg = new byte[0x40];
public int[] slot_on_flag = new int[18];
/* Rythm Mode : 0 = OFF, 1 = ON */
public int rythm_mode;
/* Pitch Modulator */
public UInt32 pm_phase;
public Int32 lfo_pm;
/* Amp Modulator */
public Int32 am_phase;
public Int32 lfo_am;
/* Noise Generator */
public UInt32 noise_seed;
public UInt32 whitenoise;
public UInt32 noiseA;
public UInt32 noiseB;
public UInt32 noiseA_phase;
public UInt32 noiseB_phase;
public UInt32 noiseA_idx;
public UInt32 noiseB_idx;
public UInt32 noiseA_dphase;
public UInt32 noiseB_dphase;
}
public static class Emu2413API
{
public static void OPLL_init(UInt32 c, UInt32 r)
{
makePmTable();
makeAmTable();
makeDB2LinTable();
makeAdjustTable();
makeTllTable();
makeRksTable();
makeSinTable();
makeDefaultPatch();
OPLL_setClock(c, r);
}
private static void OPLL_setClock(uint c, uint r)
{
throw new NotImplementedException();
}
private static void makeDefaultPatch()
{
throw new NotImplementedException();
}
private static void makeSinTable()
{
throw new NotImplementedException();
}
private static void makeRksTable()
{
throw new NotImplementedException();
}
private static void makeTllTable()
{
throw new NotImplementedException();
}
private static void makeAdjustTable()
{
throw new NotImplementedException();
}
private static void makeDB2LinTable()
{
throw new NotImplementedException();
}
private static void makeAmTable()
{
throw new NotImplementedException();
}
private static void makePmTable()
{
throw new NotImplementedException();
}
}
}

View File

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

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualNes.Core
namespace VirtualNes.Core
{
// 昤夋曽幃
public enum EnumRenderMethod

View File

@ -0,0 +1,17 @@
using System.Runtime.CompilerServices;
namespace VirtualNes.Core
{
public static class MemoryUtility
{
public static void ZEROMEMORY(byte[] array, uint length)
{
memset(array, 0, length);
}
public static void memset(byte[] array, byte value, uint length)
{
Unsafe.InitBlock(ref array[0], value, length);
}
}
}

View File

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

View File

@ -1,11 +1,11 @@
namespace VirtualNes.Core
{
public struct NesConfig
public class NesConfig
{
public float BaseClock; // NTSC:21477270.0 PAL:21281364.0
public float CpuClock; // NTSC: 1789772.5 PAL: 1773447.0
public int TotalScanLines; // NTSC: 262 PAL: 312
public int TotalScanlines; // NTSC: 262 PAL: 312
public int ScanlineCycles; // NTSC:1364 PAL:1362
@ -19,40 +19,33 @@
public int FrameRate; // NTSC:60(59.94) PAL:50
public float FramePeriod; // NTSC:16.683 PAL:20.0
public static NesConfig GetNTSC()
public static NesConfig NESCONFIG_NTSC = new NesConfig
{
return new NesConfig
{
BaseClock = 21477270.0f,
CpuClock = 1789772.5f,
TotalScanLines = 262,
ScanlineCycles = 1364,
HDrawCycles = 1024,
HBlankCycles = 340,
ScanlineEndCycles = 4,
FrameCycles = 1364 * 262,
FrameIrqCycles = 29830,
FrameRate = 60,
FramePeriod = 1000.0f / 60.0f
};
}
public static NesConfig GetPAL()
BaseClock = 21477270.0f,
CpuClock = 1789772.5f,
TotalScanlines = 262,
ScanlineCycles = 1364,
HDrawCycles = 1024,
HBlankCycles = 340,
ScanlineEndCycles = 4,
FrameCycles = 1364 * 262,
FrameIrqCycles = 29830,
FrameRate = 60,
FramePeriod = 1000.0f / 60.0f
};
public static NesConfig NESCONFIG_PAL = new NesConfig
{
return new NesConfig
{
BaseClock = 26601714.0f,
CpuClock = 1662607.125f,
TotalScanLines = 312,
ScanlineCycles = 1278,
HDrawCycles = 960,
HBlankCycles = 318,
ScanlineEndCycles = 2,
FrameCycles = 1278 * 312,
FrameIrqCycles = 33252,
FrameRate = 50,
FramePeriod = 1000.0f / 50.0f
};
}
BaseClock = 26601714.0f,
CpuClock = 1662607.125f,
TotalScanlines = 312,
ScanlineCycles = 1278,
HDrawCycles = 960,
HBlankCycles = 318,
ScanlineEndCycles = 2,
FrameCycles = 1278 * 312,
FrameIrqCycles = 33252,
FrameRate = 50,
FramePeriod = 1000.0f / 50.0f
};
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace VirtualNes.Core
{
@ -27,7 +24,7 @@ namespace VirtualNes.Core
NSF
}
public struct NSFHEADER
public class NSFHEADER
{
byte[] ID;
byte Version;
@ -43,7 +40,7 @@ namespace VirtualNes.Core
byte[] BankSwitch;
ushort SpeedPAL;
byte NTSC_PALbits;
byte ExtraChipSelect;
public byte ExtraChipSelect;
byte[] Expansion; // must be 0
@ -65,7 +62,7 @@ namespace VirtualNes.Core
}
}
public struct NESHEADER
public class NESHEADER
{
public byte[] ID;
public byte PRG_PAGE_SIZE;

View File

@ -1,13 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using UnityEngine;
namespace VirtualNes.Core
{
public static class RomPatch
{
public static void DoPatch(ref ulong crc, ref byte[] lpPRG, ref byte[] lpCHR, ref int mapper, ref NESHEADER header)
public static void DoPatch(ref uint crc, ref byte[] lpPRG, ref byte[] lpCHR, ref int mapper, ref NESHEADER header)
{
// Mapper 000
if (crc == 0x57970078)

View File

@ -1,9 +1,4 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
namespace VirtualNes.Core
{

View File

@ -1,26 +1,22 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
namespace VirtualNes
{
public static class MMU
{
// CPU 儊儌儕僶儞僋
public static byte[][] CPU_MEM_BANK = new byte[8][]; // 8K扨埵
public static Memory<byte>[] CPU_MEM_BANK = new Memory<byte>[8]; // 8K扨埵
public static byte[] CPU_MEM_TYPE = new byte[8];
public static int[] CPU_MEM_PAGE = new int[8]; // 僗僥乕僩僙乕僽梡
// PPU 儊儌儕僶儞僋
public static byte[][] PPU_MEM_BANK = new byte[12][]; // 1K扨埵
public static Memory<byte>[] PPU_MEM_BANK = new Memory<byte>[12]; // 1K扨埵
public static byte[] PPU_MEM_TYPE = new byte[12];
public static int[] PPU_MEM_PAGE = new int[12]; // 僗僥乕僩僙乕僽梡
public static byte[] CRAM_USED = new byte[16]; // 僗僥乕僩僙乕僽梡
// NES儊儌儕
public static byte[] RAM = new byte[8 * 1024]; // NES撪憻RAM
public static byte[] WARM = new byte[128 * 1024]; // 儚乕僋/僶僢僋傾僢僾RAM
public static byte[] WRAM = new byte[128 * 1024]; // 儚乕僋/僶僢僋傾僢僾RAM
public static byte[] DRAM = new byte[40 * 1024]; // 僨傿僗僋僔僗僥儉RAM
public static byte[] XRAM = new byte[8 * 1024]; // 僟儈乕僶儞僋
public static byte[] ERAM = new byte[32 * 1024]; // 奼挘婡婍梡RAM
@ -42,6 +38,17 @@ namespace VirtualNes
public static ushort loopy_v; // same as $2005/$2006
public static ushort loopy_x; // tile x offset
// ROM僨乕僞億僀儞僞
public static byte[] PROM; // PROM ptr
public static byte[] VROM; // VROM ptr
// For dis...
public static byte PROM_ACCESS;
// ROM 僶儞僋僒僀僘
public static int PROM_8K_SIZE, PROM_16K_SIZE, PROM_32K_SIZE;
public static int VROM_1K_SIZE, VROM_2K_SIZE, VROM_4K_SIZE, VROM_8K_SIZE;
// 儊儌儕僞僀僾
// For PROM (CPU)
public const byte BANKTYPE_ROM = 0x00;
@ -60,5 +67,170 @@ namespace VirtualNes
public const byte VRAM_MIRROR4L = 0x03; // PA10 L屌掕 $2000-$23FF偺儈儔乕
public const byte VRAM_MIRROR4H = 0x04; // PA10 H屌掕 $2400-$27FF偺儈儔乕
internal static void SetPROM_Bank(byte page, Memory<byte> ptr, byte type)
{
CPU_MEM_BANK[page] = ptr;
CPU_MEM_TYPE[page] = type;
CPU_MEM_PAGE[page] = 0;
}
internal static void SetPROM_8K_Bank(byte page, int bank)
{
bank %= PROM_8K_SIZE;
CPU_MEM_BANK[page] = new Memory<byte>(MMU.PROM, 0x2000 * bank, MMU.PROM.Length - 0x2000 * bank);
CPU_MEM_TYPE[page] = BANKTYPE_ROM;
CPU_MEM_PAGE[page] = bank;
}
internal static void SetPROM_16K_Bank(byte page, int bank)
{
SetPROM_8K_Bank((byte)(page + 0), bank * 2 + 0);
SetPROM_8K_Bank((byte)(page + 1), bank * 2 + 1);
}
internal static void SetPROM_32K_Bank(int bank)
{
SetPROM_8K_Bank(4, bank * 4 + 0);
SetPROM_8K_Bank(5, bank * 4 + 1);
SetPROM_8K_Bank(6, bank * 4 + 2);
SetPROM_8K_Bank(7, bank * 4 + 3);
}
internal static void SetPROM_32K_Bank(int bank0, int bank1, int bank2, int bank3)
{
SetPROM_8K_Bank(4, bank0);
SetPROM_8K_Bank(5, bank1);
SetPROM_8K_Bank(6, bank2);
SetPROM_8K_Bank(7, bank3);
}
// PPU VROM bank
internal static void SetVROM_Bank(byte page, Memory<byte> ptr, byte type)
{
PPU_MEM_BANK[page] = ptr;
PPU_MEM_TYPE[page] = type;
PPU_MEM_PAGE[page] = 0;
}
internal static void SetVROM_1K_Bank(byte page, int bank)
{
bank %= VROM_1K_SIZE;
PPU_MEM_BANK[page] = new Memory<byte>(VROM, 0x0400 * bank, VROM.Length - (0x0400 * bank));
PPU_MEM_TYPE[page] = BANKTYPE_VROM;
PPU_MEM_PAGE[page] = bank;
}
internal static void SetVROM_2K_Bank(byte page, int bank)
{
SetVROM_1K_Bank((byte)(page + 0), bank * 2 + 0);
SetVROM_1K_Bank((byte)(page + 1), bank * 2 + 1);
}
internal static void SetVROM_4K_Bank(byte page, int bank)
{
SetVROM_1K_Bank((byte)(page + 0), bank * 4 + 0);
SetVROM_1K_Bank((byte)(page + 1), bank * 4 + 1);
SetVROM_1K_Bank((byte)(page + 2), bank * 4 + 2);
SetVROM_1K_Bank((byte)(page + 3), bank * 4 + 3);
}
internal static void SetVROM_8K_Bank(int bank)
{
for (byte i = 0; i < 8; i++)
{
SetVROM_1K_Bank(i, bank * 8 + i);
}
}
internal static void SetVROM_8K_Bank(int bank0, int bank1, int bank2, int bank3,
int bank4, int bank5, int bank6, int bank7)
{
SetVROM_1K_Bank(0, bank0);
SetVROM_1K_Bank(1, bank1);
SetVROM_1K_Bank(2, bank2);
SetVROM_1K_Bank(3, bank3);
SetVROM_1K_Bank(4, bank4);
SetVROM_1K_Bank(5, bank5);
SetVROM_1K_Bank(6, bank6);
SetVROM_1K_Bank(7, bank7);
}
internal static void SetCRAM_1K_Bank(byte page, int bank)
{
bank &= 0x1F;
PPU_MEM_BANK[page] = new Memory<byte>(MMU.CRAM, 0x0400 * bank, MMU.CRAM.Length - 0x0400 * bank);
PPU_MEM_TYPE[page] = BANKTYPE_CRAM;
PPU_MEM_PAGE[page] = bank;
CRAM_USED[bank >> 2] = 0xFF; // CRAM巊梡僼儔僌
}
internal static void SetCRAM_2K_Bank(byte page, int bank)
{
SetCRAM_1K_Bank((byte)(page + 0), bank * 2 + 0);
SetCRAM_1K_Bank((byte)(page + 1), bank * 2 + 1);
}
internal static void SetCRAM_4K_Bank(byte page, int bank)
{
SetCRAM_1K_Bank((byte)(page + 0), bank * 4 + 0);
SetCRAM_1K_Bank((byte)(page + 1), bank * 4 + 1);
SetCRAM_1K_Bank((byte)(page + 2), bank * 4 + 2);
SetCRAM_1K_Bank((byte)(page + 3), bank * 4 + 3);
}
internal static void SetCRAM_8K_Bank(int bank)
{
for (byte i = 0; i < 8; i++)
{
SetCRAM_1K_Bank(i, bank * 8 + 1);
}
}
internal static void SetVRAM_1K_Bank(byte page, int bank)
{
bank &= 3;
PPU_MEM_BANK[page] = new Memory<byte>(VRAM, 0x0400 * bank, VRAM.Length - 0x0400 * bank);
PPU_MEM_TYPE[page] = BANKTYPE_VRAM;
PPU_MEM_PAGE[page] = bank;
}
internal static void SetVRAM_Bank(int bank0, int bank1, int bank2, int bank3)
{
SetVRAM_1K_Bank(8, bank0);
SetVRAM_1K_Bank(9, bank1);
SetVRAM_1K_Bank(10, bank2);
SetVRAM_1K_Bank(11, bank3);
}
internal static void SetVRAM_Mirror(int type)
{
switch (type)
{
case VRAM_HMIRROR:
SetVRAM_Bank(0, 0, 1, 1);
break;
case VRAM_VMIRROR:
SetVRAM_Bank(0, 1, 0, 1);
break;
case VRAM_MIRROR4L:
SetVRAM_Bank(0, 0, 0, 0);
break;
case VRAM_MIRROR4H:
SetVRAM_Bank(1, 1, 1, 1);
break;
case VRAM_MIRROR4:
SetVRAM_Bank(0, 1, 2, 3);
break;
}
}
internal static void SetVRAM_Mirror(int bank0, int bank1, int bank2, int bank3)
{
SetVRAM_1K_Bank(8, bank0);
SetVRAM_1K_Bank(9, bank1);
SetVRAM_1K_Bank(10, bank2);
SetVRAM_1K_Bank(11, bank3);
}
}
}

View File

@ -1,9 +1,4 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
namespace VirtualNes.Core
{
@ -30,7 +25,7 @@ namespace VirtualNes.Core
// $6000-$7FFF WRAM
if (addr >= 0x6000 && addr <= 0x7FFF)
{
return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
return MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF];
}
return (byte)(addr >> 8);
@ -39,7 +34,7 @@ namespace VirtualNes.Core
{
if (addr >= 0x6000 && addr <= 0x7FFF)
{
MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] = data;
}
}

View File

@ -1,4 +1,3 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections.Generic;
using System.IO;
@ -18,10 +17,14 @@ namespace VirtualNes.Core
public NesConfig nescfg;
private List<CHEATCODE> m_CheatCode = new List<CHEATCODE>();
private List<GENIECODE> m_GenieCode = new List<GENIECODE>();
private bool m_bDiskThrottle;
private int m_CommandRequest;
private int m_nSnapNo;
private bool m_bNsfPlaying;
private bool m_bNsfInit;
private int m_nNsfSongNo;
private int m_nNsfSongMode;
private bool m_bMoviePlay;
private bool m_bMovieRec;
private Stream m_fpMovie;
@ -96,7 +99,7 @@ namespace VirtualNes.Core
bVideoMode = false;
nescfg = NesConfig.GetNTSC();
nescfg = NesConfig.NESCONFIG_NTSC;
CheatInitial();
@ -203,18 +206,203 @@ namespace VirtualNes.Core
SaveDISK();
SaveTurboFile();
//todo : ʵÏÖ
// RAM Clear
MemoryUtility.ZEROMEMORY(MMU.RAM, (uint)MMU.RAM.Length);
if (rom.GetPROM_CRC() == 0x29401686)
{ // Minna no Taabou no Nakayoshi Dai Sakusen(J)
MemoryUtility.memset(MMU.RAM, 0xFF, (uint)MMU.RAM.Length);
}
// RAM set
if (!rom.IsSAVERAM() && rom.GetMapperNo() != 20)
{
MemoryUtility.memset(MMU.WRAM, 0xFF, (uint)MMU.WRAM.Length);
}
MemoryUtility.ZEROMEMORY(MMU.CRAM, (uint)MMU.CRAM.Length);
MemoryUtility.ZEROMEMORY(MMU.VRAM, (uint)MMU.VRAM.Length);
MemoryUtility.ZEROMEMORY(MMU.SPRAM, (uint)MMU.SPRAM.Length);
MemoryUtility.ZEROMEMORY(MMU.BGPAL, (uint)MMU.BGPAL.Length);
MemoryUtility.ZEROMEMORY(MMU.SPPAL, (uint)MMU.SPPAL.Length);
MemoryUtility.ZEROMEMORY(MMU.CPUREG, (uint)MMU.CPUREG.Length);
MemoryUtility.ZEROMEMORY(MMU.PPUREG, (uint)MMU.PPUREG.Length);
m_bDiskThrottle = false;
SetRenderMethod(EnumRenderMethod.PRE_RENDER);
if (rom.IsPAL())
{
SetVideoMode(true);
}
MMU.PROM = rom.GetPROM();
MMU.VROM = rom.GetVROM();
MMU.PROM_8K_SIZE = rom.GetPROM_SIZE() * 2;
MMU.PROM_16K_SIZE = rom.GetPROM_SIZE();
MMU.PROM_32K_SIZE = rom.GetPROM_SIZE() / 2;
MMU.VROM_1K_SIZE = rom.GetVROM_SIZE() * 8;
MMU.VROM_2K_SIZE = rom.GetVROM_SIZE() * 4;
MMU.VROM_4K_SIZE = rom.GetVROM_SIZE() * 2;
MMU.VROM_8K_SIZE = rom.GetVROM_SIZE();
// デフォルトバンク
if (MMU.VROM_8K_SIZE != 0)
{
MMU.SetVROM_8K_Bank(0);
}
else
{
MMU.SetCRAM_8K_Bank(0);
}
// ミラー
if (rom.Is4SCREEN())
{
MMU.SetVRAM_Mirror(MMU.VRAM_MIRROR4);
}
else if (rom.IsVMIRROR())
{
MMU.SetVRAM_Mirror(MMU.VRAM_VMIRROR);
}
else
{
MMU.SetVRAM_Mirror(MMU.VRAM_HMIRROR);
}
apu.SelectExSound(0);
ppu.Reset();
mapper.Reset();
// Trainer
if (rom.IsTRAINER())
{
Array.Copy(rom.GetTRAINER(), 0, MMU.WRAM, 0x1000, 512);
}
pad.Reset();
cpu.Reset();
apu.Reset();
if (rom.IsNSF())
{
mapper.Reset();
}
base_cycles = emul_cycles = 0;
}
internal void SetVideoMode(bool bMode)
{
bVideoMode = bMode;
if (!bVideoMode)
{
nescfg = NesConfig.NESCONFIG_NTSC;
}
else
{
nescfg = NesConfig.NESCONFIG_PAL;
}
apu.SoundSetup();
}
public void SetRenderMethod(EnumRenderMethod type)
{
RenderMethod = type;
}
internal void SoftReset()
{
//todo : ʵÏÖ
pad.Reset();
cpu.Reset();
apu.Reset();
if (rom.IsNSF())
{
mapper.Reset();
}
m_bDiskThrottle = false;
base_cycles = emul_cycles = 0;
}
internal void EmulateNSF()
{
//todo : ʵÏÖNSFÄ£Äâ
throw new NotImplementedException("EmulateNSF");
R6502 reg = null;
ppu.Reset();
mapper.VSync();
//DEBUGOUT( "Frame\n" );
if (m_bNsfPlaying)
{
if (m_bNsfInit)
{
MemoryUtility.ZEROMEMORY(MMU.RAM, (uint)MMU.RAM.Length);
if ((rom.GetNsfHeader().ExtraChipSelect & 0x04) == 0)
{
MemoryUtility.ZEROMEMORY(MMU.RAM, 0x2000);
}
apu.Reset();
apu.Write(0x4015, 0x0F);
apu.Write(0x4017, 0xC0);
apu.ExWrite(0x4080, 0x80); // FDS Volume 0
apu.ExWrite(0x408A, 0xE8); // FDS Envelope Speed
cpu.GetContext(ref reg);
reg.PC = 0x4710; // Init Address
reg.A = (byte)m_nNsfSongNo;
reg.X = (byte)m_nNsfSongMode;
reg.Y = 0;
reg.S = 0xFF;
reg.P = CPU.Z_FLAG | CPU.R_FLAG | CPU.I_FLAG;
// 安全対策を兼ねてあえてループに(1秒分)
for (int i = 0; i < nescfg.TotalScanlines * 60; i++)
{
EmulationCPU(nescfg.ScanlineCycles);
cpu.GetContext(ref reg);
// 無限ループに入ったことを確認したら抜ける
if (reg.PC == 0x4700)
{
break;
}
}
m_bNsfInit = false;
}
cpu.GetContext(ref reg);
// 無限ループに入っていたら再設定する
if (reg.PC == 0x4700)
{
reg.PC = 0x4720; // Play Address
reg.A = 0;
reg.S = 0xFF;
}
for (int i = 0; i < nescfg.TotalScanlines; i++)
{
EmulationCPU(nescfg.ScanlineCycles);
}
}
else
{
cpu.GetContext(ref reg);
reg.PC = 0x4700; // 無限ループ
reg.S = 0xFF;
EmulationCPU(nescfg.ScanlineCycles * nescfg.TotalScanlines);
}
}
internal void CheatCodeProcess()
@ -239,7 +427,7 @@ namespace VirtualNes.Core
for (i = 0; i < SAVERAM_SIZE; i++)
{
if (MMU.WARM[i] != 0x00)
if (MMU.WRAM[i] != 0x00)
break;
}
@ -249,7 +437,7 @@ namespace VirtualNes.Core
Debuger.Log($"Saving SAVERAM...[{romName}]");
Supporter.SaveSRAMToFile(MMU.WARM, romName);
Supporter.SaveSRAMToFile(MMU.WRAM, romName);
}
}
@ -382,7 +570,7 @@ namespace VirtualNes.Core
case 0x05: // $A000-$BFFF
case 0x06: // $C000-$DFFF
case 0x07: // $E000-$FFFF
return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
return MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF];
}
return 0x00; // Warning—\h
@ -508,23 +696,47 @@ namespace VirtualNes.Core
}
else
{
mapper->WriteLow(addr, data);
mapper.WriteLow(addr, data);
}
break;
case 0x03: // $6000-$7FFF
mapper->WriteLow(addr, data);
mapper.WriteLow(addr, data);
break;
case 0x04: // $8000-$9FFF
case 0x05: // $A000-$BFFF
case 0x06: // $C000-$DFFF
case 0x07: // $E000-$FFFF
mapper->Write(addr, data);
mapper.Write(addr, data);
GenieCodeProcess();
break;
}
}
private void GenieCodeProcess()
{
ushort addr;
for (int i = 0; i < m_GenieCode.Count; i++)
{
addr = m_GenieCode[i].address;
if ((addr & 0x8000) != 0)
{
// 8character codes
if (MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] == m_GenieCode[i].cmp)
{
MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] = m_GenieCode[i].data;
}
}
else
{
// 6character codes
addr |= 0x8000;
MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] = m_GenieCode[i].data;
}
}
}
private void WriteReg(ushort addr, byte data)
{
switch (addr & 0xFF)
@ -561,20 +773,20 @@ namespace VirtualNes.Core
case 0x16:
mapper.ExWrite(addr, data); // For VS-Unisystem
pad.Write(addr, data);
CPUREG[addr & 0xFF] = data;
MMU.CPUREG[addr & 0xFF] = data;
m_TapeIn = data;
break;
case 0x17:
CPUREG[addr & 0xFF] = data;
pad->Write(addr, data);
apu->Write(addr, data);
MMU.CPUREG[addr & 0xFF] = data;
pad.Write(addr, data);
apu.Write(addr, data);
break;
// VirtuaNESŒÅ—Lƒ|<7C>[ƒg
case 0x18:
apu->Write(addr, data);
apu.Write(addr, data);
break;
default:
mapper->ExWrite(addr, data);
mapper.ExWrite(addr, data);
break;
}
}

View File

@ -1,4 +1,5 @@
using System;
using Codice.CM.Client.Differences;
using System;
namespace VirtualNes.Core
{
@ -17,6 +18,10 @@ namespace VirtualNes.Core
private byte[] padbitsync = new byte[4];
private byte micbitsync;
private bool bBarcodeWorld;
private int[][] padcnt = new int[4][]
{
new int[2],new int[2],new int[2],new int[2],
};
public uint pad1bit, pad2bit, pad3bit, pad4bit;
@ -79,6 +84,326 @@ namespace VirtualNes.Core
return data;
}
public void Dispose() { }
internal void Write(ushort addr, byte data)
{
if (addr == 0x4016)
{
if ((data & 0x01) != 0)
{
bStrobe = true;
}
else if (bStrobe)
{
bStrobe = false;
Strobe();
if (expad != null)
{
expad.Strobe();
}
}
if (expad != null)
{
expad.Write4016(data);
}
}
if (addr == 0x4017)
{
if (expad != null)
{
expad.Write4017(data);
}
}
}
private void Strobe()
{
// For VS-Unisystem
if (nes.rom.IsVSUNISYSTEM())
{
uint pad1 = (uint)(padbitsync[0] & 0xF3);
uint pad2 = (uint)(padbitsync[1] & 0xF3);
uint st1 = (uint)(padbitsync[0] & 0x08) >> 3;
uint st2 = (uint)(padbitsync[1] & 0x08) >> 3;
switch (nVSSwapType)
{
case VSType.VS_TYPE0:
pad1bit = pad1 | (st1 << 2);
pad2bit = pad2 | (st2 << 2);
break;
case VSType.VS_TYPE1:
pad1bit = pad2 | (st1 << 2);
pad2bit = pad1 | (st2 << 2);
break;
case VSType.VS_TYPE2:
pad1bit = pad1 | (st1 << 2) | (st2 << 3);
pad2bit = pad2;
break;
case VSType.VS_TYPE3:
pad1bit = pad2 | (st1 << 2) | (st2 << 3);
pad2bit = pad1;
break;
case VSType.VS_TYPE4:
pad1bit = pad1 | (st1 << 2) | 0x08; // 0x08=Start Protect
pad2bit = pad2 | (st2 << 2) | 0x08; // 0x08=Start Protect
break;
case VSType.VS_TYPE5:
pad1bit = pad2 | (st1 << 2) | 0x08; // 0x08=Start Protect
pad2bit = pad1 | (st2 << 2) | 0x08; // 0x08=Start Protect
break;
case VSType.VS_TYPE6:
pad1bit = pad1 | (st1 << 2) | (((uint)padbitsync[0] & 0x04) << 1);
pad2bit = pad2 | (st2 << 2) | (((uint)padbitsync[1] & 0x04) << 1);
break;
case VSType.VS_TYPEZ:
pad1bit = 0;
pad2bit = 0;
break;
}
// Coin 2偲旐傞堊偵徚偡
micbit = 0;
}
else
{
if (Supporter.Config.emulator.bFourPlayer)
{
// NES type
pad1bit = padbitsync[0] | ((uint)padbitsync[2] << 8) | 0x00080000;
pad2bit = padbitsync[1] | ((uint)padbitsync[3] << 8) | 0x00040000;
}
else
{
// Famicom type
pad1bit = padbitsync[0];
pad2bit = padbitsync[1];
}
}
pad3bit = padbitsync[2];
pad4bit = padbitsync[3];
}
internal void Reset()
{
pad1bit = pad2bit = 0;
bStrobe = false;
bBarcodeWorld = false;
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 2; y++)
{
padcnt[x][y] = 0;
}
}
// Select Extension Devices
uint crc = nes.rom.GetPROM_CRC();
if (crc == 0xfbfc6a6c // Adventures of Bayou Billy, The(E)
|| crc == 0xcb275051 // Adventures of Bayou Billy, The(U)
|| crc == 0xfb69c131 // Baby Boomer(Unl)(U)
|| crc == 0xf2641ad0 // Barker Bill's Trick Shooting(U)
|| crc == 0xbc1dce96 // Chiller (Unl)(U)
|| crc == 0x90ca616d // Duck Hunt(JUE)
|| crc == 0x59e3343f // Freedom Force(U)
|| crc == 0x242a270c // Gotcha!(U)
|| crc == 0x7b5bd2de // Gumshoe(UE)
|| crc == 0x255b129c // Gun Sight(J)
|| crc == 0x8963ae6e // Hogan's Alley(JU)
|| crc == 0x51d2112f // Laser Invasion(U)
|| crc == 0x0a866c94 // Lone Ranger, The(U)
// || crc == 0xe4c04eea // Mad City(J)
|| crc == 0x9eef47aa // Mechanized Attack(U)
|| crc == 0xc2db7551 // Shooting Range(U)
|| crc == 0x163e86c0 // To The Earth(U)
|| crc == 0x42d893e4 // Operation Wolf(J)
|| crc == 0x1388aeb9 // Operation Wolf(U)
|| crc == 0x0d3cf705 // Wild Gunman(J)
|| crc == 0x389960db)
{ // Wild Gunman(JUE)
SetExController(EXCONTROLLER.EXCONTROLLER_ZAPPER);
}
if (crc == 0x35893b67 // Arkanoid(J)
|| crc == 0x6267fbd1)
{ // Arkanoid 2(J)
SetExController(EXCONTROLLER.EXCONTROLLER_PADDLE);
}
if (crc == 0xff6621ce // Hyper Olympic(J)
|| crc == 0xdb9418e8 // Hyper Olympic(Tonosama Ban)(J)
|| crc == 0xac98cd70)
{ // Hyper Sports(J)
SetExController(EXCONTROLLER.EXCONTROLLER_HYPERSHOT);
}
if (crc == 0xf9def527 // Family BASIC(Ver2.0)
|| crc == 0xde34526e // Family BASIC(Ver2.1a)
|| crc == 0xf050b611 // Family BASIC(Ver3)
|| crc == 0x3aaeed3f // Family BASIC(Ver3)(Alt)
|| crc == 0x868FCD89 // Family BASIC(Ver1.0)
|| crc == 0x2D6B7E5A // PLAYBOX BASIC(J) (Prototype_v0.0)
|| crc == 0xDA03D908)
{ // PLAYBOX BASIC (J)
SetExController(EXCONTROLLER.EXCONTROLLER_KEYBOARD);
}
if (crc == 0x589b6b0d // Supor Computer V3.0
|| crc == 0x8b265862 // Supor English
|| crc == 0x41401c6d // Supor Computer V4.0
|| crc == 0x82F1Fb96 // Supor Computer(Russia) V1.0
|| crc == 0xd5d6eac4)
{ // EDU(C) Computer
SetExController(EXCONTROLLER.EXCONTROLLER_SUPOR_KEYBOARD);
nes.SetVideoMode(true);
}
if (crc == 0xc68363f6 // Crazy Climber(J)
|| crc == 0x2989ead6 // Smash TV(U) [!]
|| crc == 0x0b8f8128)
{ // Smash TV(E) [!]
SetExController(EXCONTROLLER.EXCONTROLLER_CRAZYCLIMBER);
}
if (crc == 0x20d22251)
{ // Top rider(J)
SetExController(EXCONTROLLER.EXCONTROLLER_TOPRIDER);
}
if (crc == 0x0cd00488)
{ // Space Shadow(J)
SetExController(EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN);
}
if (crc == 0x8c8fa83b // Family Trainer - Athletic World (J)
|| crc == 0x7e704a14 // Family Trainer - Jogging Race (J)
|| crc == 0x2330a5d3)
{ // Family Trainer - Rairai Kyonshiizu (J)
SetExController(EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_A);
}
if (crc == 0xf8da2506 // Family Trainer - Aerobics Studio (J)
|| crc == 0xca26a0f1 // Family Trainer - Dai Undoukai (J)
|| crc == 0x28068b8c // Family Trainer - Fuuun Takeshi Jou 2 (J)
|| crc == 0x10bb8f9a // Family Trainer - Manhattan Police (J)
|| crc == 0xad3df455 // Family Trainer - Meiro Dai Sakusen (J)
|| crc == 0x8a5b72c0 // Family Trainer - Running Stadium (J)
|| crc == 0x59794f2d)
{ // Family Trainer - Totsugeki Fuuun Takeshi Jou (J)
SetExController(EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_B);
}
if (crc == 0x9fae4d46 // Ide Yousuke Meijin no Jissen Mahjong (J)
|| crc == 0x7b44fb2a)
{ // Ide Yousuke Meijin no Jissen Mahjong 2 (J)
SetExController(EXCONTROLLER.EXCONTROLLER_MAHJANG);
}
if (crc == 0x786148b6)
{ // Exciting Boxing (J)
SetExController(EXCONTROLLER.EXCONTROLLER_EXCITINGBOXING);
}
if (crc == 0xc3c0811d // Oeka Kids - Anpanman no Hiragana Daisuki (J)
|| crc == 0x9d048ea4)
{ // Oeka Kids - Anpanman to Oekaki Shiyou!! (J)
SetExController(EXCONTROLLER.EXCONTROLLER_OEKAKIDS_TABLET);
}
if (crc == 0x67898319)
{ // Barcode World (J)
bBarcodeWorld = true;
}
// VS-Unisystem
if (nes.rom.IsVSUNISYSTEM())
{
if (crc == 0xff5135a3 // VS Hogan's Alley
|| crc == 0xed588f00 // VS Duck Hunt
|| crc == 0x17ae56be)
{ // VS Freedom Force
SetExController(EXCONTROLLER.EXCONTROLLER_VSZAPPER);
}
else
{
SetExController(EXCONTROLLER.EXCONTROLLER_VSUNISYSTEM);
}
}
if (crc == 0x21b099f3)
{ // Gyromite (JUE)
SetExController(EXCONTROLLER.EXCONTROLLER_GYROMITE);
}
}
private void SetExController(EXCONTROLLER type)
{
excontroller_select = (int)type;
expad?.Dispose();
expad = null;
bZapperMode = false;
// ExPad Instance create
switch (type)
{
case EXCONTROLLER.EXCONTROLLER_ZAPPER:
expad = new EXPAD_Zapper(nes);
bZapperMode = true;
break;
case EXCONTROLLER.EXCONTROLLER_PADDLE:
expad = new EXPAD_Paddle(nes);
break;
case EXCONTROLLER.EXCONTROLLER_HYPERSHOT:
expad = new EXPAD_HyperShot(nes);
break;
case EXCONTROLLER.EXCONTROLLER_KEYBOARD:
expad = new EXPAD_Keyboard(nes);
break;
case EXCONTROLLER.EXCONTROLLER_SUPOR_KEYBOARD:
expad = new EXPAD_Supor_Keyboard(nes);
break;
case EXCONTROLLER.EXCONTROLLER_CRAZYCLIMBER:
expad = new EXPAD_CrazyClimber(nes);
break;
case EXCONTROLLER.EXCONTROLLER_TOPRIDER:
expad = new EXPAD_Toprider(nes);
break;
case EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN:
expad = new EXPAD_SpaceShadowGun(nes);
bZapperMode = true;
break;
case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_A:
case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_B:
expad = new EXPAD_FamlyTrainer(nes);
break;
case EXCONTROLLER.EXCONTROLLER_EXCITINGBOXING:
expad = new EXPAD_ExcitingBoxing(nes);
break;
case EXCONTROLLER.EXCONTROLLER_MAHJANG:
expad = new EXPAD_Mahjang(nes);
break;
case EXCONTROLLER.EXCONTROLLER_OEKAKIDS_TABLET:
expad = new EXPAD_OekakidsTablet(nes);
break;
case EXCONTROLLER.EXCONTROLLER_TURBOFILE:
expad = new EXPAD_TurboFile(nes);
break;
case EXCONTROLLER.EXCONTROLLER_VSUNISYSTEM:
expad = new EXPAD_VSUnisystem(nes);
break;
case EXCONTROLLER.EXCONTROLLER_VSZAPPER:
expad = new EXPAD_VSZapper(nes);
bZapperMode = true;
break;
case EXCONTROLLER.EXCONTROLLER_GYROMITE:
expad = new EXPAD_Gyromite(nes);
break;
default:
break;
}
if (expad != null)
{
expad.Reset();
}
}
}
public enum VSType
@ -92,4 +417,31 @@ namespace VirtualNes.Core
VS_TYPE6, // SELECT1P=START1P/SELECT2P=START2P 1P/2P Reverse (For Golf)
VS_TYPEZ, // ZAPPER
}
public enum EXCONTROLLER
{
EXCONTROLLER_NONE = 0,
EXCONTROLLER_PADDLE,
EXCONTROLLER_HYPERSHOT,
EXCONTROLLER_ZAPPER,
EXCONTROLLER_KEYBOARD,
EXCONTROLLER_CRAZYCLIMBER,
EXCONTROLLER_TOPRIDER,
EXCONTROLLER_SPACESHADOWGUN,
EXCONTROLLER_FAMILYTRAINER_A,
EXCONTROLLER_FAMILYTRAINER_B,
EXCONTROLLER_EXCITINGBOXING,
EXCONTROLLER_MAHJANG,
EXCONTROLLER_OEKAKIDS_TABLET,
EXCONTROLLER_TURBOFILE,
EXCONTROLLER_VSUNISYSTEM,
EXCONTROLLER_VSZAPPER,
EXCONTROLLER_GYROMITE,
EXCONTROLLER_STACKUP,
EXCONTROLLER_SUPOR_KEYBOARD,
}
}

View File

@ -95,15 +95,26 @@ namespace VirtualNes.Core
public const byte SP_COLOR_BIT = 0x03;
private NES nes;
private bool bExtLatch; // For MMC5
private bool bChrLatch; // For MMC2/MMC4
private bool bExtNameTable; // For Super Monkey no Dai Bouken
private bool bExtMono; // For Final Fantasy
private ushort loopy_y;
private ushort loopy_shift;
private byte[] lpScreen;
/// <summary> 作为lpScreen数组的索引 </summary>
private int lpScanline;
private int ScanlineNo;
private byte[] lpColormode;
private bool bVSMode;
private int nVSColorMap;
private byte VSSecurityData;
private byte[] Bit2Rev = new byte[256];
private int ScanlineNo;
/// <summary> 作为lpScreen数组的索引 </summary>
private int lpScanline;
public PPU(NES nes)
{
@ -128,9 +139,7 @@ namespace VirtualNes.Core
}
}
public void Dispose()
{
}
public void Dispose() { }
internal byte Read(ushort addr)
{
@ -178,7 +187,7 @@ namespace VirtualNes.Core
}
addr &= 0xEFFF;
}
MMU.PPU7_Temp = MMU.PPU_MEM_BANK[addr >> 10][addr & 0x03FF];
MMU.PPU7_Temp = MMU.PPU_MEM_BANK[addr >> 10].Span[addr & 0x03FF];
break;
}
@ -314,7 +323,7 @@ namespace VirtualNes.Core
}
if (MMU.PPU_MEM_TYPE[vaddr >> 10] != MMU.BANKTYPE_VROM)
{
MMU.PPU_MEM_BANK[vaddr >> 10][vaddr & 0x03FF] = data;
MMU.PPU_MEM_BANK[vaddr >> 10].Span[vaddr & 0x03FF] = data;
}
break;
}
@ -330,6 +339,30 @@ namespace VirtualNes.Core
}
}
internal void Reset()
{
bExtLatch = false;
bChrLatch = false;
bExtNameTable = false;
bExtMono = false;
MMU.PPUREG[0] = MMU.PPUREG[1] = 0;
MMU.PPU56Toggle = 0;
MMU.PPU7_Temp = 0xFF; // VS Excitebike偱偍偐偟偔側傞($2006傪撉傒偵峴偔僶僌偑偁傞)
// PPU7_Temp = 0;
MMU.loopy_v = MMU.loopy_t = 0;
MMU.loopy_x = loopy_y = 0;
loopy_shift = 0;
if (lpScreen != null)
MemoryUtility.memset(lpScreen, 0x3F, (int)(Screen.SCREEN_WIDTH) * (int)(Screen.SCREEN_HEIGHT));
if (lpColormode != null)
MemoryUtility.memset(lpColormode, 0, (int)(Screen.SCREEN_HEIGHT));
}
private enum Screen
{
SCREEN_WIDTH = 256 + 16,

View File

@ -1,8 +1,3 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace VirtualNes.Core
{
public class EXPAD
@ -23,7 +18,7 @@ namespace VirtualNes.Core
public virtual void Write4016(byte data) { }
public virtual void Write4017(byte data) { }
public virtual void Sync() { }
public virtual void SetSyncData(int type,int data) { }
public virtual void SetSyncData(int type, int data) { }
public virtual int GetSyncData(int type) { return 0x00; }
}
}

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_CrazyClimber : EXPAD
{
public EXPAD_CrazyClimber(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_ExcitingBoxing : EXPAD
{
public EXPAD_ExcitingBoxing(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_FamlyTrainer : EXPAD
{
public EXPAD_FamlyTrainer(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_Gyromite : EXPAD
{
public EXPAD_Gyromite(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_HyperShot : EXPAD
{
public EXPAD_HyperShot(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_Keyboard : EXPAD
{
public EXPAD_Keyboard(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_Mahjang : EXPAD
{
public EXPAD_Mahjang(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_OekakidsTablet : EXPAD
{
public EXPAD_OekakidsTablet(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
public class EXPAD_Paddle : EXPAD
{
public EXPAD_Paddle(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_SpaceShadowGun : EXPAD
{
public EXPAD_SpaceShadowGun(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_Supor_Keyboard : EXPAD
{
public EXPAD_Supor_Keyboard(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_Toprider : EXPAD
{
public EXPAD_Toprider(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_TurboFile : EXPAD
{
public EXPAD_TurboFile(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_VSUnisystem : EXPAD
{
public EXPAD_VSUnisystem(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,9 @@
namespace VirtualNes.Core
{
internal class EXPAD_VSZapper : EXPAD
{
public EXPAD_VSZapper(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualNes.Core
{
/// <summary>
/// 光枪
/// </summary>
public class EXPAD_Zapper : EXPAD
{
public EXPAD_Zapper(NES parent) : base(parent)
{
}
}
}

View File

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

View File

@ -1,9 +1,6 @@
using Codice.CM.Client.Differences;
using System;
using System;
using System.IO;
using System.Linq;
using VirtualNes.Core.Debug;
using static UnityEditor.PlayerSettings;
namespace VirtualNes.Core
{
@ -22,13 +19,13 @@ namespace VirtualNes.Core
protected byte[] lpTrainer;
protected byte[] lpDiskBios;
protected byte[] lpDisk;
protected ulong crc;
protected ulong crcall;
protected ulong crcvrom;
protected uint crc;
protected uint crcall;
protected uint crcvrom;
protected int mapper;
protected int diskno;
protected ulong fdsmakerID;
protected ulong fdsgameID;
protected uint fdsmakerID;
protected uint fdsgameID;
public ROM(string fname)
{
@ -256,7 +253,7 @@ namespace VirtualNes.Core
crc = crcall = crcvrom = 0;
fdsmakerID = lpPRG[0x1F];
fdsgameID = (ulong)((lpPRG[0x20] << 24) | (lpPRG[0x21] << 16) | (lpPRG[0x22] << 8) | (lpPRG[0x23] << 0));
fdsgameID = (uint)((lpPRG[0x20] << 24) | (lpPRG[0x21] << 16) | (lpPRG[0x22] << 8) | (lpPRG[0x23] << 0));
}
}
else //NSF
@ -301,6 +298,10 @@ namespace VirtualNes.Core
{
return bNSF;
}
public bool IsPAL()
{
return bPAL;
}
public bool IsSAVERAM()
{
@ -331,6 +332,11 @@ namespace VirtualNes.Core
return lpPRG;
}
internal byte[] GetVROM()
{
return lpCHR;
}
internal byte[] GetDISK()
{
return lpDisk;
@ -355,6 +361,41 @@ namespace VirtualNes.Core
{
return (header.control2 & (byte)EnumRomControlByte2.ROM_VSUNISYSTEM) != 0;
}
internal uint GetPROM_CRC()
{
return crc;
}
internal byte GetPROM_SIZE()
{
return header.PRG_PAGE_SIZE;
}
internal byte GetVROM_SIZE()
{
return header.CHR_PAGE_SIZE;
}
internal bool Is4SCREEN()
{
return (header.control1 & (byte)EnumRomControlByte1.ROM_4SCREEN) != 0;
}
internal bool IsVMIRROR()
{
return (header.control1 & (byte)EnumRomControlByte1.ROM_VMIRROR) != 0;
}
internal byte[] GetTRAINER()
{
return lpTrainer;
}
internal NSFHEADER GetNsfHeader()
{
return nsfheader;
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fd0714f580724604da063207fe69e274
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgController
{
}
}

View File

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

View File

@ -0,0 +1,18 @@
namespace VirtualNes.Core
{
public class CfgEmulator
{
public bool bIllegalOp { get; set; } = false;
public bool bAutoFrameSkip { get; set; } = true;
public bool bThrottle { get; set; } = true;
public int nThrottleFPS { get; set; } = 120;
public bool bBackground { get; set; } = false;
public int nPriority { get; set; } = 3;
public bool bFourPlayer { get; set; } = true;
public bool bCrcCheck { get; set; } = true;
public bool bDiskThrottle { get; set; } = true;
public bool bLoadFullscreen { get; set; } = false;
public bool bPNGsnapshot { get; set; } = false;
public bool bAutoIPS { get; set; } = false;
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgExtraSound
{
}
}

View File

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

View File

@ -1,6 +1,7 @@
namespace VirtualNes.Core
{
public class CHEATCODE
public class CfgGeneral
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgGraphics
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgLanguage
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgLauncher
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgMovie
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgNetPlay
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgPath
{
}
}

View File

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

View File

@ -0,0 +1,6 @@
namespace VirtualNes.Core
{
public class CfgShortCut
{
}
}

View File

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

View File

@ -0,0 +1,19 @@
namespace VirtualNes.Core
{
public class CfgSound
{
public bool bEnable { get; set; } = true;
public int nRate { get; set; } = 22050;
public int nBits { get; set; } = 8;
public int nBufferSize { get; set; } = 4;
public int nFilterType { get; set; } = 0;
public bool bChangeTone { get; set; } = false;
public bool bDisableVolumeEffect { get; set; } = false;
public bool bExtraSoundEnable { get; set; } = true;
public short[] nVolume { get; set; } = new short[16]
{
100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
};
}
}

View File

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

View File

@ -0,0 +1,20 @@
namespace VirtualNes.Core
{
public class EmulatorConfig
{
private bool m_bKeyboardDisable;
public CfgGeneral general { get; private set; } = new CfgGeneral();
public CfgPath path { get; private set; } = new CfgPath();
public CfgEmulator emulator { get; private set; } = new CfgEmulator();
public CfgGraphics graphics { get; private set; } = new CfgGraphics();
public CfgSound sound { get; private set; } = new CfgSound();
public CfgShortCut shortcut { get; private set; } = new CfgShortCut();
public CfgLanguage language { get; private set; } = new CfgLanguage();
public CfgController controller { get; private set; } = new CfgController();
public CfgMovie movie { get; private set; } = new CfgMovie();
public CfgLauncher launcher { get; private set; } = new CfgLauncher();
public CfgExtraSound extsound { get; private set; } = new CfgExtraSound();
public CfgNetPlay netplay { get; private set; } = new CfgNetPlay();
}
}

View File

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

View File

@ -1,7 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace VirtualNes.Core
{
@ -37,6 +34,8 @@ namespace VirtualNes.Core
{
s_support.SaveDISKToFile(diskFileContent, romName);
}
public static EmulatorConfig Config => s_support.Config;
}
public interface ISupporterImpl
@ -46,5 +45,6 @@ namespace VirtualNes.Core
Stream OpenFile_DISKSYS();
void SaveSRAMToFile(byte[] sramContent, string romName);
void SaveDISKToFile(byte[] diskFileContent, string romName);
EmulatorConfig Config { get; }
}
}

Some files were not shown because too many files have changed in this diff Show More