Debugger: Lua - Support small arrays in getState/setState

This is needed to e.g have access to the GBA CPU's registers, etc.
Also hid some internal GBA state from getState to improve performance
This commit is contained in:
Sour 2025-04-15 22:43:52 +09:00
parent fb2a9c7f6f
commit a17a97fb7b
8 changed files with 113 additions and 91 deletions

View File

@ -1075,7 +1075,7 @@ int LuaApi::GetState(lua_State *lua)
Serializer s(0, true, SerializeFormat::Map);
s.Stream(*_emu->GetConsole().get(), "", -1);
//Add some more Lua-specific values
uint32_t frameCount = _emu->GetFrameCount();
uint32_t masterClock = _emu->GetMasterClock();
@ -1093,12 +1093,12 @@ int LuaApi::GetState(lua_State *lua)
lua_newtable(lua);
for(auto& kvp : values) {
lua_pushstring(lua, kvp.first.c_str());
lua_pushlstring(lua, kvp.first.c_str(), kvp.first.size());
switch(kvp.second.Format) {
case SerializeMapValueFormat::Integer: lua_pushinteger(lua, kvp.second.Value.Integer); break;
case SerializeMapValueFormat::Double: lua_pushnumber(lua, kvp.second.Value.Double); break;
case SerializeMapValueFormat::Bool: lua_pushboolean(lua, kvp.second.Value.Bool); break;
case SerializeMapValueFormat::String: lua_pushstring(lua, kvp.second.StringValue.c_str()); break;
case SerializeMapValueFormat::String: lua_pushlstring(lua, kvp.second.StringValue.c_str(), kvp.second.StringValue.size()); break;
}
lua_settable(lua, -3);
}
@ -1107,7 +1107,6 @@ int LuaApi::GetState(lua_State *lua)
int LuaApi::SetState(lua_State* lua)
{
LuaCallHelper l(lua);
lua_settop(lua, 1);
luaL_checktype(lua, -1, LUA_TTABLE);
@ -1146,17 +1145,5 @@ int LuaApi::SetState(lua_State* lua)
s.LoadFromMap(map);
s.Stream(*_emu->GetConsole().get(), "", -1);
unordered_map<string, SerializeMapValue>& values = s.GetMapValues();
lua_newtable(lua);
for(auto& kvp : values) {
lua_pushstring(lua, kvp.first.c_str());
switch(kvp.second.Format) {
case SerializeMapValueFormat::Integer: lua_pushinteger(lua, kvp.second.Value.Integer); break;
case SerializeMapValueFormat::Double: lua_pushnumber(lua, kvp.second.Value.Double); break;
case SerializeMapValueFormat::Bool: lua_pushboolean(lua, kvp.second.Value.Bool); break;
}
lua_settable(lua, -3);
}
return 1;
return 0;
}

View File

@ -552,17 +552,19 @@ void GbaApu::Serialize(Serializer& s)
SV(_state.Bias);
SV(_state.SamplingRate);
SV(_prevClockCount);
SV(_enabledChannels);
SV(_leftSample);
SV(_rightSample);
if(s.GetFormat() != SerializeFormat::Map) {
SV(_prevClockCount);
SV(_enabledChannels);
SV(_leftSample);
SV(_rightSample);
SV(_fifo[0]);
SV(_fifo[1]);
SV(_filterL);
SV(_filterR);
SV(_fifo[0]);
SV(_fifo[1]);
SV(_filterL);
SV(_filterR);
SV(_powerOnCycle);
SV(_powerOnCycle);
}
SV(_square1);
SV(_square2);

View File

@ -331,35 +331,39 @@ void GbaDmaController::WriteRegister(uint32_t addr, uint8_t value)
void GbaDmaController::Serialize(Serializer& s)
{
for(int i = 0; i < 4; i++) {
SVI(_state.Ch[i].ReadValue);
SVI(_state.Ch[i].Control);
SVI(_state.Ch[i].Destination);
SVI(_state.Ch[i].Source);
SVI(_state.Ch[i].Length);
SVI(_state.Ch[i].DestLatch);
SVI(_state.Ch[i].SrcLatch);
SVI(_state.Ch[i].LenLatch);
if(s.GetFormat() != SerializeFormat::Map) {
SVI(_state.Ch[i].DestLatch);
SVI(_state.Ch[i].SrcLatch);
SVI(_state.Ch[i].LenLatch);
SVI(_state.Ch[i].Control);
SVI(_state.Ch[i].ReadValue);
SVI(_state.Ch[i].DestMode);
SVI(_state.Ch[i].SrcMode);
SVI(_state.Ch[i].DestMode);
SVI(_state.Ch[i].SrcMode);
SVI(_state.Ch[i].Repeat);
SVI(_state.Ch[i].WordTransfer);
SVI(_state.Ch[i].DrqMode);
SVI(_state.Ch[i].Repeat);
SVI(_state.Ch[i].WordTransfer);
SVI(_state.Ch[i].DrqMode);
SVI(_state.Ch[i].Trigger);
SVI(_state.Ch[i].IrqEnabled);
SVI(_state.Ch[i].Enabled);
SVI(_state.Ch[i].Active);
SVI(_state.Ch[i].Trigger);
SVI(_state.Ch[i].IrqEnabled);
SVI(_state.Ch[i].Enabled);
SVI(_state.Ch[i].Active);
SVI(_state.Ch[i].Pending);
SVI(_state.Ch[i].Pending);
}
}
SV(_dmaRunning);
SV(_dmaPending);
SV(_dmaActiveChannel);
SV(_dmaStartDelay);
if(s.GetFormat() != SerializeFormat::Map) {
SV(_dmaRunning);
SV(_dmaPending);
SV(_dmaActiveChannel);
SV(_dmaStartDelay);
}
}

View File

@ -867,36 +867,42 @@ int64_t GbaMemoryManager::GetRelativeAddress(AddressInfo& absAddress)
void GbaMemoryManager::Serialize(Serializer& s)
{
SV(_masterClock);
SV(_hasPendingUpdates);
SV(_hasPendingLateUpdates);
SV(_pendingIrqSource);
SV(_pendingIrqSourceDelay);
SV(_haltModeUsed);
SV(_biosLocked);
SV(_state.IE);
SV(_state.IF);
SV(_state.IME);
SV(_state.NewIE);
SV(_state.NewIF);
SV(_state.NewIME);
SV(_state.WaitControl);
SVArray(_state.PrgWaitStates0, 2);
SVArray(_state.PrgWaitStates1, 2);
SVArray(_state.PrgWaitStates2, 2);
SV(_state.SramWaitStates);
SV(_state.PrefetchEnabled);
SV(_state.IME);
SV(_state.IrqUpdateCounter);
SV(_state.IrqPending);
SV(_state.IrqLine);
SV(_state.BusLocked);
SV(_state.StopMode);
SV(_state.PostBootFlag);
SVArray(_state.BootRomOpenBus, 4);
SVArray(_state.InternalOpenBus, 4);
SVArray(_state.IwramOpenBus, 4);
if(s.GetFormat() != SerializeFormat::Map) {
SV(_hasPendingUpdates);
SV(_hasPendingLateUpdates);
SV(_pendingIrqSource);
SV(_pendingIrqSourceDelay);
SV(_haltModeUsed);
SV(_biosLocked);
SVArray(_state.BootRomOpenBus, 4);
SVArray(_state.InternalOpenBus, 4);
SVArray(_state.IwramOpenBus, 4);
SVArray(_state.PrgWaitStates0, 2);
SVArray(_state.PrgWaitStates1, 2);
SVArray(_state.PrgWaitStates2, 2);
SV(_state.SramWaitStates);
SV(_state.IrqUpdateCounter);
SV(_state.IrqPending);
SV(_state.IrqLine);
SV(_state.BusLocked);
SV(_state.StopMode);
SV(_state.PostBootFlag);
}
if(!s.IsSaving()) {
GenerateWaitStateLut();

View File

@ -226,6 +226,10 @@ public:
void Serialize(Serializer& s) override
{
if(s.GetFormat() == SerializeFormat::Map) {
return;
}
SV(_state.ClockCounter);
SV(_state.ReadAddr);
SV(_state.PrefetchAddr);

View File

@ -177,18 +177,8 @@ public:
void Serialize(Serializer& s) override
{
SV(_state.StartMasterClock);
SV(_state.EndMasterClock);
SV(_state.IrqMasterClock);
SVArray(_state.Data, 4);
SV(_state.Control);
SV(_state.InternalShiftClock);
SV(_state.InternalShiftClockSpeed2MHz);
SV(_state.Active);
SV(_state.TransferWord);
SV(_state.IrqEnabled);
SVArray(_state.Data, 4);
SV(_state.SendData);
SV(_state.Mode);
@ -196,5 +186,17 @@ public:
SV(_state.JoyReceive);
SV(_state.JoySend);
SV(_state.JoyStatus);
if(s.GetFormat() != SerializeFormat::Map) {
SV(_state.StartMasterClock);
SV(_state.EndMasterClock);
SV(_state.IrqMasterClock);
SV(_state.InternalShiftClock);
SV(_state.InternalShiftClockSpeed2MHz);
SV(_state.Active);
SV(_state.TransferWord);
SV(_state.IrqEnabled);
}
}
};

View File

@ -140,16 +140,22 @@ void GbaTimer::Serialize(Serializer& s)
{
for(int i = 0; i < 4; i++) {
SVI(_state.Timer[i].ReloadValue);
SVI(_state.Timer[i].NewReloadValue);
SVI(_state.Timer[i].Control);
SVI(_state.Timer[i].PrescaleMask);
SVI(_state.Timer[i].Timer);
SVI(_state.Timer[i].EnableDelay);
SVI(_state.Timer[i].WritePending);
SVI(_state.Timer[i].Mode);
SVI(_state.Timer[i].IrqEnabled);
SVI(_state.Timer[i].Enabled);
SVI(_state.Timer[i].ProcessTimer);
if(s.GetFormat() != SerializeFormat::Map) {
SVI(_state.Timer[i].PrescaleMask);
SVI(_state.Timer[i].Mode);
SVI(_state.Timer[i].IrqEnabled);
SVI(_state.Timer[i].Enabled);
SVI(_state.Timer[i].ProcessTimer);
SVI(_state.Timer[i].NewReloadValue);
SVI(_state.Timer[i].WritePending);
SVI(_state.Timer[i].EnableDelay);
}
}
if(s.GetFormat() != SerializeFormat::Map) {
SV(_hasPendingTimers);
}
SV(_hasPendingTimers);
}

View File

@ -134,7 +134,7 @@ private:
_mapValues.try_emplace(key, SerializeMapValueFormat::Double, (double)value);
} else if constexpr(std::is_same<T, string>::value) {
_mapValues.try_emplace(key, value);
}
}
}
template<typename T>
@ -206,7 +206,7 @@ private:
__forceinline void CheckDuplicateKey(string& key)
{
#ifndef MESENRELEASE
#ifdef DEBUG
if(!_usedKeys.emplace(key).second) {
throw std::runtime_error("Duplicate key");
}
@ -345,14 +345,25 @@ public:
template<typename T> void StreamArray(T* arrayValues, uint32_t elementCount, const char* name)
{
if(_format == SerializeFormat::Map) {
return;
}
string key = GetKey(name, -1);
CheckDuplicateKey(key);
if(_format == SerializeFormat::Map) {
if(elementCount <= 64) {
//Only save/load small arrays (otherwise this would end up serializing work/save ram, etc.)
for(uint32_t i = 0; i < elementCount; i++) {
string elemKey = key + std::to_string(i);
if(_saving) {
WriteMapFormat(elemKey, arrayValues[i]);
} else {
ReadMapFormat(elemKey, arrayValues[i]);
}
}
}
return;
}
//TODO detect big vs little endian
constexpr bool isBigEndian = false;
if(_saving) {