implement GB CDL

This commit is contained in:
zeromus 2015-10-26 19:16:38 -05:00
parent bef877365c
commit 10bbf6e9d0
12 changed files with 238 additions and 33 deletions

View File

@ -6,6 +6,8 @@ using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Components.H6280;
using BizHawk.Emulation.Cores.PCEngine;
@ -17,7 +19,7 @@ namespace BizHawk.Client.EmuHawk
public partial class PCECDL : Form, IToolFormAutoConfig
{
[RequiredService]
private PCEngine _emu { get; set; }
public IEmulator _emu { get; private set; }
private CodeDataLog _cdl;
private RecentFiles _recent_fld = new RecentFiles();
@ -59,9 +61,18 @@ namespace BizHawk.Client.EmuHawk
public void Restart()
{
LoggingActiveCheckbox.Checked = _emu.Cpu.CDLLoggingActive;
_cdl = _emu.Cpu.CDL;
_emu.InitCDLMappings();
if (_emu.SystemId == "PCE")
{
var pce = _emu as PCEngine;
LoggingActiveCheckbox.Checked = pce.Cpu.CDLLoggingActive;
_cdl = pce.Cpu.CDL;
pce.InitCDLMappings();
}
else if(_emu.SystemId == "GB")
{
var gambatte = _emu as Gameboy;
_cdl = gambatte.CDL;
}
UpdateDisplay();
}
@ -116,17 +127,32 @@ namespace BizHawk.Client.EmuHawk
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
var newCDL = CodeDataLog.Load(fs);
if (!newCDL.CheckConsistency(_emu.Cpu.Mappings))
//this check may be inadequate in the future
if(newCDL.SubType != _emu.SystemId)
throw new InvalidDataException("File is a CDL file of the wrong target core (like, a different game console)!");
_cdl = newCDL;
if (_emu.SystemId == "PCE")
{
MessageBox.Show(this, "CDL file does not match emulator's current memory map!");
var pce = _emu as PCEngine;
var cdl_pce = newCDL as CodeDataLog_PCE;
if (!cdl_pce.CheckConsistency(pce.Cpu.Mappings))
{
MessageBox.Show(this, "CDL file does not match emulator's current memory map!");
return;
}
pce.Cpu.CDL = _cdl;
}
else
else if (_emu.SystemId == "GB")
{
_cdl = newCDL;
_emu.Cpu.CDL = _cdl;
UpdateDisplay();
var gambatte = _emu as Gameboy;
var cdl_gb = newCDL as CodeDataLog_GB;
gambatte.CDL = cdl_gb;
}
}
UpdateDisplay();
}
#region Events
@ -154,8 +180,21 @@ namespace BizHawk.Client.EmuHawk
var result = MessageBox.Show(this, "OK to create new CDL?", "Query", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
_cdl = CodeDataLog.Create(_emu.Cpu.Mappings);
_emu.Cpu.CDL = _cdl;
if (_emu.SystemId == "PCE")
{
var pce = _emu as PCEngine;
_cdl = CodeDataLog_PCE.Create(pce.Cpu.Mappings);
pce.Cpu.CDL = _cdl;
}
else if (_emu.SystemId == "GB")
{
var gambatte = _emu as Gameboy;
var memd = gambatte.AsMemoryDomains();
var cdl_gb = CodeDataLog_GB.Create(memd);
gambatte.CDL = cdl_gb;
_cdl = cdl_gb;
}
UpdateDisplay();
}
}
@ -173,22 +212,7 @@ namespace BizHawk.Client.EmuHawk
if (file != null)
{
using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
{
var newCDL = CodeDataLog.Load(fs);
if (!newCDL.CheckConsistency(_emu.Cpu.Mappings))
{
MessageBox.Show(this, "CDL file does not match emulator's current memory map!");
}
else
{
_cdl = newCDL;
_emu.Cpu.CDL = _cdl;
UpdateDisplay();
_recent.Add(file.FullName);
_currentFileName = file.FullName;
}
}
LoadFile(file.FullName);
}
}
}
@ -314,7 +338,14 @@ namespace BizHawk.Client.EmuHawk
LoggingActiveCheckbox.Checked = false;
}
_emu.Cpu.CDLLoggingActive = LoggingActiveCheckbox.Checked;
if (_emu.SystemId == "PCE")
{
//set a special flag on the CPU to indicate CDL is running, maybe it's faster, who knows
var pce = _emu as PCEngine;
pce.Cpu.CDLLoggingActive = LoggingActiveCheckbox.Checked;
}
_cdl.Active = LoggingActiveCheckbox.Checked;
}
private void PCECDL_DragEnter(object sender, DragEventArgs e)

View File

@ -173,6 +173,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
TimeCallback = new LibGambatte.RTCCallback(GetCurrentTime);
LibGambatte.gambatte_setrtccallback(GambatteState, TimeCallback);
//seems to have near negligable speed impact. lets always use it, for now.
//someone who cares can make it controllable
CDCallback = new LibGambatte.CDCallback(CDCallbackProc);
LibGambatte.gambatte_setcdcallback(GambatteState, CDCallback);
NewSaveCoreSetBuff();
}
catch
@ -182,6 +187,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
}
}
public CodeDataLog_GB CDL;
LibGambatte.CDCallback CDCallback;
void CDCallbackProc(int addr, LibGambatte.CDLog_AddrType addrtype, LibGambatte.CDLog_Flags flags)
{
if (CDL == null) return;
if (!CDL.Active) return;
string key;
switch (addrtype)
{
case LibGambatte.CDLog_AddrType.ROM: key = "ROM"; break;
case LibGambatte.CDLog_AddrType.HRAM: key = "HRAM"; break;
case LibGambatte.CDLog_AddrType.WRAM: key = "WRAM"; break;
case LibGambatte.CDLog_AddrType.CartRAM: key = "CartRAM"; break;
default: throw new InvalidOperationException("Juniper lightbulb proxy");
}
CDL[key][addr] |= (byte)flags;
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
#region ALL SAVESTATEABLE STATE GOES HERE

View File

@ -34,6 +34,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
MULTICART_COMPAT = 4
}
public enum CDLog_AddrType : int
{
ROM, HRAM, WRAM, CartRAM
}
[Flags]
public enum CDLog_Flags : int
{
ExecFirst = 1,
ExecOperand = 2,
Data = 4
}
/// <summary>
/// Load ROM image.
/// </summary>
@ -161,6 +174,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MemoryCallback(uint address);
/// <summary>
/// type of the CDLogger callback
/// </summary>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CDCallback(int addr, CDLog_AddrType addrtype, CDLog_Flags flags);
/// <summary>
/// set a callback to occur immediately BEFORE EVERY cpu read, except for opcode first byte fetches
/// </summary>
@ -185,6 +204,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void gambatte_setexeccallback(IntPtr core, MemoryCallback callback);
/// <summary>
/// set a callback whicih enables CD Logger feedback
/// </summary>
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void gambatte_setcdcallback(IntPtr core, CDCallback callback);
/// <summary>
/// type of the cpu trace callback
/// </summary>

View File

@ -28,6 +28,21 @@
namespace gambatte {
enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 };
typedef void (*CDCallback)(int32_t addr, int32_t addrtype, int32_t flags);
enum eCDLog_AddrType
{
eCDLog_AddrType_ROM, eCDLog_AddrType_HRAM, eCDLog_AddrType_WRAM, eCDLog_AddrType_CartRAM,
eCDLog_AddrType_None
};
enum eCDLog_Flags
{
eCDLog_Flags_ExecFirst = 1,
eCDLog_Flags_ExecOperand = 2,
eCDLog_Flags_Data = 4,
};
class GB {
public:
GB();
@ -88,6 +103,7 @@ public:
void setReadCallback(void (*callback)(unsigned));
void setWriteCallback(void (*callback)(unsigned));
void setExecCallback(void (*callback)(unsigned));
void setCDCallback(CDCallback);
void setTraceCallback(void (*callback)(void *));
void setScanlineCallback(void (*callback)(), int sl);
void setRTCCallback(std::uint32_t (*callback)());

View File

@ -83,6 +83,12 @@ GBEXPORT void gambatte_setexeccallback(GB *g, void (*callback)(unsigned))
g->setExecCallback(callback);
}
GBEXPORT void gambatte_setcdcallback(GB *g, CDCallback cdc)
{
g->setCDCallback(cdc);
}
GBEXPORT void gambatte_settracecallback(GB *g, void (*callback)(void *))
{
g->setTraceCallback(callback);

View File

@ -112,7 +112,8 @@ void CPU::loadState(const SaveState &state) {
#define READ(dest, addr) do { (dest) = memory.read(addr, cycleCounter); cycleCounter += 4; } while (0)
// #define PC_READ(dest, addr) do { (dest) = memory.pc_read(addr, cycleCounter); cycleCounter += 4; } while (0)
#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter, false); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
#define PC_READ_FIRST(dest) do { (dest) = memory.read_excb(PC, cycleCounter, true); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
#define FF_READ(dest, addr) do { (dest) = memory.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0)
#define WRITE(addr, data) do { memory.write(addr, data, cycleCounter); cycleCounter += 4; } while (0)
@ -518,13 +519,13 @@ void CPU::process(const unsigned long cycles) {
result[9] = H;
result[10] = L;
result[11] = skip;
PC_READ(opcode);
PC_READ_FIRST(opcode);
result[12] = opcode;
result[13] = memory.debugGetLY();
tracecallback((void *)result);
}
else {
PC_READ(opcode);
PC_READ_FIRST(opcode);
}
if (skip) {

View File

@ -79,6 +79,10 @@ public:
memory.setExecCallback(callback);
}
void setCDCallback(CDCallback cdc) {
memory.setCDCallback(cdc);
}
void setTraceCallback(void (*callback)(void *)) {
tracecallback = callback;
}

View File

@ -114,6 +114,10 @@ void GB::setExecCallback(void (*callback)(unsigned)) {
p_->cpu.setExecCallback(callback);
}
void GB::setCDCallback(CDCallback cdc) {
p_->cpu.setCDCallback(cdc);
}
void GB::setTraceCallback(void (*callback)(void *)) {
p_->cpu.setTraceCallback(callback);
}

View File

@ -29,12 +29,26 @@
namespace gambatte {
//DOOM
//enum eAddressMappingType
//{
// eAddressMappingType_ROM,
// eAddressMappingType_RAM
//};
//
//struct AddressMapping
//{
// int32_t address;
// eAddressMappingType type;
//};
class Mbc {
public:
virtual ~Mbc() {}
virtual void romWrite(unsigned P, unsigned data) = 0;
virtual void loadState(const SaveState::Mem &ss) = 0;
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
//virtual void mapAddress(AddressMapping* mapping, unsigned address) const = 0; //DOOM
template<bool isReader>void SyncState(NewState *ns)
{

View File

@ -28,6 +28,7 @@ Memory::Memory(const Interrupter &interrupter_in)
: readCallback(0),
writeCallback(0),
execCallback(0),
cdCallback(0),
getInput(0),
divLastUpdate(0),
lastOamDmaUpdate(DISABLED_TIME),

View File

@ -25,6 +25,7 @@
#include "interrupter.h"
#include "tima.h"
#include "newstate.h"
#include "gambatte.h"
namespace gambatte {
class InputGetter;
@ -37,6 +38,7 @@ class Memory {
void (*readCallback)(unsigned);
void (*writeCallback)(unsigned);
void (*execCallback)(unsigned);
CDCallback cdCallback;
unsigned (*getInput)();
unsigned long divLastUpdate;
@ -117,15 +119,78 @@ public:
return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00];
}
struct CDMapResult
{
eCDLog_AddrType type;
unsigned addr;
};
CDMapResult CDMap(const unsigned P) const
{
if(P<0x4000)
{
CDMapResult ret = { eCDLog_AddrType_ROM, P };
return ret;
}
else if(P<0x8000)
{
unsigned bank = cart.rmem(P>>12) - cart.rmem(0);
unsigned addr = P+bank;
CDMapResult ret = { eCDLog_AddrType_ROM, addr };
return ret;
}
else if(P<0xA000) {}
else if(P<0xC000)
{
if(cart.wsrambankptr())
{
//not bankable
unsigned addr = P&0x1FFF;
CDMapResult ret = { eCDLog_AddrType_CartRAM, addr };
return ret;
}
}
else if(P<0xE000)
{
unsigned bank = cart.wramdata(P >> 12 & 1) - cart.wramdata(0);
unsigned addr = (P&0xFFF)+bank;
CDMapResult ret = { eCDLog_AddrType_WRAM, addr };
return ret;
}
else if(P<0xFF80) {}
else
{
////this is just for debugging, really, it's pretty useless
//CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) };
//return ret;
}
CDMapResult ret = { eCDLog_AddrType_None };
return ret;
}
unsigned read(const unsigned P, const unsigned long cycleCounter) {
if (readCallback)
readCallback(P);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
}
unsigned read_excb(const unsigned P, const unsigned long cycleCounter) {
unsigned read_excb(const unsigned P, const unsigned long cycleCounter, bool first) {
if (execCallback)
execCallback(P);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
}
@ -147,6 +212,12 @@ public:
nontrivial_write(P, data, cycleCounter);
if (writeCallback)
writeCallback(P);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
}
}
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
@ -154,6 +225,12 @@ public:
ioamhram[P - 0xFE00] = data;
} else
nontrivial_ff_write(P, data, cycleCounter);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
}
}
unsigned long event(unsigned long cycleCounter);
@ -174,6 +251,9 @@ public:
void setExecCallback(void (*callback)(unsigned)) {
this->execCallback = callback;
}
void setCDCallback(CDCallback cdc) {
this->cdCallback = cdc;
}
void setScanlineCallback(void (*callback)(), int sl) {
display.setScanlineCallback(callback, sl);

Binary file not shown.