support bsnes xml files and super road blaster MSU-1 game

This commit is contained in:
zeromus 2013-04-24 22:09:11 +00:00
parent f3a8cee8bc
commit df99f36464
7 changed files with 114 additions and 41 deletions

View File

@ -261,16 +261,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
if (buffer.Length < offset + count) throw new IndexOutOfRangeException(); if (buffer.Length < offset + count) throw new IndexOutOfRangeException();
fixed (byte* pbuffer = &buffer[offset]) if(buffer.Length != 0)
buf.Read((IntPtr)pbuffer, count); fixed (byte* pbuffer = &buffer[offset])
buf.Read((IntPtr)pbuffer, count);
return count; return count;
} }
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
if (buffer.Length < offset + count) throw new IndexOutOfRangeException(); if (buffer.Length < offset + count) throw new IndexOutOfRangeException();
fixed (byte* pbuffer = &buffer[offset]) if(buffer.Length != 0)
buf.Write((IntPtr)pbuffer, count); fixed (byte* pbuffer = &buffer[offset])
buf.Write((IntPtr)pbuffer, count);
} }
} }
@ -646,11 +648,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
return ret; return ret;
} }
public bool snes_load_cartridge_normal(string rom_xml, byte[] rom_data) public bool snes_load_cartridge_normal(byte[] rom_xml, byte[] rom_data)
{ {
WritePipeMessage(eMessage.eMessage_snes_load_cartridge_normal); WritePipeMessage(eMessage.eMessage_snes_load_cartridge_normal);
WritePipeString(rom_xml ?? ""); WritePipeBlob(rom_xml ?? new byte[0]);
WritePipeBlob(rom_data); WritePipeBlob(rom_data ?? new byte[0]);
//not a very obvious order.. because we do tons of work immediately after the last param goes down and need to answer messages //not a very obvious order.. because we do tons of work immediately after the last param goes down and need to answer messages
WaitForCompletion(); WaitForCompletion();
bool ret = brPipe.ReadBoolean(); bool ret = brPipe.ReadBoolean();

View File

@ -9,6 +9,8 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -101,15 +103,36 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
string snes_path_request(int slot, string hint) string snes_path_request(int slot, string hint)
{ {
//heres how to get MSU-1 working: //every rom requests msu1.rom... why? who knows.
//if (hint == "msu1.rom") return @"c:\roms\SuperRoadBlaster\SuperRoadBlaster.msu"; //also handle msu-1 pcm files here
//if (Path.GetExtension(hint).ToLower() == ".pcm") bool is_msu1_rom = hint == "msu1.rom";
// return Path.Combine(@"c:\roms\SuperRoadBlaster\", hint); bool is_msu1_pcm = Path.GetExtension(hint).ToLower() == ".pcm";
//to do this accurately, we should be loading the xml file. if (is_msu1_rom || is_msu1_pcm)
//perhaps, if we do that, bsnes will be asking us for the correct paths. at the very least, we could parse the xml ourselves and return the correct thing for msu1.rom {
//well, check if we have an msu-1 xml
if (romxml != null && romxml["cartridge"] != null && romxml["cartridge"]["msu1"] != null)
{
var msu1 = romxml["cartridge"]["msu1"];
if (is_msu1_rom && msu1["rom"].Attributes["name"] != null)
return CoreComm.AcquireSubfilePath(msu1["rom"].Attributes["name"].Value);
if (is_msu1_pcm)
{
//return @"D:\roms\snes\SuperRoadBlaster\SuperRoadBlaster-1.pcm";
//return "";
int wantsTrackNumber = int.Parse(hint.Replace("track-", "").Replace(".pcm", ""));
wantsTrackNumber++;
string wantsTrackString = wantsTrackNumber.ToString();
foreach (var child in msu1.ChildNodes.Cast<XmlNode>())
{
if (child.Name == "track" && child.Attributes["number"].Value == wantsTrackString)
return CoreComm.AcquireSubfilePath(child.Attributes["name"].Value);
}
}
}
//every rom requests this byuu homemade rom //not found.. what to do? (every rom will get here when msu1.rom is requested)
if (hint == "msu1.rom") return ""; return "";
}
//build romfilename //build romfilename
string test = Path.Combine(CoreComm.SNES_FirmwaresPath ?? "", hint); string test = Path.Combine(CoreComm.SNES_FirmwaresPath ?? "", hint);
@ -143,6 +166,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
} }
public LibsnesApi api; public LibsnesApi api;
System.Xml.XmlDocument romxml;
public LibsnesCore(CoreComm comm) public LibsnesCore(CoreComm comm)
{ {
@ -155,7 +179,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
LibsnesApi.snes_trace_t tracecb; LibsnesApi.snes_trace_t tracecb;
LibsnesApi.snes_audio_sample_t soundcb; LibsnesApi.snes_audio_sample_t soundcb;
public void Load(GameInfo game, byte[] romData, byte[] sgbRomData, bool DeterministicEmulation) public void Load(GameInfo game, byte[] romData, byte[] sgbRomData, bool DeterministicEmulation, byte[] xmlData)
{ {
ScanlineHookManager = new MyScanlineHookManager(this); ScanlineHookManager = new MyScanlineHookManager(this);
@ -181,12 +205,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
InitAudio(); InitAudio();
//strip header //strip header
if ((romData.Length & 0x7FFF) == 512) if(romData != null)
{ if ((romData.Length & 0x7FFF) == 512)
var newData = new byte[romData.Length - 512]; {
Array.Copy(romData, 512, newData, 0, newData.Length); var newData = new byte[romData.Length - 512];
romData = newData; Array.Copy(romData, 512, newData, 0, newData.Length);
} romData = newData;
}
if (game["SGB"]) if (game["SGB"])
{ {
@ -197,8 +222,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
} }
else else
{ {
//we may need to get some information out of the cart, even during the following bootup/load process
if (xmlData != null)
{
romxml = new System.Xml.XmlDocument();
romxml.Load(new MemoryStream(xmlData));
//bsnes wont inspect the xml to load the necessary sfc file.
//so, we have to do that here and pass it in as the romData :/
if (romxml["cartridge"] != null && romxml["cartridge"]["rom"] != null)
romData = File.ReadAllBytes(CoreComm.AcquireSubfilePath(romxml["cartridge"]["rom"].Attributes["name"].Value));
else
throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file");
}
SystemId = "SNES"; SystemId = "SNES";
if (!api.snes_load_cartridge_normal(null, romData)) if (!api.snes_load_cartridge_normal(xmlData, romData))
throw new Exception("snes_load_cartridge_normal() failed"); throw new Exception("snes_load_cartridge_normal() failed");
} }
@ -822,14 +861,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
{ {
MemoryDomains = new List<MemoryDomain>(); MemoryDomains = new List<MemoryDomain>();
var romDomain = new MemoryDomain("CARTROM", romData.Length, Endian.Little, if (romData != null)
(addr) => romData[addr], {
(addr, value) => romData[addr] = value); var romDomain = new MemoryDomain("CARTROM", romData.Length, Endian.Little,
(addr) => romData[addr],
(addr, value) => romData[addr] = value);
MemoryDomains.Add(romDomain);
}
MainMemory = MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, Endian.Little); MainMemory = MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, Endian.Little);
MemoryDomains.Add(romDomain);
//someone needs to comprehensively address these in SGB mode, and go hook them up in the gameboy core //someone needs to comprehensively address these in SGB mode, and go hook them up in the gameboy core
if (!IsSGB) if (!IsSGB)

View File

@ -1,4 +1,6 @@
using System.Text; using System;
using System.IO;
using System.Text;
namespace BizHawk namespace BizHawk
{ {
public class CoreComm public class CoreComm
@ -15,6 +17,8 @@ namespace BizHawk
public string SNES_FirmwaresPath; public string SNES_FirmwaresPath;
public string C64_FirmwaresPath; public string C64_FirmwaresPath;
public Func<string, string> AcquireSubfilePath;
public string SNES_ExePath; public string SNES_ExePath;
public string SNES_Profile; public string SNES_Profile;
public bool SNES_UseRingBuffer; public bool SNES_UseRingBuffer;

View File

@ -1793,7 +1793,7 @@ namespace BizHawk.MultiClient
if (path == null) return false; if (path == null) return false;
using (var file = new HawkFile()) using (var file = new HawkFile())
{ {
string[] romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL" }; string[] romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML" };
//lets not use this unless we need to //lets not use this unless we need to
//file.NonArchiveExtensions = romExtensions; //file.NonArchiveExtensions = romExtensions;
@ -1927,6 +1927,17 @@ namespace BizHawk.MultiClient
rom = new RomGame(file); rom = new RomGame(file);
game = rom.GameInfo; game = rom.GameInfo;
bool isXml = false;
//right now, xml is always snes.
//later, we may need to inspect the XML ourselves to dispatch it to the correct system (if any other systems ever use xml...)
if (file.Extension.ToLower() == ".xml")
{
game.System = "SNES";
isXml = true;
}
RETRY: RETRY:
switch (game.System) switch (game.System)
{ {
@ -1934,9 +1945,20 @@ namespace BizHawk.MultiClient
{ {
game.System = "SNES"; game.System = "SNES";
nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile); nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile);
//this isnt completely correct. might need to deal with the archive somehow.
//once done, code should be factored out to be useful in other platforms as well
//BUT!!! right now bsnes needs to open the file itself. lame.
//nextComm.AcquireSubfile = (subpath) =>
// File.OpenRead(Path.Combine(Path.GetDirectoryName(path),subpath));
nextComm.AcquireSubfilePath = (subpath) =>
Path.Combine(Path.GetDirectoryName(path),subpath);
var snes = new LibsnesCore(nextComm); var snes = new LibsnesCore(nextComm);
nextEmulator = snes; nextEmulator = snes;
snes.Load(game, rom.FileData, null, deterministicemulation); byte[] romData = isXml?null:rom.FileData;
byte[] xmlData = isXml?rom.FileData:null;
snes.Load(game, romData, null, deterministicemulation, xmlData);
} }
break; break;
case "SMS": case "SMS":
@ -2081,7 +2103,7 @@ namespace BizHawk.MultiClient
var snes = new LibsnesCore(nextComm); var snes = new LibsnesCore(nextComm);
nextEmulator = snes; nextEmulator = snes;
game.FirmwareHash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(sgbrom)); game.FirmwareHash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(sgbrom));
snes.Load(game, rom.FileData, sgbrom, deterministicemulation); snes.Load(game, rom.FileData, sgbrom, deterministicemulation, null);
} }
} }
//} //}
@ -3596,11 +3618,11 @@ namespace BizHawk.MultiClient
if (INTERIM) if (INTERIM)
{ {
ofd.Filter = FormatFilter( ofd.Filter = FormatFilter(
"Rom Files", "*.nes;*.fds;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.cue;*.exe;*.gb;*.gbc;*.gen;*.md;*.col;.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.sgb;%ARCH%", "Rom Files", "*.nes;*.fds;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.cue;*.exe;*.gb;*.gbc;*.gen;*.md;*.col;.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.sgb;*.xml;%ARCH%",
"Music Files", "*.psf;*.sid", "Music Files", "*.psf;*.sid",
"Disc Images", "*.cue", "Disc Images", "*.cue",
"NES", "*.nes;*.fds;%ARCH%", "NES", "*.nes;*.fds;%ARCH%",
"Super NES", "*.smc;*.sfc;%ARCH%", "Super NES", "*.smc;*.sfc;*.xml;%ARCH%",
"Master System", "*.sms;*.gg;*.sg;%ARCH%", "Master System", "*.sms;*.gg;*.sg;%ARCH%",
"PC Engine", "*.pce;*.sgx;*.cue;%ARCH%", "PC Engine", "*.pce;*.sgx;*.cue;%ARCH%",
"TI-83", "*.rom;%ARCH%", "TI-83", "*.rom;%ARCH%",
@ -3621,10 +3643,10 @@ namespace BizHawk.MultiClient
else else
{ {
ofd.Filter = FormatFilter( ofd.Filter = FormatFilter(
"Rom Files", "*.nes;*.fds;*.sms;*.gg;*.sg;*.gb;*.gbc;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.smc;*.sfc;*.a26;*.a78;*.col;*.rom;*.cue;*.sgb;%ARCH%", "Rom Files", "*.nes;*.fds;*.sms;*.gg;*.sg;*.gb;*.gbc;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.smc;*.sfc;*.a26;*.a78;*.col;*.rom;*.cue;*.sgb;*.xml;%ARCH%",
"Disc Images", "*.cue", "Disc Images", "*.cue",
"NES", "*.nes;*.fds;%ARCH%", "NES", "*.nes;*.fds;%ARCH%",
"Super NES", "*.smc;*.sfc;%ARCH%", "Super NES", "*.smc;*.sfc;*.xml;%ARCH%",
"Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%", "Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%",
"Master System", "*.sms;*.gg;*.sg;%ARCH%", "Master System", "*.sms;*.gg;*.sg;%ARCH%",
"PC Engine", "*.pce;*.sgx;*.cue;%ARCH%", "PC Engine", "*.pce;*.sgx;*.cue;%ARCH%",

View File

@ -507,11 +507,16 @@ void RunMessageLoop()
case eMessage_snes_load_cartridge_normal: case eMessage_snes_load_cartridge_normal:
{ {
std::string xml = ReadPipeString(); Blob xml = ReadPipeBlob();
Blob rom_data = ReadPipeBlob(); xml.push_back(0); //make sure the xml is null terminated
const char* xmlptr = NULL; const char* xmlptr = NULL;
if(xml != "") xmlptr = xml.c_str(); if(xml.size() != 1) xmlptr = &xml[0];
bool ret = snes_load_cartridge_normal(xmlptr,(unsigned char*)&rom_data[0],rom_data.size());
Blob rom_data = ReadPipeBlob();
const unsigned char* rom_ptr = NULL;
if(rom_data.size() != 0) rom_ptr = (unsigned char*)&rom_data[0];
bool ret = snes_load_cartridge_normal(xmlptr,rom_ptr,rom_data.size());
WritePipe(eMessage_Complete); WritePipe(eMessage_Complete);
WritePipe((char)(ret?1:0)); WritePipe((char)(ret?1:0));
break; break;