[NES] overhaul database and board configuration system some more and reorg code a bit
This commit is contained in:
parent
47b9a5ffb4
commit
be69565135
|
@ -55,6 +55,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Consoles\Calculator\TI83.cs" />
|
<Compile Include="Consoles\Calculator\TI83.cs" />
|
||||||
|
<Compile Include="Consoles\Nintendo\NES\BoardSystem.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\NES\Boards\AxROM.cs">
|
<Compile Include="Consoles\Nintendo\NES\Boards\AxROM.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -70,14 +71,16 @@
|
||||||
<Compile Include="Consoles\Nintendo\NES\Boards\IC_74x377.cs">
|
<Compile Include="Consoles\Nintendo\NES\Boards\IC_74x377.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Nintendo\NES\Boards\NROM.cs" />
|
<Compile Include="Consoles\Nintendo\NES\Boards\NROM.cs">
|
||||||
<Compile Include="Consoles\Nintendo\NES\BoardDetector.cs" />
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Consoles\Nintendo\NES\Boards\SxROM.cs">
|
<Compile Include="Consoles\Nintendo\NES\Boards\SxROM.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Nintendo\NES\Boards\UxROM.cs">
|
<Compile Include="Consoles\Nintendo\NES\Boards\UxROM.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\NES\Core.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\NES\iNES.cs" />
|
<Compile Include="Consoles\Nintendo\NES\iNES.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\NES\NES.cs" />
|
<Compile Include="Consoles\Nintendo\NES\NES.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\NES\Palettes.cs" />
|
<Compile Include="Consoles\Nintendo\NES\Palettes.cs" />
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Xml;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
|
||||||
{
|
|
||||||
partial class NES
|
|
||||||
{
|
|
||||||
public class BootGodDB
|
|
||||||
{
|
|
||||||
bool validate = true;
|
|
||||||
|
|
||||||
public static BootGodDB Instance;
|
|
||||||
public static Func<byte[]> GetDatabaseBytes;
|
|
||||||
public static void Initialize()
|
|
||||||
{
|
|
||||||
if(Instance == null)
|
|
||||||
Instance = new BootGodDB();
|
|
||||||
}
|
|
||||||
int ParseSize(string str)
|
|
||||||
{
|
|
||||||
int temp = 0;
|
|
||||||
if(validate) if (!str.EndsWith("k")) throw new Exception();
|
|
||||||
int len=str.Length-1;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
temp *= 10;
|
|
||||||
temp += (str[i] - '0');
|
|
||||||
}
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
public BootGodDB()
|
|
||||||
{
|
|
||||||
//notes: there can be multiple each of prg,chr,wram,vram
|
|
||||||
//we arent tracking the individual hashes yet.
|
|
||||||
|
|
||||||
//in anticipation of any slowness annoying people, and just for shits and giggles, i made a super fast parser
|
|
||||||
int state=0;
|
|
||||||
var xmlreader = XmlReader.Create(new MemoryStream(GetDatabaseBytes()));
|
|
||||||
Game currGame = null;
|
|
||||||
Cart currCart = null;
|
|
||||||
while (xmlreader.Read())
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "game")
|
|
||||||
{
|
|
||||||
currGame = new Game();
|
|
||||||
currGame.name = xmlreader.GetAttribute("name");
|
|
||||||
state = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "cartridge")
|
|
||||||
{
|
|
||||||
currCart = new Cart();
|
|
||||||
currCart.game = currGame;
|
|
||||||
currCart.system = xmlreader.GetAttribute("system");
|
|
||||||
currCart.sha1 = "sha1:" + xmlreader.GetAttribute("sha1");
|
|
||||||
state = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "board")
|
|
||||||
{
|
|
||||||
currCart.board_type = xmlreader.GetAttribute("type");
|
|
||||||
int mapper = byte.Parse(xmlreader.GetAttribute("mapper"));
|
|
||||||
if (validate && mapper > 255) throw new Exception("didnt expect mapper>255!");
|
|
||||||
currCart.mapper = (byte)mapper;
|
|
||||||
state = 3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.Element)
|
|
||||||
{
|
|
||||||
switch(xmlreader.Name)
|
|
||||||
{
|
|
||||||
case "prg":
|
|
||||||
currCart.prg_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
|
||||||
break;
|
|
||||||
case "chr":
|
|
||||||
currCart.chr_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
|
||||||
break;
|
|
||||||
case "vram":
|
|
||||||
currCart.vram_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
|
||||||
break;
|
|
||||||
case "wram":
|
|
||||||
currCart.wram_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
|
||||||
if (xmlreader.GetAttribute("battery") != null)
|
|
||||||
currCart.wram_battery = true;
|
|
||||||
break;
|
|
||||||
case "pad":
|
|
||||||
currCart.pad_h = byte.Parse(xmlreader.GetAttribute("h"));
|
|
||||||
currCart.pad_v = byte.Parse(xmlreader.GetAttribute("v"));
|
|
||||||
break;
|
|
||||||
case "chip":
|
|
||||||
currCart.chips.Add(xmlreader.GetAttribute("type"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.EndElement && xmlreader.Name == "board")
|
|
||||||
{
|
|
||||||
state = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.EndElement && xmlreader.Name == "cartridge")
|
|
||||||
{
|
|
||||||
currGame.carts.Add(currCart);
|
|
||||||
currCart = null;
|
|
||||||
state = 5;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if (xmlreader.NodeType == XmlNodeType.EndElement && xmlreader.Name == "game")
|
|
||||||
{
|
|
||||||
games.Add(currGame);
|
|
||||||
currGame = null;
|
|
||||||
state = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} //end xmlreader loop
|
|
||||||
|
|
||||||
//analyze
|
|
||||||
foreach (Game game in games)
|
|
||||||
{
|
|
||||||
foreach (Cart cart in game.carts)
|
|
||||||
{
|
|
||||||
sha1_table[cart.sha1].Add(cart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class Cart
|
|
||||||
{
|
|
||||||
//we have merged board into cartridge because there is never more than one board per cartridge
|
|
||||||
public Game game;
|
|
||||||
|
|
||||||
public short chr_size;
|
|
||||||
public short prg_size;
|
|
||||||
public short wram_size, vram_size;
|
|
||||||
public byte pad_h, pad_v, mapper;
|
|
||||||
public bool wram_battery;
|
|
||||||
|
|
||||||
public string board_type;
|
|
||||||
|
|
||||||
public string sha1;
|
|
||||||
public string system;
|
|
||||||
public List<string> chips = new List<string>();
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format("r={0},vr={1},pr={2},cr={3},ba={4},pa={5},{6},brd={7},map={8},sys={9}", prg_size, chr_size, wram_size, vram_size, wram_battery, pad_h, pad_v, board_type, mapper, system);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Game
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public List<Cart> carts = new List<Cart>();
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format("name={0}", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Game> games = new List<Game>(); //maybe we dont need to track this
|
|
||||||
Bag<string, Cart> sha1_table = new Bag<string, Cart>();
|
|
||||||
|
|
||||||
public List<Cart> Identify(string sha1)
|
|
||||||
{
|
|
||||||
if (!sha1_table.ContainsKey(sha1)) return new List<Cart>();
|
|
||||||
return sha1_table[sha1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// static class BoardDetector
|
|
||||||
// {
|
|
||||||
// public static string Detect(RomInfo romInfo)
|
|
||||||
// {
|
|
||||||
// string key = string.Format("{0} {1} {2} {3}",romInfo.MapperNumber,romInfo.PRG_Size,romInfo.CHR_Size,romInfo.PRAM_Size);
|
|
||||||
// string board;
|
|
||||||
// Table.TryGetValue(key, out board);
|
|
||||||
// return board;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static Dictionary<string,string> Table = new Dictionary<string,string>();
|
|
||||||
// static BoardDetector()
|
|
||||||
// {
|
|
||||||
// var sr = new StringReader(ClassifyTable);
|
|
||||||
// string line;
|
|
||||||
// while ((line = sr.ReadLine()) != null)
|
|
||||||
// {
|
|
||||||
// var parts = line.Split('\t');
|
|
||||||
// if (parts.Length < 5) continue;
|
|
||||||
// string key = parts[0] + "\t" + parts[1] + "\t" + parts[2] + "\t" + parts[3];
|
|
||||||
// string board = line.Replace(key, "");
|
|
||||||
// board = board.TrimStart('\t');
|
|
||||||
// if (board.IndexOf(';') != -1)
|
|
||||||
// board = board.Substring(0, board.IndexOf(';'));
|
|
||||||
// Table[key] = board;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
////MAP PRG CHR PRAM BOARD
|
|
||||||
// static string ClassifyTable = @"
|
|
||||||
//0 1 1 0 NROM
|
|
||||||
//0 2 1 0 NROM
|
|
||||||
//1 8 0 8 SNROM; this handles zelda,
|
|
||||||
//2 8 0 0 UNROM
|
|
||||||
//2 16 0 0 UOROM
|
|
||||||
//3 2 2 0 CNROM
|
|
||||||
//3 2 4 0 CNROM
|
|
||||||
//7 8 0 0 ANROM
|
|
||||||
//7 16 0 0 AOROM
|
|
||||||
//11 4 2 0 Discrete_74x377
|
|
||||||
//11 2 4 0 Discrete_74x377
|
|
||||||
//13 2 0 0 CPROM
|
|
||||||
//66 4 2 0 GxROM
|
|
||||||
//66 8 4 0 GxROM
|
|
||||||
//";
|
|
||||||
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//STD_SAROM = MakeId< 1, 64, 64, 8, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SBROM = MakeId< 1, 64, 64, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SCROM = MakeId< 1, 64, 128, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SEROM = MakeId< 1, 32, 64, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SFROM = MakeId< 1, 256, 64, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SGROM = MakeId< 1, 256, 0, 0, 0, CRM_8, NMT_H, 0 >::ID,
|
|
||||||
//STD_SHROM = MakeId< 1, 32, 128, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SJROM = MakeId< 1, 256, 64, 8, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SKROM = MakeId< 1, 256, 128, 8, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SLROM = MakeId< 1, 256, 128, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
|
||||||
//STD_SNROM = MakeId< 1, 256, 0, 8, 0, CRM_8, NMT_H, 0 >::ID,
|
|
||||||
//STD_SOROM = MakeId< 1, 256, 0, 8, 8, CRM_8, NMT_H, 0 >::ID,
|
|
||||||
//STD_SUROM = MakeId< 1, 512, 0, 8, 0, CRM_8, NMT_H, 0 >::ID,
|
|
||||||
//STD_SXROM = MakeId< 1, 512, 0, 32, 0, CRM_8, NMT_H, 0 >::ID,
|
|
|
@ -0,0 +1,478 @@
|
||||||
|
using System;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
|
{
|
||||||
|
partial class NES
|
||||||
|
{
|
||||||
|
public interface INESBoard
|
||||||
|
{
|
||||||
|
void Create(NES nes);
|
||||||
|
bool Configure();
|
||||||
|
byte ReadPRG(int addr);
|
||||||
|
byte ReadPPU(int addr); byte PeekPPU(int addr);
|
||||||
|
byte ReadPRAM(int addr);
|
||||||
|
void WritePRG(int addr, byte value);
|
||||||
|
void WritePPU(int addr, byte value);
|
||||||
|
void WritePRAM(int addr, byte value);
|
||||||
|
byte[] SaveRam { get; }
|
||||||
|
byte[] WRAM { get; set; }
|
||||||
|
byte[] VRAM { get; set; }
|
||||||
|
byte[] ROM { get; set; }
|
||||||
|
byte[] VROM { get; set; }
|
||||||
|
void SaveStateBinary(BinaryWriter bw);
|
||||||
|
void LoadStateBinary(BinaryReader br);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
[INESBoardImpl]
|
||||||
|
public abstract class NESBoardBase : INESBoard
|
||||||
|
{
|
||||||
|
public virtual void Create(NES nes)
|
||||||
|
{
|
||||||
|
this.NES = nes;
|
||||||
|
}
|
||||||
|
public abstract bool Configure();
|
||||||
|
|
||||||
|
public CartInfo Cart { get { return NES.cart; } }
|
||||||
|
public NES NES { get; set; }
|
||||||
|
|
||||||
|
public virtual void SaveStateBinary(BinaryWriter bw)
|
||||||
|
{
|
||||||
|
Util.WriteByteBuffer(bw, VRAM);
|
||||||
|
Util.WriteByteBuffer(bw, WRAM);
|
||||||
|
for (int i = 0; i < 4; i++) bw.Write(mirroring[i]);
|
||||||
|
}
|
||||||
|
public virtual void LoadStateBinary(BinaryReader br)
|
||||||
|
{
|
||||||
|
VRAM = Util.ReadByteBuffer(br, true);
|
||||||
|
WRAM = Util.ReadByteBuffer(br, true);
|
||||||
|
for (int i = 0; i < 4; i++) mirroring[i] = br.ReadInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] mirroring = new int[4];
|
||||||
|
protected void SetMirroring(int a, int b, int c, int d)
|
||||||
|
{
|
||||||
|
mirroring[0] = a;
|
||||||
|
mirroring[1] = b;
|
||||||
|
mirroring[2] = c;
|
||||||
|
mirroring[3] = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetMirrorType(int pad_h, int pad_v)
|
||||||
|
{
|
||||||
|
if (pad_h == 0)
|
||||||
|
if (pad_v == 0)
|
||||||
|
SetMirrorType(EMirrorType.OneScreenA);
|
||||||
|
else SetMirrorType(EMirrorType.Horizontal);
|
||||||
|
else
|
||||||
|
if (pad_v == 0)
|
||||||
|
SetMirrorType(EMirrorType.Vertical);
|
||||||
|
else SetMirrorType(EMirrorType.OneScreenB);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetMirrorType(EMirrorType mirrorType)
|
||||||
|
{
|
||||||
|
switch (mirrorType)
|
||||||
|
{
|
||||||
|
case EMirrorType.Horizontal: SetMirroring(0, 0, 1, 1); break;
|
||||||
|
case EMirrorType.Vertical: SetMirroring(0, 1, 0, 1); break;
|
||||||
|
case EMirrorType.OneScreenA: SetMirroring(0, 0, 0, 0); break;
|
||||||
|
case EMirrorType.OneScreenB: SetMirroring(1, 1, 1, 1); break;
|
||||||
|
default: SetMirroring(-1, -1, -1, -1); break; //crash!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ApplyMirroring(int addr)
|
||||||
|
{
|
||||||
|
int block = (addr >> 10) & 3;
|
||||||
|
block = mirroring[block];
|
||||||
|
int ofs = addr & 0x3FF;
|
||||||
|
return (block << 10) | ofs;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte HandleNormalPRGConflict(int addr, byte value)
|
||||||
|
{
|
||||||
|
byte old_value = value;
|
||||||
|
value &= ReadPRG(addr);
|
||||||
|
Debug.Assert(old_value == value, "Found a test case of bus conflict. please report.");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual byte ReadPRG(int addr) { return ROM[addr]; }
|
||||||
|
public virtual void WritePRG(int addr, byte value) { }
|
||||||
|
|
||||||
|
public virtual void WritePRAM(int addr, byte value) { }
|
||||||
|
public virtual byte ReadPRAM(int addr) { return 0xFF; }
|
||||||
|
|
||||||
|
|
||||||
|
public virtual void WritePPU(int addr, byte value)
|
||||||
|
{
|
||||||
|
if (addr < 0x2000)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NES.CIRAM[ApplyMirroring(addr)] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual byte PeekPPU(int addr) { return ReadPPU(addr); }
|
||||||
|
|
||||||
|
public virtual byte ReadPPU(int addr)
|
||||||
|
{
|
||||||
|
if (addr < 0x2000)
|
||||||
|
{
|
||||||
|
return VROM[addr];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NES.CIRAM[ApplyMirroring(addr)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual byte[] SaveRam { get { return null; } }
|
||||||
|
public byte[] WRAM { get; set; }
|
||||||
|
public byte[] VRAM { get; set; }
|
||||||
|
public byte[] ROM { get; set; }
|
||||||
|
public byte[] VROM { get; set; }
|
||||||
|
|
||||||
|
protected void Assert(bool test, string comment, params object[] args)
|
||||||
|
{
|
||||||
|
if (!test) throw new Exception(string.Format(comment, args));
|
||||||
|
}
|
||||||
|
protected void Assert(bool test)
|
||||||
|
{
|
||||||
|
if (!test) throw new Exception("assertion failed in board setup!");
|
||||||
|
}
|
||||||
|
protected void AssertPrg(params int[] prg) { Assert_memtype(Cart.prg_size, "prg", prg); }
|
||||||
|
protected void AssertChr(params int[] chr) { Assert_memtype(Cart.chr_size, "chr", chr); }
|
||||||
|
protected void AssertWram(params int[] wram) { Assert_memtype(Cart.wram_size, "wram", wram); }
|
||||||
|
protected void AssertVram(params int[] vram) { Assert_memtype(Cart.vram_size, "vram", vram); }
|
||||||
|
protected void Assert_memtype(int value, string name, int[] valid)
|
||||||
|
{
|
||||||
|
foreach (int i in valid) if (value == i) return;
|
||||||
|
Assert(false, "unhandled {0} size", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//this will be used to track classes that implement boards
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class INESBoardImplAttribute : Attribute { }
|
||||||
|
static List<Type> INESBoardImplementors = new List<Type>();
|
||||||
|
|
||||||
|
static NES()
|
||||||
|
{
|
||||||
|
//scan types in this assembly to find ones that implement boards to add them to the list
|
||||||
|
foreach (Type type in typeof(NES).Assembly.GetTypes())
|
||||||
|
{
|
||||||
|
var attrs = type.GetCustomAttributes(typeof(INESBoardImplAttribute), true);
|
||||||
|
if (attrs.Length == 0) continue;
|
||||||
|
if (type.IsAbstract) continue;
|
||||||
|
INESBoardImplementors.Add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All information necessary for a board to set itself up
|
||||||
|
/// </summary>
|
||||||
|
public class CartInfo
|
||||||
|
{
|
||||||
|
public GameInfo game;
|
||||||
|
|
||||||
|
public short chr_size;
|
||||||
|
public short prg_size;
|
||||||
|
public short wram_size, vram_size;
|
||||||
|
public byte pad_h, pad_v, mapper;
|
||||||
|
public bool wram_battery;
|
||||||
|
|
||||||
|
public string board_type;
|
||||||
|
|
||||||
|
public string sha1;
|
||||||
|
public string system;
|
||||||
|
public List<string> chips = new List<string>();
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("r={0},vr={1},pr={2},cr={3},ba={4},pa={5},{6},brd={7},map={8},sys={9}", prg_size, chr_size, wram_size, vram_size, wram_battery, pad_h, pad_v, board_type, mapper, system);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logical game information. May exist in form of several carts (different revisions)
|
||||||
|
/// </summary>
|
||||||
|
public class GameInfo
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public List<CartInfo> carts = new List<CartInfo>();
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("name={0}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// finds a board class which can handle the provided cart
|
||||||
|
/// </summary>
|
||||||
|
static Type FindBoard(CartInfo cart)
|
||||||
|
{
|
||||||
|
NES nes = new NES();
|
||||||
|
nes.cart = cart;
|
||||||
|
foreach (var type in INESBoardImplementors)
|
||||||
|
{
|
||||||
|
INESBoard board = (INESBoard)Activator.CreateInstance(type);
|
||||||
|
board.Create(nes);
|
||||||
|
if (board.Configure())
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// looks up from the bootgod DB
|
||||||
|
/// </summary>
|
||||||
|
CartInfo IdentifyFromBootGodDB(string hash_sha1)
|
||||||
|
{
|
||||||
|
BootGodDB.Initialize();
|
||||||
|
List<CartInfo> choices = BootGodDB.Instance.Identify(hash_sha1);
|
||||||
|
if (choices.Count == 0) return null;
|
||||||
|
|
||||||
|
//pick the first board for this hash arbitrarily. it probably doesn't make a difference
|
||||||
|
Console.WriteLine("Chose board from nescartdb:");
|
||||||
|
return choices[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// looks up from the game DB
|
||||||
|
/// </summary>
|
||||||
|
CartInfo IdentifyFromGameDB(string hash)
|
||||||
|
{
|
||||||
|
var gi = Database.CheckDatabase(hash);
|
||||||
|
if (gi == null) return null;
|
||||||
|
|
||||||
|
GameInfo game = new GameInfo();
|
||||||
|
CartInfo cart = new CartInfo();
|
||||||
|
game.carts.Add(cart);
|
||||||
|
|
||||||
|
//try generating a bootgod cart descriptor from the game database
|
||||||
|
var dict = gi.ParseOptionsDictionary();
|
||||||
|
game.name = gi.Name;
|
||||||
|
cart.game = game;
|
||||||
|
cart.board_type = dict["board"];
|
||||||
|
if (dict.ContainsKey("PRG"))
|
||||||
|
cart.prg_size = short.Parse(dict["PRG"]);
|
||||||
|
if (dict.ContainsKey("CHR"))
|
||||||
|
cart.chr_size = short.Parse(dict["CHR"]);
|
||||||
|
if(dict.ContainsKey("VRAM"))
|
||||||
|
cart.vram_size = short.Parse(dict["VRAM"]);
|
||||||
|
if (dict.ContainsKey("WRAM"))
|
||||||
|
cart.wram_size = short.Parse(dict["WRAM"]);
|
||||||
|
|
||||||
|
return cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BootGodDB
|
||||||
|
{
|
||||||
|
bool validate = true;
|
||||||
|
|
||||||
|
public static BootGodDB Instance;
|
||||||
|
public static Func<byte[]> GetDatabaseBytes;
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
if(Instance == null)
|
||||||
|
Instance = new BootGodDB();
|
||||||
|
}
|
||||||
|
int ParseSize(string str)
|
||||||
|
{
|
||||||
|
int temp = 0;
|
||||||
|
if(validate) if (!str.EndsWith("k")) throw new Exception();
|
||||||
|
int len=str.Length-1;
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
temp *= 10;
|
||||||
|
temp += (str[i] - '0');
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
public BootGodDB()
|
||||||
|
{
|
||||||
|
//notes: there can be multiple each of prg,chr,wram,vram
|
||||||
|
//we arent tracking the individual hashes yet.
|
||||||
|
|
||||||
|
//in anticipation of any slowness annoying people, and just for shits and giggles, i made a super fast parser
|
||||||
|
int state=0;
|
||||||
|
var xmlreader = XmlReader.Create(new MemoryStream(GetDatabaseBytes()));
|
||||||
|
GameInfo currGame = null;
|
||||||
|
CartInfo currCart = null;
|
||||||
|
while (xmlreader.Read())
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "game")
|
||||||
|
{
|
||||||
|
currGame = new GameInfo();
|
||||||
|
currGame.name = xmlreader.GetAttribute("name");
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "cartridge")
|
||||||
|
{
|
||||||
|
currCart = new CartInfo();
|
||||||
|
currCart.game = currGame;
|
||||||
|
currCart.system = xmlreader.GetAttribute("system");
|
||||||
|
currCart.sha1 = "sha1:" + xmlreader.GetAttribute("sha1");
|
||||||
|
state = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "board")
|
||||||
|
{
|
||||||
|
currCart.board_type = xmlreader.GetAttribute("type");
|
||||||
|
int mapper = byte.Parse(xmlreader.GetAttribute("mapper"));
|
||||||
|
if (validate && mapper > 255) throw new Exception("didnt expect mapper>255!");
|
||||||
|
currCart.mapper = (byte)mapper;
|
||||||
|
state = 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
switch(xmlreader.Name)
|
||||||
|
{
|
||||||
|
case "prg":
|
||||||
|
currCart.prg_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
||||||
|
break;
|
||||||
|
case "chr":
|
||||||
|
currCart.chr_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
||||||
|
break;
|
||||||
|
case "vram":
|
||||||
|
currCart.vram_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
||||||
|
break;
|
||||||
|
case "wram":
|
||||||
|
currCart.wram_size += (short)ParseSize(xmlreader.GetAttribute("size"));
|
||||||
|
if (xmlreader.GetAttribute("battery") != null)
|
||||||
|
currCart.wram_battery = true;
|
||||||
|
break;
|
||||||
|
case "pad":
|
||||||
|
currCart.pad_h = byte.Parse(xmlreader.GetAttribute("h"));
|
||||||
|
currCart.pad_v = byte.Parse(xmlreader.GetAttribute("v"));
|
||||||
|
break;
|
||||||
|
case "chip":
|
||||||
|
currCart.chips.Add(xmlreader.GetAttribute("type"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.EndElement && xmlreader.Name == "board")
|
||||||
|
{
|
||||||
|
state = 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.EndElement && xmlreader.Name == "cartridge")
|
||||||
|
{
|
||||||
|
currGame.carts.Add(currCart);
|
||||||
|
currCart = null;
|
||||||
|
state = 5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (xmlreader.NodeType == XmlNodeType.EndElement && xmlreader.Name == "game")
|
||||||
|
{
|
||||||
|
games.Add(currGame);
|
||||||
|
currGame = null;
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} //end xmlreader loop
|
||||||
|
|
||||||
|
//analyze
|
||||||
|
foreach (GameInfo game in games)
|
||||||
|
{
|
||||||
|
foreach (CartInfo cart in game.carts)
|
||||||
|
{
|
||||||
|
sha1_table[cart.sha1].Add(cart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<GameInfo> games = new List<GameInfo>(); //maybe we dont need to track this
|
||||||
|
Bag<string, CartInfo> sha1_table = new Bag<string, CartInfo>();
|
||||||
|
|
||||||
|
public List<CartInfo> Identify(string sha1)
|
||||||
|
{
|
||||||
|
if (!sha1_table.ContainsKey(sha1)) return new List<CartInfo>();
|
||||||
|
return sha1_table[sha1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static class BoardDetector
|
||||||
|
// {
|
||||||
|
// public static string Detect(RomInfo romInfo)
|
||||||
|
// {
|
||||||
|
// string key = string.Format("{0} {1} {2} {3}",romInfo.MapperNumber,romInfo.PRG_Size,romInfo.CHR_Size,romInfo.PRAM_Size);
|
||||||
|
// string board;
|
||||||
|
// Table.TryGetValue(key, out board);
|
||||||
|
// return board;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public static Dictionary<string,string> Table = new Dictionary<string,string>();
|
||||||
|
// static BoardDetector()
|
||||||
|
// {
|
||||||
|
// var sr = new StringReader(ClassifyTable);
|
||||||
|
// string line;
|
||||||
|
// while ((line = sr.ReadLine()) != null)
|
||||||
|
// {
|
||||||
|
// var parts = line.Split('\t');
|
||||||
|
// if (parts.Length < 5) continue;
|
||||||
|
// string key = parts[0] + "\t" + parts[1] + "\t" + parts[2] + "\t" + parts[3];
|
||||||
|
// string board = line.Replace(key, "");
|
||||||
|
// board = board.TrimStart('\t');
|
||||||
|
// if (board.IndexOf(';') != -1)
|
||||||
|
// board = board.Substring(0, board.IndexOf(';'));
|
||||||
|
// Table[key] = board;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
////MAP PRG CHR PRAM BOARD
|
||||||
|
// static string ClassifyTable = @"
|
||||||
|
//0 1 1 0 NROM
|
||||||
|
//0 2 1 0 NROM
|
||||||
|
//1 8 0 8 SNROM; this handles zelda,
|
||||||
|
//2 8 0 0 UNROM
|
||||||
|
//2 16 0 0 UOROM
|
||||||
|
//3 2 2 0 CNROM
|
||||||
|
//3 2 4 0 CNROM
|
||||||
|
//7 8 0 0 ANROM
|
||||||
|
//7 16 0 0 AOROM
|
||||||
|
//11 4 2 0 Discrete_74x377
|
||||||
|
//11 2 4 0 Discrete_74x377
|
||||||
|
//13 2 0 0 CPROM
|
||||||
|
//66 4 2 0 GxROM
|
||||||
|
//66 8 4 0 GxROM
|
||||||
|
//";
|
||||||
|
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//STD_SAROM = MakeId< 1, 64, 64, 8, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SBROM = MakeId< 1, 64, 64, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SCROM = MakeId< 1, 64, 128, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SEROM = MakeId< 1, 32, 64, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SFROM = MakeId< 1, 256, 64, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SGROM = MakeId< 1, 256, 0, 0, 0, CRM_8, NMT_H, 0 >::ID,
|
||||||
|
//STD_SHROM = MakeId< 1, 32, 128, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SJROM = MakeId< 1, 256, 64, 8, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SKROM = MakeId< 1, 256, 128, 8, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SLROM = MakeId< 1, 256, 128, 0, 0, CRM_0, NMT_H, 0 >::ID,
|
||||||
|
//STD_SNROM = MakeId< 1, 256, 0, 8, 0, CRM_8, NMT_H, 0 >::ID,
|
||||||
|
//STD_SOROM = MakeId< 1, 256, 0, 8, 8, CRM_8, NMT_H, 0 >::ID,
|
||||||
|
//STD_SUROM = MakeId< 1, 512, 0, 8, 0, CRM_8, NMT_H, 0 >::ID,
|
||||||
|
//STD_SXROM = MakeId< 1, 512, 0, 32, 0, CRM_8, NMT_H, 0 >::ID,
|
|
@ -2,14 +2,10 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
//generally mapper7
|
//generally mapper7
|
||||||
|
|
||||||
//Battletoads
|
|
||||||
//Time Lord
|
|
||||||
//Marble Madness
|
|
||||||
|
|
||||||
public class AxROM : NES.NESBoardBase
|
public class AxROM : NES.NESBoardBase
|
||||||
{
|
{
|
||||||
//configuration
|
//configuration
|
||||||
|
@ -18,49 +14,40 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
int prg_mask;
|
int prg_mask;
|
||||||
|
|
||||||
//state
|
//state
|
||||||
byte[] cram;
|
|
||||||
int prg;
|
int prg;
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//configure
|
//configure
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "NES-ANROM":
|
case "NES-ANROM": //marble madness
|
||||||
BoardInfo.PRG_Size = 128;
|
AssertPrg(128); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
bus_conflict = false;
|
bus_conflict = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "NES-AN1ROM":
|
case "NES-AN1ROM": //R.C. Pro-Am
|
||||||
BoardInfo.PRG_Size = 64;
|
AssertPrg(64); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
bus_conflict = false;
|
bus_conflict = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "NES-AMROM":
|
case "NES-AMROM": //time lord
|
||||||
BoardInfo.PRG_Size = 128;
|
AssertPrg(128); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
bus_conflict = true;
|
bus_conflict = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "NES-AOROM":
|
case "NES-AOROM": //battletoads
|
||||||
case "HVC-AOROM":
|
case "HVC-AOROM":
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
AssertPrg(128,256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
bus_conflict = true; //MAYBE. apparently it varies
|
||||||
bus_conflict = true; //MAYBE. apparently it varies
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//these boards always have 8KB of CRAM
|
prg_mask = (Cart.prg_size / 16) - 1;
|
||||||
BoardInfo.CRAM_Size = 8;
|
cram_byte_mask = 8 * 1024 - 1; //these boards always have 8KB of CRAM
|
||||||
cram = new byte[BoardInfo.CRAM_Size * 1024];
|
|
||||||
cram_byte_mask = cram.Length - 1;
|
|
||||||
|
|
||||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
|
|
||||||
//it is necessary to write during initialization to set the mirroring
|
//it is necessary to write during initialization to set the mirroring
|
||||||
WritePRG(0, 0);
|
WritePRG(0, 0);
|
||||||
|
@ -87,7 +74,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
if (addr < 0x2000)
|
if (addr < 0x2000)
|
||||||
{
|
{
|
||||||
return cram[addr & cram_byte_mask];
|
return VRAM[addr & cram_byte_mask];
|
||||||
}
|
}
|
||||||
else return base.ReadPPU(addr);
|
else return base.ReadPPU(addr);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +83,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
if (addr < 0x2000)
|
if (addr < 0x2000)
|
||||||
{
|
{
|
||||||
cram[addr & cram_byte_mask] = value;
|
VRAM[addr & cram_byte_mask] = value;
|
||||||
}
|
}
|
||||||
else base.WritePPU(addr,value);
|
else base.WritePPU(addr,value);
|
||||||
}
|
}
|
||||||
|
@ -105,14 +92,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
base.SaveStateBinary(bw);
|
base.SaveStateBinary(bw);
|
||||||
bw.Write(prg);
|
bw.Write(prg);
|
||||||
Util.WriteByteBuffer(bw, cram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LoadStateBinary(BinaryReader br)
|
public override void LoadStateBinary(BinaryReader br)
|
||||||
{
|
{
|
||||||
base.LoadStateBinary(br);
|
base.LoadStateBinary(br);
|
||||||
prg = br.ReadInt32();
|
prg = br.ReadInt32();
|
||||||
cram = Util.ReadByteBuffer(br, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,37 +2,31 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
|
|
||||||
public class CPROM : NES.NESBoardBase
|
public class CPROM : NES.NESBoardBase
|
||||||
{
|
{
|
||||||
//generally mapper 13
|
//generally mapper 13
|
||||||
|
|
||||||
//Videomation
|
|
||||||
|
|
||||||
//state
|
//state
|
||||||
byte[] cram;
|
|
||||||
int chr;
|
int chr;
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//configure
|
//configure
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "NES-CPROM":
|
case "NES-CPROM": //videomation
|
||||||
BoardInfo.PRG_Size = 32;
|
AssertPrg(32); AssertChr(0); AssertVram(16); AssertWram(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cram = new byte[16*1024];
|
|
||||||
SetMirrorType(NES.EMirrorType.Vertical);
|
SetMirrorType(NES.EMirrorType.Vertical);
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,18 +39,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
public override byte ReadPPU(int addr)
|
public override byte ReadPPU(int addr)
|
||||||
{
|
{
|
||||||
if (addr < 0x1000)
|
if (addr < 0x1000)
|
||||||
return cram[addr];
|
return VRAM[addr];
|
||||||
else if(addr<0x2000)
|
else if(addr<0x2000)
|
||||||
return cram[addr-0x1000 + (chr<<12)];
|
return VRAM[addr - 0x1000 + (chr << 12)];
|
||||||
else return base.ReadPPU(addr);
|
else return base.ReadPPU(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WritePPU(int addr, byte value)
|
public override void WritePPU(int addr, byte value)
|
||||||
{
|
{
|
||||||
if (addr < 0x1000)
|
if (addr < 0x1000)
|
||||||
cram[addr] = value;
|
VRAM[addr] = value;
|
||||||
else if (addr < 0x2000)
|
else if (addr < 0x2000)
|
||||||
cram[addr - 0x1000 + (chr << 12)] = value;
|
VRAM[addr - 0x1000 + (chr << 12)] = value;
|
||||||
else base.WritePPU(addr,value);
|
else base.WritePPU(addr,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,14 +58,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
base.SaveStateBinary(bw);
|
base.SaveStateBinary(bw);
|
||||||
bw.Write(chr);
|
bw.Write(chr);
|
||||||
Util.WriteByteBuffer(bw, cram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LoadStateBinary(BinaryReader br)
|
public override void LoadStateBinary(BinaryReader br)
|
||||||
{
|
{
|
||||||
base.LoadStateBinary(br);
|
base.LoadStateBinary(br);
|
||||||
chr = br.ReadInt32();
|
chr = br.ReadInt32();
|
||||||
cram = Util.ReadByteBuffer(br, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
//generally mapper3
|
//generally mapper3
|
||||||
|
|
||||||
|
@ -21,32 +21,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
//state
|
//state
|
||||||
int chr;
|
int chr;
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//configure
|
//configure
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "NES-CNROM":
|
case "NES-CNROM": //adventure island
|
||||||
case "HVC-CNROM":
|
case "HVC-CNROM":
|
||||||
Assert(cart.prg_size == 16 || cart.prg_size == 32);
|
AssertPrg(16, 32); AssertChr(16,32);
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
prg_mask = (Cart.prg_size / 16) - 1;
|
||||||
chr_mask = (BoardInfo.CHR_Size / 8) - 1;
|
chr_mask = (Cart.chr_size / 8) - 1;
|
||||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||||
bus_conflict = true;
|
bus_conflict = true;
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
//generally mapper66
|
//generally mapper66
|
||||||
|
|
||||||
|
@ -22,31 +22,26 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
//state
|
//state
|
||||||
int prg, chr;
|
int prg, chr;
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//configure
|
//configure
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "NES-GNROM":
|
case "NES-GNROM": //thunder & lightning
|
||||||
case "BANDAI-GNROM":
|
case "BANDAI-GNROM":
|
||||||
case "HVC-GNROM":
|
case "HVC-GNROM":
|
||||||
case "NES-MHROM":
|
case "NES-MHROM": //Super Mario Bros. / Duck Hunt
|
||||||
Assert(cart.chr_size == 8 || cart.chr_size == 16 || cart.chr_size == 32);
|
AssertPrg(Cart.board_type == "NES-MHROM" ? 64 : 128); AssertChr(8, 16, 32); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.PRG_Size = (cart.board_type == "NES-MHROM" ? 64 : 128);
|
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prg_mask = (BoardInfo.PRG_Size/8/2) - 1;
|
prg_mask = (Cart.prg_size/8/2) - 1;
|
||||||
chr_mask = (BoardInfo.CHR_Size / 8) - 1;
|
chr_mask = (Cart.chr_size / 8) - 1;
|
||||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
//mapper 11
|
//mapper 11
|
||||||
|
|
||||||
|
@ -18,27 +18,20 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
//state
|
//state
|
||||||
int prg, chr;
|
int prg, chr;
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "COLORDREAMS-74*377":
|
case "COLORDREAMS-74*377":
|
||||||
Assert(cart.prg_size == 32 || cart.prg_size == 64 || cart.prg_size == 128);
|
AssertPrg(32,64,128); AssertChr(16,32,64,128); AssertVram(0); AssertWram(0);
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64 || cart.chr_size == 128);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prg_mask = (BoardInfo.PRG_Size/8/2)-1;
|
prg_mask = (Cart.prg_size/8/2)-1;
|
||||||
chr_mask = (BoardInfo.CHR_Size / 8 - 1);
|
chr_mask = (Cart.chr_size / 8 - 1);
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
public class NROM : NES.NESBoardBase
|
public class NROM : NES.NESBoardBase
|
||||||
{
|
{
|
||||||
|
@ -11,37 +11,31 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
//state
|
//state
|
||||||
//(none)
|
//(none)
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//configure
|
//configure
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "HVC-NROM-256":
|
case "HVC-NROM-256": //super mario bros.
|
||||||
BoardInfo.PRG_Size = 32;
|
AssertPrg(32); AssertChr(8); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.CHR_Size = 8;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "HVC-RROM":
|
case "HVC-RROM": //balloon fight
|
||||||
case "HVC-NROM-128":
|
case "HVC-NROM-128":
|
||||||
case "IREM-NROM-128":
|
case "IREM-NROM-128":
|
||||||
case "KONAMI-NROM-128":
|
case "KONAMI-NROM-128":
|
||||||
case "NES-NROM-128":
|
case "NES-NROM-128":
|
||||||
case "NAMCOT-3301":
|
case "NAMCOT-3301":
|
||||||
BoardInfo.PRG_Size = 16;
|
AssertPrg(16); AssertChr(8); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.CHR_Size = 8;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prg_byte_mask = (BoardInfo.PRG_Size << 10) - 1;
|
prg_byte_mask = (Cart.prg_size*1024) - 1;
|
||||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
//AKA MMC1
|
//AKA MMC1
|
||||||
//http://wiki.nesdev.com/w/index.php/SxROM
|
//http://wiki.nesdev.com/w/index.php/SxROM
|
||||||
|
@ -176,7 +176,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
int cram_mask, pram_mask;
|
int cram_mask, pram_mask;
|
||||||
|
|
||||||
//state
|
//state
|
||||||
byte[] cram, pram;
|
|
||||||
MMC1 mmc1;
|
MMC1 mmc1;
|
||||||
|
|
||||||
public override void WritePRG(int addr, byte value)
|
public override void WritePRG(int addr, byte value)
|
||||||
|
@ -203,8 +202,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
if (addr < 0x2000)
|
if (addr < 0x2000)
|
||||||
{
|
{
|
||||||
if (BoardInfo.CRAM_Size != 0)
|
if (Cart.vram_size != 0)
|
||||||
return cram[addr & cram_mask];
|
return VRAM[addr & cram_mask];
|
||||||
else return VROM[Gen_CHR_Address(addr)];
|
else return VROM[Gen_CHR_Address(addr)];
|
||||||
}
|
}
|
||||||
else return base.ReadPPU(addr);
|
else return base.ReadPPU(addr);
|
||||||
|
@ -214,260 +213,130 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
if (addr < 0x2000)
|
if (addr < 0x2000)
|
||||||
{
|
{
|
||||||
if (BoardInfo.CRAM_Size != 0)
|
if (Cart.vram_size != 0)
|
||||||
cram[addr & cram_mask] = value;
|
VRAM[addr & cram_mask] = value;
|
||||||
}
|
}
|
||||||
else base.WritePPU(addr, value);
|
else base.WritePPU(addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadPRAM(int addr)
|
public override byte ReadPRAM(int addr)
|
||||||
{
|
{
|
||||||
if (BoardInfo.PRAM_Size != 0)
|
if (Cart.wram_size != 0)
|
||||||
return pram[addr & pram_mask];
|
return WRAM[addr & pram_mask];
|
||||||
else return 0xFF;
|
else return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WritePRAM(int addr, byte value)
|
public override void WritePRAM(int addr, byte value)
|
||||||
{
|
{
|
||||||
if (BoardInfo.PRAM_Size != 0)
|
if (Cart.wram_size != 0)
|
||||||
pram[addr & pram_mask] = value;
|
WRAM[addr & pram_mask] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte[] SaveRam
|
public override byte[] SaveRam
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!BoardInfo.Battery) return null;
|
if (!Cart.wram_battery) return null;
|
||||||
return pram;
|
return WRAM;
|
||||||
//some boards have a pram that is backed-up or not backed-up. need to handle that somehow
|
//some boards have a pram that is backed-up or not backed-up. need to handle that somehow
|
||||||
//(nestopia splits it into NVWRAM and WRAM but i didnt like that at first.. but it may player better with this architecture)
|
//(nestopia splits it into NVWRAM and WRAM but i didnt like that at first.. but it may player better with this architecture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte[] PRam
|
public override void SaveStateBinary(BinaryWriter bw)
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (BoardInfo.PRAM_Size > 0)
|
|
||||||
return pram;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override byte[] CRam
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (BoardInfo.CRAM_Size > 0)
|
|
||||||
return cram;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SaveStateBinary(BinaryWriter bw)
|
|
||||||
{
|
{
|
||||||
base.SaveStateBinary(bw);
|
base.SaveStateBinary(bw);
|
||||||
mmc1.SaveStateBinary(bw);
|
mmc1.SaveStateBinary(bw);
|
||||||
Util.WriteByteBuffer(bw, pram);
|
|
||||||
Util.WriteByteBuffer(bw, cram);
|
|
||||||
}
|
}
|
||||||
public override void LoadStateBinary(BinaryReader br)
|
public override void LoadStateBinary(BinaryReader br)
|
||||||
{
|
{
|
||||||
base.LoadStateBinary(br);
|
base.LoadStateBinary(br);
|
||||||
mmc1.LoadStateBinary(br);
|
mmc1.LoadStateBinary(br);
|
||||||
pram = Util.ReadByteBuffer(br, false);
|
|
||||||
cram = Util.ReadByteBuffer(br, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//analyze board type
|
//analyze board type
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "NES-SAROM":
|
case "NES-SAROM": //dragon warrior
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
AssertPrg(64); AssertChr(16, 32, 64); AssertVram(0); AssertWram(8);
|
||||||
BoardInfo.PRG_Size = 64;
|
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 8;
|
|
||||||
break;
|
break;
|
||||||
case "NES-SBROM":
|
case "NES-SBROM": //dance aerobics
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
AssertPrg(64); AssertChr(16, 32, 64); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.PRG_Size = 64;
|
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
break;
|
break;
|
||||||
case "NES-SCROM":
|
case "NES-SCROM": //mechanized attack
|
||||||
case "NES-SC1ROM":
|
case "NES-SC1ROM": //knight rider
|
||||||
BoardInfo.PRG_Size = 64;
|
AssertPrg(64); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.CHR_Size = 128;
|
break;
|
||||||
BoardInfo.CRAM_Size = 0;
|
case "NES-SEROM": //lolo
|
||||||
BoardInfo.PRAM_Size = 0;
|
case "HVC-SEROM": //dr. mario
|
||||||
break;
|
AssertPrg(32); AssertChr(32); AssertVram(0); AssertWram(0);
|
||||||
case "NES-SEROM":
|
break;
|
||||||
BoardInfo.PRG_Size = 32;
|
case "NES-SFROM": //bubble bobble
|
||||||
BoardInfo.CHR_Size = 32;
|
AssertPrg(128,256); AssertChr(16,32,64); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.CRAM_Size = 0;
|
break;
|
||||||
BoardInfo.PRAM_Size = 0;
|
case "NES-SGROM": //bionic commando
|
||||||
break;
|
AssertPrg(128, 256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
case "NES-SFROM":
|
break;
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
case "NES-SHROM": //family feud
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
case "NES-SH1ROM": //airwolf
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
AssertPrg(32); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
break;
|
||||||
BoardInfo.CRAM_Size = 0;
|
case "HVC-SIROM": //Igo: Kyuu Roban Taikyoku
|
||||||
BoardInfo.PRAM_Size = 0;
|
AssertPrg(32); AssertChr(16); AssertVram(0); AssertWram(8);
|
||||||
break;
|
break;
|
||||||
case "NES-SGROM":
|
case "NES-SJROM": //air fortress
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
AssertPrg(128,256); AssertChr(16,32,64); AssertVram(0); AssertWram(8);
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
break;
|
||||||
BoardInfo.CHR_Size = 0;
|
case "NES-SKROM": //zelda 2
|
||||||
BoardInfo.CRAM_Size = 8;
|
AssertPrg(128, 256); AssertChr(128); AssertVram(0); AssertWram(8);
|
||||||
BoardInfo.PRAM_Size = 0;
|
break;
|
||||||
break;
|
case "NES-SLROM": //castlevania 2
|
||||||
case "NES-SHROM":
|
AssertPrg(128, 256); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
case "NES-SH1ROM":
|
break;
|
||||||
BoardInfo.PRG_Size = 32;
|
case "NES-SL1ROM": //hoops
|
||||||
BoardInfo.CHR_Size = 128;
|
AssertPrg(64, 128, 256); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.PRAM_Size = 0;
|
break;
|
||||||
BoardInfo.CRAM_Size = 0;
|
case "NES-SL2ROM": //blaster master
|
||||||
break;
|
AssertPrg(128); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
case "HVC-SIROM":
|
break;
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
case "NES-SL3ROM": //goal!
|
||||||
BoardInfo.PRG_Size = 32;
|
AssertPrg(256); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
break;
|
||||||
BoardInfo.CRAM_Size = 0;
|
case "NES-SLRROM": //tecmo bowl
|
||||||
BoardInfo.PRAM_Size = 0;
|
AssertPrg(128); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||||
break;
|
break;
|
||||||
case "NES-SJROM":
|
case "HVC-SMROM": //Hokkaidou Rensa Satsujin: Okhotsu ni Shoyu
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
AssertPrg(256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
break;
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
case "NES-SNROM": //dragon warrior 2
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
case "HVC-SNROM":
|
||||||
BoardInfo.CRAM_Size = 0;
|
//prg=16 is unexpected but blargg's tests use it
|
||||||
BoardInfo.PRAM_Size = 8;
|
AssertPrg(16, 128, 256); AssertChr(0); AssertVram(8); AssertWram(8);
|
||||||
break;
|
|
||||||
case "NES-SKROM":
|
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = cart.chr_size;
|
|
||||||
BoardInfo.PRAM_Size = 8;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
break;
|
|
||||||
case "NES-SLROM":
|
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = 128;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
break;
|
|
||||||
case "NES-SL1ROM":
|
|
||||||
Assert(cart.prg_size == 64 || cart.prg_size == 128 || cart.prg_size == 256);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = 128;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
break;
|
|
||||||
case "NES-SL2ROM":
|
|
||||||
Assert(cart.prg_size == 128);
|
|
||||||
Assert(cart.chr_size == 128);
|
|
||||||
BoardInfo.PRG_Size = 128;
|
|
||||||
BoardInfo.CHR_Size = 128;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
break;
|
|
||||||
case "NES-SL3ROM":
|
|
||||||
Assert(cart.prg_size == 256);
|
|
||||||
Assert(cart.chr_size == 128);
|
|
||||||
BoardInfo.PRG_Size = 256;
|
|
||||||
BoardInfo.CHR_Size = 128;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
break;
|
|
||||||
case "NES-SLRROM":
|
|
||||||
Assert(cart.prg_size == 128);
|
|
||||||
Assert(cart.chr_size == 128);
|
|
||||||
BoardInfo.PRG_Size = 128;
|
|
||||||
BoardInfo.CHR_Size = 128;
|
|
||||||
BoardInfo.CRAM_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
break;
|
|
||||||
case "HVC-SMROM":
|
|
||||||
BoardInfo.PRG_Size = 256;
|
|
||||||
BoardInfo.CHR_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 0;
|
|
||||||
BoardInfo.CRAM_Size = 8;
|
|
||||||
break;
|
|
||||||
case "NES-SNROM":
|
|
||||||
Assert(cart.prg_size == 16 || cart.prg_size == 128 || cart.prg_size == 256);
|
|
||||||
//16 is unexpected but blargg's tests use it
|
|
||||||
//TODO - consider making a unique board type for homebrew, as i discover how more of them are working
|
//TODO - consider making a unique board type for homebrew, as i discover how more of them are working
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = 0;
|
|
||||||
BoardInfo.CRAM_Size = 8;
|
|
||||||
BoardInfo.PRAM_Size = 8;
|
|
||||||
break;
|
|
||||||
case "NES-SOROM":
|
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = 0;
|
|
||||||
BoardInfo.CRAM_Size = 8;
|
|
||||||
BoardInfo.PRAM_Size = 16;
|
|
||||||
break;
|
|
||||||
case "NES-SUROM":
|
|
||||||
BoardInfo.PRG_Size = 512;
|
|
||||||
BoardInfo.CHR_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 8;
|
|
||||||
BoardInfo.CRAM_Size = 8;
|
|
||||||
break;
|
|
||||||
case "HVC-SXROM":
|
|
||||||
Assert(cart.prg_size == 128 || cart.prg_size == 256 || cart.prg_size == 512);
|
|
||||||
BoardInfo.PRG_Size = cart.prg_size;
|
|
||||||
BoardInfo.CHR_Size = 0;
|
|
||||||
BoardInfo.PRAM_Size = 32;
|
|
||||||
BoardInfo.CRAM_Size = 8;
|
|
||||||
break;
|
break;
|
||||||
|
case "NES-SOROM": //Nobunaga's Ambition
|
||||||
|
AssertPrg(128, 256); AssertChr(0); AssertVram(8); AssertWram(16);
|
||||||
|
break;
|
||||||
|
case "NES-SUROM": //dragon warrior 4
|
||||||
|
case "HVC-SUROM":
|
||||||
|
AssertPrg(512); AssertChr(0); AssertVram(8); AssertWram(8);
|
||||||
|
break;
|
||||||
|
case "HVC-SXROM": //final fantasy 1& 2
|
||||||
|
AssertPrg(128,256,512); AssertChr(0); AssertVram(8); AssertWram(32);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//validate and setup the basics
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
|
||||||
mmc1 = new MMC1();
|
mmc1 = new MMC1();
|
||||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
prg_mask = (Cart.prg_size / 16) - 1;
|
||||||
chr_mask = (BoardInfo.CHR_Size / 8) - 1;
|
cram_mask = (Cart.vram_size*1024) - 1;
|
||||||
BoardInfo.Battery = cart.wram_battery;
|
pram_mask = (Cart.wram_size*1024) - 1;
|
||||||
|
chr_mask = (Cart.chr_size / 8 * 2) - 1;
|
||||||
//boards that don't contain CHR rom will contain CRAM. only one size is supported; set it up if it is there.
|
|
||||||
Debug.Assert(BoardInfo.CRAM_Size == 0 || BoardInfo.CRAM_Size == 8);
|
|
||||||
if (BoardInfo.CRAM_Size != 0)
|
|
||||||
{
|
|
||||||
cram = new byte[BoardInfo.CRAM_Size * 1024];
|
|
||||||
cram_mask = cram.Length - 1;
|
|
||||||
}
|
|
||||||
else cram = new byte[0];
|
|
||||||
|
|
||||||
//some boards contain PRAM. we only understand one size right now. set it up if it is there.
|
|
||||||
Debug.Assert(BoardInfo.PRAM_Size == 0 || BoardInfo.PRAM_Size == 8 || BoardInfo.PRAM_Size == 16 || BoardInfo.PRAM_Size == 32);
|
|
||||||
if (BoardInfo.PRAM_Size != 0)
|
|
||||||
{
|
|
||||||
pram = new byte[BoardInfo.PRAM_Size * 1024];
|
|
||||||
pram_mask = pram.Length - 1;
|
|
||||||
}
|
|
||||||
else pram = new byte[0];
|
|
||||||
|
|
||||||
//some boards contain CHR roms, so set that up here.
|
|
||||||
if (BoardInfo.CHR_Size != 0)
|
|
||||||
{
|
|
||||||
Debug.Assert(BoardInfo.CHR_Size == 16 || BoardInfo.CHR_Size == 32 || BoardInfo.CHR_Size == 128);
|
|
||||||
chr_mask = (BoardInfo.CHR_Size / 8 * 2) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetMirrorType(mmc1.mirror);
|
SetMirrorType(mmc1.mirror);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
//generally mapper2
|
//generally mapper2
|
||||||
|
|
||||||
|
@ -22,37 +22,30 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
|
|
||||||
//state
|
//state
|
||||||
int prg;
|
int prg;
|
||||||
byte[] cram;
|
|
||||||
|
|
||||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
public override bool Configure()
|
||||||
{
|
{
|
||||||
//configure
|
//configure
|
||||||
switch (cart.board_type)
|
switch (Cart.board_type)
|
||||||
{
|
{
|
||||||
case "NES-UNROM":
|
case "NES-UNROM": //mega man
|
||||||
case "HVC-UNROM":
|
case "HVC-UNROM":
|
||||||
case "KONAMI-UNROM":
|
case "KONAMI-UNROM":
|
||||||
BoardInfo.PRG_Size = 128;
|
AssertPrg(128); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "NES-UOROM":
|
case "NES-UOROM": //paperboy 2
|
||||||
case "HVC-UOROM":
|
case "HVC-UOROM":
|
||||||
BoardInfo.PRG_Size = 256;
|
AssertPrg(256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//these boards always have 8KB of CRAM
|
//these boards always have 8KB of CRAM
|
||||||
BoardInfo.CRAM_Size = 8;
|
cram_byte_mask = (Cart.vram_size*1024) - 1;
|
||||||
cram = new byte[BoardInfo.CRAM_Size * 1024];
|
prg_mask = (Cart.prg_size / 16) - 1;
|
||||||
cram_byte_mask = cram.Length - 1;
|
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
|
||||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
|
||||||
|
|
||||||
|
|
||||||
//validate
|
|
||||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +66,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
if (addr < 0x2000)
|
if (addr < 0x2000)
|
||||||
{
|
{
|
||||||
return cram[addr & cram_byte_mask];
|
return VRAM[addr & cram_byte_mask];
|
||||||
}
|
}
|
||||||
else return base.ReadPPU(addr);
|
else return base.ReadPPU(addr);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +75,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
if (addr < 0x2000)
|
if (addr < 0x2000)
|
||||||
{
|
{
|
||||||
cram[addr & cram_byte_mask] = value;
|
VRAM[addr & cram_byte_mask] = value;
|
||||||
}
|
}
|
||||||
else base.WritePPU(addr,value);
|
else base.WritePPU(addr,value);
|
||||||
}
|
}
|
||||||
|
@ -91,14 +84,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||||
{
|
{
|
||||||
base.SaveStateBinary(bw);
|
base.SaveStateBinary(bw);
|
||||||
bw.Write(prg);
|
bw.Write(prg);
|
||||||
Util.WriteByteBuffer(bw, cram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LoadStateBinary(BinaryReader br)
|
public override void LoadStateBinary(BinaryReader br)
|
||||||
{
|
{
|
||||||
base.LoadStateBinary(br);
|
base.LoadStateBinary(br);
|
||||||
prg = br.ReadInt32();
|
prg = br.ReadInt32();
|
||||||
cram = Util.ReadByteBuffer(br, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using BizHawk.Emulation.CPUs.M6502;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
|
{
|
||||||
|
public partial class NES : IEmulator
|
||||||
|
{
|
||||||
|
//hardware/state
|
||||||
|
protected MOS6502 cpu;
|
||||||
|
int cpu_accumulate; //cpu timekeeper
|
||||||
|
public PPU ppu;
|
||||||
|
byte[] ram;
|
||||||
|
protected byte[] CIRAM; //AKA nametables
|
||||||
|
string game_name; //friendly name exposed to user and used as filename base
|
||||||
|
CartInfo cart; //the current cart prototype. should be moved into the board, perhaps
|
||||||
|
INESBoard board; //the board hardware that is currently driving things
|
||||||
|
|
||||||
|
//user configuration
|
||||||
|
int[,] palette; //TBD!!
|
||||||
|
IPortDevice[] ports;
|
||||||
|
|
||||||
|
public void HardReset()
|
||||||
|
{
|
||||||
|
cpu = new MOS6502();
|
||||||
|
cpu.ReadMemory = ReadMemory;
|
||||||
|
cpu.WriteMemory = WriteMemory;
|
||||||
|
ppu = new PPU(this);
|
||||||
|
ram = new byte[0x800];
|
||||||
|
CIRAM = new byte[0x800];
|
||||||
|
ports = new IPortDevice[2];
|
||||||
|
ports[0] = new JoypadPortDevice(this);
|
||||||
|
ports[1] = new NullPortDevice();
|
||||||
|
|
||||||
|
//fceux uses this technique, which presumably tricks some games into thinking the memory is randomized
|
||||||
|
for (int i = 0; i < 0x800; i++)
|
||||||
|
{
|
||||||
|
if ((i & 4) != 0) ram[i] = 0xFF; else ram[i] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
//in this emulator, reset takes place instantaneously
|
||||||
|
cpu.PC = (ushort)(ReadMemory(0xFFFC) | (ReadMemory(0xFFFD) << 8));
|
||||||
|
|
||||||
|
//cpu.debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FrameAdvance(bool render)
|
||||||
|
{
|
||||||
|
Controller.UpdateControls(Frame++);
|
||||||
|
ppu.FrameAdvance();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RunCpu(int cycles)
|
||||||
|
{
|
||||||
|
if (ppu.PAL)
|
||||||
|
cycles *= 15;
|
||||||
|
else
|
||||||
|
cycles *= 16;
|
||||||
|
|
||||||
|
cpu_accumulate += cycles;
|
||||||
|
int todo = cpu_accumulate / 48;
|
||||||
|
cpu_accumulate -= todo * 48;
|
||||||
|
if (todo > 0)
|
||||||
|
cpu.Execute(todo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadPPUReg(int addr)
|
||||||
|
{
|
||||||
|
return ppu.ReadReg(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadReg(int addr)
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x4016:
|
||||||
|
case 0x4017:
|
||||||
|
return read_joyport(addr);
|
||||||
|
default:
|
||||||
|
//Console.WriteLine("read register: {0:x4}", addr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WritePPUReg(int addr, byte val)
|
||||||
|
{
|
||||||
|
ppu.WriteReg(addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteReg(int addr, byte val)
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x4014: Exec_OAMDma(val); break;
|
||||||
|
case 0x4016:
|
||||||
|
ports[0].Write(val & 1);
|
||||||
|
ports[1].Write(val & 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//Console.WriteLine("wrote register: {0:x4} = {1:x2}", addr, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte read_joyport(int addr)
|
||||||
|
{
|
||||||
|
//read joystick port
|
||||||
|
//many todos here
|
||||||
|
if (addr == 0x4016)
|
||||||
|
{
|
||||||
|
byte ret = ports[0].Read();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Exec_OAMDma(byte val)
|
||||||
|
{
|
||||||
|
ushort addr = (ushort)(val << 8);
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
byte db = ReadMemory((ushort)addr);
|
||||||
|
WriteMemory(0x2004, db);
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
cpu.PendingCycles -= 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadMemory(ushort addr)
|
||||||
|
{
|
||||||
|
if (addr < 0x0800) return ram[addr];
|
||||||
|
else if (addr < 0x1000) return ram[addr - 0x0800];
|
||||||
|
else if (addr < 0x1800) return ram[addr - 0x1000];
|
||||||
|
else if (addr < 0x2000) return ram[addr - 0x1800];
|
||||||
|
else if (addr < 0x4000) return ReadPPUReg(addr & 7);
|
||||||
|
else if (addr < 0x4020) return ReadReg(addr); //we're not rebasing the register just to keep register names canonical
|
||||||
|
else if (addr < 0x6000) return 0xFF; //exp rom
|
||||||
|
else if (addr < 0x8000) return board.ReadPRAM(addr);
|
||||||
|
else return board.ReadPRG(addr - 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteMemory(ushort addr, byte value)
|
||||||
|
{
|
||||||
|
if (addr < 0x0800) ram[addr] = value;
|
||||||
|
else if (addr < 0x1000) ram[addr - 0x0800] = value;
|
||||||
|
else if (addr < 0x1800) ram[addr - 0x1000] = value;
|
||||||
|
else if (addr < 0x2000) ram[addr - 0x1800] = value;
|
||||||
|
else if (addr < 0x4000) WritePPUReg(addr & 7, value);
|
||||||
|
else if (addr < 0x4020) WriteReg(addr, value); //we're not rebasing the register just to keep register names canonical
|
||||||
|
else if (addr < 0x6000) { } //exp rom
|
||||||
|
else if (addr < 0x8000) board.WritePRAM(addr, value);
|
||||||
|
else board.WritePRG(addr - 0x8000, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ using BizHawk.Emulation.CPUs.M6502;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
{
|
{
|
||||||
|
|
||||||
public partial class NES : IEmulator
|
public partial class NES : IEmulator
|
||||||
{
|
{
|
||||||
//Game issues:
|
//Game issues:
|
||||||
|
@ -25,54 +26,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
//Knight Rider - very glitchy and seems to be a good timing case!
|
//Knight Rider - very glitchy and seems to be a good timing case!
|
||||||
//Dragon warrior 3/4 certainly need some additional work done to the mapper wiring to get to the super big PRG (probably SXROM too)
|
//Dragon warrior 3/4 certainly need some additional work done to the mapper wiring to get to the super big PRG (probably SXROM too)
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
public NES()
|
||||||
public class INESBoardImplAttribute : Attribute {}
|
|
||||||
static List<Type> INESBoardImplementors = new List<Type>();
|
|
||||||
|
|
||||||
static NES()
|
|
||||||
{
|
{
|
||||||
foreach (Type type in typeof(NES).Assembly.GetTypes())
|
BootGodDB.Initialize();
|
||||||
{
|
palette = Palettes.FCEUX_Standard;
|
||||||
var attrs = type.GetCustomAttributes(typeof(INESBoardImplAttribute), true);
|
|
||||||
if (attrs.Length == 0) continue;
|
|
||||||
if (type.IsAbstract) continue;
|
|
||||||
INESBoardImplementors.Add(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Type FindBoard(BootGodDB.Cart cart)
|
|
||||||
{
|
|
||||||
NES nes = new NES();
|
|
||||||
foreach (var type in INESBoardImplementors)
|
|
||||||
{
|
|
||||||
INESBoard board = (INESBoard)Activator.CreateInstance(type);
|
|
||||||
board.Create(nes);
|
|
||||||
if (board.Configure(cart))
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//the main rom class that contains all information necessary for the board to operate
|
|
||||||
public class RomInfo
|
|
||||||
{
|
|
||||||
public enum EInfoSource
|
|
||||||
{
|
|
||||||
None, INesHeader, GameDatabase
|
|
||||||
}
|
|
||||||
|
|
||||||
public EInfoSource InfoSource;
|
|
||||||
public int PRG_Size = -1, CHR_Size = -1;
|
|
||||||
public int CRAM_Size = -1, PRAM_Size = -1;
|
|
||||||
public string BoardName;
|
|
||||||
public EMirrorType MirrorType;
|
|
||||||
public bool Battery;
|
|
||||||
|
|
||||||
public int MapperNumber; //it annoys me that this junky mapper number is even in here. it might be nice to wrap this class in something else to contain the MapperNumber
|
|
||||||
|
|
||||||
public string MD5;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EMirrorType
|
public enum EMirrorType
|
||||||
|
@ -83,263 +40,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
External
|
External
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface INESBoard
|
|
||||||
{
|
|
||||||
void Create(NES nes);
|
|
||||||
bool Configure(BootGodDB.Cart cart);
|
|
||||||
void InstallRoms(byte[] ROM, byte[] VROM);
|
|
||||||
byte ReadPRG(int addr);
|
|
||||||
byte ReadPPU(int addr); byte PeekPPU(int addr);
|
|
||||||
byte ReadPRAM(int addr);
|
|
||||||
void WritePRG(int addr, byte value);
|
|
||||||
void WritePPU(int addr, byte value);
|
|
||||||
void WritePRAM(int addr, byte value);
|
|
||||||
byte[] SaveRam { get; }
|
|
||||||
byte[] PRam { get; }
|
|
||||||
byte[] CRam { get; }
|
|
||||||
byte[] ROM { get; }
|
|
||||||
byte[] VROM { get; }
|
|
||||||
void SaveStateBinary(BinaryWriter bw);
|
|
||||||
void LoadStateBinary(BinaryReader br);
|
|
||||||
};
|
|
||||||
|
|
||||||
[INESBoardImpl]
|
|
||||||
public abstract class NESBoardBase : INESBoard
|
|
||||||
{
|
|
||||||
public virtual void Create(NES nes)
|
|
||||||
{
|
|
||||||
this.NES = nes;
|
|
||||||
}
|
|
||||||
public abstract bool Configure(BootGodDB.Cart cart);
|
|
||||||
public void InstallRoms(byte[] ROM, byte[] VROM)
|
|
||||||
{
|
|
||||||
this.ROM = ROM;
|
|
||||||
this.VROM = VROM;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RomInfo BoardInfo { get { return NES.romInfo; } }
|
|
||||||
public NES NES { get; set; }
|
|
||||||
|
|
||||||
public virtual void SaveStateBinary(BinaryWriter bw)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 4; i++) bw.Write(mirroring[i]);
|
|
||||||
}
|
|
||||||
public virtual void LoadStateBinary(BinaryReader br)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 4; i++) mirroring[i] = br.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] mirroring = new int[4];
|
|
||||||
protected void SetMirroring(int a, int b, int c, int d)
|
|
||||||
{
|
|
||||||
mirroring[0] = a;
|
|
||||||
mirroring[1] = b;
|
|
||||||
mirroring[2] = c;
|
|
||||||
mirroring[3] = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetMirrorType(int pad_h, int pad_v)
|
|
||||||
{
|
|
||||||
if (pad_h == 0)
|
|
||||||
if (pad_v == 0)
|
|
||||||
SetMirrorType(EMirrorType.OneScreenA);
|
|
||||||
else SetMirrorType(EMirrorType.Horizontal);
|
|
||||||
else
|
|
||||||
if (pad_v == 0)
|
|
||||||
SetMirrorType(EMirrorType.Vertical);
|
|
||||||
else SetMirrorType(EMirrorType.OneScreenB);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetMirrorType(EMirrorType mirrorType)
|
|
||||||
{
|
|
||||||
switch (mirrorType)
|
|
||||||
{
|
|
||||||
case EMirrorType.Horizontal: SetMirroring(0, 0, 1, 1); break;
|
|
||||||
case EMirrorType.Vertical: SetMirroring(0, 1, 0, 1); break;
|
|
||||||
case EMirrorType.OneScreenA: SetMirroring(0, 0, 0, 0); break;
|
|
||||||
case EMirrorType.OneScreenB: SetMirroring(1, 1, 1, 1); break;
|
|
||||||
default: SetMirroring(-1, -1, -1, -1); break; //crash!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ApplyMirroring(int addr)
|
|
||||||
{
|
|
||||||
int block = (addr >> 10) & 3;
|
|
||||||
block = mirroring[block];
|
|
||||||
int ofs = addr & 0x3FF;
|
|
||||||
return (block << 10) | ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected byte HandleNormalPRGConflict(int addr, byte value)
|
|
||||||
{
|
|
||||||
byte old_value = value;
|
|
||||||
value &= ReadPRG(addr);
|
|
||||||
Debug.Assert(old_value == value, "Found a test case of bus conflict. please report.");
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual byte ReadPRG(int addr) { return ROM[addr];}
|
|
||||||
public virtual void WritePRG(int addr, byte value) { }
|
|
||||||
|
|
||||||
public virtual void WritePRAM(int addr, byte value) { }
|
|
||||||
public virtual byte ReadPRAM(int addr) { return 0xFF; }
|
|
||||||
|
|
||||||
|
|
||||||
public virtual void WritePPU(int addr, byte value)
|
|
||||||
{
|
|
||||||
if (addr < 0x2000)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NES.CIRAM[ApplyMirroring(addr)] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual byte PeekPPU(int addr) { return ReadPPU(addr); }
|
|
||||||
|
|
||||||
public virtual byte ReadPPU(int addr)
|
|
||||||
{
|
|
||||||
if (addr < 0x2000)
|
|
||||||
{
|
|
||||||
return VROM[addr];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NES.CIRAM[ApplyMirroring(addr)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual byte[] SaveRam { get { return null; } }
|
|
||||||
public virtual byte[] PRam { get { return null; } }
|
|
||||||
public virtual byte[] CRam { get { return null; } }
|
|
||||||
|
|
||||||
public byte[] ROM { get; set; }
|
|
||||||
public byte[] VROM { get; set; }
|
|
||||||
|
|
||||||
protected void Assert(bool test, string comment, params object[] args)
|
|
||||||
{
|
|
||||||
if (!test) throw new Exception(string.Format(comment, args));
|
|
||||||
}
|
|
||||||
protected void Assert(bool test)
|
|
||||||
{
|
|
||||||
if (!test) throw new Exception("assertion failed in board setup!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//hardware/state
|
|
||||||
protected MOS6502 cpu;
|
|
||||||
INESBoard board;
|
|
||||||
public PPU ppu;
|
|
||||||
byte[] ram;
|
|
||||||
protected byte[] CIRAM;
|
|
||||||
int cpu_accumulate;
|
|
||||||
string game_name;
|
|
||||||
|
|
||||||
//user configuration
|
|
||||||
int[,] palette; //TBD!!
|
|
||||||
IPortDevice[] ports;
|
|
||||||
RomInfo romInfo = new RomInfo();
|
|
||||||
|
|
||||||
public byte ReadPPUReg(int addr)
|
|
||||||
{
|
|
||||||
return ppu.ReadReg(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte ReadReg(int addr)
|
|
||||||
{
|
|
||||||
switch (addr)
|
|
||||||
{
|
|
||||||
case 0x4016:
|
|
||||||
case 0x4017:
|
|
||||||
return read_joyport(addr);
|
|
||||||
default:
|
|
||||||
//Console.WriteLine("read register: {0:x4}", addr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WritePPUReg(int addr, byte val)
|
|
||||||
{
|
|
||||||
ppu.WriteReg(addr,val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteReg(int addr, byte val)
|
|
||||||
{
|
|
||||||
switch (addr)
|
|
||||||
{
|
|
||||||
case 0x4014: Exec_OAMDma(val); break;
|
|
||||||
case 0x4016:
|
|
||||||
ports[0].Write(val & 1);
|
|
||||||
ports[1].Write(val & 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
//Console.WriteLine("wrote register: {0:x4} = {1:x2}", addr, val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
byte read_joyport(int addr)
|
|
||||||
{
|
|
||||||
//read joystick port
|
|
||||||
//many todos here
|
|
||||||
if (addr == 0x4016)
|
|
||||||
{
|
|
||||||
byte ret = ports[0].Read();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Exec_OAMDma(byte val)
|
|
||||||
{
|
|
||||||
ushort addr = (ushort)(val << 8);
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
byte db = ReadMemory((ushort)addr);
|
|
||||||
WriteMemory(0x2004, db);
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
cpu.PendingCycles-=512;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte ReadMemory(ushort addr)
|
|
||||||
{
|
|
||||||
if (addr < 0x0800) return ram[addr];
|
|
||||||
else if (addr < 0x1000) return ram[addr - 0x0800];
|
|
||||||
else if (addr < 0x1800) return ram[addr - 0x1000];
|
|
||||||
else if (addr < 0x2000) return ram[addr - 0x1800];
|
|
||||||
else if (addr < 0x4000) return ReadPPUReg(addr & 7);
|
|
||||||
else if (addr < 0x4020) return ReadReg(addr); //we're not rebasing the register just to keep register names canonical
|
|
||||||
else if (addr < 0x6000) return 0xFF; //exp rom
|
|
||||||
else if (addr < 0x8000) return board.ReadPRAM(addr);
|
|
||||||
else return board.ReadPRG(addr - 0x8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteMemory(ushort addr, byte value)
|
|
||||||
{
|
|
||||||
if (addr < 0x0800) ram[addr] = value;
|
|
||||||
else if (addr < 0x1000) ram[addr - 0x0800] = value;
|
|
||||||
else if (addr < 0x1800) ram[addr - 0x1000] = value;
|
|
||||||
else if (addr < 0x2000) ram[addr - 0x1800] = value;
|
|
||||||
else if (addr < 0x4000) WritePPUReg(addr & 7,value);
|
|
||||||
else if (addr < 0x4020) WriteReg(addr, value); //we're not rebasing the register just to keep register names canonical
|
|
||||||
else if (addr < 0x6000) { } //exp rom
|
|
||||||
else if (addr < 0x8000) board.WritePRAM(addr,value);
|
|
||||||
else board.WritePRG(addr - 0x8000, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public NES()
|
|
||||||
{
|
|
||||||
BootGodDB.Initialize();
|
|
||||||
palette = Palettes.FCEUX_Standard;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyVideoProvider : IVideoProvider
|
class MyVideoProvider : IVideoProvider
|
||||||
{
|
{
|
||||||
NES emu;
|
NES emu;
|
||||||
|
@ -392,27 +92,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
set { controller = value; }
|
set { controller = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FrameAdvance(bool render)
|
|
||||||
{
|
|
||||||
//TODO!
|
|
||||||
//cpu.Execute(10000);
|
|
||||||
Controller.UpdateControls(Frame++);
|
|
||||||
ppu.FrameAdvance();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void RunCpu(int cycles)
|
|
||||||
{
|
|
||||||
if (ppu.PAL)
|
|
||||||
cycles *= 15;
|
|
||||||
else
|
|
||||||
cycles *= 16;
|
|
||||||
|
|
||||||
cpu_accumulate += cycles;
|
|
||||||
int todo = cpu_accumulate / 48;
|
|
||||||
cpu_accumulate -= todo * 48;
|
|
||||||
if(todo>0)
|
|
||||||
cpu.Execute(todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IPortDevice
|
interface IPortDevice
|
||||||
{
|
{
|
||||||
|
@ -472,29 +151,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HardReset()
|
|
||||||
{
|
|
||||||
cpu = new MOS6502();
|
|
||||||
cpu.ReadMemory = ReadMemory;
|
|
||||||
cpu.WriteMemory = WriteMemory;
|
|
||||||
ppu = new PPU(this);
|
|
||||||
ram = new byte[0x800];
|
|
||||||
CIRAM = new byte[0x800];
|
|
||||||
ports = new IPortDevice[2];
|
|
||||||
ports[0] = new JoypadPortDevice(this);
|
|
||||||
ports[1] = new NullPortDevice();
|
|
||||||
|
|
||||||
//fceux uses this technique, which presumably tricks some games into thinking the memory is randomized
|
|
||||||
for (int i = 0; i < 0x800; i++)
|
|
||||||
{
|
|
||||||
if ((i & 4) != 0) ram[i] = 0xFF; else ram[i] = 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
//in this emulator, reset takes place instantaneously
|
|
||||||
cpu.PC = (ushort)(ReadMemory(0xFFFC) | (ReadMemory(0xFFFD) << 8));
|
|
||||||
|
|
||||||
//cpu.debug = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Frame { get; set; }
|
public int Frame { get; set; }
|
||||||
|
|
||||||
|
@ -519,19 +175,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
private void SetupMemoryDomains()
|
private void SetupMemoryDomains()
|
||||||
{
|
{
|
||||||
var domains = new List<MemoryDomain>();
|
var domains = new List<MemoryDomain>();
|
||||||
var WRAM = new MemoryDomain("WRAM", 0x800, Endian.Little,
|
var RAM = new MemoryDomain("RAM", 0x800, Endian.Little,
|
||||||
addr => ram[addr & 0x07FF], (addr, value) => ram[addr & 0x07FF] = value);
|
addr => ram[addr & 0x07FF], (addr, value) => ram[addr & 0x07FF] = value);
|
||||||
var MainMemory = new MemoryDomain("System Bus", 0x10000, Endian.Little,
|
var SystemBus = new MemoryDomain("System Bus", 0x10000, Endian.Little,
|
||||||
addr => ReadMemory((ushort)addr), (addr, value) => WriteMemory((ushort)addr, value));
|
addr => ReadMemory((ushort)addr), (addr, value) => WriteMemory((ushort)addr, value));
|
||||||
var PPUBus = new MemoryDomain("PPU Bus", 0x4000, Endian.Little,
|
var PPUBus = new MemoryDomain("PPU Bus", 0x4000, Endian.Little,
|
||||||
addr => ppu.ppubus_read(addr), (addr, value) => ppu.ppubus_write(addr, value));
|
addr => ppu.ppubus_read(addr), (addr, value) => ppu.ppubus_write(addr, value));
|
||||||
//TODO: board PRG, PRAM & SaveRAM, or whatever useful things from the board
|
var dCIRAM = new MemoryDomain("CIRAM (nametables)", 0x800, Endian.Little,
|
||||||
|
addr => CIRAM[addr & 0x07FF], (addr, value) => CIRAM[addr & 0x07FF] = value);
|
||||||
|
|
||||||
|
domains.Add(RAM);
|
||||||
domains.Add(WRAM);
|
domains.Add(SystemBus);
|
||||||
domains.Add(MainMemory);
|
|
||||||
domains.Add(PPUBus);
|
domains.Add(PPUBus);
|
||||||
|
domains.Add(dCIRAM);
|
||||||
|
|
||||||
if (board.SaveRam != null)
|
if (board.SaveRam != null)
|
||||||
{
|
{
|
||||||
|
@ -540,29 +196,29 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
domains.Add(BatteryRam);
|
domains.Add(BatteryRam);
|
||||||
}
|
}
|
||||||
|
|
||||||
var PRGROM = new MemoryDomain("PRG Rom", romInfo.PRG_Size * 16384, Endian.Little,
|
var PRGROM = new MemoryDomain("PRG ROM", cart.prg_size * 1024, Endian.Little,
|
||||||
addr => board.ROM[addr], (addr, value) => board.ROM[addr] = value);
|
addr => board.ROM[addr], (addr, value) => board.ROM[addr] = value);
|
||||||
domains.Add(PRGROM);
|
domains.Add(PRGROM);
|
||||||
|
|
||||||
if (romInfo.CHR_Size > 0)
|
if (board.VROM != null)
|
||||||
{
|
{
|
||||||
var CHRROM = new MemoryDomain("CHR Rom", romInfo.CHR_Size * 8192, Endian.Little,
|
var CHRROM = new MemoryDomain("CHR VROM", cart.chr_size * 1024, Endian.Little,
|
||||||
addr => board.VROM[addr], (addr, value) => board.VROM[addr] = value);
|
addr => board.VROM[addr], (addr, value) => board.VROM[addr] = value);
|
||||||
domains.Add(CHRROM);
|
domains.Add(CHRROM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (board.CRam != null)
|
if (board.VRAM != null)
|
||||||
{
|
{
|
||||||
var CRAM = new MemoryDomain("CRAM", board.CRam.Length, Endian.Little,
|
var VRAM = new MemoryDomain("VRAM", board.VRAM.Length, Endian.Little,
|
||||||
addr => board.CRam[addr], (addr, value) => board.CRam[addr] = value);
|
addr => board.VRAM[addr], (addr, value) => board.VRAM[addr] = value);
|
||||||
domains.Add(CRAM);
|
domains.Add(VRAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (board.PRam != null)
|
if (board.WRAM != null)
|
||||||
{
|
{
|
||||||
var PRAM = new MemoryDomain("PRAM", board.PRam.Length, Endian.Little,
|
var WRAM = new MemoryDomain("WRAM", board.WRAM.Length, Endian.Little,
|
||||||
addr => board.PRam[addr], (addr, value) => board.PRam[addr] = value);
|
addr => board.WRAM[addr], (addr, value) => board.WRAM[addr] = value);
|
||||||
domains.Add(PRAM);
|
domains.Add(WRAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryDomains = domains.AsReadOnly();
|
memoryDomains = domains.AsReadOnly();
|
||||||
|
@ -634,34 +290,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//turning this off probably doesnt work right now due to asserts in boards finding things set by the iNES header parsing
|
|
||||||
//need to separate those fields
|
|
||||||
const bool ENABLE_DB = true;
|
|
||||||
|
|
||||||
public string GameName { get { return game_name; } }
|
public string GameName { get { return game_name; } }
|
||||||
|
|
||||||
BootGodDB.Cart IdentifyFromGameDB(string hash)
|
|
||||||
{
|
|
||||||
GameInfo gi = Database.CheckDatabase(hash);
|
|
||||||
if (gi == null) return null;
|
|
||||||
|
|
||||||
BootGodDB.Game game = new BootGodDB.Game();
|
|
||||||
BootGodDB.Cart cart = new BootGodDB.Cart();
|
|
||||||
game.carts.Add(cart);
|
|
||||||
|
|
||||||
var dict = gi.ParseOptionsDictionary();
|
|
||||||
game.name = gi.Name;
|
|
||||||
cart.game = game;
|
|
||||||
cart.board_type = dict["board"];
|
|
||||||
if(dict.ContainsKey("PRG"))
|
|
||||||
cart.prg_size = short.Parse(dict["PRG"]);
|
|
||||||
if(dict.ContainsKey("CHR"))
|
|
||||||
cart.chr_size = short.Parse(dict["CHR"]);
|
|
||||||
|
|
||||||
return cart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void LoadGame(IGame game)
|
public unsafe void LoadGame(IGame game)
|
||||||
{
|
{
|
||||||
byte[] file = game.GetFileData();
|
byte[] file = game.GetFileData();
|
||||||
|
@ -690,13 +320,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
Console.WriteLine("headerless rom hash: {0}", hash_sha1);
|
Console.WriteLine("headerless rom hash: {0}", hash_sha1);
|
||||||
Console.WriteLine("headerless rom hash: {0}", hash_md5);
|
Console.WriteLine("headerless rom hash: {0}", hash_md5);
|
||||||
|
|
||||||
//check the bootgod database
|
CartInfo choice = IdentifyFromBootGodDB(hash_sha1);
|
||||||
BootGodDB.Initialize();
|
if(choice == null)
|
||||||
List<BootGodDB.Cart> choices = BootGodDB.Instance.Identify(hash_sha1);
|
|
||||||
BootGodDB.Cart choice;
|
|
||||||
if (choices.Count == 0)
|
|
||||||
{
|
{
|
||||||
//try generating a bootgod cart descriptor from the game database
|
|
||||||
choice = IdentifyFromGameDB(hash_md5);
|
choice = IdentifyFromGameDB(hash_md5);
|
||||||
if (choice == null)
|
if (choice == null)
|
||||||
choice = IdentifyFromGameDB(hash_sha1);
|
choice = IdentifyFromGameDB(hash_sha1);
|
||||||
|
@ -705,18 +331,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
else
|
else
|
||||||
Console.WriteLine("Chose board from gamedb: ");
|
Console.WriteLine("Chose board from gamedb: ");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("Chose board from nescartdb:");
|
|
||||||
//pick the first board for this hash arbitrarily. it probably doesn't make a difference
|
|
||||||
choice = choices[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(choice.game);
|
Console.WriteLine(choice.game);
|
||||||
Console.WriteLine(choice);
|
Console.WriteLine(choice);
|
||||||
game_name = choice.game.name;
|
|
||||||
|
|
||||||
//todo - generate better name with region and system
|
//todo - generate better name with region and system
|
||||||
|
game_name = choice.game.name;
|
||||||
|
|
||||||
//find a INESBoard to handle this
|
//find a INESBoard to handle this
|
||||||
Type boardType = FindBoard(choice);
|
Type boardType = FindBoard(choice);
|
||||||
|
@ -726,18 +346,24 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
}
|
}
|
||||||
board = (INESBoard)Activator.CreateInstance(boardType);
|
board = (INESBoard)Activator.CreateInstance(boardType);
|
||||||
|
|
||||||
|
cart = choice;
|
||||||
board.Create(this);
|
board.Create(this);
|
||||||
board.Configure(choice);
|
board.Configure();
|
||||||
|
|
||||||
byte[] rom, vrom = null;
|
//create the board's rom and vrom
|
||||||
rom = new byte[romInfo.PRG_Size * 1024];
|
board.ROM = new byte[choice.prg_size * 1024];
|
||||||
Array.Copy(file, 16, rom, 0, rom.Length);
|
Array.Copy(file, 16, board.ROM, 0, board.ROM.Length);
|
||||||
if (romInfo.CHR_Size > 0)
|
if (choice.chr_size > 0)
|
||||||
{
|
{
|
||||||
vrom = new byte[romInfo.CHR_Size * 1024];
|
board.VROM = new byte[choice.chr_size * 1024];
|
||||||
Array.Copy(file, 16 + rom.Length, vrom, 0, vrom.Length);
|
Array.Copy(file, 16 + board.ROM.Length, board.VROM, 0, board.VROM.Length);
|
||||||
}
|
}
|
||||||
board.InstallRoms(rom, vrom);
|
|
||||||
|
//create the vram and wram if necessary
|
||||||
|
if (cart.wram_size != 0)
|
||||||
|
board.WRAM = new byte[cart.wram_size * 1024];
|
||||||
|
if (cart.vram_size != 0)
|
||||||
|
board.VRAM = new byte[cart.vram_size * 1024];
|
||||||
|
|
||||||
HardReset();
|
HardReset();
|
||||||
SetupMemoryDomains();
|
SetupMemoryDomains();
|
||||||
|
|
|
@ -58,34 +58,34 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RomInfo Analyze()
|
//public RomInfo Analyze()
|
||||||
{
|
//{
|
||||||
var ret = new RomInfo();
|
// var ret = new RomInfo();
|
||||||
ret.MapperNumber = (ROM_type >> 4);
|
// ret.MapperNumber = (ROM_type >> 4);
|
||||||
ret.MapperNumber |= (ROM_type2 & 0xF0);
|
// ret.MapperNumber |= (ROM_type2 & 0xF0);
|
||||||
int mirroring = (ROM_type & 1);
|
// int mirroring = (ROM_type & 1);
|
||||||
if ((ROM_type & 8) != 0) mirroring = 2;
|
// if ((ROM_type & 8) != 0) mirroring = 2;
|
||||||
if (mirroring == 0) ret.MirrorType = EMirrorType.Horizontal;
|
// if (mirroring == 0) ret.MirrorType = EMirrorType.Horizontal;
|
||||||
else if (mirroring == 1) ret.MirrorType = EMirrorType.Vertical;
|
// else if (mirroring == 1) ret.MirrorType = EMirrorType.Vertical;
|
||||||
else ret.MirrorType = EMirrorType.External;
|
// else ret.MirrorType = EMirrorType.External;
|
||||||
ret.PRG_Size = ROM_size;
|
// ret.PRG_Size = ROM_size;
|
||||||
if (ret.PRG_Size == 0)
|
// if (ret.PRG_Size == 0)
|
||||||
ret.PRG_Size = 256;
|
// ret.PRG_Size = 256;
|
||||||
ret.CHR_Size = VROM_size;
|
// ret.CHR_Size = VROM_size;
|
||||||
ret.Battery = (ROM_type & 2) != 0;
|
// ret.Battery = (ROM_type & 2) != 0;
|
||||||
|
|
||||||
fixed (iNES_HEADER* self = &this) ret.PRAM_Size = self->reserve[0] * 8;
|
// fixed (iNES_HEADER* self = &this) ret.PRAM_Size = self->reserve[0] * 8;
|
||||||
//0 is supposed to mean 1 (for compatibility, as this is an extension to original iNES format)
|
// //0 is supposed to mean 1 (for compatibility, as this is an extension to original iNES format)
|
||||||
if (ret.PRAM_Size == 0) ret.PRAM_Size = 8;
|
// if (ret.PRAM_Size == 0) ret.PRAM_Size = 8;
|
||||||
|
|
||||||
Console.WriteLine("iNES header: map:{0}, mirror:{1}, PRG:{2}, CHR:{3}, CRAM:{4}, PRAM:{5}, bat:{6}", ret.MapperNumber, ret.MirrorType, ret.PRG_Size, ret.CHR_Size, ret.CRAM_Size, ret.PRAM_Size, ret.Battery ? 1 : 0);
|
// Console.WriteLine("iNES header: map:{0}, mirror:{1}, PRG:{2}, CHR:{3}, CRAM:{4}, PRAM:{5}, bat:{6}", ret.MapperNumber, ret.MirrorType, ret.PRG_Size, ret.CHR_Size, ret.CRAM_Size, ret.PRAM_Size, ret.Battery ? 1 : 0);
|
||||||
|
|
||||||
//fceux calls uppow2(PRG_Banks) here, and also ups the chr size as well
|
// //fceux calls uppow2(PRG_Banks) here, and also ups the chr size as well
|
||||||
//then it does something complicated that i don't understand with making sure it doesnt read too much data
|
// //then it does something complicated that i don't understand with making sure it doesnt read too much data
|
||||||
//fceux only allows this condition for mappers in the list "not_power2" which is only 228
|
// //fceux only allows this condition for mappers in the list "not_power2" which is only 228
|
||||||
|
|
||||||
return ret;
|
// return ret;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2270,14 +2270,14 @@ sha1:894F20405286F5F75133CE4648300E2C67972B40 Solomon's Key (U) NES board=NES-
|
||||||
sha1:0C53B06E1D13AE917536BB39010914EA3D111FF5 Thunder & Lightning (U) NES board=NES-GNROM;PRG=128;CHR=32
|
sha1:0C53B06E1D13AE917536BB39010914EA3D111FF5 Thunder & Lightning (U) NES board=NES-GNROM;PRG=128;CHR=32
|
||||||
|
|
||||||
;blargg's tests
|
;blargg's tests
|
||||||
md5:FCDA199AE2DD1824F377AC3EC40E68CD blargg/sprite_hit_tests_2005.10.05/01.basics.nes NES board=NES-SNROM;PRG=16
|
md5:FCDA199AE2DD1824F377AC3EC40E68CD blargg/sprite_hit_tests_2005.10.05/01.basics.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:8BE5342D1A1F5E63602B0B2AD4D3E957 blargg/sprite_hit_tests_2005.10.05/02.alignment.nes NES board=NES-SNROM;PRG=16
|
md5:8BE5342D1A1F5E63602B0B2AD4D3E957 blargg/sprite_hit_tests_2005.10.05/02.alignment.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:E7F1424401BA5C3484F10CB6F9E7328F blargg/sprite_hit_tests_2005.10.05/03.corners.nes NES board=NES-SNROM;PRG=16
|
md5:E7F1424401BA5C3484F10CB6F9E7328F blargg/sprite_hit_tests_2005.10.05/03.corners.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:64836B8BAA2D19AE0F41F8F00390478A blargg/sprite_hit_tests_2005.10.05/04.flip.nes NES board=NES-SNROM;PRG=16
|
md5:64836B8BAA2D19AE0F41F8F00390478A blargg/sprite_hit_tests_2005.10.05/04.flip.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:99E18274B94CB11D0F67984D36B476BB blargg/sprite_hit_tests_2005.10.05/05.left_clip.nes NES board=NES-SNROM;PRG=16
|
md5:99E18274B94CB11D0F67984D36B476BB blargg/sprite_hit_tests_2005.10.05/05.left_clip.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:9ADB96106B2D57D92A22CC67ACA43963 blargg/sprite_hit_tests_2005.10.05/06.right_edge.nes NES board=NES-SNROM;PRG=16
|
md5:9ADB96106B2D57D92A22CC67ACA43963 blargg/sprite_hit_tests_2005.10.05/06.right_edge.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:8D917EFB12AA4C6D08BE86C809A68F4A blargg/sprite_hit_tests_2005.10.05/07.screen_bottom.nes NES board=NES-SNROM;PRG=16
|
md5:8D917EFB12AA4C6D08BE86C809A68F4A blargg/sprite_hit_tests_2005.10.05/07.screen_bottom.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:57DE8767DAB3F8A150EA5C63B374F825 blargg/sprite_hit_tests_2005.10.05/08.double_height.nes NES board=NES-SNROM;PRG=16
|
md5:57DE8767DAB3F8A150EA5C63B374F825 blargg/sprite_hit_tests_2005.10.05/08.double_height.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:594E8568C4C621EC95A6390D559CA504 blargg/sprite_hit_tests_2005.10.05/09.timing_basics.nes NES board=NES-SNROM;PRG=16
|
md5:594E8568C4C621EC95A6390D559CA504 blargg/sprite_hit_tests_2005.10.05/09.timing_basics.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:7B42B8672F35068E96EB1D4D2CA1A33B blargg/sprite_hit_tests_2005.10.05/10.timing_order.nes NES board=NES-SNROM;PRG=16
|
md5:7B42B8672F35068E96EB1D4D2CA1A33B blargg/sprite_hit_tests_2005.10.05/10.timing_order.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
||||||
md5:55AD5FFC60CA9AEF60FEB8AEC900214E blargg/sprite_hit_tests_2005.10.05/11.edge_timing.nes NES board=NES-SNROM;PRG=16
|
md5:55AD5FFC60CA9AEF60FEB8AEC900214E blargg/sprite_hit_tests_2005.10.05/11.edge_timing.nes NES board=NES-SNROM;PRG=16;VRAM=8;WRAM=8
|
Loading…
Reference in New Issue