forked from sin365/AxibugEmuOnline
Merge branch 'master' of http://git.axibug.com/sin365/AxibugEmuOnline
This commit is contained in:
commit
82e0275b5e
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b52033f7628c4346a6dd0b2806e75ee
|
||||
guid: 319a1a12506a5334ebd963b4fd991c2a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccf426abdad56c74682de4e38b3048e3
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
14
AxibugEmuOnline.Client/Assets/Resources/NES/ROMDB.asset
Normal file
14
AxibugEmuOnline.Client/Assets/Resources/NES/ROMDB.asset
Normal file
@ -0,0 +1,14 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 29131082dba8d234481296f0cf29a1fe, type: 3}
|
||||
m_Name: ROMDB
|
||||
m_EditorClassIdentifier:
|
@ -1,8 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6645567e4c11d9447b1aee2406f681c5
|
||||
guid: 42cbfafb123e63b45841ae95eb432053
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
86999
AxibugEmuOnline.Client/Assets/Resources/NES/nes20db.xml
Normal file
86999
AxibugEmuOnline.Client/Assets/Resources/NES/nes20db.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31d7b6b33f06e3d468b409ab9e71bf1f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,40 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!84 &8400000
|
||||
RenderTexture:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: RenderTexture
|
||||
m_ImageContentsHash:
|
||||
serializedVersion: 2
|
||||
Hash: 00000000000000000000000000000000
|
||||
m_ForcedFallbackFormat: 4
|
||||
m_DownscaleFallback: 0
|
||||
m_IsAlphaChannelOptional: 0
|
||||
serializedVersion: 5
|
||||
m_Width: 256
|
||||
m_Height: 240
|
||||
m_AntiAliasing: 1
|
||||
m_MipCount: -1
|
||||
m_DepthStencilFormat: 92
|
||||
m_ColorFormat: 8
|
||||
m_MipMap: 0
|
||||
m_GenerateMips: 1
|
||||
m_SRGB: 0
|
||||
m_UseDynamicScale: 0
|
||||
m_BindMS: 0
|
||||
m_EnableCompatibleFormat: 1
|
||||
m_EnableRandomWrite: 0
|
||||
m_TextureSettings:
|
||||
serializedVersion: 2
|
||||
m_FilterMode: 1
|
||||
m_Aniso: 0
|
||||
m_MipBias: 0
|
||||
m_WrapU: 1
|
||||
m_WrapV: 1
|
||||
m_WrapW: 1
|
||||
m_Dimension: 2
|
||||
m_VolumeDepth: 1
|
||||
m_ShadowSamplingMode: 2
|
@ -1,8 +1,8 @@
|
||||
using AxibugEmuOnline.Client.ClientCore;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
using VirtualNes.Core;
|
||||
|
||||
@ -15,9 +15,9 @@ namespace AxibugEmuOnline.Client
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return "Assets/StreamingAssets/Roms";
|
||||
return "Assets/StreamingAssets/NES/Roms";
|
||||
#else
|
||||
return $"{Application.streamingAssetsPath}/Roms";
|
||||
return $"{Application.streamingAssetsPath}/NES/Roms";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,7 @@ namespace AxibugEmuOnline.Client
|
||||
|
||||
public Stream OpenFile_DISKSYS()
|
||||
{
|
||||
return File.Open($"{Application.streamingAssetsPath}/Disksys.rom", FileMode.Open, FileAccess.Read);
|
||||
return new MemoryStream(Resources.Load<TextAsset>("NES/Disksys.rom").bytes);
|
||||
}
|
||||
|
||||
public void SaveSRAMToFile(byte[] sramContent, string romName)
|
||||
@ -92,5 +92,11 @@ namespace AxibugEmuOnline.Client
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool TryGetMapperNo(ROM rom, out int mapperNo)
|
||||
{
|
||||
var db = Resources.Load<RomDB>("NES/ROMDB");
|
||||
return db.GetMapperNo(rom.GetPROM_CRC(), out mapperNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using AxibugEmuOnline.Client.ClientCore;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
using VirtualNes.Core;
|
||||
using VirtualNes.Core.Debug;
|
||||
@ -56,5 +58,29 @@ namespace AxibugEmuOnline.Client
|
||||
AudioProvider.ProcessSound(m_nesIns);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ContextMenu("IMPORT")]
|
||||
public void TTTA()
|
||||
{
|
||||
var db = Resources.Load<RomDB>("NES/ROMDB");
|
||||
db.Clear();
|
||||
|
||||
var dbFile = Resources.Load<TextAsset>("NES/nes20db");
|
||||
var xml = XDocument.Parse(dbFile.text);
|
||||
var games = xml.Element("nes20db").Elements("game");
|
||||
foreach (var game in games)
|
||||
{
|
||||
var crcStr = game.Element("rom").Attribute("crc32").Value;
|
||||
var crc = uint.Parse($"{crcStr}", System.Globalization.NumberStyles.HexNumber);
|
||||
|
||||
var mapper = int.Parse($"{game.Element("pcb").Attribute("mapper").Value}");
|
||||
|
||||
db.AddInfo(new RomDB.RomInfo { CRC = crc, Mapper = mapper });
|
||||
}
|
||||
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
55
AxibugEmuOnline.Client/Assets/Script/NesEmulator/RomDB.cs
Normal file
55
AxibugEmuOnline.Client/Assets/Script/NesEmulator/RomDB.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AxibugEmuOnline.Client.ClientCore
|
||||
{
|
||||
public class RomDB : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
private List<RomInfo> romInfos = new List<RomInfo>();
|
||||
|
||||
private Dictionary<uint, RomInfo> crc_Info_mapper;
|
||||
|
||||
public void AddInfo(RomInfo romInfo)
|
||||
{
|
||||
romInfos.Add(romInfo);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
romInfos.Clear();
|
||||
}
|
||||
|
||||
public bool GetMapperNo(uint crc, out int mapperNo)
|
||||
{
|
||||
if (crc_Info_mapper == null)
|
||||
{
|
||||
crc_Info_mapper = new Dictionary<uint, RomInfo>();
|
||||
foreach (var info in romInfos)
|
||||
{
|
||||
crc_Info_mapper[info.CRC] = info;
|
||||
}
|
||||
}
|
||||
|
||||
if (crc_Info_mapper.TryGetValue(crc, out var romInfo))
|
||||
{
|
||||
mapperNo = romInfo.Mapper;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapperNo = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RomInfo
|
||||
{
|
||||
public uint CRC;
|
||||
public int Mapper;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29131082dba8d234481296f0cf29a1fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,5 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 588a6a32c9d46b943b4909b1757f4572
|
||||
guid: fc7102c34a9fa4148b4aa74d54e82b1f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
@ -415,12 +415,6 @@ namespace VirtualNes.Core
|
||||
{
|
||||
header.control2 |= (byte)EnumRomControlByte2.ROM_VSUNISYSTEM;
|
||||
}
|
||||
|
||||
//吞食天地2 豪华中文版
|
||||
if (crc == 0x19B9E732)
|
||||
{
|
||||
mapper = 199;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,21 @@ namespace VirtualNes.Core
|
||||
//todo : 实现加载mapper
|
||||
switch (no)
|
||||
{
|
||||
case 0: return new Mapper000(parent);
|
||||
case 1: return new Mapper001(parent);
|
||||
case 2: return new Mapper002(parent);
|
||||
case 3: return new Mapper003(parent);
|
||||
case 4: return new Mapper004(parent);
|
||||
case 5: return new Mapper005(parent);
|
||||
case 6: return new Mapper006(parent);
|
||||
case 7: return new Mapper007(parent);
|
||||
case 8: return new Mapper008(parent);
|
||||
case 9: return new Mapper009(parent);
|
||||
case 10: return new Mapper010(parent);
|
||||
case 11: return new Mapper011(parent);
|
||||
case 12: return new Mapper012(parent);
|
||||
case 13: return new Mapper013(parent);
|
||||
case 15: return new Mapper015(parent);
|
||||
case 16: return new Mapper016(parent);
|
||||
case 17: return new Mapper017(parent);
|
||||
case 18: return new Mapper018(parent);
|
||||
|
@ -0,0 +1,47 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper000 //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper000 : Mapper
|
||||
{
|
||||
|
||||
public Mapper000(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
switch (PROM_16K_SIZE)
|
||||
{
|
||||
default:
|
||||
case 1: // 16K only
|
||||
SetPROM_16K_Bank(4, 0);
|
||||
SetPROM_16K_Bank(6, 0);
|
||||
break;
|
||||
case 2: // 32K
|
||||
SetPROM_32K_Bank(0);
|
||||
break;
|
||||
}
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
if (crc == 0x4e7db5af)
|
||||
{ // Circus Charlie(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_RENDER);
|
||||
}
|
||||
if (crc == 0x57970078)
|
||||
{ // F-1 Race(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_RENDER);
|
||||
}
|
||||
if (crc == 0xaf2bbcbc // Mach Rider(JU)
|
||||
|| crc == 0x3acd4bf1)
|
||||
{ // Mach Rider(Alt)(JU)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_RENDER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,411 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper001 Nintendo MMC1 //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper001 : Mapper
|
||||
{
|
||||
|
||||
uint last_addr;
|
||||
|
||||
BYTE patch;
|
||||
BYTE wram_patch;
|
||||
BYTE wram_bank;
|
||||
BYTE wram_count;
|
||||
|
||||
BYTE[] reg = new byte[4];
|
||||
BYTE shift, regbuf;
|
||||
|
||||
public Mapper001(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
reg[0] = 0x0C; // D3=1,D2=1
|
||||
reg[1] = reg[2] = reg[3] = 0;
|
||||
shift = regbuf = 0;
|
||||
|
||||
patch = 0;
|
||||
wram_patch = 0;
|
||||
|
||||
if (PROM_16K_SIZE < 32)
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For 512K/1M byte Cartridge
|
||||
SetPROM_16K_Bank(4, 0);
|
||||
SetPROM_16K_Bank(6, 16 - 1);
|
||||
|
||||
patch = 1;
|
||||
}
|
||||
|
||||
if (VROM_8K_SIZE != 0)
|
||||
{
|
||||
// SetVROM_8K_Bank( 0 );
|
||||
}
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0xb8e16bd0)
|
||||
{ // Snow Bros.(J)
|
||||
patch = 2;
|
||||
}
|
||||
// if( crc == 0x9b565541 ) { // Triathron, The(J)
|
||||
// nes.SetFrameIRQmode( FALSE );
|
||||
// }
|
||||
if (crc == 0xc96c6f04)
|
||||
{ // Venus Senki(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
// if( crc == 0x5e3f7004 ) { // Softball Tengoku(J)
|
||||
// }
|
||||
|
||||
if (crc == 0x4d2edf70)
|
||||
{ // Night Rider(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
}
|
||||
if (crc == 0xcd2a73f0)
|
||||
{ // Pirates!(U)
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
patch = 2;
|
||||
}
|
||||
|
||||
// if( crc == 0x09efe54b ) { // Majaventure - Mahjong Senki(J)
|
||||
// nes.SetFrameIRQmode( FALSE );
|
||||
// }
|
||||
|
||||
if (crc == 0x11469ce3)
|
||||
{ // Viva! Las Vegas(J)
|
||||
}
|
||||
if (crc == 0xd878ebf5)
|
||||
{ // Ninja Ryukenden(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER);
|
||||
}
|
||||
|
||||
// if( crc == 0x7bd7b849 ) { // Nekketsu Koukou - Dodgeball Bu(J)
|
||||
// }
|
||||
|
||||
if (crc == 0x466efdc2)
|
||||
{ // Final Fantasy(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
nes.ppu.SetExtMonoMode(true);
|
||||
}
|
||||
if (crc == 0xc9556b36)
|
||||
{ // Final Fantasy I&II(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER);
|
||||
nes.ppu.SetExtMonoMode(true);
|
||||
nes.SetSAVERAM_SIZE(16 * 1024);
|
||||
wram_patch = 2;
|
||||
}
|
||||
|
||||
if (crc == 0x717e1169)
|
||||
{ // Cosmic Wars(J)
|
||||
nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0xC05D2034)
|
||||
{ // Snake's Revenge(U)
|
||||
nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0xb8747abf // Best Play - Pro Yakyuu Special(J)
|
||||
|| crc == 0x29449ba9 // Nobunaga no Yabou - Zenkoku Ban(J)
|
||||
|| crc == 0x2b11e0b0 // Nobunaga no Yabou - Zenkoku Ban(J)(alt)
|
||||
|| crc == 0x4642dda6 // Nobunaga's Ambition(U)
|
||||
|| crc == 0xfb69743a // Aoki Ookami to Shiroki Mejika - Genghis Khan(J)
|
||||
|| crc == 0x2225c20f // Genghis Khan(U)
|
||||
|| crc == 0xabbf7217 // Sangokushi(J)
|
||||
)
|
||||
{
|
||||
|
||||
nes.SetSAVERAM_SIZE(16 * 1024);
|
||||
wram_patch = 1;
|
||||
wram_bank = 0;
|
||||
wram_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper001::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
// DEBUGOUT( "MMC1 %04X=%02X\n", addr&0xFFFF,data&0xFF );
|
||||
|
||||
if (wram_patch == 1 && addr == 0xBFFF)
|
||||
{
|
||||
wram_count++;
|
||||
wram_bank += (byte)(data & 0x01);
|
||||
if (wram_count == 5)
|
||||
{
|
||||
if (wram_bank != 0)
|
||||
{
|
||||
SetPROM_Bank(3, &WRAM[0x2000], BANKTYPE_RAM);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_Bank(3, &WRAM[0x0000], BANKTYPE_RAM);
|
||||
}
|
||||
wram_bank = wram_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (patch != 1)
|
||||
{
|
||||
if ((addr & 0x6000) != (last_addr & 0x6000))
|
||||
{
|
||||
shift = regbuf = 0;
|
||||
}
|
||||
last_addr = addr;
|
||||
}
|
||||
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
shift = regbuf = 0;
|
||||
// reg[0] = 0x0C; // D3=1,D2=1
|
||||
reg[0] |= 0x0C; // D3=1,D2=1 残りはリセットされない
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data & 0x01) != 0) regbuf |= (byte)(1 << shift);
|
||||
if (++shift < 5)
|
||||
return;
|
||||
addr = (ushort)((addr & 0x7FFF) >> 13);
|
||||
reg[addr] = regbuf;
|
||||
|
||||
// DEBUGOUT( "MMC1 %d=%02X\n", addr&0xFFFF,regbuf&0xFF );
|
||||
|
||||
regbuf = 0;
|
||||
shift = 0;
|
||||
|
||||
if (patch != 1)
|
||||
{
|
||||
// For Normal Cartridge
|
||||
switch (addr)
|
||||
{
|
||||
case 0:
|
||||
if ((reg[0] & 0x02) != 0)
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Register #1
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank lower($0000-$0FFF)
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
// CHR 4K bank higher($1000-$1FFF)
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHR 8K bank($0000-$1FFF)
|
||||
SetVROM_8K_Bank(reg[1] >> 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Register #2
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank lower($0000-$0FFF)
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
// CHR 4K bank higher($1000-$1FFF)
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHR 8K bank($0000-$1FFF)
|
||||
SetVROM_8K_Bank(reg[1] >> 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!((reg[0] & 0x08) != 0))
|
||||
{
|
||||
// PRG 32K bank ($8000-$FFFF)
|
||||
SetPROM_32K_Bank(reg[3] >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x04) != 0)
|
||||
{
|
||||
// PRG 16K bank ($8000-$BFFF)
|
||||
SetPROM_16K_Bank(4, reg[3]);
|
||||
SetPROM_16K_Bank(6, PROM_16K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PRG 16K bank ($C000-$FFFF)
|
||||
SetPROM_16K_Bank(6, reg[3]);
|
||||
SetPROM_16K_Bank(4, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For 512K/1M byte Cartridge
|
||||
INT PROM_BASE = 0;
|
||||
if (PROM_16K_SIZE >= 32)
|
||||
{
|
||||
PROM_BASE = reg[1] & 0x10;
|
||||
}
|
||||
|
||||
// For FinalFantasy I&II
|
||||
if (wram_patch == 2)
|
||||
{
|
||||
if (((reg[1] & 0x18) == 0))
|
||||
{
|
||||
SetPROM_Bank(3, &WRAM[0x0000], BANKTYPE_RAM);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_Bank(3, &WRAM[0x2000], BANKTYPE_RAM);
|
||||
}
|
||||
}
|
||||
|
||||
// Register #0
|
||||
if (addr == 0)
|
||||
{
|
||||
if ((reg[0] & 0x02) != 0)
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
}
|
||||
// Register #1
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank lower($0000-$0FFF)
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHR 8K bank($0000-$1FFF)
|
||||
SetVROM_8K_Bank(reg[1] >> 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
}
|
||||
// Register #2
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
// CHR 4K bank higher($1000-$1FFF)
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For Romancia
|
||||
if ((reg[0] & 0x10) != 0)
|
||||
{
|
||||
SetCRAM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
}
|
||||
// Register #3
|
||||
if (((reg[0] & 0x08) == 0))
|
||||
{
|
||||
// PRG 32K bank ($8000-$FFFF)
|
||||
SetPROM_32K_Bank((reg[3] & (0xF + PROM_BASE)) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x04) != 0)
|
||||
{
|
||||
// PRG 16K bank ($8000-$BFFF)
|
||||
SetPROM_16K_Bank(4, PROM_BASE + (reg[3] & 0x0F));
|
||||
if (PROM_16K_SIZE >= 32) SetPROM_16K_Bank(6, PROM_BASE + 16 - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PRG 16K bank ($C000-$FFFF)
|
||||
SetPROM_16K_Bank(6, PROM_BASE + (reg[3] & 0x0F));
|
||||
if (PROM_16K_SIZE >= 32) SetPROM_16K_Bank(4, PROM_BASE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper001::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = reg[0];
|
||||
p[1] = reg[1];
|
||||
p[2] = reg[2];
|
||||
p[3] = reg[3];
|
||||
p[4] = shift;
|
||||
p[5] = regbuf;
|
||||
|
||||
p[6] = wram_bank;
|
||||
p[7] = wram_count;
|
||||
}
|
||||
|
||||
//void Mapper001::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
reg[0] = p[0];
|
||||
reg[1] = p[1];
|
||||
reg[2] = p[2];
|
||||
reg[3] = p[3];
|
||||
shift = p[4];
|
||||
regbuf = p[5];
|
||||
|
||||
wram_bank = p[6];
|
||||
wram_count = p[7];
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper002 UNROM //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper002 : Mapper
|
||||
{
|
||||
|
||||
BYTE patch;
|
||||
public Mapper002(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
patch = 0;
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
// if( crc == 0x322c9b09 ) { // Metal Gear (Alt)(J)
|
||||
//// nes.SetFrameIRQmode( FALSE );
|
||||
// }
|
||||
// if( crc == 0xe7a3867b ) { // Dragon Quest 2(Alt)(J)
|
||||
// nes.SetFrameIRQmode( FALSE );
|
||||
// }
|
||||
//// if( crc == 0x9622fbd9 ) { // Ballblazer(J)
|
||||
//// patch = 0;
|
||||
//// }
|
||||
if (crc == 0x8c3d54e8 // Ikari(J)
|
||||
|| crc == 0x655efeed // Ikari Warriors(U)
|
||||
|| crc == 0x538218b2)
|
||||
{ // Ikari Warriors(E)
|
||||
patch = 1;
|
||||
}
|
||||
|
||||
if (crc == 0xb20c1030)
|
||||
{ // Shanghai(J)(original)
|
||||
patch = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//void Mapper002::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (!nes.rom.IsSAVERAM())
|
||||
{
|
||||
if (addr >= 0x5000 && patch == 1)
|
||||
SetPROM_16K_Bank(4, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper002::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
if (patch != 2)
|
||||
SetPROM_16K_Bank(4, data);
|
||||
else
|
||||
SetPROM_16K_Bank(4, data >> 4);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper003 CNROM //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper003 : Mapper
|
||||
{
|
||||
|
||||
public Mapper003(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
switch (PROM_16K_SIZE)
|
||||
{
|
||||
case 1: // 16K only
|
||||
SetPROM_16K_Bank(4, 0);
|
||||
SetPROM_16K_Bank(6, 0);
|
||||
break;
|
||||
case 2: // 32K
|
||||
SetPROM_32K_Bank(0);
|
||||
break;
|
||||
}
|
||||
// nes.SetRenderMethod( NES::TILE_RENDER );
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0x2b72fe7e)
|
||||
{ // Ganso Saiyuuki - Super Monkey Dai Bouken(J)
|
||||
nes.SetRenderMethod( EnumRenderMethod.TILE_RENDER);
|
||||
nes.ppu.SetExtNameTableMode(true);
|
||||
}
|
||||
|
||||
// if( crc == 0xE44D95B5 ) { // ひみつw
|
||||
// }
|
||||
}
|
||||
|
||||
#if FALSE//0
|
||||
void Mapper003::WriteLow( WORD addr, BYTE data )
|
||||
{
|
||||
if( patch ) {
|
||||
Mapper::WriteLow( addr, data );
|
||||
} else {
|
||||
if( nes.rom.IsSAVERAM() ) {
|
||||
Mapper::WriteLow( addr, data );
|
||||
} else {
|
||||
if( addr >= 0x4800 ) {
|
||||
SetVROM_8K_Bank( data & 0x03 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//void Mapper003::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
SetVROM_8K_Bank(data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,847 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper005 Nintendo MMC5 //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper005 : Mapper
|
||||
{
|
||||
BYTE sram_size;
|
||||
|
||||
BYTE prg_size; // $5100
|
||||
BYTE chr_size; // $5101
|
||||
BYTE sram_we_a, sram_we_b; // $5102-$5103
|
||||
BYTE graphic_mode; // $5104
|
||||
BYTE nametable_mode; // $5105
|
||||
BYTE[] nametable_type = new byte[4]; // $5105 use
|
||||
|
||||
BYTE sram_page; // $5113
|
||||
|
||||
BYTE fill_chr, fill_pal; // $5106-$5107
|
||||
BYTE split_control; // $5200
|
||||
BYTE split_scroll; // $5201
|
||||
BYTE split_page; // $5202
|
||||
|
||||
BYTE split_x;
|
||||
ushort split_addr;
|
||||
ushort split_yofs;
|
||||
|
||||
BYTE chr_type;
|
||||
BYTE chr_mode; // $5120-$512B use
|
||||
//BYTE chr_page[2][8];
|
||||
BYTE[,] chr_page = new byte[2,8]; // $5120-$512B
|
||||
LPBYTE BG_MEM_BANK[8]; // BGパターン用バンク
|
||||
BYTE BG_MEM_PAGE[8];
|
||||
|
||||
BYTE irq_status; // $5204(R)
|
||||
BYTE irq_enable; // $5204(W)
|
||||
BYTE irq_line; // $5203
|
||||
BYTE irq_scanline;
|
||||
BYTE irq_clear; // HSyncで使用
|
||||
BYTE irq_type;
|
||||
|
||||
BYTE mult_a, mult_b; // $5205-$5206
|
||||
public Mapper005(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
INT i;
|
||||
|
||||
prg_size = 3;
|
||||
chr_size = 3;
|
||||
|
||||
sram_we_a = 0x00;
|
||||
sram_we_b = 0x00;
|
||||
|
||||
graphic_mode = 0;
|
||||
nametable_mode = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
nametable_type[i] = 0;
|
||||
}
|
||||
|
||||
fill_chr = fill_pal = 0;
|
||||
split_control = split_scroll = split_page = 0;
|
||||
|
||||
irq_enable = 0;
|
||||
irq_status = 0;
|
||||
irq_scanline = 0;
|
||||
irq_line = 0;
|
||||
irq_clear = 0;
|
||||
|
||||
irq_type = 0;
|
||||
|
||||
mult_a = mult_b = 0;
|
||||
|
||||
chr_type = 0;
|
||||
chr_mode = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chr_page[0][i] = i;
|
||||
chr_page[1][i] = 4 + (i & 0x03);
|
||||
}
|
||||
|
||||
SetPROM_32K_Bank(PROM_8K_SIZE - 1, PROM_8K_SIZE - 1, PROM_8K_SIZE - 1, PROM_8K_SIZE - 1);
|
||||
SetVROM_8K_Bank(0);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
BG_MEM_BANK[i] = VROM + 0x0400 * i;
|
||||
BG_MEM_PAGE[i] = i;
|
||||
}
|
||||
|
||||
// SRAM設定
|
||||
SetBank_SRAM(3, 0);
|
||||
|
||||
sram_size = 0;
|
||||
nes.SetSAVERAM_SIZE(16 * 1024);
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
|
||||
if (crc == 0x2b548d75 // Bandit Kings of Ancient China(U)
|
||||
|| crc == 0xf4cd4998 // Dai Koukai Jidai(J)
|
||||
|| crc == 0x8fa95456 // Ishin no Arashi(J)
|
||||
|| crc == 0x98c8e090 // Nobunaga no Yabou - Sengoku Gunyuu Den(J)
|
||||
|| crc == 0x8e9a5e2f // L'Empereur(Alt)(U)
|
||||
|| crc == 0x57e3218b // L'Empereur(U)
|
||||
|| crc == 0x2f50bd38 // L'Empereur(J)
|
||||
|| crc == 0xb56958d1 // Nobunaga's Ambition 2(U)
|
||||
|| crc == 0xe6c28c5f // Suikoden - Tenmei no Chikai(J)
|
||||
|| crc == 0xcd35e2e9)
|
||||
{ // Uncharted Waters(U)
|
||||
sram_size = 1;
|
||||
nes.SetSAVERAM_SIZE(32 * 1024);
|
||||
}
|
||||
else
|
||||
if (crc == 0xf4120e58 // Aoki Ookami to Shiroki Mejika - Genchou Hishi(J)
|
||||
|| crc == 0x286613d8 // Nobunaga no Yabou - Bushou Fuuun Roku(J)
|
||||
|| crc == 0x11eaad26 // Romance of the Three Kingdoms 2(U)
|
||||
|| crc == 0x95ba5733)
|
||||
{ // Sangokushi 2(J)
|
||||
sram_size = 2;
|
||||
nes.SetSAVERAM_SIZE(64 * 1024);
|
||||
}
|
||||
|
||||
if (crc == 0x95ca9ec7)
|
||||
{ // Castlevania 3 - Dracula's Curse(U)
|
||||
nes.SetRenderMethod(NES::TILE_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0xcd9acf43)
|
||||
{ // Metal Slader Glory(J)
|
||||
irq_type = MMC5_IRQ_METAL;
|
||||
}
|
||||
|
||||
if (crc == 0xe91548d8)
|
||||
{ // Shin 4 Nin Uchi Mahjong - Yakuman Tengoku(J)
|
||||
chr_type = 1;
|
||||
}
|
||||
|
||||
nes.ppu.SetExtLatchMode(true);
|
||||
nes.apu.SelectExSound(8);
|
||||
}
|
||||
|
||||
//BYTE Mapper005::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
BYTE data = (BYTE)(addr >> 8);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x5015:
|
||||
data = nes.apu.ExRead(addr);
|
||||
break;
|
||||
|
||||
case 0x5204:
|
||||
data = irq_status;
|
||||
// irq_status = 0;
|
||||
irq_status &= ~0x80;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x5205:
|
||||
data = mult_a * mult_b;
|
||||
break;
|
||||
case 0x5206:
|
||||
data = (BYTE)(((WORD)mult_a * (WORD)mult_b) >> 8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (addr >= 0x5C00 && addr <= 0x5FFF)
|
||||
{
|
||||
if (graphic_mode >= 2)
|
||||
{ // ExRAM mode
|
||||
data = VRAM[0x0800 + (addr & 0x3FF)];
|
||||
}
|
||||
}
|
||||
else if (addr >= 0x6000 && addr <= 0x7FFF)
|
||||
{
|
||||
data = base.ReadLow(addr);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//void Mapper005::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
INT i;
|
||||
|
||||
#if FALSE//0
|
||||
if( addr >= 0x5000 && addr <=0x50FF ) {
|
||||
DEBUGOUT( "$%04X=%02X C:%10d\n", addr, data, nes.cpu.GetTotalCycles() );
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x5100:
|
||||
prg_size = data & 0x03;
|
||||
break;
|
||||
case 0x5101:
|
||||
chr_size = data & 0x03;
|
||||
break;
|
||||
|
||||
case 0x5102:
|
||||
sram_we_a = data & 0x03;
|
||||
break;
|
||||
case 0x5103:
|
||||
sram_we_b = data & 0x03;
|
||||
break;
|
||||
|
||||
case 0x5104:
|
||||
graphic_mode = data & 0x03;
|
||||
break;
|
||||
case 0x5105:
|
||||
nametable_mode = data;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
nametable_type[i] = data & 0x03;
|
||||
SetVRAM_1K_Bank(8 + i, nametable_type[i]);
|
||||
data >>= 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5106:
|
||||
fill_chr = data;
|
||||
break;
|
||||
case 0x5107:
|
||||
fill_pal = data & 0x03;
|
||||
break;
|
||||
|
||||
case 0x5113:
|
||||
SetBank_SRAM(3, data & 0x07);
|
||||
break;
|
||||
|
||||
case 0x5114:
|
||||
case 0x5115:
|
||||
case 0x5116:
|
||||
case 0x5117:
|
||||
SetBank_CPU(addr, data);
|
||||
break;
|
||||
|
||||
case 0x5120:
|
||||
case 0x5121:
|
||||
case 0x5122:
|
||||
case 0x5123:
|
||||
case 0x5124:
|
||||
case 0x5125:
|
||||
case 0x5126:
|
||||
case 0x5127:
|
||||
chr_mode = 0;
|
||||
chr_page[0][addr & 0x07] = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
|
||||
case 0x5128:
|
||||
case 0x5129:
|
||||
case 0x512A:
|
||||
case 0x512B:
|
||||
chr_mode = 1;
|
||||
chr_page[1][(addr & 0x03) + 0] = data;
|
||||
chr_page[1][(addr & 0x03) + 4] = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
|
||||
case 0x5200:
|
||||
split_control = data;
|
||||
break;
|
||||
case 0x5201:
|
||||
split_scroll = data;
|
||||
break;
|
||||
case 0x5202:
|
||||
split_page = data & 0x3F;
|
||||
break;
|
||||
|
||||
case 0x5203:
|
||||
irq_line = data;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x5204:
|
||||
irq_enable = data;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
|
||||
case 0x5205:
|
||||
mult_a = data;
|
||||
break;
|
||||
case 0x5206:
|
||||
mult_b = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr >= 0x5000 && addr <= 0x5015)
|
||||
{
|
||||
nes.apu.ExWrite(addr, data);
|
||||
}
|
||||
else if (addr >= 0x5C00 && addr <= 0x5FFF)
|
||||
{
|
||||
if (graphic_mode == 2)
|
||||
{ // ExRAM
|
||||
VRAM[0x0800 + (addr & 0x3FF)] = data;
|
||||
}
|
||||
else if (graphic_mode != 3)
|
||||
{ // Split,ExGraphic
|
||||
if ((irq_status & 0x40)!=0)
|
||||
{
|
||||
VRAM[0x0800 + (addr & 0x3FF)] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
VRAM[0x0800 + (addr & 0x3FF)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (addr >= 0x6000 && addr <= 0x7FFF)
|
||||
{
|
||||
if ((sram_we_a == 0x02) && (sram_we_b == 0x01))
|
||||
{
|
||||
if (CPU_MEM_TYPE[3] == BANKTYPE_RAM)
|
||||
{
|
||||
CPU_MEM_BANK[3][addr & 0x1FFF] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper005::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
if (sram_we_a == 0x02 && sram_we_b == 0x01)
|
||||
{
|
||||
if (addr >= 0x8000 && addr < 0xE000)
|
||||
{
|
||||
if (CPU_MEM_TYPE[addr >> 13] == BANKTYPE_RAM)
|
||||
{
|
||||
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_CPU(uint addr, BYTE data)
|
||||
{
|
||||
if ((data & 0x80)!=0)
|
||||
{
|
||||
// PROM Bank
|
||||
switch (addr & 7)
|
||||
{
|
||||
case 4:
|
||||
if (prg_size == 3)
|
||||
{
|
||||
SetPROM_8K_Bank(4, data & 0x7F);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (prg_size == 1 || prg_size == 2)
|
||||
{
|
||||
SetPROM_16K_Bank(4, (data & 0x7F) >> 1);
|
||||
}
|
||||
else if (prg_size == 3)
|
||||
{
|
||||
SetPROM_8K_Bank(5, (data & 0x7F));
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (prg_size == 2 || prg_size == 3)
|
||||
{
|
||||
SetPROM_8K_Bank(6, (data & 0x7F));
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (prg_size == 0)
|
||||
{
|
||||
SetPROM_32K_Bank((data & 0x7F) >> 2);
|
||||
}
|
||||
else if (prg_size == 1)
|
||||
{
|
||||
SetPROM_16K_Bank(6, (data & 0x7F) >> 1);
|
||||
}
|
||||
else if (prg_size == 2 || prg_size == 3)
|
||||
{
|
||||
SetPROM_8K_Bank(7, (data & 0x7F));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// WRAM Bank
|
||||
switch (addr & 7)
|
||||
{
|
||||
case 4:
|
||||
if (prg_size == 3)
|
||||
{
|
||||
SetBank_SRAM(4, data & 0x07);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (prg_size == 1 || prg_size == 2)
|
||||
{
|
||||
SetBank_SRAM(4, (data & 0x06) + 0);
|
||||
SetBank_SRAM(5, (data & 0x06) + 1);
|
||||
}
|
||||
else if (prg_size == 3)
|
||||
{
|
||||
SetBank_SRAM(5, data & 0x07);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (prg_size == 2 || prg_size == 3)
|
||||
{
|
||||
SetBank_SRAM(6, data & 0x07);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_SRAM(BYTE page, BYTE data)
|
||||
{
|
||||
if (sram_size == 0) data = (byte)((data > 3) ? 8 : 0);
|
||||
if (sram_size == 1) data = (byte)((data > 3) ? 1 : 0);
|
||||
if (sram_size == 2) data = (byte)((data > 3) ? 8 : data);
|
||||
if (sram_size == 3) data = (byte)((data > 3) ? 4 : data);
|
||||
|
||||
if (data != 8)
|
||||
{
|
||||
SetPROM_Bank(page, &WRAM[0x2000 * data], BANKTYPE_RAM);
|
||||
CPU_MEM_PAGE[page] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU_MEM_TYPE[page] = BANKTYPE_ROM;
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper005::SetBank_PPU()
|
||||
{
|
||||
INT i;
|
||||
|
||||
if (chr_mode == 0)
|
||||
{
|
||||
// PPU SP Bank
|
||||
switch (chr_size)
|
||||
{
|
||||
case 0:
|
||||
SetVROM_8K_Bank(chr_page[0][7]);
|
||||
break;
|
||||
case 1:
|
||||
SetVROM_4K_Bank(0, chr_page[0][3]);
|
||||
SetVROM_4K_Bank(4, chr_page[0][7]);
|
||||
break;
|
||||
case 2:
|
||||
SetVROM_2K_Bank(0, chr_page[0][1]);
|
||||
SetVROM_2K_Bank(2, chr_page[0][3]);
|
||||
SetVROM_2K_Bank(4, chr_page[0][5]);
|
||||
SetVROM_2K_Bank(6, chr_page[0][7]);
|
||||
break;
|
||||
case 3:
|
||||
SetVROM_8K_Bank(chr_page[0][0],
|
||||
chr_page[0][1],
|
||||
chr_page[0][2],
|
||||
chr_page[0][3],
|
||||
chr_page[0][4],
|
||||
chr_page[0][5],
|
||||
chr_page[0][6],
|
||||
chr_page[0][7]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (chr_mode == 1)
|
||||
{
|
||||
// PPU BG Bank
|
||||
switch (chr_size)
|
||||
{
|
||||
case 0:
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
BG_MEM_BANK[i] = VROM + 0x2000 * (chr_page[1][7] % VROM_8K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_PAGE[i] = (chr_page[1][7] % VROM_8K_SIZE) * 8 + i;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
BG_MEM_BANK[i + 0] = VROM + 0x1000 * (chr_page[1][3] % VROM_4K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_BANK[i + 4] = VROM + 0x1000 * (chr_page[1][7] % VROM_4K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_PAGE[i + 0] = (chr_page[1][3] % VROM_4K_SIZE) * 4 + i;
|
||||
BG_MEM_PAGE[i + 4] = (chr_page[1][7] % VROM_4K_SIZE) * 4 + i;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
BG_MEM_BANK[i + 0] = VROM + 0x0800 * (chr_page[1][1] % VROM_2K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_BANK[i + 2] = VROM + 0x0800 * (chr_page[1][3] % VROM_2K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_BANK[i + 4] = VROM + 0x0800 * (chr_page[1][5] % VROM_2K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_BANK[i + 6] = VROM + 0x0800 * (chr_page[1][7] % VROM_2K_SIZE) + 0x0400 * i;
|
||||
BG_MEM_PAGE[i + 0] = (chr_page[1][1] % VROM_2K_SIZE) * 2 + i;
|
||||
BG_MEM_PAGE[i + 2] = (chr_page[1][3] % VROM_2K_SIZE) * 2 + i;
|
||||
BG_MEM_PAGE[i + 4] = (chr_page[1][5] % VROM_2K_SIZE) * 2 + i;
|
||||
BG_MEM_PAGE[i + 6] = (chr_page[1][7] % VROM_2K_SIZE) * 2 + i;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
BG_MEM_BANK[i] = VROM + 0x0400 * (chr_page[1][i] % VROM_1K_SIZE);
|
||||
BG_MEM_PAGE[i] = (chr_page[1][i] % VROM_1K_SIZE) + i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mapper005::HSync(INT scanline)
|
||||
{
|
||||
if (irq_type & MMC5_IRQ_METAL)
|
||||
{
|
||||
if (irq_scanline == irq_line)
|
||||
{
|
||||
irq_status |= 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
// if( nes.ppu.IsDispON() && scanline < 239 ) {
|
||||
if (nes.ppu.IsDispON() && scanline < 240)
|
||||
{
|
||||
irq_scanline++;
|
||||
irq_status |= 0x40;
|
||||
irq_clear = 0;
|
||||
}
|
||||
else if (irq_type & MMC5_IRQ_METAL)
|
||||
{
|
||||
irq_scanline = 0;
|
||||
irq_status &= ~0x80;
|
||||
irq_status &= ~0x40;
|
||||
}
|
||||
|
||||
if (!(irq_type & MMC5_IRQ_METAL))
|
||||
{
|
||||
if (irq_scanline == irq_line)
|
||||
{
|
||||
irq_status |= 0x80;
|
||||
}
|
||||
|
||||
if (++irq_clear > 2)
|
||||
{
|
||||
irq_scanline = 0;
|
||||
irq_status &= ~0x80;
|
||||
irq_status &= ~0x40;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
|
||||
if ((irq_enable & 0x80) && (irq_status & 0x80) && (irq_status & 0x40))
|
||||
{
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
/// nes.cpu.IRQ_NotPending();
|
||||
#if 0
|
||||
{
|
||||
LPBYTE lpScn = nes.ppu.GetScreenPtr();
|
||||
|
||||
lpScn = lpScn+(256+16)*scanline;
|
||||
|
||||
for( INT i = 0; i < 256+16; i++ ) {
|
||||
lpScn[i] = 22;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// For Split mode!
|
||||
if (scanline == 0)
|
||||
{
|
||||
split_yofs = (ushort)(split_scroll & 0x07);
|
||||
split_addr = (ushort)(((split_scroll & 0xF8) << 2));
|
||||
}
|
||||
else if (nes.ppu.IsDispON())
|
||||
{
|
||||
if (split_yofs == 7)
|
||||
{
|
||||
split_yofs = 0;
|
||||
if ((split_addr & 0x03E0) == 0x03A0)
|
||||
{
|
||||
split_addr &= 0x001F;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((split_addr & 0x03E0) == 0x03E0)
|
||||
{
|
||||
split_addr &= 0x001F;
|
||||
}
|
||||
else
|
||||
{
|
||||
split_addr += 0x0020;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
split_yofs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper005::PPU_ExtLatchX(INT x)
|
||||
public override void PPU_ExtLatchX(int x)
|
||||
{
|
||||
split_x = x;
|
||||
}
|
||||
|
||||
//void Mapper005::PPU_ExtLatch(WORD addr, BYTE& chr_l, BYTE& chr_h, BYTE& attr )
|
||||
public override void PPU_ExtLatch(ushort addr, ref byte chr_l, ref byte chr_h, ref byte attr)
|
||||
{
|
||||
ushort ntbladr, attradr, tileadr, tileofs;
|
||||
ushort tile_yofs;
|
||||
uint tilebank;
|
||||
bool bSplit;
|
||||
|
||||
tile_yofs = nes.ppu.GetTILEY();
|
||||
|
||||
bSplit = FALSE;
|
||||
if (split_control & 0x80)
|
||||
{
|
||||
if (!(split_control & 0x40))
|
||||
{
|
||||
// Left side
|
||||
if ((split_control & 0x1F) > split_x)
|
||||
{
|
||||
bSplit = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Right side
|
||||
if ((split_control & 0x1F) <= split_x)
|
||||
{
|
||||
bSplit = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bSplit)
|
||||
{
|
||||
if (nametable_type[(addr & 0x0C00) >> 10] == 3)
|
||||
{
|
||||
// Fill mode
|
||||
if (graphic_mode == 1)
|
||||
{
|
||||
// ExGraphic mode
|
||||
ntbladr = 0x2000 + (addr & 0x0FFF);
|
||||
// Get Nametable
|
||||
tileadr = fill_chr * 0x10 + tile_yofs;
|
||||
// Get TileBank
|
||||
tilebank = 0x1000 * ((VRAM[0x0800 + (ntbladr & 0x03FF)] & 0x3F) % VROM_4K_SIZE);
|
||||
// Attribute
|
||||
attr = (fill_pal << 2) & 0x0C;
|
||||
// Get Pattern
|
||||
chr_l = VROM[tilebank + tileadr];
|
||||
chr_h = VROM[tilebank + tileadr + 8];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal
|
||||
tileofs = (PPUREG[0] & PPU_BGTBL_BIT) ? 0x1000 : 0x0000;
|
||||
tileadr = tileofs + fill_chr * 0x10 + tile_yofs;
|
||||
attr = (fill_pal << 2) & 0x0C;
|
||||
// Get Pattern
|
||||
if (chr_type)
|
||||
{
|
||||
chr_l = PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
|
||||
chr_h = PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
|
||||
}
|
||||
else
|
||||
{
|
||||
chr_l = BG_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
|
||||
chr_h = BG_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (graphic_mode == 1)
|
||||
{
|
||||
// ExGraphic mode
|
||||
ntbladr = 0x2000 + (addr & 0x0FFF);
|
||||
// Get Nametable
|
||||
tileadr = (WORD)PPU_MEM_BANK[ntbladr >> 10][ntbladr & 0x03FF] * 0x10 + tile_yofs;
|
||||
// Get TileBank
|
||||
tilebank = 0x1000 * ((VRAM[0x0800 + (ntbladr & 0x03FF)] & 0x3F) % VROM_4K_SIZE);
|
||||
// Get Attribute
|
||||
attr = (VRAM[0x0800 + (ntbladr & 0x03FF)] & 0xC0) >> 4;
|
||||
// Get Pattern
|
||||
chr_l = VROM[tilebank + tileadr];
|
||||
chr_h = VROM[tilebank + tileadr + 8];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal or ExVRAM
|
||||
tileofs = (PPUREG[0] & PPU_BGTBL_BIT) ? 0x1000 : 0x0000;
|
||||
ntbladr = 0x2000 + (addr & 0x0FFF);
|
||||
attradr = 0x23C0 + (addr & 0x0C00) + ((addr & 0x0380) >> 4) + ((addr & 0x001C) >> 2);
|
||||
// Get Nametable
|
||||
tileadr = tileofs + PPU_MEM_BANK[ntbladr >> 10][ntbladr & 0x03FF] * 0x10 + tile_yofs;
|
||||
// Get Attribute
|
||||
attr = PPU_MEM_BANK[attradr >> 10][attradr & 0x03FF];
|
||||
if (ntbladr & 0x0002) attr >>= 2;
|
||||
if (ntbladr & 0x0040) attr >>= 4;
|
||||
attr = (attr & 0x03) << 2;
|
||||
// Get Pattern
|
||||
if (chr_type)
|
||||
{
|
||||
chr_l = PPU_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
|
||||
chr_h = PPU_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
|
||||
}
|
||||
else
|
||||
{
|
||||
chr_l = BG_MEM_BANK[tileadr >> 10][tileadr & 0x03FF];
|
||||
chr_h = BG_MEM_BANK[tileadr >> 10][(tileadr & 0x03FF) + 8];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ntbladr = ((split_addr & 0x03E0) | (split_x & 0x1F)) & 0x03FF;
|
||||
// Get Split TileBank
|
||||
tilebank = 0x1000 * ((INT)split_page % VROM_4K_SIZE);
|
||||
tileadr = (ushort)VRAM[0x0800 + ntbladr] * 0x10 + split_yofs;
|
||||
// Get Attribute
|
||||
attradr = 0x03C0 + ((ntbladr & 0x0380) >> 4) + ((ntbladr & 0x001C) >> 2);
|
||||
attr = VRAM[0x0800 + attradr];
|
||||
if (ntbladr & 0x0002) attr >>= 2;
|
||||
if (ntbladr & 0x0040) attr >>= 4;
|
||||
attr = (attr & 0x03) << 2;
|
||||
// Get Pattern
|
||||
chr_l = VROM[tilebank + tileadr];
|
||||
chr_h = VROM[tilebank + tileadr + 8];
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper005::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = prg_size;
|
||||
p[1] = chr_size;
|
||||
p[2] = sram_we_a;
|
||||
p[3] = sram_we_b;
|
||||
p[4] = graphic_mode;
|
||||
p[5] = nametable_mode;
|
||||
p[6] = nametable_type[0];
|
||||
p[7] = nametable_type[1];
|
||||
p[8] = nametable_type[2];
|
||||
p[9] = nametable_type[3];
|
||||
p[10] = sram_page;
|
||||
p[11] = fill_chr;
|
||||
p[12] = fill_pal;
|
||||
p[13] = split_control;
|
||||
p[14] = split_scroll;
|
||||
p[15] = split_page;
|
||||
p[16] = chr_mode;
|
||||
p[17] = irq_status;
|
||||
p[18] = irq_enable;
|
||||
p[19] = irq_line;
|
||||
p[20] = irq_scanline;
|
||||
p[21] = irq_clear;
|
||||
p[22] = mult_a;
|
||||
p[23] = mult_b;
|
||||
|
||||
INT i, j;
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
p[24 + j * 8 + i] = chr_page[j][i];
|
||||
}
|
||||
}
|
||||
// for( i = 0; i < 8; i++ ) {
|
||||
// p[40+i] = BG_MEM_PAGE[i];
|
||||
// }
|
||||
}
|
||||
|
||||
//void Mapper005::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
prg_size = p[0];
|
||||
chr_size = p[1];
|
||||
sram_we_a = p[2];
|
||||
sram_we_b = p[3];
|
||||
graphic_mode = p[4];
|
||||
nametable_mode = p[5];
|
||||
nametable_type[0] = p[6];
|
||||
nametable_type[1] = p[7];
|
||||
nametable_type[2] = p[8];
|
||||
nametable_type[3] = p[9];
|
||||
sram_page = p[10];
|
||||
fill_chr = p[11];
|
||||
fill_pal = p[12];
|
||||
split_control = p[13];
|
||||
split_scroll = p[14];
|
||||
split_page = p[15];
|
||||
chr_mode = p[16];
|
||||
irq_status = p[17];
|
||||
irq_enable = p[18];
|
||||
irq_line = p[19];
|
||||
irq_scanline = p[20];
|
||||
irq_clear = p[21];
|
||||
mult_a = p[22];
|
||||
mult_b = p[23];
|
||||
|
||||
INT i, j;
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
chr_page[j][i] = p[24 + j * 8 + i];
|
||||
}
|
||||
}
|
||||
// // BGバンクの再設定処理
|
||||
// for( i = 0; i < 8; i++ ) {
|
||||
// BG_MEM_PAGE[i] = p[40+i]%VROM_1K_SIZE;
|
||||
// }
|
||||
// for( i = 0; i < 8; i++ ) {
|
||||
// BG_MEM_BANK[i] = VROM+0x0400*BG_MEM_PAGE[i];
|
||||
// }
|
||||
|
||||
SetBank_PPU();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper006 FFE F4xxx //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper006 : Mapper
|
||||
{
|
||||
BYTE irq_enable;
|
||||
INT irq_counter;
|
||||
public Mapper006(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 14, 15);
|
||||
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_8K_Bank(0);
|
||||
}
|
||||
|
||||
irq_enable = 0;
|
||||
irq_counter = 0;
|
||||
}
|
||||
|
||||
//void Mapper006::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x42FE:
|
||||
if ((data & 0x10) != 0) SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
break;
|
||||
case 0x42FF:
|
||||
if ((data & 0x10) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
break;
|
||||
|
||||
case 0x4501:
|
||||
irq_enable = 0;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0x4502:
|
||||
irq_counter = (irq_counter & 0xFF00) | data;
|
||||
break;
|
||||
case 0x4503:
|
||||
irq_counter = (irq_counter & 0x00FF) | ((INT)data << 8);
|
||||
irq_enable = 0xFF;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
default:
|
||||
base.WriteLow(addr, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper006::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
SetPROM_16K_Bank(4, (data & 0x3C) >> 2);
|
||||
SetCRAM_8K_Bank(data & 0x03);
|
||||
}
|
||||
|
||||
//void Mapper006::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if (irq_enable != 0)
|
||||
{
|
||||
irq_counter += 133;
|
||||
if (irq_counter >= 0xFFFF)
|
||||
{
|
||||
// nes.cpu.IRQ();
|
||||
irq_counter = 0;
|
||||
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper006::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
//p[0] = irq_enable;
|
||||
//*(INT*)&p[1] = irq_counter;
|
||||
}
|
||||
|
||||
//void Mapper006::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
//irq_enable = p[0];
|
||||
//irq_counter = *(INT*)&p[1];
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper007 AOROM/AMROM //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper007 : Mapper
|
||||
{
|
||||
|
||||
BYTE patch;
|
||||
public Mapper007(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
patch = 0;
|
||||
|
||||
SetPROM_32K_Bank(0);
|
||||
SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
|
||||
uint crc = nes.rom.GetPROM_CRC();
|
||||
if (crc == 0x3c9fe649)
|
||||
{ // WWF Wrestlemania Challenge(U)
|
||||
SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
patch = 1;
|
||||
}
|
||||
if (crc == 0x09874777)
|
||||
{ // Marble Madness(U)
|
||||
nes.SetRenderMethod( EnumRenderMethod.TILE_RENDER);
|
||||
}
|
||||
|
||||
if (crc == 0x279710DC // Battletoads (U)
|
||||
|| crc == 0xCEB65B06)
|
||||
{ // Battletoads Double Dragon (U)
|
||||
nes.SetRenderMethod( EnumRenderMethod.PRE_ALL_RENDER);
|
||||
//::memset(WRAM, 0, sizeof(WRAM));
|
||||
MemoryUtility.ZEROMEMORY(WRAM, WRAM.Length);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper007::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
SetPROM_32K_Bank(data & 0x07);
|
||||
|
||||
if (patch!=0)
|
||||
{
|
||||
if ((data & 0x10)!=0) SetVRAM_Mirror(VRAM_MIRROR4H);
|
||||
else SetVRAM_Mirror(VRAM_MIRROR4L);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper008 FFE F3xxx //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper008 : Mapper
|
||||
{
|
||||
|
||||
public Mapper008(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 2, 3);
|
||||
SetVROM_8K_Bank(0);
|
||||
}
|
||||
|
||||
//void Mapper008::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
SetPROM_16K_Bank(4, (data & 0xF8) >> 3);
|
||||
SetVROM_8K_Bank(data & 0x07);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper009 Nintendo MMC2 //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper009 : Mapper
|
||||
{
|
||||
BYTE[] reg = new byte[4];
|
||||
BYTE latch_a, latch_b;
|
||||
|
||||
public Mapper009(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
reg[0] = 0; reg[1] = 4;
|
||||
reg[2] = 0; reg[3] = 0;
|
||||
|
||||
latch_a = 0xFE;
|
||||
latch_b = 0xFE;
|
||||
SetVROM_4K_Bank(0, 4);
|
||||
SetVROM_4K_Bank(4, 0);
|
||||
|
||||
nes.ppu.SetChrLatchMode(true);
|
||||
}
|
||||
|
||||
//void Mapper009::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
switch (addr & 0xF000)
|
||||
{
|
||||
case 0xA000:
|
||||
SetPROM_8K_Bank(4, data);
|
||||
break;
|
||||
case 0xB000:
|
||||
reg[0] = data;
|
||||
if (latch_a == 0xFD)
|
||||
{
|
||||
SetVROM_4K_Bank(0, reg[0]);
|
||||
}
|
||||
break;
|
||||
case 0xC000:
|
||||
reg[1] = data;
|
||||
if (latch_a == 0xFE)
|
||||
{
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
break;
|
||||
case 0xD000:
|
||||
reg[2] = data;
|
||||
if (latch_b == 0xFD)
|
||||
{
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
break;
|
||||
case 0xE000:
|
||||
reg[3] = data;
|
||||
if (latch_b == 0xFE)
|
||||
{
|
||||
SetVROM_4K_Bank(4, reg[3]);
|
||||
}
|
||||
break;
|
||||
case 0xF000:
|
||||
if ((data & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper009::PPU_ChrLatch(WORD addr)
|
||||
public override void PPU_ChrLatch(ushort addr)
|
||||
{
|
||||
if ((addr & 0x1FF0) == 0x0FD0 && latch_a != 0xFD)
|
||||
{
|
||||
latch_a = 0xFD;
|
||||
SetVROM_4K_Bank(0, reg[0]);
|
||||
}
|
||||
else if ((addr & 0x1FF0) == 0x0FE0 && latch_a != 0xFE)
|
||||
{
|
||||
latch_a = 0xFE;
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
else if ((addr & 0x1FF0) == 0x1FD0 && latch_b != 0xFD)
|
||||
{
|
||||
latch_b = 0xFD;
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
else if ((addr & 0x1FF0) == 0x1FE0 && latch_b != 0xFE)
|
||||
{
|
||||
latch_b = 0xFE;
|
||||
SetVROM_4K_Bank(4, reg[3]);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper009::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = reg[0];
|
||||
p[1] = reg[1];
|
||||
p[2] = reg[2];
|
||||
p[3] = reg[3];
|
||||
p[4] = latch_a;
|
||||
p[5] = latch_b;
|
||||
}
|
||||
|
||||
//void Mapper009::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
reg[0] = p[0];
|
||||
reg[1] = p[1];
|
||||
reg[2] = p[2];
|
||||
reg[3] = p[3];
|
||||
latch_a = p[4];
|
||||
latch_b = p[5];
|
||||
}
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper010 Nintendo MMC4 //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper010 : Mapper
|
||||
{
|
||||
BYTE[] reg = new byte[4];
|
||||
BYTE latch_a, latch_b;
|
||||
|
||||
public Mapper010(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
|
||||
reg[0] = 0; reg[1] = 4;
|
||||
reg[2] = 0; reg[3] = 0;
|
||||
|
||||
latch_a = 0xFE;
|
||||
latch_b = 0xFE;
|
||||
SetVROM_4K_Bank(0, 4);
|
||||
SetVROM_4K_Bank(4, 0);
|
||||
|
||||
nes.ppu.SetChrLatchMode(true);
|
||||
}
|
||||
|
||||
//void Mapper010::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
switch (addr & 0xF000)
|
||||
{
|
||||
case 0xA000:
|
||||
SetPROM_16K_Bank(4, data);
|
||||
break;
|
||||
case 0xB000:
|
||||
reg[0] = data;
|
||||
if (latch_a == 0xFD)
|
||||
{
|
||||
SetVROM_4K_Bank(0, reg[0]);
|
||||
}
|
||||
break;
|
||||
case 0xC000:
|
||||
reg[1] = data;
|
||||
if (latch_a == 0xFE)
|
||||
{
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
break;
|
||||
case 0xD000:
|
||||
reg[2] = data;
|
||||
if (latch_b == 0xFD)
|
||||
{
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
break;
|
||||
case 0xE000:
|
||||
reg[3] = data;
|
||||
if (latch_b == 0xFE)
|
||||
{
|
||||
SetVROM_4K_Bank(4, reg[3]);
|
||||
}
|
||||
break;
|
||||
case 0xF000:
|
||||
if ((data & 0x01) != 0)
|
||||
SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper010::PPU_ChrLatch(WORD addr)
|
||||
public override void PPU_ChrLatch(ushort addr)
|
||||
{
|
||||
if ((addr & 0x1FF0) == 0x0FD0 && latch_a != 0xFD)
|
||||
{
|
||||
latch_a = 0xFD;
|
||||
SetVROM_4K_Bank(0, reg[0]);
|
||||
}
|
||||
else if ((addr & 0x1FF0) == 0x0FE0 && latch_a != 0xFE)
|
||||
{
|
||||
latch_a = 0xFE;
|
||||
SetVROM_4K_Bank(0, reg[1]);
|
||||
}
|
||||
else if ((addr & 0x1FF0) == 0x1FD0 && latch_b != 0xFD)
|
||||
{
|
||||
latch_b = 0xFD;
|
||||
SetVROM_4K_Bank(4, reg[2]);
|
||||
}
|
||||
else if ((addr & 0x1FF0) == 0x1FE0 && latch_b != 0xFE)
|
||||
{
|
||||
latch_b = 0xFE;
|
||||
SetVROM_4K_Bank(4, reg[3]);
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper010::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
p[0] = reg[0];
|
||||
p[1] = reg[1];
|
||||
p[2] = reg[2];
|
||||
p[3] = reg[3];
|
||||
p[4] = latch_a;
|
||||
p[5] = latch_b;
|
||||
}
|
||||
|
||||
//void Mapper010::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
reg[0] = p[0];
|
||||
reg[1] = p[1];
|
||||
reg[2] = p[2];
|
||||
reg[3] = p[3];
|
||||
latch_a = p[4];
|
||||
latch_b = p[5];
|
||||
}
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper011 Color Dreams //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper011 : Mapper
|
||||
{
|
||||
|
||||
public Mapper011(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0);
|
||||
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(0);
|
||||
// SetVROM_8K_Bank( 1 );
|
||||
}
|
||||
SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
|
||||
//void Mapper011::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//DEBUGOUT("WR A:%04X D:%02X\n", addr, data);
|
||||
SetPROM_32K_Bank(data);
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(data >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,331 @@
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper012 : Mapper
|
||||
{
|
||||
uint vb0, vb1;
|
||||
BYTE[] reg = new byte[8];
|
||||
BYTE prg0, prg1;
|
||||
BYTE chr01, chr23, chr4, chr5, chr6, chr7;
|
||||
BYTE we_sram;
|
||||
|
||||
BYTE irq_enable;
|
||||
BYTE irq_counter;
|
||||
BYTE irq_latch;
|
||||
BYTE irq_request;
|
||||
BYTE irq_preset;
|
||||
BYTE irq_preset_vbl;
|
||||
|
||||
public Mapper012(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
for (INT i = 0; i < 8; i++)
|
||||
{
|
||||
reg[i] = 0x00;
|
||||
}
|
||||
|
||||
prg0 = 0;
|
||||
prg1 = 1;
|
||||
SetBank_CPU();
|
||||
|
||||
vb0 = 0;
|
||||
vb1 = 0;
|
||||
chr01 = 0;
|
||||
chr23 = 2;
|
||||
chr4 = 4;
|
||||
chr5 = 5;
|
||||
chr6 = 6;
|
||||
chr7 = 7;
|
||||
SetBank_PPU();
|
||||
|
||||
we_sram = 0; // Disable
|
||||
irq_enable = 0; // Disable
|
||||
irq_counter = 0;
|
||||
irq_latch = 0xFF;
|
||||
irq_request = 0;
|
||||
irq_preset = 0;
|
||||
irq_preset_vbl = 0;
|
||||
}
|
||||
|
||||
//void Mapper012::WriteLow(WORD addr, BYTE data)
|
||||
public override void WriteLow(ushort addr, byte data)
|
||||
{
|
||||
if (addr > 0x4100 && addr < 0x6000)
|
||||
{
|
||||
vb0 = (byte)((data & 0x01) << 8);
|
||||
vb1 = (byte)((data & 0x10) << 4);
|
||||
SetBank_PPU();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteLow(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
//BYTE Mapper012::ReadLow(WORD addr)
|
||||
public override byte ReadLow(ushort addr)
|
||||
{
|
||||
return 0x01;
|
||||
}
|
||||
|
||||
//void Mapper012::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles() );
|
||||
|
||||
switch (addr & 0xE001)
|
||||
{
|
||||
case 0x8000:
|
||||
reg[0] = data;
|
||||
SetBank_CPU();
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x8001:
|
||||
reg[1] = data;
|
||||
|
||||
switch (reg[0] & 0x07)
|
||||
{
|
||||
case 0x00:
|
||||
chr01 = (byte)(data & 0xFE);
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x01:
|
||||
chr23 = (byte)(data & 0xFE);
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x02:
|
||||
chr4 = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x03:
|
||||
chr5 = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x04:
|
||||
chr6 = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x05:
|
||||
chr7 = data;
|
||||
SetBank_PPU();
|
||||
break;
|
||||
case 0x06:
|
||||
prg0 = data;
|
||||
SetBank_CPU();
|
||||
break;
|
||||
case 0x07:
|
||||
prg1 = data;
|
||||
SetBank_CPU();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
reg[2] = data;
|
||||
if (!nes.rom.Is4SCREEN())
|
||||
{
|
||||
if ((data & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
}
|
||||
break;
|
||||
case 0xA001:
|
||||
reg[3] = data;
|
||||
break;
|
||||
case 0xC000:
|
||||
reg[4] = data;
|
||||
irq_latch = data;
|
||||
break;
|
||||
case 0xC001:
|
||||
reg[5] = data;
|
||||
if (nes.GetScanline() < 240)
|
||||
{
|
||||
irq_counter |= 0x80;
|
||||
irq_preset = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_counter |= 0x80;
|
||||
irq_preset_vbl = 0xFF;
|
||||
irq_preset = 0;
|
||||
}
|
||||
break;
|
||||
case 0xE000:
|
||||
reg[6] = data;
|
||||
irq_enable = 0;
|
||||
irq_request = 0;
|
||||
|
||||
nes.cpu.ClrIRQ(IRQ_MAPPER);
|
||||
break;
|
||||
case 0xE001:
|
||||
reg[7] = data;
|
||||
irq_enable = 1;
|
||||
irq_request = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper012::HSync(INT scanline)
|
||||
public override void HSync(int scanline)
|
||||
{
|
||||
if ((scanline >= 0 && scanline <= 239) && nes.ppu.IsDispON())
|
||||
{
|
||||
if (irq_preset_vbl != 0)
|
||||
{
|
||||
irq_counter = irq_latch;
|
||||
irq_preset_vbl = 0;
|
||||
}
|
||||
if (irq_preset != 0)
|
||||
{
|
||||
irq_counter = irq_latch;
|
||||
irq_preset = 0;
|
||||
}
|
||||
else if (irq_counter > 0)
|
||||
{
|
||||
irq_counter--;
|
||||
}
|
||||
|
||||
if (irq_counter == 0)
|
||||
{
|
||||
// Some game set irq_latch to zero to disable irq. So check it here.
|
||||
if (irq_enable != 0 && irq_latch != 0)
|
||||
{
|
||||
irq_request = 0xFF;
|
||||
nes.cpu.SetIRQ(IRQ_MAPPER);
|
||||
}
|
||||
irq_preset = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_CPU()
|
||||
{
|
||||
if ((reg[0] & 0x40) != 0)
|
||||
{
|
||||
SetPROM_32K_Bank(PROM_8K_SIZE - 2, prg1, prg0, PROM_8K_SIZE - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_32K_Bank(prg0, prg1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void SetBank_PPU()
|
||||
{
|
||||
if (VROM_1K_SIZE != 0)
|
||||
{
|
||||
if ((reg[0] & 0x80) != 0)
|
||||
{
|
||||
SetVROM_8K_Bank(
|
||||
(int)(vb0 + chr4),
|
||||
(int)(vb0 + chr5),
|
||||
(int)(vb0 + chr6),
|
||||
(int)(vb0 + chr7),
|
||||
(int)(vb1 + chr01),
|
||||
(int)(vb1 + chr01 + 1),
|
||||
(int)(vb1 + chr23),
|
||||
(int)(vb1 + chr23 + 1)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVROM_8K_Bank(
|
||||
(int)(vb0 + chr01),
|
||||
(int)(vb0 + chr01 + 1),
|
||||
(int)(vb0 + chr23),
|
||||
(int)(vb0 + chr23 + 1),
|
||||
(int)(vb1 + chr4),
|
||||
(int)(vb1 + chr5),
|
||||
(int)(vb1 + chr6),
|
||||
(int)(vb1 + chr7))
|
||||
;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((reg[0] & 0x80) != 0)
|
||||
{
|
||||
SetCRAM_1K_Bank(4, (chr01 + 0) & 0x07);
|
||||
SetCRAM_1K_Bank(5, (chr01 + 1) & 0x07);
|
||||
SetCRAM_1K_Bank(6, (chr23 + 0) & 0x07);
|
||||
SetCRAM_1K_Bank(7, (chr23 + 1) & 0x07);
|
||||
SetCRAM_1K_Bank(0, chr4 & 0x07);
|
||||
SetCRAM_1K_Bank(1, chr5 & 0x07);
|
||||
SetCRAM_1K_Bank(2, chr6 & 0x07);
|
||||
SetCRAM_1K_Bank(3, chr7 & 0x07);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCRAM_1K_Bank(0, (chr01 + 0) & 0x07);
|
||||
SetCRAM_1K_Bank(1, (chr01 + 1) & 0x07);
|
||||
SetCRAM_1K_Bank(2, (chr23 + 0) & 0x07);
|
||||
SetCRAM_1K_Bank(3, (chr23 + 1) & 0x07);
|
||||
SetCRAM_1K_Bank(4, chr4 & 0x07);
|
||||
SetCRAM_1K_Bank(5, chr5 & 0x07);
|
||||
SetCRAM_1K_Bank(6, chr6 & 0x07);
|
||||
SetCRAM_1K_Bank(7, chr7 & 0x07);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Mapper012::SaveState(LPBYTE p)
|
||||
public override void SaveState(byte[] p)
|
||||
{
|
||||
//for (INT i = 0; i < 8; i++)
|
||||
//{
|
||||
// p[i] = reg[i];
|
||||
//}
|
||||
//p[8] = prg0;
|
||||
//p[9] = prg1;
|
||||
//p[10] = chr01;
|
||||
//p[11] = chr23;
|
||||
//p[12] = chr4;
|
||||
//p[13] = chr5;
|
||||
//p[14] = chr6;
|
||||
//p[15] = chr7;
|
||||
//p[16] = irq_enable;
|
||||
//p[17] = (BYTE)irq_counter;
|
||||
//p[18] = irq_latch;
|
||||
//p[19] = irq_request;
|
||||
//p[20] = irq_preset;
|
||||
//p[21] = irq_preset_vbl;
|
||||
//*((DWORD*)&p[22]) = vb0;
|
||||
//*((DWORD*)&p[26]) = vb1;
|
||||
}
|
||||
|
||||
//void Mapper012::LoadState(LPBYTE p)
|
||||
public override void LoadState(byte[] p)
|
||||
{
|
||||
//for (INT i = 0; i < 8; i++)
|
||||
//{
|
||||
// reg[i] = p[i];
|
||||
//}
|
||||
//prg0 = p[8];
|
||||
//prg1 = p[9];
|
||||
//chr01 = p[10];
|
||||
//chr23 = p[11];
|
||||
//chr4 = p[12];
|
||||
//chr5 = p[13];
|
||||
//chr6 = p[14];
|
||||
//chr7 = p[15];
|
||||
//irq_enable = p[16];
|
||||
//irq_counter = (INT)p[17];
|
||||
//irq_latch = p[18];
|
||||
//irq_request = p[19];
|
||||
//irq_preset = p[20];
|
||||
//irq_preset_vbl = p[21];
|
||||
//vb0 = *((DWORD*)&p[22]);
|
||||
//vb1 = *((DWORD*)&p[26]);
|
||||
}
|
||||
|
||||
|
||||
public override bool IsStateSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper013 CPROM //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper013 : Mapper
|
||||
{
|
||||
|
||||
public Mapper013(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 2, 3);
|
||||
SetCRAM_4K_Bank(0, 0);
|
||||
SetCRAM_4K_Bank(4, 0);
|
||||
}
|
||||
|
||||
//void Mapper013::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
SetPROM_32K_Bank((data & 0x30) >> 4);
|
||||
SetCRAM_4K_Bank(4, data & 0x03);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mapper015 100-in-1 chip //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
using static VirtualNes.MMU;
|
||||
using static VirtualNes.Core.CPU;
|
||||
using INT = System.Int32;
|
||||
using BYTE = System.Byte;
|
||||
using Codice.CM.Client.Differences;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class Mapper015 : Mapper
|
||||
{
|
||||
|
||||
public Mapper015(NES parent) : base(parent) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
SetPROM_32K_Bank(0, 1, 2, 3);
|
||||
}
|
||||
|
||||
//void Mapper015::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x8000:
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 3);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 2);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 3);
|
||||
}
|
||||
if ((data & 0x40) != 0)
|
||||
SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
break;
|
||||
case 0x8001:
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 1);
|
||||
}
|
||||
break;
|
||||
case 0x8002:
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 0);
|
||||
}
|
||||
break;
|
||||
case 0x8003:
|
||||
if ((data & 0x80) != 0)
|
||||
{
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 1);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 0);
|
||||
SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 1);
|
||||
}
|
||||
if ((data & 0x40) != 0) SetVRAM_Mirror(VRAM_HMIRROR);
|
||||
else SetVRAM_Mirror(VRAM_VMIRROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -247,8 +247,8 @@ namespace VirtualNes.Core
|
||||
Debuger.Log($"Mapper : #{rom.GetMapperNo():D3}");
|
||||
Debuger.Log($"PROM-CRC : #{rom.GetPROM_CRC():X2}");
|
||||
Debuger.Log($"VROM-CRC : #{rom.GetVROM_CRC():X2}");
|
||||
Debuger.Log($"PRG SIZE : {16 * rom.GetPROM_SIZE():4:0000}K");
|
||||
Debuger.Log($"CHR SIZE : {8 * rom.GetVROM_SIZE():4:0000}K");
|
||||
Debuger.Log($"PRG SIZE : {16 * rom.GetPROM_SIZE():0000}K");
|
||||
Debuger.Log($"CHR SIZE : {8 * rom.GetVROM_SIZE():0000}K");
|
||||
|
||||
Debuger.Log($"V MIRROR :{rom.IsVMIRROR()}");
|
||||
Debuger.Log($"4 SCREEN :{rom.Is4SCREEN()}");
|
||||
|
@ -244,6 +244,11 @@ namespace VirtualNes.Core
|
||||
|
||||
FileNameCheck(fname);
|
||||
|
||||
if (Supporter.TryGetMapperNo(this, out int mapperNo))
|
||||
{
|
||||
mapper = mapperNo;
|
||||
}
|
||||
|
||||
RomPatch.DoPatch(ref crc, ref lpPRG, ref lpCHR, ref mapper, ref header);
|
||||
|
||||
fdsmakerID = fdsgameID = 0;
|
||||
@ -362,7 +367,7 @@ namespace VirtualNes.Core
|
||||
return (header.control2 & (byte)EnumRomControlByte2.ROM_VSUNISYSTEM) != 0;
|
||||
}
|
||||
|
||||
internal uint GetPROM_CRC()
|
||||
public uint GetPROM_CRC()
|
||||
{
|
||||
return crc;
|
||||
}
|
||||
|
@ -49,6 +49,11 @@ namespace VirtualNes.Core
|
||||
return s_support.OpenFile(directPath, fileName);
|
||||
}
|
||||
|
||||
public static bool TryGetMapperNo(ROM rom, out int mapperNo)
|
||||
{
|
||||
return s_support.TryGetMapperNo(rom, out mapperNo);
|
||||
}
|
||||
|
||||
public static EmulatorConfig Config => s_support.Config;
|
||||
}
|
||||
|
||||
@ -64,5 +69,6 @@ namespace VirtualNes.Core
|
||||
void PrepareDirectory(string directPath);
|
||||
void SaveFile(byte[] fileData, string directPath, string fileName);
|
||||
Stream OpenFile(string directPath, string fileName);
|
||||
bool TryGetMapperNo(ROM rom, out int mapperNo);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user