mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
+ Fixed VRAM read to wait until next available CPU access slot + Fixed NMI triggering on the wrong scanline on SMS + Fixed NMI issues on ColecoVision + Fixed random ram option not working properly on SG-1000 + Added "Mem access" tab to tilemap viewer to see fetch patterns
209 lines
6.3 KiB
C++
209 lines
6.3 KiB
C++
#include "pch.h"
|
|
#include "SMS/Debugger/SmsEventManager.h"
|
|
#include "SMS/SmsCpu.h"
|
|
#include "SMS/SmsVdp.h"
|
|
#include "SMS/SmsConsole.h"
|
|
#include "Shared/ColorUtilities.h"
|
|
#include "Debugger/DebugTypes.h"
|
|
#include "Debugger/Debugger.h"
|
|
#include "Debugger/DebugBreakHelper.h"
|
|
#include "Debugger/BaseEventManager.h"
|
|
|
|
SmsEventManager::SmsEventManager(Debugger* debugger, SmsConsole* console, SmsCpu* cpu, SmsVdp* vdp)
|
|
{
|
|
_debugger = debugger;
|
|
_console = console;
|
|
_cpu = cpu;
|
|
_vdp = vdp;
|
|
|
|
_ppuBuffer = new uint16_t[256*240];
|
|
memset(_ppuBuffer, 0, 256*240 * sizeof(uint16_t));
|
|
}
|
|
|
|
SmsEventManager::~SmsEventManager()
|
|
{
|
|
delete[] _ppuBuffer;
|
|
}
|
|
|
|
void SmsEventManager::AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId)
|
|
{
|
|
DebugEventInfo evt = {};
|
|
evt.Type = type;
|
|
evt.Flags = (uint32_t)EventFlags::ReadWriteOp;
|
|
evt.Operation = operation;
|
|
evt.Scanline = _vdp->GetScanline();
|
|
evt.Cycle = _vdp->GetCycle();
|
|
evt.BreakpointId = breakpointId;
|
|
evt.DmaChannel = -1;
|
|
|
|
if(evt.Operation.Type == MemoryOperationType::Write) {
|
|
switch(evt.Operation.Address & 0xC1) {
|
|
case 0x80:
|
|
if(_vdp->GetState().CodeReg == 3) {
|
|
evt.Flags |= (uint32_t)EventFlags::SmsVdpPaletteWrite | (uint32_t)EventFlags::WithTargetMemory;
|
|
evt.TargetMemory.MemType = MemoryType::SmsPaletteRam;
|
|
evt.TargetMemory.Type = operation.Type;
|
|
evt.TargetMemory.Value = operation.Value;
|
|
|
|
if(_console->GetModel() == SmsModel::GameGear) {
|
|
evt.TargetMemory.Address = _vdp->GetState().AddressReg & 0x3F;
|
|
} else {
|
|
evt.TargetMemory.Address = _vdp->GetState().AddressReg & 0x1F;
|
|
}
|
|
} else {
|
|
evt.Flags |= (uint32_t)EventFlags::WithTargetMemory;
|
|
evt.TargetMemory.MemType = MemoryType::SmsVideoRam;
|
|
evt.TargetMemory.Value = operation.Value;
|
|
evt.TargetMemory.Type = operation.Type;
|
|
evt.TargetMemory.Address = _vdp->GetState().AddressReg;
|
|
}
|
|
break;
|
|
|
|
case 0x81:
|
|
if(_vdp->GetState().ControlPortMsbToggle) {
|
|
evt.Flags |= (uint32_t)EventFlags::RegSecondWrite;
|
|
if((evt.Operation.Value >> 6) == 2) {
|
|
//Value written to the register
|
|
evt.RegisterId = _vdp->GetState().AddressReg & 0xFF;
|
|
}
|
|
} else {
|
|
evt.Flags |= (uint32_t)EventFlags::RegFirstWrite;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
evt.ProgramCounter = _debugger->GetProgramCounter(CpuType::Sms, true);
|
|
_debugEvents.push_back(evt);
|
|
}
|
|
|
|
void SmsEventManager::AddEvent(DebugEventType type)
|
|
{
|
|
DebugEventInfo evt = {};
|
|
evt.Type = type;
|
|
evt.Scanline = _vdp->GetScanline();
|
|
evt.Cycle = _vdp->GetCycle();
|
|
evt.BreakpointId = -1;
|
|
evt.DmaChannel = -1;
|
|
evt.ProgramCounter = _cpu->GetState().PC;
|
|
_debugEvents.push_back(evt);
|
|
}
|
|
|
|
DebugEventInfo SmsEventManager::GetEvent(uint16_t y, uint16_t x)
|
|
{
|
|
auto lock = _lock.AcquireSafe();
|
|
|
|
x /= 2; //convert to cycle value
|
|
y /= 2; //convert to scanline value
|
|
|
|
//Search without including larger background color first
|
|
for(DebugEventInfo& evt : _sentEvents) {
|
|
if(evt.Cycle == x && evt.Scanline == y) {
|
|
return evt;
|
|
}
|
|
}
|
|
|
|
//If no exact match, extend to the background color
|
|
for(int i = (int)_sentEvents.size() - 1; i >= 0; i--){
|
|
DebugEventInfo& evt = _sentEvents[i];
|
|
if(std::abs((int)evt.Cycle - (int)x) <= 1 && std::abs((int)evt.Scanline - (int)y) <= 1) {
|
|
return evt;
|
|
}
|
|
}
|
|
|
|
DebugEventInfo empty = {};
|
|
empty.ProgramCounter = 0xFFFFFFFF;
|
|
return empty;
|
|
}
|
|
|
|
bool SmsEventManager::ShowPreviousFrameEvents()
|
|
{
|
|
return _config.ShowPreviousFrameEvents;
|
|
}
|
|
|
|
void SmsEventManager::SetConfiguration(BaseEventViewerConfig& config)
|
|
{
|
|
_config = (SmsEventViewerConfig&)config;
|
|
}
|
|
|
|
EventViewerCategoryCfg SmsEventManager::GetEventConfig(DebugEventInfo& evt)
|
|
{
|
|
switch(evt.Type) {
|
|
default: return {};
|
|
case DebugEventType::Breakpoint: return _config.MarkedBreakpoints;
|
|
case DebugEventType::Irq: return _config.Irq;
|
|
case DebugEventType::Register:
|
|
if(_console->GetModel() == SmsModel::GameGear && evt.Operation.Address <= 6) {
|
|
return evt.Operation.Type == MemoryOperationType::Read ? _config.GameGearPortRead : _config.GameGearPortWrite;
|
|
} else if(evt.Operation.Type == MemoryOperationType::Read) {
|
|
switch(evt.Operation.Address & 0xC1) {
|
|
case 0x40: return _config.VdpVCounterRead;
|
|
case 0x41: return _config.VdpHCounterRead;
|
|
case 0x80: return _config.VdpVramRead;
|
|
case 0x81: return _config.VdpControlPortRead;
|
|
case 0xC0: case 0xC1: return _config.IoRead;
|
|
default: return {};
|
|
}
|
|
} else {
|
|
switch(evt.Operation.Address & 0xC1) {
|
|
case 0x00: return _config.MemoryControlWrite;
|
|
case 0x01: return _config.IoWrite;
|
|
case 0x40: case 0x41: return _config.PsgWrite;
|
|
case 0x80: return (evt.Flags & (uint32_t)EventFlags::SmsVdpPaletteWrite) ? _config.VdpPaletteWrite : _config.VdpVramWrite;
|
|
case 0x81: return _config.VdpControlPortWrite;
|
|
default: return {};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmsEventManager::ConvertScanlineCycleToRowColumn(int32_t& x, int32_t& y)
|
|
{
|
|
y *= 2;
|
|
x *= 2;
|
|
}
|
|
|
|
uint32_t SmsEventManager::TakeEventSnapshot(bool forAutoRefresh)
|
|
{
|
|
DebugBreakHelper breakHelper(_debugger);
|
|
auto lock = _lock.AcquireSafe();
|
|
|
|
uint16_t cycle = _vdp->GetCycle();
|
|
uint16_t scanline = _vdp->GetScanline();
|
|
|
|
if(scanline >= _vdp->GetState().VisibleScanlineCount || (forAutoRefresh && (scanline == 0 && cycle == 0))) {
|
|
memcpy(_ppuBuffer, _vdp->GetScreenBuffer(false), 256 * 240 * sizeof(uint16_t));
|
|
} else {
|
|
uint32_t offset = 256 * scanline;
|
|
memcpy(_ppuBuffer, _vdp->GetScreenBuffer(false), offset * sizeof(uint16_t));
|
|
memcpy(_ppuBuffer + offset, _vdp->GetScreenBuffer(true) + offset, (256 * 240 - offset) * sizeof(uint16_t));
|
|
}
|
|
|
|
_snapshotCurrentFrame = _debugEvents;
|
|
_snapshotPrevFrame = _prevDebugEvents;
|
|
_snapshotScanline = scanline;
|
|
_snapshotCycle = cycle;
|
|
_forAutoRefresh = forAutoRefresh;
|
|
_visibleScanlineCount = _vdp->GetState().VisibleScanlineCount;
|
|
_scanlineCount = _vdp->GetScanlineCount();
|
|
return _scanlineCount;
|
|
}
|
|
|
|
FrameInfo SmsEventManager::GetDisplayBufferSize()
|
|
{
|
|
FrameInfo size;
|
|
size.Width = SmsEventManager::ScanlineWidth;
|
|
size.Height = _scanlineCount * 2;
|
|
return size;
|
|
}
|
|
|
|
void SmsEventManager::DrawScreen(uint32_t* buffer)
|
|
{
|
|
uint16_t *src = _ppuBuffer;
|
|
for(uint32_t y = 0, len = _visibleScanlineCount * 2; y < len; y++) {
|
|
for(uint32_t x = 0; x < 256*2; x++) {
|
|
int srcOffset = (y >> 1) * 256 + (x >> 1);
|
|
buffer[y*SmsEventManager::ScanlineWidth + x + SmsVdp::SmsVdpLeftBorder * 2] = ColorUtilities::Rgb555ToArgb(src[srcOffset]);
|
|
}
|
|
}
|
|
}
|