[NES] overhaul database and board configuration system some more and reorg code a bit

This commit is contained in:
zeromus 2011-03-08 07:25:35 +00:00
parent 47b9a5ffb4
commit be69565135
15 changed files with 876 additions and 1040 deletions

View File

@ -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" />

View File

@ -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,

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();

View File

@ -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;
//}
}
}

View File

@ -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