[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>
|
||||
<Compile Include="Consoles\Calculator\TI83.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\BoardSystem.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\AxROM.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
@ -70,14 +71,16 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\IC_74x377.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\NROM.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\BoardDetector.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\NROM.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\SxROM.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\UxROM.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\Core.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\iNES.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\NES.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.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//generally mapper7
|
||||
|
||||
//Battletoads
|
||||
//Time Lord
|
||||
//Marble Madness
|
||||
|
||||
public class AxROM : NES.NESBoardBase
|
||||
{
|
||||
//configuration
|
||||
|
@ -18,49 +14,40 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
int prg_mask;
|
||||
|
||||
//state
|
||||
byte[] cram;
|
||||
int prg;
|
||||
|
||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
||||
public override bool Configure()
|
||||
{
|
||||
//configure
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "NES-ANROM":
|
||||
BoardInfo.PRG_Size = 128;
|
||||
case "NES-ANROM": //marble madness
|
||||
AssertPrg(128); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
bus_conflict = false;
|
||||
break;
|
||||
|
||||
case "NES-AN1ROM":
|
||||
BoardInfo.PRG_Size = 64;
|
||||
bus_conflict = false;
|
||||
break;
|
||||
case "NES-AN1ROM": //R.C. Pro-Am
|
||||
AssertPrg(64); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
bus_conflict = false;
|
||||
break;
|
||||
|
||||
case "NES-AMROM":
|
||||
BoardInfo.PRG_Size = 128;
|
||||
bus_conflict = true;
|
||||
break;
|
||||
case "NES-AMROM": //time lord
|
||||
AssertPrg(128); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
bus_conflict = true;
|
||||
break;
|
||||
|
||||
case "NES-AOROM":
|
||||
case "NES-AOROM": //battletoads
|
||||
case "HVC-AOROM":
|
||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
||||
BoardInfo.PRG_Size = cart.prg_size;
|
||||
bus_conflict = true; //MAYBE. apparently it varies
|
||||
break;
|
||||
AssertPrg(128,256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
bus_conflict = true; //MAYBE. apparently it varies
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
//these boards always have 8KB of CRAM
|
||||
BoardInfo.CRAM_Size = 8;
|
||||
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);
|
||||
prg_mask = (Cart.prg_size / 16) - 1;
|
||||
cram_byte_mask = 8 * 1024 - 1; //these boards always have 8KB of CRAM
|
||||
|
||||
//it is necessary to write during initialization to set the mirroring
|
||||
WritePRG(0, 0);
|
||||
|
@ -87,7 +74,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
return cram[addr & cram_byte_mask];
|
||||
return VRAM[addr & cram_byte_mask];
|
||||
}
|
||||
else return base.ReadPPU(addr);
|
||||
}
|
||||
|
@ -96,7 +83,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
cram[addr & cram_byte_mask] = value;
|
||||
VRAM[addr & cram_byte_mask] = value;
|
||||
}
|
||||
else base.WritePPU(addr,value);
|
||||
}
|
||||
|
@ -105,14 +92,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
base.SaveStateBinary(bw);
|
||||
bw.Write(prg);
|
||||
Util.WriteByteBuffer(bw, cram);
|
||||
}
|
||||
|
||||
public override void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
base.LoadStateBinary(br);
|
||||
prg = br.ReadInt32();
|
||||
cram = Util.ReadByteBuffer(br, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,37 +2,31 @@ using System;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
|
||||
public class CPROM : NES.NESBoardBase
|
||||
{
|
||||
//generally mapper 13
|
||||
|
||||
//Videomation
|
||||
|
||||
//state
|
||||
byte[] cram;
|
||||
int chr;
|
||||
|
||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
||||
public override bool Configure()
|
||||
{
|
||||
//configure
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "NES-CPROM":
|
||||
BoardInfo.PRG_Size = 32;
|
||||
case "NES-CPROM": //videomation
|
||||
AssertPrg(32); AssertChr(0); AssertVram(16); AssertWram(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
cram = new byte[16*1024];
|
||||
SetMirrorType(NES.EMirrorType.Vertical);
|
||||
|
||||
//validate
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -45,18 +39,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
public override byte ReadPPU(int addr)
|
||||
{
|
||||
if (addr < 0x1000)
|
||||
return cram[addr];
|
||||
return VRAM[addr];
|
||||
else if(addr<0x2000)
|
||||
return cram[addr-0x1000 + (chr<<12)];
|
||||
return VRAM[addr - 0x1000 + (chr << 12)];
|
||||
else return base.ReadPPU(addr);
|
||||
}
|
||||
|
||||
public override void WritePPU(int addr, byte value)
|
||||
{
|
||||
if (addr < 0x1000)
|
||||
cram[addr] = value;
|
||||
VRAM[addr] = value;
|
||||
else if (addr < 0x2000)
|
||||
cram[addr - 0x1000 + (chr << 12)] = value;
|
||||
VRAM[addr - 0x1000 + (chr << 12)] = value;
|
||||
else base.WritePPU(addr,value);
|
||||
}
|
||||
|
||||
|
@ -64,14 +58,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
base.SaveStateBinary(bw);
|
||||
bw.Write(chr);
|
||||
Util.WriteByteBuffer(bw, cram);
|
||||
}
|
||||
|
||||
public override void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
base.LoadStateBinary(br);
|
||||
chr = br.ReadInt32();
|
||||
cram = Util.ReadByteBuffer(br, false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//generally mapper3
|
||||
|
||||
|
@ -21,32 +21,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
//state
|
||||
int chr;
|
||||
|
||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
||||
public override bool Configure()
|
||||
{
|
||||
//configure
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "NES-CNROM":
|
||||
case "NES-CNROM": //adventure island
|
||||
case "HVC-CNROM":
|
||||
Assert(cart.prg_size == 16 || cart.prg_size == 32);
|
||||
Assert(cart.chr_size == 16 || cart.chr_size == 32);
|
||||
BoardInfo.PRG_Size = cart.prg_size;
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
AssertPrg(16, 32); AssertChr(16,32);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
||||
chr_mask = (BoardInfo.CHR_Size / 8) - 1;
|
||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
||||
prg_mask = (Cart.prg_size / 16) - 1;
|
||||
chr_mask = (Cart.chr_size / 8) - 1;
|
||||
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||
bus_conflict = true;
|
||||
|
||||
//validate
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//generally mapper66
|
||||
|
||||
|
@ -22,31 +22,26 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
//state
|
||||
int prg, chr;
|
||||
|
||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
||||
public override bool Configure()
|
||||
{
|
||||
//configure
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "NES-GNROM":
|
||||
case "NES-GNROM": //thunder & lightning
|
||||
case "BANDAI-GNROM":
|
||||
case "HVC-GNROM":
|
||||
case "NES-MHROM":
|
||||
Assert(cart.chr_size == 8 || cart.chr_size == 16 || cart.chr_size == 32);
|
||||
BoardInfo.PRG_Size = (cart.board_type == "NES-MHROM" ? 64 : 128);
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
case "NES-MHROM": //Super Mario Bros. / Duck Hunt
|
||||
AssertPrg(Cart.board_type == "NES-MHROM" ? 64 : 128); AssertChr(8, 16, 32); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
prg_mask = (BoardInfo.PRG_Size/8/2) - 1;
|
||||
chr_mask = (BoardInfo.CHR_Size / 8) - 1;
|
||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
||||
prg_mask = (Cart.prg_size/8/2) - 1;
|
||||
chr_mask = (Cart.chr_size / 8) - 1;
|
||||
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||
|
||||
//validate
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//mapper 11
|
||||
|
||||
|
@ -18,27 +18,20 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
//state
|
||||
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":
|
||||
Assert(cart.prg_size == 32 || cart.prg_size == 64 || cart.prg_size == 128);
|
||||
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;
|
||||
AssertPrg(32,64,128); AssertChr(16,32,64,128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
prg_mask = (BoardInfo.PRG_Size/8/2)-1;
|
||||
chr_mask = (BoardInfo.CHR_Size / 8 - 1);
|
||||
|
||||
//validate
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
||||
prg_mask = (Cart.prg_size/8/2)-1;
|
||||
chr_mask = (Cart.chr_size / 8 - 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
public class NROM : NES.NESBoardBase
|
||||
{
|
||||
|
@ -11,37 +11,31 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
//state
|
||||
//(none)
|
||||
|
||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
||||
public override bool Configure()
|
||||
{
|
||||
//configure
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "HVC-NROM-256":
|
||||
BoardInfo.PRG_Size = 32;
|
||||
BoardInfo.CHR_Size = 8;
|
||||
case "HVC-NROM-256": //super mario bros.
|
||||
AssertPrg(32); AssertChr(8); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
|
||||
case "HVC-RROM":
|
||||
case "HVC-RROM": //balloon fight
|
||||
case "HVC-NROM-128":
|
||||
case "IREM-NROM-128":
|
||||
case "KONAMI-NROM-128":
|
||||
case "NES-NROM-128":
|
||||
case "NAMCOT-3301":
|
||||
BoardInfo.PRG_Size = 16;
|
||||
BoardInfo.CHR_Size = 8;
|
||||
AssertPrg(16); AssertChr(8); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
prg_byte_mask = (BoardInfo.PRG_Size << 10) - 1;
|
||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
||||
prg_byte_mask = (Cart.prg_size*1024) - 1;
|
||||
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||
|
||||
//validate
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//AKA MMC1
|
||||
//http://wiki.nesdev.com/w/index.php/SxROM
|
||||
|
@ -176,7 +176,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
int cram_mask, pram_mask;
|
||||
|
||||
//state
|
||||
byte[] cram, pram;
|
||||
MMC1 mmc1;
|
||||
|
||||
public override void WritePRG(int addr, byte value)
|
||||
|
@ -203,8 +202,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (BoardInfo.CRAM_Size != 0)
|
||||
return cram[addr & cram_mask];
|
||||
if (Cart.vram_size != 0)
|
||||
return VRAM[addr & cram_mask];
|
||||
else return VROM[Gen_CHR_Address(addr)];
|
||||
}
|
||||
else return base.ReadPPU(addr);
|
||||
|
@ -214,260 +213,130 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (BoardInfo.CRAM_Size != 0)
|
||||
cram[addr & cram_mask] = value;
|
||||
if (Cart.vram_size != 0)
|
||||
VRAM[addr & cram_mask] = value;
|
||||
}
|
||||
else base.WritePPU(addr, value);
|
||||
}
|
||||
|
||||
public override byte ReadPRAM(int addr)
|
||||
{
|
||||
if (BoardInfo.PRAM_Size != 0)
|
||||
return pram[addr & pram_mask];
|
||||
if (Cart.wram_size != 0)
|
||||
return WRAM[addr & pram_mask];
|
||||
else return 0xFF;
|
||||
}
|
||||
|
||||
public override void WritePRAM(int addr, byte value)
|
||||
{
|
||||
if (BoardInfo.PRAM_Size != 0)
|
||||
pram[addr & pram_mask] = value;
|
||||
if (Cart.wram_size != 0)
|
||||
WRAM[addr & pram_mask] = value;
|
||||
}
|
||||
|
||||
public override byte[] SaveRam
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!BoardInfo.Battery) return null;
|
||||
return pram;
|
||||
if (!Cart.wram_battery) return null;
|
||||
return WRAM;
|
||||
//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)
|
||||
}
|
||||
}
|
||||
|
||||
public override byte[] PRam
|
||||
{
|
||||
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)
|
||||
public override void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
base.SaveStateBinary(bw);
|
||||
mmc1.SaveStateBinary(bw);
|
||||
Util.WriteByteBuffer(bw, pram);
|
||||
Util.WriteByteBuffer(bw, cram);
|
||||
|
||||
}
|
||||
public override void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
base.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
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "NES-SAROM":
|
||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
||||
BoardInfo.PRG_Size = 64;
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 8;
|
||||
case "NES-SAROM": //dragon warrior
|
||||
AssertPrg(64); AssertChr(16, 32, 64); AssertVram(0); AssertWram(8);
|
||||
break;
|
||||
case "NES-SBROM":
|
||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
||||
BoardInfo.PRG_Size = 64;
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 0;
|
||||
case "NES-SBROM": //dance aerobics
|
||||
AssertPrg(64); AssertChr(16, 32, 64); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SCROM":
|
||||
case "NES-SC1ROM":
|
||||
BoardInfo.PRG_Size = 64;
|
||||
BoardInfo.CHR_Size = 128;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 0;
|
||||
break;
|
||||
case "NES-SEROM":
|
||||
BoardInfo.PRG_Size = 32;
|
||||
BoardInfo.CHR_Size = 32;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 0;
|
||||
break;
|
||||
case "NES-SFROM":
|
||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
||||
BoardInfo.PRG_Size = cart.prg_size;
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 0;
|
||||
break;
|
||||
case "NES-SGROM":
|
||||
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 = 0;
|
||||
break;
|
||||
case "NES-SHROM":
|
||||
case "NES-SH1ROM":
|
||||
BoardInfo.PRG_Size = 32;
|
||||
BoardInfo.CHR_Size = 128;
|
||||
BoardInfo.PRAM_Size = 0;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
break;
|
||||
case "HVC-SIROM":
|
||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
||||
BoardInfo.PRG_Size = 32;
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 0;
|
||||
break;
|
||||
case "NES-SJROM":
|
||||
Assert(cart.prg_size == 128 || cart.prg_size == 256);
|
||||
Assert(cart.chr_size == 16 || cart.chr_size == 32 || cart.chr_size == 64);
|
||||
BoardInfo.PRG_Size = cart.prg_size;
|
||||
BoardInfo.CHR_Size = cart.chr_size;
|
||||
BoardInfo.CRAM_Size = 0;
|
||||
BoardInfo.PRAM_Size = 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
|
||||
case "NES-SCROM": //mechanized attack
|
||||
case "NES-SC1ROM": //knight rider
|
||||
AssertPrg(64); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SEROM": //lolo
|
||||
case "HVC-SEROM": //dr. mario
|
||||
AssertPrg(32); AssertChr(32); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SFROM": //bubble bobble
|
||||
AssertPrg(128,256); AssertChr(16,32,64); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SGROM": //bionic commando
|
||||
AssertPrg(128, 256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
break;
|
||||
case "NES-SHROM": //family feud
|
||||
case "NES-SH1ROM": //airwolf
|
||||
AssertPrg(32); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "HVC-SIROM": //Igo: Kyuu Roban Taikyoku
|
||||
AssertPrg(32); AssertChr(16); AssertVram(0); AssertWram(8);
|
||||
break;
|
||||
case "NES-SJROM": //air fortress
|
||||
AssertPrg(128,256); AssertChr(16,32,64); AssertVram(0); AssertWram(8);
|
||||
break;
|
||||
case "NES-SKROM": //zelda 2
|
||||
AssertPrg(128, 256); AssertChr(128); AssertVram(0); AssertWram(8);
|
||||
break;
|
||||
case "NES-SLROM": //castlevania 2
|
||||
AssertPrg(128, 256); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SL1ROM": //hoops
|
||||
AssertPrg(64, 128, 256); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SL2ROM": //blaster master
|
||||
AssertPrg(128); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SL3ROM": //goal!
|
||||
AssertPrg(256); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "NES-SLRROM": //tecmo bowl
|
||||
AssertPrg(128); AssertChr(128); AssertVram(0); AssertWram(0);
|
||||
break;
|
||||
case "HVC-SMROM": //Hokkaidou Rensa Satsujin: Okhotsu ni Shoyu
|
||||
AssertPrg(256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
break;
|
||||
case "NES-SNROM": //dragon warrior 2
|
||||
case "HVC-SNROM":
|
||||
//prg=16 is unexpected but blargg's tests use it
|
||||
AssertPrg(16, 128, 256); AssertChr(0); AssertVram(8); AssertWram(8);
|
||||
//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;
|
||||
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:
|
||||
return false;
|
||||
}
|
||||
|
||||
//validate and setup the basics
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
Assert(cart.chr_size == BoardInfo.CHR_Size);
|
||||
mmc1 = new MMC1();
|
||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
||||
chr_mask = (BoardInfo.CHR_Size / 8) - 1;
|
||||
BoardInfo.Battery = cart.wram_battery;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
prg_mask = (Cart.prg_size / 16) - 1;
|
||||
cram_mask = (Cart.vram_size*1024) - 1;
|
||||
pram_mask = (Cart.wram_size*1024) - 1;
|
||||
chr_mask = (Cart.chr_size / 8 * 2) - 1;
|
||||
SetMirrorType(mmc1.mirror);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
||||
namespace BizHawk.Emulation.Consoles.Nintendo
|
||||
{
|
||||
//generally mapper2
|
||||
|
||||
|
@ -22,37 +22,30 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
|
||||
//state
|
||||
int prg;
|
||||
byte[] cram;
|
||||
|
||||
public override bool Configure(NES.BootGodDB.Cart cart)
|
||||
public override bool Configure()
|
||||
{
|
||||
//configure
|
||||
switch (cart.board_type)
|
||||
switch (Cart.board_type)
|
||||
{
|
||||
case "NES-UNROM":
|
||||
case "NES-UNROM": //mega man
|
||||
case "HVC-UNROM":
|
||||
case "KONAMI-UNROM":
|
||||
BoardInfo.PRG_Size = 128;
|
||||
AssertPrg(128); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
break;
|
||||
|
||||
case "NES-UOROM":
|
||||
case "NES-UOROM": //paperboy 2
|
||||
case "HVC-UOROM":
|
||||
BoardInfo.PRG_Size = 256;
|
||||
AssertPrg(256); AssertChr(0); AssertVram(8); AssertWram(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
//these boards always have 8KB of CRAM
|
||||
BoardInfo.CRAM_Size = 8;
|
||||
cram = new byte[BoardInfo.CRAM_Size * 1024];
|
||||
cram_byte_mask = cram.Length - 1;
|
||||
prg_mask = (BoardInfo.PRG_Size / 16) - 1;
|
||||
SetMirrorType(cart.pad_h, cart.pad_v);
|
||||
|
||||
|
||||
//validate
|
||||
Assert(cart.prg_size == BoardInfo.PRG_Size);
|
||||
cram_byte_mask = (Cart.vram_size*1024) - 1;
|
||||
prg_mask = (Cart.prg_size / 16) - 1;
|
||||
SetMirrorType(Cart.pad_h, Cart.pad_v);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -73,7 +66,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
return cram[addr & cram_byte_mask];
|
||||
return VRAM[addr & cram_byte_mask];
|
||||
}
|
||||
else return base.ReadPPU(addr);
|
||||
}
|
||||
|
@ -82,7 +75,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
cram[addr & cram_byte_mask] = value;
|
||||
VRAM[addr & cram_byte_mask] = value;
|
||||
}
|
||||
else base.WritePPU(addr,value);
|
||||
}
|
||||
|
@ -91,14 +84,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.Boards
|
|||
{
|
||||
base.SaveStateBinary(bw);
|
||||
bw.Write(prg);
|
||||
Util.WriteByteBuffer(bw, cram);
|
||||
}
|
||||
|
||||
public override void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
base.LoadStateBinary(br);
|
||||
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
|
||||
{
|
||||
|
||||
public partial class NES : IEmulator
|
||||
{
|
||||
//Game issues:
|
||||
|
@ -25,54 +26,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
//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)
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class INESBoardImplAttribute : Attribute {}
|
||||
static List<Type> INESBoardImplementors = new List<Type>();
|
||||
|
||||
static NES()
|
||||
public NES()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
BootGodDB.Initialize();
|
||||
palette = Palettes.FCEUX_Standard;
|
||||
}
|
||||
|
||||
public enum EMirrorType
|
||||
|
@ -83,263 +40,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
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
|
||||
{
|
||||
NES emu;
|
||||
|
@ -392,27 +92,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
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
|
||||
{
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -519,19 +175,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
private void SetupMemoryDomains()
|
||||
{
|
||||
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);
|
||||
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));
|
||||
var PPUBus = new MemoryDomain("PPU Bus", 0x4000, Endian.Little,
|
||||
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(WRAM);
|
||||
domains.Add(MainMemory);
|
||||
domains.Add(RAM);
|
||||
domains.Add(SystemBus);
|
||||
domains.Add(PPUBus);
|
||||
domains.Add(dCIRAM);
|
||||
|
||||
if (board.SaveRam != null)
|
||||
{
|
||||
|
@ -540,29 +196,29 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
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);
|
||||
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);
|
||||
domains.Add(CHRROM);
|
||||
}
|
||||
|
||||
if (board.CRam != null)
|
||||
if (board.VRAM != null)
|
||||
{
|
||||
var CRAM = new MemoryDomain("CRAM", board.CRam.Length, Endian.Little,
|
||||
addr => board.CRam[addr], (addr, value) => board.CRam[addr] = value);
|
||||
domains.Add(CRAM);
|
||||
var VRAM = new MemoryDomain("VRAM", board.VRAM.Length, Endian.Little,
|
||||
addr => board.VRAM[addr], (addr, value) => board.VRAM[addr] = value);
|
||||
domains.Add(VRAM);
|
||||
}
|
||||
|
||||
if (board.PRam != null)
|
||||
if (board.WRAM != null)
|
||||
{
|
||||
var PRAM = new MemoryDomain("PRAM", board.PRam.Length, Endian.Little,
|
||||
addr => board.PRam[addr], (addr, value) => board.PRam[addr] = value);
|
||||
domains.Add(PRAM);
|
||||
var WRAM = new MemoryDomain("WRAM", board.WRAM.Length, Endian.Little,
|
||||
addr => board.WRAM[addr], (addr, value) => board.WRAM[addr] = value);
|
||||
domains.Add(WRAM);
|
||||
}
|
||||
|
||||
memoryDomains = domains.AsReadOnly();
|
||||
|
@ -634,34 +290,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
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; } }
|
||||
|
||||
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)
|
||||
{
|
||||
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_md5);
|
||||
|
||||
//check the bootgod database
|
||||
BootGodDB.Initialize();
|
||||
List<BootGodDB.Cart> choices = BootGodDB.Instance.Identify(hash_sha1);
|
||||
BootGodDB.Cart choice;
|
||||
if (choices.Count == 0)
|
||||
CartInfo choice = IdentifyFromBootGodDB(hash_sha1);
|
||||
if(choice == null)
|
||||
{
|
||||
//try generating a bootgod cart descriptor from the game database
|
||||
choice = IdentifyFromGameDB(hash_md5);
|
||||
if (choice == null)
|
||||
choice = IdentifyFromGameDB(hash_sha1);
|
||||
|
@ -705,18 +331,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
else
|
||||
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_name = choice.game.name;
|
||||
|
||||
//todo - generate better name with region and system
|
||||
game_name = choice.game.name;
|
||||
|
||||
//find a INESBoard to handle this
|
||||
Type boardType = FindBoard(choice);
|
||||
|
@ -726,18 +346,24 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
board = (INESBoard)Activator.CreateInstance(boardType);
|
||||
|
||||
cart = choice;
|
||||
board.Create(this);
|
||||
board.Configure(choice);
|
||||
board.Configure();
|
||||
|
||||
byte[] rom, vrom = null;
|
||||
rom = new byte[romInfo.PRG_Size * 1024];
|
||||
Array.Copy(file, 16, rom, 0, rom.Length);
|
||||
if (romInfo.CHR_Size > 0)
|
||||
//create the board's rom and vrom
|
||||
board.ROM = new byte[choice.prg_size * 1024];
|
||||
Array.Copy(file, 16, board.ROM, 0, board.ROM.Length);
|
||||
if (choice.chr_size > 0)
|
||||
{
|
||||
vrom = new byte[romInfo.CHR_Size * 1024];
|
||||
Array.Copy(file, 16 + rom.Length, vrom, 0, vrom.Length);
|
||||
board.VROM = new byte[choice.chr_size * 1024];
|
||||
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();
|
||||
SetupMemoryDomains();
|
||||
|
|
|
@ -58,34 +58,34 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
}
|
||||
|
||||
public RomInfo Analyze()
|
||||
{
|
||||
var ret = new RomInfo();
|
||||
ret.MapperNumber = (ROM_type >> 4);
|
||||
ret.MapperNumber |= (ROM_type2 & 0xF0);
|
||||
int mirroring = (ROM_type & 1);
|
||||
if ((ROM_type & 8) != 0) mirroring = 2;
|
||||
if (mirroring == 0) ret.MirrorType = EMirrorType.Horizontal;
|
||||
else if (mirroring == 1) ret.MirrorType = EMirrorType.Vertical;
|
||||
else ret.MirrorType = EMirrorType.External;
|
||||
ret.PRG_Size = ROM_size;
|
||||
if (ret.PRG_Size == 0)
|
||||
ret.PRG_Size = 256;
|
||||
ret.CHR_Size = VROM_size;
|
||||
ret.Battery = (ROM_type & 2) != 0;
|
||||
//public RomInfo Analyze()
|
||||
//{
|
||||
// var ret = new RomInfo();
|
||||
// ret.MapperNumber = (ROM_type >> 4);
|
||||
// ret.MapperNumber |= (ROM_type2 & 0xF0);
|
||||
// int mirroring = (ROM_type & 1);
|
||||
// if ((ROM_type & 8) != 0) mirroring = 2;
|
||||
// if (mirroring == 0) ret.MirrorType = EMirrorType.Horizontal;
|
||||
// else if (mirroring == 1) ret.MirrorType = EMirrorType.Vertical;
|
||||
// else ret.MirrorType = EMirrorType.External;
|
||||
// ret.PRG_Size = ROM_size;
|
||||
// if (ret.PRG_Size == 0)
|
||||
// ret.PRG_Size = 256;
|
||||
// ret.CHR_Size = VROM_size;
|
||||
// ret.Battery = (ROM_type & 2) != 0;
|
||||
|
||||
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)
|
||||
if (ret.PRAM_Size == 0) ret.PRAM_Size = 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)
|
||||
// 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
|
||||
//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 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
|
||||
// //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
|
||||
|
||||
;blargg's tests
|
||||
md5:FCDA199AE2DD1824F377AC3EC40E68CD blargg/sprite_hit_tests_2005.10.05/01.basics.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
|
||||
md5:E7F1424401BA5C3484F10CB6F9E7328F blargg/sprite_hit_tests_2005.10.05/03.corners.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
|
||||
md5:99E18274B94CB11D0F67984D36B476BB blargg/sprite_hit_tests_2005.10.05/05.left_clip.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
|
||||
md5:8D917EFB12AA4C6D08BE86C809A68F4A blargg/sprite_hit_tests_2005.10.05/07.screen_bottom.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
|
||||
md5:594E8568C4C621EC95A6390D559CA504 blargg/sprite_hit_tests_2005.10.05/09.timing_basics.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
|
||||
md5:55AD5FFC60CA9AEF60FEB8AEC900214E blargg/sprite_hit_tests_2005.10.05/11.edge_timing.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;VRAM=8;WRAM=8
|
||||
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;VRAM=8;WRAM=8
|
||||
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;VRAM=8;WRAM=8
|
||||
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;VRAM=8;WRAM=8
|
||||
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;VRAM=8;WRAM=8
|
||||
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