add system bus memory domain to gambatte
in order to guarantee correct resolution of mappings and mmio every time, all calls go straight to the core and are not cached this makes this domain slower in performance than the other ones. it can also be more difficult to use in some cases because you have to resolve mappings that you may not care about. there is also the possibility of side-effects on reads, although i do not believe that this actually happens in any situations. still, use at your own risk.
This commit is contained in:
parent
1c4b218289
commit
12d06a2c94
|
@ -334,38 +334,46 @@ namespace BizHawk.Emulation.Consoles.GB
|
|||
IntPtr data = IntPtr.Zero;
|
||||
int length = 0;
|
||||
|
||||
int i = (int)which;
|
||||
|
||||
if (!LibGambatte.gambatte_getmemoryarea(GambatteState, which, ref data, ref length))
|
||||
throw new Exception("gambatte_getmemoryarea() failed!");
|
||||
|
||||
// if length == 0, it's an empty block; (usually rambank on some carts); that's ok
|
||||
// TODO: when length == 0, should we simply not add the memory domain at all?
|
||||
if (data == IntPtr.Zero && length > 0)
|
||||
throw new Exception("bad return from gambatte_getmemoryarea()");
|
||||
|
||||
|
||||
MemoryRefreshers[i] = new MemoryRefresher(data, length);
|
||||
var refresher = new MemoryRefresher(data, length);
|
||||
|
||||
MemoryDomains[i] = new MemoryDomain(which.ToString(), length, Endian.Little, MemoryRefreshers[i].Peek, MemoryRefreshers[i].Poke);
|
||||
MemoryRefreshers.Add(refresher);
|
||||
|
||||
MemoryDomains.Add(new MemoryDomain(which.ToString(), length, Endian.Little, refresher.Peek, refresher.Poke));
|
||||
}
|
||||
|
||||
void InitMemoryDomains()
|
||||
{
|
||||
MemoryDomains = new MemoryDomain[6];
|
||||
MemoryRefreshers = new MemoryRefresher[6];
|
||||
MemoryDomains = new List<MemoryDomain>();
|
||||
MemoryRefreshers = new List<MemoryRefresher>();
|
||||
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.cartram);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.wram);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.rom);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.vram);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.wram);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.cartram);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.oam);
|
||||
CreateMemoryDomain(LibGambatte.MemoryAreas.hram);
|
||||
|
||||
// fixme: other code brokenly assumes that MainMemory is MemoryDomains[0]
|
||||
// (here, we'd want it to be MemoryDomains[2])
|
||||
var tmp = MemoryDomains[2];
|
||||
MemoryDomains[2] = MemoryDomains[0];
|
||||
MemoryDomains[0] = tmp;
|
||||
// also add a special memory domain for the system bus, where calls get sent directly to the core each time
|
||||
|
||||
MemoryDomains.Add(new MemoryDomain("sysbus", 65536, Endian.Little,
|
||||
delegate(int addr)
|
||||
{
|
||||
return LibGambatte.gambatte_cpuread(GambatteState, (ushort)addr);
|
||||
},
|
||||
delegate(int addr, byte val)
|
||||
{
|
||||
LibGambatte.gambatte_cpuwrite(GambatteState, (ushort)addr, val);
|
||||
}));
|
||||
|
||||
// this is the wram area and matches the bizhawk convention for what MainMemory means
|
||||
MainMemory = MemoryDomains[0];
|
||||
}
|
||||
|
||||
|
@ -373,7 +381,7 @@ namespace BizHawk.Emulation.Consoles.GB
|
|||
|
||||
public MemoryDomain MainMemory { get; private set; }
|
||||
|
||||
MemoryRefresher[] MemoryRefreshers;
|
||||
List <MemoryRefresher> MemoryRefreshers;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -283,6 +283,7 @@ namespace BizHawk.Emulation.Consoles.GB
|
|||
|
||||
/// <summary>
|
||||
/// get pointer to internal memory areas, for debugging purposes
|
||||
/// so long as you don't write to it, you should be completely sync-safe
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="which">which memory area to access</param>
|
||||
|
@ -291,5 +292,25 @@ namespace BizHawk.Emulation.Consoles.GB
|
|||
/// <returns>success</returns>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool gambatte_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length);
|
||||
|
||||
/// <summary>
|
||||
/// read a single byte from the cpu bus. this includes all ram, rom, mmio, etc, as it is visible to the cpu (including mappers).
|
||||
/// while there is no cycle cost to these reads, there may be other side effects! use at your own risk.
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointer</param>
|
||||
/// <param name="addr">system bus address</param>
|
||||
/// <returns>byte read</returns>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern byte gambatte_cpuread(IntPtr core, ushort addr);
|
||||
|
||||
/// <summary>
|
||||
/// write a single byte to the cpu bus. while there is no cycle cost to these writes, there can be quite a few side effects.
|
||||
/// use at your own risk.
|
||||
/// </summary>
|
||||
/// <param name="core">opaque state pointe</param>
|
||||
/// <param name="addr">system bus address</param>
|
||||
/// <param name="val">byte to write</param>
|
||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void gambatte_cpuwrite(IntPtr core, ushort addr, byte val);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -147,6 +147,10 @@ public:
|
|||
* @param codes Game Shark codes in format 01HHHHHH;01HHHHHH;... where H is [0-9]|[A-F]
|
||||
*/
|
||||
void setGameShark(const std::string &codes);
|
||||
|
||||
unsigned char ExternalRead(unsigned short addr);
|
||||
void ExternalWrite(unsigned short addr, unsigned char val);
|
||||
|
||||
|
||||
private:
|
||||
struct Priv;
|
||||
|
|
|
@ -192,3 +192,15 @@ __declspec(dllexport) int gambatte_getmemoryarea(void *core, int which, unsigned
|
|||
GB *g = (GB *) core;
|
||||
return g->getMemoryArea(which, data, length);
|
||||
}
|
||||
|
||||
__declspec(dllexport) unsigned char gambatte_cpuread(void *core, unsigned short addr)
|
||||
{
|
||||
GB *g = (GB *) core;
|
||||
return g->ExternalRead(addr);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void gambatte_cpuwrite(void *core, unsigned short addr, unsigned char val)
|
||||
{
|
||||
GB *g = (GB *) core;
|
||||
g->ExternalWrite(addr, val);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@ extern "C"
|
|||
__declspec(dllexport) void gambatte_setgameshark(void *core, const char *codes);
|
||||
|
||||
__declspec(dllexport) int gambatte_getmemoryarea(void *core, int which, unsigned char **data, int *length);
|
||||
|
||||
__declspec(dllexport) unsigned char gambatte_cpuread(void *core, unsigned short addr);
|
||||
|
||||
__declspec(dllexport) void gambatte_cpuwrite(void *core, unsigned short addr, unsigned char val);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -95,6 +95,10 @@ public:
|
|||
|
||||
void setGameGenie(const std::string &codes) { memory.setGameGenie(codes); }
|
||||
void setGameShark(const std::string &codes) { memory.setGameShark(codes); }
|
||||
|
||||
unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); }
|
||||
void ExternalWrite(unsigned short addr, unsigned char val) { memory.write(addr, val, cycleCounter_); }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -149,6 +149,19 @@ bool GB::getMemoryArea(int which, unsigned char **data, int *length) {
|
|||
return false;
|
||||
}
|
||||
|
||||
unsigned char GB::ExternalRead(unsigned short addr) {
|
||||
if (p_->cpu.loaded())
|
||||
return p_->cpu.ExternalRead(addr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GB::ExternalWrite(unsigned short addr, unsigned char val) {
|
||||
if (p_->cpu.loaded())
|
||||
p_->cpu.ExternalWrite(addr, val);
|
||||
}
|
||||
|
||||
|
||||
void GB::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
|
||||
p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue