This commit is contained in:
ALIENJACK\alien 2024-07-30 18:53:36 +08:00
parent 1a371955f3
commit 4de4291a24
20 changed files with 600 additions and 57 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@
/AxibugEmuOnline.Client/ProjectSettings/ProjectVersion.txt /AxibugEmuOnline.Client/ProjectSettings/ProjectVersion.txt
/AxibugEmuOnline.Client/ProjectSettings/AutoStreamingSettings.asset /AxibugEmuOnline.Client/ProjectSettings/AutoStreamingSettings.asset
/AxibugEmuOnline.Client/Logs /AxibugEmuOnline.Client/Logs
/virtuanessrc097-master/save

View File

@ -7,6 +7,7 @@ namespace AxibugEmuOnline.Client
{ {
public class CoreDebuger : IDebugerImpl public class CoreDebuger : IDebugerImpl
{ {
public void Log(string message) public void Log(string message)
{ {
Debug.Log(message); Debug.Log(message);

View File

@ -1,4 +1,5 @@
using System; using System;
using System.IO;
using UnityEngine; using UnityEngine;
using VirtualNes.Core; using VirtualNes.Core;
using VirtualNes.Core.Debug; using VirtualNes.Core.Debug;
@ -26,7 +27,6 @@ namespace AxibugEmuOnline.Client
try try
{ {
m_nesIns = new NES(romName); m_nesIns = new NES(romName);
m_nesIns.Command(NESCOMMAND.NESCMD_HWRESET);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -46,9 +46,17 @@ namespace AxibugEmuOnline.Client
if (m_nesIns != null) if (m_nesIns != null)
{ {
m_nesIns.EmulateFrame(true); m_nesIns.EmulateFrame(true);
var screenBuffer = m_nesIns.ppu.GetScreenPtr(); var screenBuffer = m_nesIns.ppu.GetScreenPtr();
VideoProvider.SetDrawData(screenBuffer, PPU.SCREEN_WIDTH, PPU.SCREEN_HEIGHT); var lineColorMode = m_nesIns.ppu.GetLineColorMode();
VideoProvider.SetDrawData(screenBuffer, lineColorMode, 256, 240);
} }
} }
private void OnDestroy()
{
File.WriteAllLines("E:/log.txt", Debuger.logRecords);
}
} }
} }

View File

@ -0,0 +1,242 @@
using Codice.CM.Client.Differences;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using VirtualNes.Core;
namespace AxibugEmuOnline.Client.Assets.Script.NesEmulator
{
public static class PaletteDefine
{
public class PALBUF
{
public byte r;
public byte g;
public byte b;
public PALBUF(byte r, byte g, byte b)
{
this.r = r;
this.g = g;
this.b = b;
}
}
// スキャンラインカラー
private static int m_nScanlineColor => Supporter.Config.graphics.nScanlineColor;
public static float[][] PalConvTbl = new float[8][]
{
new float[3]{1.00f, 1.00f, 1.00f},
new float[3]{1.00f, 0.80f, 0.73f},
new float[3]{0.73f, 1.00f, 0.70f},
new float[3]{0.76f, 0.78f, 0.58f},
new float[3]{0.86f, 0.80f, 1.00f},
new float[3]{0.83f, 0.68f, 0.85f},
new float[3]{0.67f, 0.77f, 0.83f},
new float[3]{0.68f, 0.68f, 0.68f},
};
public static PALBUF[] m_PaletteBuf = new PALBUF[64]
{
new PALBUF(0x7F, 0x7F, 0x7F),
new PALBUF(0x20, 0x00, 0xB0),
new PALBUF(0x28, 0x00, 0xB8),
new PALBUF(0x60, 0x10, 0xA0),
new PALBUF(0x98, 0x20, 0x78),
new PALBUF(0xB0, 0x10, 0x30),
new PALBUF(0xA0, 0x30, 0x00),
new PALBUF(0x78, 0x40, 0x00),
new PALBUF(0x48, 0x58, 0x00),
new PALBUF(0x38, 0x68, 0x00),
new PALBUF(0x38, 0x6C, 0x00),
new PALBUF(0x30, 0x60, 0x40),
new PALBUF(0x30, 0x50, 0x80),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0xBC, 0xBC, 0xBC),
new PALBUF(0x40, 0x60, 0xF8),
new PALBUF(0x40, 0x40, 0xFF),
new PALBUF(0x90, 0x40, 0xF0),
new PALBUF(0xD8, 0x40, 0xC0),
new PALBUF(0xD8, 0x40, 0x60),
new PALBUF(0xE0, 0x50, 0x00),
new PALBUF(0xC0, 0x70, 0x00),
new PALBUF(0x88, 0x88, 0x00),
new PALBUF(0x50, 0xA0, 0x00),
new PALBUF(0x48, 0xA8, 0x10),
new PALBUF(0x48, 0xA0, 0x68),
new PALBUF(0x40, 0x90, 0xC0),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0xFF, 0xFF, 0xFF),
new PALBUF(0x60, 0xA0, 0xFF),
new PALBUF(0x50, 0x80, 0xFF),
new PALBUF(0xA0, 0x70, 0xFF),
new PALBUF(0xF0, 0x60, 0xFF),
new PALBUF(0xFF, 0x60, 0xB0),
new PALBUF(0xFF, 0x78, 0x30),
new PALBUF(0xFF, 0xA0, 0x00),
new PALBUF(0xE8, 0xD0, 0x20),
new PALBUF(0x98, 0xE8, 0x00),
new PALBUF(0x70, 0xF0, 0x40),
new PALBUF(0x70, 0xE0, 0x90),
new PALBUF(0x60, 0xD0, 0xE0),
new PALBUF(0x60, 0x60, 0x60),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0xFF, 0xFF, 0xFF),
new PALBUF(0x90, 0xD0, 0xFF),
new PALBUF(0xA0, 0xB8, 0xFF),
new PALBUF(0xC0, 0xB0, 0xFF),
new PALBUF(0xE0, 0xB0, 0xFF),
new PALBUF(0xFF, 0xB8, 0xE8),
new PALBUF(0xFF, 0xC8, 0xB8),
new PALBUF(0xFF, 0xD8, 0xA0),
new PALBUF(0xFF, 0xF0, 0x90),
new PALBUF(0xC8, 0xF0, 0x80),
new PALBUF(0xA0, 0xF0, 0xA0),
new PALBUF(0xA0, 0xFF, 0xC8),
new PALBUF(0xA0, 0xFF, 0xF0),
new PALBUF(0xA0, 0xA0, 0xA0),
new PALBUF(0x00, 0x00, 0x00),
new PALBUF(0x00, 0x00, 0x00),
};
#region
// Color
public static uint[][] m_cnPalette = new uint[8][]
{
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
};
// Color/Scanline
public static uint[][] m_csPalette = new uint[8][]
{
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
};
// Monochrome
public static uint[][] m_mnPalette = new uint[8][]
{
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
};
// Monochrome/Scanline
public static uint[][] m_msPalette = new uint[8][]
{
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
new uint[256],
};
#endregion
static PaletteDefine()
{
int Rbit = 0, Gbit = 0, Bbit = 0;
int Rsft = 0, Gsft = 0, Bsft = 0;
GetBitMask(0xFF0000, ref Rsft, ref Rbit);
GetBitMask(0x00FF00, ref Gsft, ref Gbit);
GetBitMask(0x0000FF, ref Bsft, ref Bbit);
for (int j = 0; j < 8; j++)
{
for (int i = 0; i < 64; i++)
{
uint Rn, Gn, Bn;
uint Rs, Gs, Bs;
// Normal
Rn = (uint)(PalConvTbl[j][0] * m_PaletteBuf[i].r);
Gn = (uint)(PalConvTbl[j][1] * m_PaletteBuf[i].g);
Bn = (uint)(PalConvTbl[j][2] * m_PaletteBuf[i].b);
// Scanline
Rs = (uint)(PalConvTbl[j][0] * m_PaletteBuf[i].r * m_nScanlineColor / 100.0f);
Gs = (uint)(PalConvTbl[j][1] * m_PaletteBuf[i].g * m_nScanlineColor / 100.0f);
Bs = (uint)(PalConvTbl[j][2] * m_PaletteBuf[i].b * m_nScanlineColor / 100.0f);
m_cnPalette[j][i] = ((Rn >> (8 - Rbit)) << Rsft) | ((Gn >> (8 - Gbit)) << Gsft) | ((Bn >> (8 - Bbit)) << Bsft);
m_csPalette[j][i] = ((Rs >> (8 - Rbit)) << Rsft) | ((Gs >> (8 - Gbit)) << Gsft) | ((Bs >> (8 - Bbit)) << Bsft);
// Monochrome
Rn = (uint)(m_PaletteBuf[i & 0x30].r);
Gn = (uint)(m_PaletteBuf[i & 0x30].g);
Bn = (uint)(m_PaletteBuf[i & 0x30].b);
Rn =
Gn =
Bn = (uint)(0.299f * Rn + 0.587f * Gn + 0.114f * Bn);
Rn = (uint)(PalConvTbl[j][0] * Rn);
Gn = (uint)(PalConvTbl[j][1] * Gn);
Bn = (uint)(PalConvTbl[j][2] * Bn);
if (Rn > 0xFF) Rs = 0xFF;
if (Gn > 0xFF) Gs = 0xFF;
if (Bn > 0xFF) Bs = 0xFF;
// Scanline
Rs = (uint)(m_PaletteBuf[i & 0x30].r * m_nScanlineColor / 100.0f);
Gs = (uint)(m_PaletteBuf[i & 0x30].g * m_nScanlineColor / 100.0f);
Bs = (uint)(m_PaletteBuf[i & 0x30].b * m_nScanlineColor / 100.0f);
Rs =
Gs =
Bs = (uint)(0.299f * Rs + 0.587f * Gs + 0.114f * Bs);
Rs = (uint)(PalConvTbl[j][0] * Rs);
Gs = (uint)(PalConvTbl[j][1] * Gs);
Bs = (uint)(PalConvTbl[j][2] * Bs);
if (Rs > 0xFF) Rs = 0xFF;
if (Gs > 0xFF) Gs = 0xFF;
if (Bs > 0xFF) Bs = 0xFF;
m_mnPalette[j][i] = ((Rn >> (8 - Rbit)) << Rsft) | ((Gn >> (8 - Gbit)) << Gsft) | ((Bn >> (8 - Bbit)) << Bsft);
m_msPalette[j][i] = ((Rs >> (8 - Rbit)) << Rsft) | ((Gs >> (8 - Gbit)) << Gsft) | ((Bs >> (8 - Bbit)) << Bsft);
}
}
}
// ビット位置の取得
static void GetBitMask(uint val, ref int shift, ref int bits)
{
shift = 0;
while (((val & (1 << shift)) == 0) && (shift < 32))
{
shift++;
}
bits = 32;
while (((val & (1 << (bits - 1))) == 0) && (bits > 0))
{
bits--;
}
bits = bits - shift;
}
}
}

View File

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

View File

@ -1,8 +1,13 @@
using AxibugEmuOnline.Client.Assets.Script.NesEmulator;
using Codice.CM.Client.Differences;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using VirtualNes.Core;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
@ -12,14 +17,56 @@ namespace AxibugEmuOnline.Client
private Texture2D wrapTex; private Texture2D wrapTex;
public void SetDrawData(byte[] data, int width, int height) public void SetDrawData(byte[] screenData, byte[] lineColorMode, int screenWidth, int screenHeight)
{ {
if (wrapTex == null) wrapTex = new Texture2D(width, height); if (wrapTex == null) wrapTex = new Texture2D(screenWidth, screenHeight);
var colors = data.Select(d => new Color((d / 255f), (d / 255f), (d / 255f), 1)).ToArray(); var str = Encoding.ASCII.GetString(screenData, 0, screenData.Length);
wrapTex.SetPixels(colors);
wrapTex.Apply(); uint[] pPal;
Graphics.Blit(wrapTex, Image.texture as RenderTexture); int pScn = 0;
int width;
var Dst = wrapTex.GetPixels32();
var pDst = 0;
for (int line = 0; line < screenHeight; line++)
{
if ((lineColorMode[line] & 0x80) != 0)
{
pPal = PaletteDefine.m_cnPalette[lineColorMode[line] & 0x07];
} }
else
{
pPal = PaletteDefine.m_mnPalette[lineColorMode[line] & 0x07];
}
width = screenWidth;
while (width > 0)
{
Color32 temp = new Color32(255, 255, 255, 255);
var edx = screenData[pScn];
byte index = (byte)(edx & 0xFF);
var colorData = pPal[index];
var rawData = BitConverter.GetBytes(colorData);
Dst[pDst] = new Color32(rawData[0], rawData[1], rawData[2], 255);
pScn += 1;
pDst += 1;
width -= 1;
}
pScn += PPU.SCREEN_WIDTH - screenWidth;
}
wrapTex.SetPixels32(Dst);
wrapTex.Apply();
Graphics.Blit(wrapTex, Image.mainTexture as RenderTexture);
}
} }
} }

View File

@ -1169,7 +1169,7 @@ namespace VirtualNes.Core
return (ushort)(nes.Read(addr) + nes.Read((ushort)(addr + 1)) * 0x100); return (ushort)(nes.Read(addr) + nes.Read((ushort)(addr + 1)) * 0x100);
} }
var temp = MMU.CPU_MEM_BANK[addr >> 13].Span; var temp = MMU.CPU_MEM_BANK[addr >> 13];
shortTemp[0] = temp[addr & 0x1FFF]; shortTemp[0] = temp[addr & 0x1FFF];
shortTemp[1] = temp[(addr & 0x1FFF) + 1]; shortTemp[1] = temp[(addr & 0x1FFF) + 1];
return BitConverter.ToUInt16(shortTemp, 0); return BitConverter.ToUInt16(shortTemp, 0);
@ -1716,14 +1716,14 @@ namespace VirtualNes.Core
internal byte OP6502(ushort addr) internal byte OP6502(ushort addr)
{ {
return MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF]; return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
} }
private byte[] shortTemp = new byte[2]; private byte[] shortTemp = new byte[2];
internal ushort OP6502W(ushort addr) internal ushort OP6502W(ushort addr)
{ {
var bytePage = MMU.CPU_MEM_BANK[addr >> 13]; var bytePage = MMU.CPU_MEM_BANK[addr >> 13];
var spanByte = bytePage.Span; var spanByte = bytePage;
shortTemp[0] = spanByte[addr & 0x1FFF]; shortTemp[0] = spanByte[addr & 0x1FFF];
shortTemp[1] = spanByte[(addr & 0x1FFF) + 1]; shortTemp[1] = spanByte[(addr & 0x1FFF) + 1];
return BitConverter.ToUInt16(shortTemp, 0); return BitConverter.ToUInt16(shortTemp, 0);
@ -1744,11 +1744,11 @@ namespace VirtualNes.Core
else else
{ {
// Dummy access // Dummy access
mapper.Read(addr, MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF]); mapper.Read(addr, MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]);
} }
// Quick bank read // Quick bank read
return MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF]; return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
} }
private void AND() private void AND()

View File

@ -0,0 +1,28 @@
namespace VirtualNes.Core
{
public class ByteArrayRef
{
private byte[] m_rawArray;
private int m_offset;
private int m_length;
public ByteArrayRef(byte[] array, int offset, int length)
{
m_rawArray = array;
m_offset = offset;
m_length = length;
}
public byte this[int index]
{
get
{
return m_rawArray[m_offset + index];
}
set
{
m_rawArray[(m_offset + index)] = value;
}
}
}
}

View File

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

View File

@ -1,7 +1,11 @@
namespace VirtualNes.Core.Debug using System.Collections.Generic;
namespace VirtualNes.Core.Debug
{ {
public static class Debuger public static class Debuger
{ {
public static List<string> logRecords = new List<string>();
private static IDebugerImpl s_debuger; private static IDebugerImpl s_debuger;
public static void Setup(IDebugerImpl debuger) public static void Setup(IDebugerImpl debuger)
{ {
@ -10,6 +14,7 @@
public static void Log(string message) public static void Log(string message)
{ {
s_debuger.Log(message); s_debuger.Log(message);
logRecords.Add(message);
} }
public static void LogError(string message) public static void LogError(string message)

View File

@ -1,15 +1,16 @@
using System; using System;
using VirtualNes.Core;
namespace VirtualNes namespace VirtualNes
{ {
public static class MMU public static class MMU
{ {
// CPU 儊儌儕僶儞僋 // CPU 儊儌儕僶儞僋
public static Memory<byte>[] CPU_MEM_BANK = new Memory<byte>[8]; // 8K扨埵 public static ByteArrayRef[] CPU_MEM_BANK = new ByteArrayRef[8]; // 8K扨埵
public static byte[] CPU_MEM_TYPE = new byte[8]; public static byte[] CPU_MEM_TYPE = new byte[8];
public static int[] CPU_MEM_PAGE = new int[8]; // 僗僥乕僩僙乕僽梡 public static int[] CPU_MEM_PAGE = new int[8]; // 僗僥乕僩僙乕僽梡
// PPU 儊儌儕僶儞僋 // PPU 儊儌儕僶儞僋
public static Memory<byte>[] PPU_MEM_BANK = new Memory<byte>[12]; // 1K扨埵 public static ByteArrayRef[] PPU_MEM_BANK = new ByteArrayRef[12]; // 1K扨埵
public static byte[] PPU_MEM_TYPE = new byte[12]; public static byte[] PPU_MEM_TYPE = new byte[12];
public static int[] PPU_MEM_PAGE = new int[12]; // 僗僥乕僩僙乕僽梡 public static int[] PPU_MEM_PAGE = new int[12]; // 僗僥乕僩僙乕僽梡
public static byte[] CRAM_USED = new byte[16]; // 僗僥乕僩僙乕僽梡 public static byte[] CRAM_USED = new byte[16]; // 僗僥乕僩僙乕僽梡
@ -70,9 +71,9 @@ namespace VirtualNes
// Frame-IRQ儗僕僗僞($4017) // Frame-IRQ儗僕僗僞($4017)
public static int FrameIRQ; public static int FrameIRQ;
internal static void SetPROM_Bank(byte page, Memory<byte> ptr, byte type) internal static void SetPROM_Bank(byte page, byte[] ptr, byte type)
{ {
CPU_MEM_BANK[page] = ptr; CPU_MEM_BANK[page] = new ByteArrayRef(ptr, 0, ptr.Length);
CPU_MEM_TYPE[page] = type; CPU_MEM_TYPE[page] = type;
CPU_MEM_PAGE[page] = 0; CPU_MEM_PAGE[page] = 0;
} }
@ -80,7 +81,7 @@ namespace VirtualNes
internal static void SetPROM_8K_Bank(byte page, int bank) internal static void SetPROM_8K_Bank(byte page, int bank)
{ {
bank %= PROM_8K_SIZE; bank %= PROM_8K_SIZE;
CPU_MEM_BANK[page] = new Memory<byte>(MMU.PROM, 0x2000 * bank, MMU.PROM.Length - 0x2000 * bank); CPU_MEM_BANK[page] = new ByteArrayRef(MMU.PROM, 0x2000 * bank, MMU.PROM.Length - 0x2000 * bank);
CPU_MEM_TYPE[page] = BANKTYPE_ROM; CPU_MEM_TYPE[page] = BANKTYPE_ROM;
CPU_MEM_PAGE[page] = bank; CPU_MEM_PAGE[page] = bank;
} }
@ -108,7 +109,7 @@ namespace VirtualNes
} }
// PPU VROM bank // PPU VROM bank
internal static void SetVROM_Bank(byte page, Memory<byte> ptr, byte type) internal static void SetVROM_Bank(byte page, ByteArrayRef ptr, byte type)
{ {
PPU_MEM_BANK[page] = ptr; PPU_MEM_BANK[page] = ptr;
PPU_MEM_TYPE[page] = type; PPU_MEM_TYPE[page] = type;
@ -118,7 +119,7 @@ namespace VirtualNes
internal static void SetVROM_1K_Bank(byte page, int bank) internal static void SetVROM_1K_Bank(byte page, int bank)
{ {
bank %= VROM_1K_SIZE; bank %= VROM_1K_SIZE;
PPU_MEM_BANK[page] = new Memory<byte>(VROM, 0x0400 * bank, VROM.Length - (0x0400 * bank)); PPU_MEM_BANK[page] = new ByteArrayRef(VROM, 0x0400 * bank, VROM.Length - (0x0400 * bank));
PPU_MEM_TYPE[page] = BANKTYPE_VROM; PPU_MEM_TYPE[page] = BANKTYPE_VROM;
PPU_MEM_PAGE[page] = bank; PPU_MEM_PAGE[page] = bank;
} }
@ -161,7 +162,7 @@ namespace VirtualNes
internal static void SetCRAM_1K_Bank(byte page, int bank) internal static void SetCRAM_1K_Bank(byte page, int bank)
{ {
bank &= 0x1F; bank &= 0x1F;
PPU_MEM_BANK[page] = new Memory<byte>(MMU.CRAM, 0x0400 * bank, MMU.CRAM.Length - 0x0400 * bank); PPU_MEM_BANK[page] = new ByteArrayRef(MMU.CRAM, 0x0400 * bank, MMU.CRAM.Length - 0x0400 * bank);
PPU_MEM_TYPE[page] = BANKTYPE_CRAM; PPU_MEM_TYPE[page] = BANKTYPE_CRAM;
PPU_MEM_PAGE[page] = bank; PPU_MEM_PAGE[page] = bank;
@ -193,7 +194,7 @@ namespace VirtualNes
internal static void SetVRAM_1K_Bank(byte page, int bank) internal static void SetVRAM_1K_Bank(byte page, int bank)
{ {
bank &= 3; bank &= 3;
PPU_MEM_BANK[page] = new Memory<byte>(VRAM, 0x0400 * bank, VRAM.Length - 0x0400 * bank); PPU_MEM_BANK[page] = new ByteArrayRef(VRAM, 0x0400 * bank, VRAM.Length - 0x0400 * bank);
PPU_MEM_TYPE[page] = BANKTYPE_VRAM; PPU_MEM_TYPE[page] = BANKTYPE_VRAM;
PPU_MEM_PAGE[page] = bank; PPU_MEM_PAGE[page] = bank;
} }

View File

@ -26,7 +26,7 @@ namespace VirtualNes.Core
// $6000-$7FFF WRAM // $6000-$7FFF WRAM
if (addr >= 0x6000 && addr <= 0x7FFF) if (addr >= 0x6000 && addr <= 0x7FFF)
{ {
return MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF]; return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
} }
return (byte)(addr >> 8); return (byte)(addr >> 8);
@ -35,7 +35,7 @@ namespace VirtualNes.Core
{ {
if (addr >= 0x6000 && addr <= 0x7FFF) if (addr >= 0x6000 && addr <= 0x7FFF)
{ {
MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] = data; MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
} }
} }

View File

@ -75,6 +75,10 @@ namespace VirtualNes.Core
private long base_cycles; private long base_cycles;
private long emul_cycles; private long emul_cycles;
// For VS-Unisystem
byte m_VSDipValue;
VSDIPSWITCH[] m_VSDipTable;
private byte[] m_PadImg = new byte[226] private byte[] m_PadImg = new byte[226]
{ {
28, 8, 28, 8,
@ -253,6 +257,65 @@ namespace VirtualNes.Core
NesSub_MemoryInitial(); NesSub_MemoryInitial();
LoadSRAM(); LoadSRAM();
LoadDISK(); LoadDISK();
{
// Pad弁仿旦囀分午場ヽ趙正奶立件弘互綈中及匹仇仇匹
uint crc = rom.GetPROM_CRC();
if (
crc == 0xe792de94 // Best Play - Pro Yakyuu (New) (J)
|| crc == 0xf79d684a // Best Play - Pro Yakyuu (Old) (J)
|| crc == 0xc2ef3422 // Best Play - Pro Yakyuu 2 (J)
|| crc == 0x974e8840 // Best Play - Pro Yakyuu '90 (J)
|| crc == 0xb8747abf // Best Play - Pro Yakyuu Special (J)
|| crc == 0x9fa1c11f // Castle Excellent (J)
|| crc == 0x0b0d4d1b // Derby Stallion - Zenkoku Ban (J)
|| crc == 0x728c3d98 // Downtown - Nekketsu Monogatari (J)
|| crc == 0xd68a6f33 // Dungeon Kid (J)
|| crc == 0x3a51eb04 // Fleet Commander (J)
|| crc == 0x7c46998b // Haja no Fuuin (J)
|| crc == 0x7e5d2f1a // Itadaki Street - Watashi no Mise ni Yottette (J)
|| crc == 0xcee5857b // Ninjara Hoi! (J)
|| crc == 0x50ec5e8b // Wizardry - Legacy of Llylgamyn (J)
|| crc == 0x343e9146 // Wizardry - Proving Grounds of the Mad Overlord (J)
|| crc == 0x33d07e45)
{ // Wizardry - The Knight of Diamonds (J)
pad.SetExController(EXCONTROLLER.EXCONTROLLER_TURBOFILE);
}
}
LoadTurboFile();
// VS-Unisystem及犯白巧伙玄偞隅
if (rom.IsVSUNISYSTEM())
{
uint crc = rom.GetPROM_CRC();
m_VSDipValue = 0;
m_VSDipTable = VsUnisystem.vsdip_default;
}
Reset();
// 必奈丞嘐衄及犯白巧伙玄左皿扑亦件毛偞隅(偞隅𥽋允媆卞妏丹鮋)
GameOption.defRenderMethod = (int)GetRenderMethod();
GameOption.defIRQtype = GetIrqType();
GameOption.defFrameIRQ = GetFrameIRQmode();
GameOption.defVideoMode = GetVideoMode();
// 偞隅毛伕奈玉仄化偞隅允月(巨件玄伉互剠仃木壬犯白巧伙玄互⻌月)
if (rom.GetMapperNo() != 20)
{
GameOption.Load(rom.GetPROM_CRC());
}
else
{
GameOption.Load(rom.GetGameID(), rom.GetMakerID());
}
SetRenderMethod((EnumRenderMethod)GameOption.nRenderMethod);
SetIrqType((IRQMETHOD)GameOption.nIRQtype);
SetFrameIRQmode(GameOption.bFrameIRQ);
SetVideoMode(GameOption.bVideoMode);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -261,6 +324,44 @@ namespace VirtualNes.Core
} }
} }
private int GetIrqType()
{
return nIRQtype;
}
private void LoadTurboFile()
{
MemoryUtility.ZEROMEMORY(MMU.ERAM, MMU.ERAM.Length);
if (pad.GetExController() != (int)EXCONTROLLER.EXCONTROLLER_TURBOFILE)
return;
var fp = Supporter.OpenFile(Supporter.Config.path.szSavePath, "TurboFile.vtf");
try
{
if (fp == null)
{
// xxx 白央奶伙毛嶱仃引六氏
throw new Exception($"Can Not Open File [TurboFile.vtf]");
}
long size = fp.Length;
// 白央奶伙扔奶朮龰腕
if (size > 32 * 1024)
{
size = 32 * 1024;
}
fp.Read(MMU.ERAM, 0, MMU.ERAM.Length);
fp.Close();
}
catch (Exception ex)
{
fp?.Close();
Debuger.LogError($"Loading TurboFile Error.\n{ex}");
}
}
private void LoadDISK() private void LoadDISK()
{ {
//todo : ´Åµú»ú¶ÁÈ¡Ö§³Ö //todo : ´Åµú»ú¶ÁÈ¡Ö§³Ö
@ -1308,7 +1409,7 @@ namespace VirtualNes.Core
case 0x05: // $A000-$BFFF case 0x05: // $A000-$BFFF
case 0x06: // $C000-$DFFF case 0x06: // $C000-$DFFF
case 0x07: // $E000-$FFFF case 0x07: // $E000-$FFFF
return MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF]; return MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
} }
return 0x00; // Warning—\h return 0x00; // Warning—\h
@ -1414,8 +1515,13 @@ namespace VirtualNes.Core
return ret; return ret;
} }
static int NESWRITECOUNT = 0;
internal void Write(ushort addr, byte data) internal void Write(ushort addr, byte data)
{ {
NESWRITECOUNT++;
Debuger.Log($"[{NESWRITECOUNT}] addr:{addr},data:{data}");
switch (addr >> 13) switch (addr >> 13)
{ {
case 0x00: // $0000-$1FFF case 0x00: // $0000-$1FFF
@ -1461,16 +1567,16 @@ namespace VirtualNes.Core
if ((addr & 0x8000) != 0) if ((addr & 0x8000) != 0)
{ {
// 8character codes // 8character codes
if (MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] == m_GenieCode[i].cmp) if (MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] == m_GenieCode[i].cmp)
{ {
MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] = m_GenieCode[i].data; MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = m_GenieCode[i].data;
} }
} }
else else
{ {
// 6character codes // 6character codes
addr |= 0x8000; addr |= 0x8000;
MMU.CPU_MEM_BANK[addr >> 13].Span[addr & 0x1FFF] = m_GenieCode[i].data; MMU.CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = m_GenieCode[i].data;
} }
} }
} }

View File

@ -330,7 +330,7 @@ namespace VirtualNes.Core
} }
} }
private void SetExController(EXCONTROLLER type) internal void SetExController(EXCONTROLLER type)
{ {
excontroller_select = (int)type; excontroller_select = (int)type;

View File

@ -1,12 +1,4 @@
using Codice.CM.Client.Differences; namespace VirtualNes.Core
using Microsoft.Win32;
using System;
using System.IO;
using Unity.VisualScripting.Antlr3.Runtime.Tree;
using UnityEngine;
using static VirtualNes.Core.PPU;
namespace VirtualNes.Core
{ {
public class PPU public class PPU
{ {
@ -195,7 +187,7 @@ namespace VirtualNes.Core
} }
addr &= 0xEFFF; addr &= 0xEFFF;
} }
MMU.PPU7_Temp = MMU.PPU_MEM_BANK[addr >> 10].Span[addr & 0x03FF]; MMU.PPU7_Temp = MMU.PPU_MEM_BANK[addr >> 10][addr & 0x03FF];
break; break;
} }
@ -331,7 +323,7 @@ namespace VirtualNes.Core
} }
if (MMU.PPU_MEM_TYPE[vaddr >> 10] != MMU.BANKTYPE_VROM) if (MMU.PPU_MEM_TYPE[vaddr >> 10] != MMU.BANKTYPE_VROM)
{ {
MMU.PPU_MEM_BANK[vaddr >> 10].Span[vaddr & 0x03FF] = data; MMU.PPU_MEM_BANK[vaddr >> 10][vaddr & 0x03FF] = data;
} }
break; break;
} }
@ -473,7 +465,7 @@ namespace VirtualNes.Core
int attradr = 0x23C0 + (MMU.loopy_v & 0x0C00) + ((MMU.loopy_v & 0x0380) >> 4); int attradr = 0x23C0 + (MMU.loopy_v & 0x0C00) + ((MMU.loopy_v & 0x0380) >> 4);
int ntbl_x = ntbladr & 0x001F; int ntbl_x = ntbladr & 0x001F;
int attrsft = (ntbladr & 0x0040) >> 4; int attrsft = (ntbladr & 0x0040) >> 4;
var pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10].Span; var pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10];
int tileadr; int tileadr;
int cache_tile = unchecked((int)(0xFFFF0000)); int cache_tile = unchecked((int)(0xFFFF0000));
@ -486,7 +478,6 @@ namespace VirtualNes.Core
for (int i = 0; i < 33; i++) for (int i = 0; i < 33; i++)
{ {
tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y; tileadr = tileofs + pNTBL[ntbladr & 0x03FF] * 0x10 + loopy_y;
attr = (byte)(((pNTBL[attradr + (ntbl_x >> 2)] >> ((ntbl_x & 2) + attrsft)) & 3) << 2); attr = (byte)(((pNTBL[attradr + (ntbl_x >> 2)] >> ((ntbl_x & 2) + attrsft)) & 3) << 2);
@ -508,8 +499,8 @@ namespace VirtualNes.Core
{ {
cache_tile = tileadr; cache_tile = tileadr;
cache_attr = attr; cache_attr = attr;
chr_l = MMU.PPU_MEM_BANK[tileadr >> 10].Span[tileadr & 0x03FF]; chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
chr_h = MMU.PPU_MEM_BANK[tileadr >> 10].Span[(tileadr & 0x03FF) + 8]; chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
BGwrite[pBGw] = (byte)(chr_h | chr_l); BGwrite[pBGw] = (byte)(chr_h | chr_l);
int pBGPAL = attr; int pBGPAL = attr;
@ -540,7 +531,7 @@ namespace VirtualNes.Core
ntbl_x = 0; ntbl_x = 0;
ntbladr ^= 0x41F; ntbladr ^= 0x41F;
attradr = 0x03C0 + ((ntbladr & 0x0380) >> 4); attradr = 0x03C0 + ((ntbladr & 0x0380) >> 4);
pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10].Span; pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10];
} }
else else
{ {
@ -632,7 +623,7 @@ namespace VirtualNes.Core
int attradr = 0x03C0 + ((MMU.loopy_v & 0x0380) >> 4); int attradr = 0x03C0 + ((MMU.loopy_v & 0x0380) >> 4);
int ntbl_x = ntbladr & 0x001F; int ntbl_x = ntbladr & 0x001F;
int attrsft = (ntbladr & 0x0040) >> 4; int attrsft = (ntbladr & 0x0040) >> 4;
var pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10].Span; var pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10];
int tileadr = 0; int tileadr = 0;
int cache_tile = unchecked((int)(0xFFFF0000)); int cache_tile = unchecked((int)(0xFFFF0000));
@ -656,8 +647,8 @@ namespace VirtualNes.Core
cache_tile = tileadr; cache_tile = tileadr;
cache_attr = attr; cache_attr = attr;
chr_l = MMU.PPU_MEM_BANK[tileadr >> 10].Span[tileadr & 0x03FF]; chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
chr_h = MMU.PPU_MEM_BANK[tileadr >> 10].Span[(tileadr & 0x03FF) + 8]; chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
lpScreen[pBGw] = (byte)(chr_l | chr_h); lpScreen[pBGw] = (byte)(chr_l | chr_h);
int pBGPAL = attr; int pBGPAL = attr;
@ -702,7 +693,7 @@ namespace VirtualNes.Core
ntbl_x = 0; ntbl_x = 0;
ntbladr ^= 0x41F; ntbladr ^= 0x41F;
attradr = 0x03C0 + ((ntbladr & 0x0380) >> 4); attradr = 0x03C0 + ((ntbladr & 0x0380) >> 4);
pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10].Span; pNTBL = MMU.PPU_MEM_BANK[ntbladr >> 10];
} }
else else
{ {
@ -732,16 +723,16 @@ namespace VirtualNes.Core
} }
ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF); ntbladr = 0x2000 + (MMU.loopy_v & 0x0FFF);
tileadr = ((MMU.PPUREG[0] & PPU_BGTBL_BIT) << 8) + MMU.PPU_MEM_BANK[ntbladr >> 10].Span[ntbladr & 0x03FF] * 0x10 + ((MMU.loopy_v & 0x7000) >> 12); tileadr = ((MMU.PPUREG[0] & PPU_BGTBL_BIT) << 8) + MMU.PPU_MEM_BANK[ntbladr >> 10][ntbladr & 0x03FF] * 0x10 + ((MMU.loopy_v & 0x7000) >> 12);
attr = (byte)(((MMU.PPU_MEM_BANK[ntbladr >> 10].Span[0x03C0 + ((ntbladr & 0x0380) >> 4) + ((ntbladr & 0x001C) >> 2)] >> (((ntbladr & 0x40) >> 4) + (ntbladr & 0x02))) & 3) << 2); attr = (byte)(((MMU.PPU_MEM_BANK[ntbladr >> 10][0x03C0 + ((ntbladr & 0x0380) >> 4) + ((ntbladr & 0x001C) >> 2)] >> (((ntbladr & 0x40) >> 4) + (ntbladr & 0x02))) & 3) << 2);
if (cache_tile != tileadr || cache_attr != attr) if (cache_tile != tileadr || cache_attr != attr)
{ {
cache_tile = tileadr; cache_tile = tileadr;
cache_attr = attr; cache_attr = attr;
chr_l = MMU.PPU_MEM_BANK[tileadr >> 10].Span[tileadr & 0x03FF]; chr_l = MMU.PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
chr_h = MMU.PPU_MEM_BANK[tileadr >> 10].Span[(tileadr & 0x03FF) + 8]; chr_h = MMU.PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
BGwrite[pBGw] = (byte)(chr_l | chr_h); BGwrite[pBGw] = (byte)(chr_l | chr_h);
int pBGPAL = attr; int pBGPAL = attr;
@ -937,8 +928,8 @@ namespace VirtualNes.Core
spraddr += ((~sp_y & 8) << 1) + (7 - (sp_y & 7)); spraddr += ((~sp_y & 8) << 1) + (7 - (sp_y & 7));
} }
// Character pattern // Character pattern
chr_l = MMU.PPU_MEM_BANK[spraddr >> 10].Span[spraddr & 0x3FF]; chr_l = MMU.PPU_MEM_BANK[spraddr >> 10][spraddr & 0x3FF];
chr_h = MMU.PPU_MEM_BANK[spraddr >> 10].Span[(spraddr & 0x3FF) + 8]; chr_h = MMU.PPU_MEM_BANK[spraddr >> 10][(spraddr & 0x3FF) + 8];
// Character latch(For MMC2/MMC4) // Character latch(For MMC2/MMC4)
if (bChrLatch) if (bChrLatch)
@ -1117,12 +1108,18 @@ namespace VirtualNes.Core
return lpScreen; return lpScreen;
} }
public byte[] GetLineColorMode()
{
return lpColormode;
}
internal void SetScreenPtr(byte[] screenBuffer, byte[] colormode) internal void SetScreenPtr(byte[] screenBuffer, byte[] colormode)
{ {
lpScreen = screenBuffer; lpScreen = screenBuffer;
lpColormode = colormode; lpColormode = colormode;
} }
internal bool IsDispON() internal bool IsDispON()
{ {
return (MMU.PPUREG[1] & (PPU_BGDISP_BIT | PPU_SPDISP_BIT)) != 0; return (MMU.PPUREG[1] & (PPU_BGDISP_BIT | PPU_SPDISP_BIT)) != 0;

View File

@ -347,12 +347,12 @@ namespace VirtualNes.Core
return diskno; return diskno;
} }
internal ulong GetGameID() internal uint GetGameID()
{ {
return fdsgameID; return fdsgameID;
} }
internal ulong GetMakerID() internal uint GetMakerID()
{ {
return fdsmakerID; return fdsmakerID;
} }

View File

@ -17,4 +17,29 @@
public CfgExtraSound extsound { get; private set; } = new CfgExtraSound(); public CfgExtraSound extsound { get; private set; } = new CfgExtraSound();
public CfgNetPlay netplay { get; private set; } = new CfgNetPlay(); public CfgNetPlay netplay { get; private set; } = new CfgNetPlay();
} }
public static class GameOption
{
// Default保存
public static int defRenderMethod;
public static int defIRQtype;
public static bool defFrameIRQ;
public static bool defVideoMode;
// データ
public static int nRenderMethod;
public static int nIRQtype;
public static bool bFrameIRQ;
public static bool bVideoMode;
public static void Load(uint crc)
{
}
public static void Load(uint gid, uint mid)
{
}
}
} }

View File

@ -0,0 +1,49 @@
namespace VirtualNes.Core
{
public class VSDIPSWITCH
{
public string name;
public ushort value;
}
public static class VsUnisystem
{
public static VSDIPSWITCH[] vsdip_default = new VSDIPSWITCH[]
{
new VSDIPSWITCH{name="Unknown", value= 0x0100},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x01},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x0200},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x02},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x0400},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x04},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x0800},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x08},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x1000},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x10},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x2000},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x20},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x4000},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x40},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name="Unknown", value= 0x8000},
new VSDIPSWITCH{name="Off", value= 0x00},
new VSDIPSWITCH{name="On", value= 0x80},
new VSDIPSWITCH{name=null, value= 0xFF},
new VSDIPSWITCH{name=null, value= 0 },
};
}
}

View File

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

Binary file not shown.