implement GB CDL
This commit is contained in:
parent
bef877365c
commit
10bbf6e9d0
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -79,6 +79,10 @@ public:
|
|||
memory.setExecCallback(callback);
|
||||
}
|
||||
|
||||
void setCDCallback(CDCallback cdc) {
|
||||
memory.setCDCallback(cdc);
|
||||
}
|
||||
|
||||
void setTraceCallback(void (*callback)(void *)) {
|
||||
tracecallback = callback;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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.
Loading…
Reference in New Issue