mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
WS: Improved IRQ handling after IRQ flag is set or SS segment is modified
This commit is contained in:
parent
5823761791
commit
211b42e91c
3 changed files with 85 additions and 45 deletions
|
@ -49,7 +49,7 @@ void WsCpu::Exec()
|
|||
|
||||
if(irqPending) {
|
||||
_state.Halted = false;
|
||||
if(_state.Flags.Irq) {
|
||||
if(_state.Flags.Irq && _suppressIrqClock != _state.CycleCount) {
|
||||
Interrupt(_memoryManager->GetIrqVector(), true);
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +232,12 @@ void WsCpu::PopFlags()
|
|||
Idle<2>();
|
||||
uint16_t flags;
|
||||
Pop(flags);
|
||||
bool irq = _state.Flags.Irq;
|
||||
_state.Flags.Set(flags);
|
||||
if(!irq && _state.Flags.Irq) {
|
||||
//Suppress IRQs for the next instruction when irq flag gets set
|
||||
SuppressIrq(false);
|
||||
}
|
||||
}
|
||||
|
||||
void WsCpu::PopMemory()
|
||||
|
@ -475,7 +480,12 @@ void WsCpu::RetInterrupt()
|
|||
Pop(_state.CS);
|
||||
uint16_t flags;
|
||||
Pop(flags);
|
||||
bool irq = _state.Flags.Irq;
|
||||
_state.Flags.Set(flags);
|
||||
if(!irq && _state.Flags.Irq) {
|
||||
//Suppress IRQs for the next instruction when irq flag gets set
|
||||
SuppressIrq(false);
|
||||
}
|
||||
ClearPrefetch();
|
||||
}
|
||||
|
||||
|
@ -809,12 +819,33 @@ void WsCpu::Halt()
|
|||
_state.Halted = true;
|
||||
}
|
||||
|
||||
void WsCpu::SuppressIrq(bool suppressTrap)
|
||||
{
|
||||
//When the IRQ flag gets set, or when the SS segment is modified, IRQs
|
||||
//are suppressed after the current instruction and will only trigger
|
||||
//on the instruction after that.
|
||||
_suppressIrqClock = _state.CycleCount;
|
||||
if(suppressTrap) {
|
||||
_suppressTrapClock = _state.CycleCount;
|
||||
}
|
||||
}
|
||||
|
||||
void WsCpu::SetFlagValue(bool& flag, bool value)
|
||||
{
|
||||
Idle<4>();
|
||||
flag = value;
|
||||
}
|
||||
|
||||
void WsCpu::SetIrqFlag()
|
||||
{
|
||||
Idle<4>();
|
||||
if(!_state.Flags.Irq) {
|
||||
_state.Flags.Irq = true;
|
||||
//Suppress IRQs for the next instruction when irq flag gets set
|
||||
SuppressIrq(false);
|
||||
}
|
||||
}
|
||||
|
||||
void WsCpu::ClearPrefetch()
|
||||
{
|
||||
#ifndef DUMMYCPU
|
||||
|
@ -1070,6 +1101,10 @@ void WsCpu::MoveSegment()
|
|||
|
||||
if constexpr(direction) {
|
||||
SetModSegRegister(_modRm.Register, param);
|
||||
if(_modRm.Register == 2) {
|
||||
//SS was updated, suppress IRQs after this instruction
|
||||
SuppressIrq(true);
|
||||
}
|
||||
} else {
|
||||
SetModRm(param);
|
||||
}
|
||||
|
@ -1827,7 +1862,7 @@ start:
|
|||
case 0x14: ProcessAluImm<AluOp::Adc, uint8_t>(); break;
|
||||
case 0x15: ProcessAluImm<AluOp::Adc, uint16_t>(); break;
|
||||
case 0x16: PushSegment(_state.SS); break;
|
||||
case 0x17: PopSegment(_state.SS); break;
|
||||
case 0x17: PopSegment(_state.SS); SuppressIrq(true); break;
|
||||
case 0x18: ProcessAluModRm<AluOp::Sbb, false, uint8_t>(); break;
|
||||
case 0x19: ProcessAluModRm<AluOp::Sbb, false, uint16_t>(); break;
|
||||
case 0x1A: ProcessAluModRm<AluOp::Sbb, true, uint8_t>(); break;
|
||||
|
@ -2069,7 +2104,7 @@ start:
|
|||
case 0xF8: SetFlagValue(_state.Flags.Carry, false); break; //CLC
|
||||
case 0xF9: SetFlagValue(_state.Flags.Carry, true); break; //STC
|
||||
case 0xFA: SetFlagValue(_state.Flags.Irq, false); break; //CLI
|
||||
case 0xFB: SetFlagValue(_state.Flags.Irq, true); break; //STI
|
||||
case 0xFB: SetIrqFlag(); break; //STI
|
||||
case 0xFC: SetFlagValue(_state.Flags.Direction, false); break; //CLD
|
||||
case 0xFD: SetFlagValue(_state.Flags.Direction, true); break; //STD
|
||||
case 0xFE: Grp45ModRm<uint8_t>(); break;
|
||||
|
@ -2080,7 +2115,7 @@ start:
|
|||
_prefix = {};
|
||||
}
|
||||
|
||||
if(_state.Flags.Trap) {
|
||||
if(_state.Flags.Trap && _suppressTrapClock != _state.CycleCount) {
|
||||
Interrupt(1);
|
||||
}
|
||||
}
|
||||
|
@ -2129,4 +2164,7 @@ void WsCpu::Serialize(Serializer& s)
|
|||
SV(_modRm.Mode);
|
||||
SV(_modRm.Register);
|
||||
SV(_modRm.Rm);
|
||||
|
||||
SV(_suppressIrqClock);
|
||||
SV(_suppressTrapClock);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@ private:
|
|||
ModRmState _modRm = {};
|
||||
PrefixState _prefix = {};
|
||||
|
||||
uint64_t _suppressIrqClock = 0;
|
||||
uint64_t _suppressTrapClock = 0;
|
||||
|
||||
#ifndef DUMMYCPU
|
||||
WsCpuPrefetch _prefetch;
|
||||
#endif
|
||||
|
@ -253,7 +256,10 @@ private:
|
|||
void Wait();
|
||||
void Halt();
|
||||
|
||||
void SuppressIrq(bool suppressTrap);
|
||||
|
||||
void SetFlagValue(bool& flag, bool value);
|
||||
void SetIrqFlag();
|
||||
|
||||
public:
|
||||
WsCpu(Emulator* emu, WsMemoryManager* memoryManager);
|
||||
|
|
|
@ -59,10 +59,10 @@ void WsPpu::ProcessHblank()
|
|||
_timer->TickHorizontalTimer();
|
||||
if(_state.Scanline < WsConstants::ScreenHeight) {
|
||||
switch(_state.Mode) {
|
||||
case WsVideoMode::Monochrome: DrawScanline<WsVideoMode::Monochrome>(); break;
|
||||
case WsVideoMode::Color2bpp: DrawScanline<WsVideoMode::Color2bpp>(); break;
|
||||
case WsVideoMode::Color4bpp: DrawScanline<WsVideoMode::Color4bpp>(); break;
|
||||
case WsVideoMode::Color4bppPacked: DrawScanline<WsVideoMode::Color4bppPacked>(); break;
|
||||
case WsVideoMode::Monochrome: DrawScanline<WsVideoMode::Monochrome>(); break;
|
||||
case WsVideoMode::Color2bpp: DrawScanline<WsVideoMode::Color2bpp>(); break;
|
||||
case WsVideoMode::Color4bpp: DrawScanline<WsVideoMode::Color4bpp>(); break;
|
||||
case WsVideoMode::Color4bppPacked: DrawScanline<WsVideoMode::Color4bppPacked>(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,11 +157,9 @@ void WsPpu::DrawSprites()
|
|||
|
||||
if(x >= 224) {
|
||||
continue;
|
||||
}
|
||||
else if(_rowData[rowIndex][x].Priority > 0) {
|
||||
} else if(_rowData[rowIndex][x].Priority > 0) {
|
||||
continue;
|
||||
}
|
||||
else if(_state.SpriteWindow.EnabledLatch && showOutsideWindow == _state.SpriteWindow.IsInsideWindow(x, scanline)) {
|
||||
} else if(_state.SpriteWindow.EnabledLatch && showOutsideWindow == _state.SpriteWindow.IsInsideWindow(x, scanline)) {
|
||||
//Don't draw this pixel, it's outside/inside the window and should only be drawn on the other side
|
||||
continue;
|
||||
}
|
||||
|
@ -257,40 +255,39 @@ template<WsVideoMode mode>
|
|||
uint16_t WsPpu::GetPixelColor(uint16_t tileAddr, uint8_t column)
|
||||
{
|
||||
switch(mode) {
|
||||
case WsVideoMode::Monochrome: {
|
||||
uint8_t tileData = _vram[tileAddr];
|
||||
uint8_t tileData2 = _vram[tileAddr + 1];
|
||||
return (
|
||||
((tileData << column) & 0x80) >> 7 |
|
||||
((tileData2 << column) & 0x80) >> 6
|
||||
case WsVideoMode::Monochrome: {
|
||||
uint8_t tileData = _vram[tileAddr];
|
||||
uint8_t tileData2 = _vram[tileAddr + 1];
|
||||
return (
|
||||
((tileData << column) & 0x80) >> 7 |
|
||||
((tileData2 << column) & 0x80) >> 6
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
case WsVideoMode::Color2bpp: {
|
||||
uint8_t tileData = _vram[tileAddr];
|
||||
uint8_t tileData2 = _vram[tileAddr + 1];
|
||||
return (
|
||||
((tileData << column) & 0x80) >> 7 |
|
||||
((tileData2 << column) & 0x80) >> 6
|
||||
case WsVideoMode::Color2bpp: {
|
||||
uint8_t tileData = _vram[tileAddr];
|
||||
uint8_t tileData2 = _vram[tileAddr + 1];
|
||||
return (
|
||||
((tileData << column) & 0x80) >> 7 |
|
||||
((tileData2 << column) & 0x80) >> 6
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
case WsVideoMode::Color4bpp: {
|
||||
uint8_t tileData = _vram[tileAddr];
|
||||
uint8_t tileData2 = _vram[tileAddr + 1];
|
||||
uint8_t tileData3 = _vram[tileAddr + 2];
|
||||
uint8_t tileData4 = _vram[tileAddr + 3];
|
||||
return (
|
||||
((tileData << column) & 0x80) >> 7 |
|
||||
((tileData2 << column) & 0x80) >> 6 |
|
||||
((tileData3 << column) & 0x80) >> 5 |
|
||||
((tileData4 << column) & 0x80) >> 4
|
||||
case WsVideoMode::Color4bpp: {
|
||||
uint8_t tileData = _vram[tileAddr];
|
||||
uint8_t tileData2 = _vram[tileAddr + 1];
|
||||
uint8_t tileData3 = _vram[tileAddr + 2];
|
||||
uint8_t tileData4 = _vram[tileAddr + 3];
|
||||
return (
|
||||
((tileData << column) & 0x80) >> 7 |
|
||||
((tileData2 << column) & 0x80) >> 6 |
|
||||
((tileData3 << column) & 0x80) >> 5 |
|
||||
((tileData4 << column) & 0x80) >> 4
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
case WsVideoMode::Color4bppPacked: {
|
||||
return (_vram[tileAddr + column / 2] >> (column & 0x01 ? 0 : 4)) & 0x0F;
|
||||
}
|
||||
case WsVideoMode::Color4bppPacked:
|
||||
return (_vram[tileAddr + column / 2] >> (column & 0x01 ? 0 : 4)) & 0x0F;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -535,7 +532,7 @@ uint8_t WsPpu::ReadPort(uint16_t port)
|
|||
return (
|
||||
(_state.LcdEnabled ? 0x01 : 0) |
|
||||
(_state.HighContrast ? 0x02 : 0)
|
||||
);
|
||||
);
|
||||
|
||||
case 0x15: return _state.Icons.Value;
|
||||
case 0x16: return _state.LastScanline;
|
||||
|
@ -549,14 +546,14 @@ uint8_t WsPpu::ReadPort(uint16_t port)
|
|||
return (
|
||||
_state.BwShades[(port - 0x1C) * 2] |
|
||||
(_state.BwShades[(port - 0x1C) * 2 + 1] << 4)
|
||||
);
|
||||
);
|
||||
|
||||
default:
|
||||
if(port >= 0x20 && port <= 0x3F) {
|
||||
return (
|
||||
_state.BwPalettes[(port - 0x20) * 2] |
|
||||
(_state.BwPalettes[(port - 0x20) * 2 + 1] << 4)
|
||||
);
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogDebug("[Debug] PPU Read - missing handler: $" + HexUtilities::ToHex(port));
|
||||
|
@ -647,8 +644,7 @@ void WsPpu::WritePort(uint16_t port, uint8_t value)
|
|||
if(port >= 0x20 && port <= 0x3F) {
|
||||
_state.BwPalettes[(port - 0x20) * 2] = value & 0x07;
|
||||
_state.BwPalettes[(port - 0x20) * 2 + 1] = (value >> 4) & 0x07;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LogDebug("[Debug] PPU Write - missing handler: $" + HexUtilities::ToHex(port) + " = " + HexUtilities::ToHex(value));
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Add table
Reference in a new issue