DMA: Pack state in struct
This commit is contained in:
parent
536b48d706
commit
e1a4c7dfdd
181
src/core/dma.cpp
181
src/core/dma.cpp
|
@ -90,7 +90,7 @@ struct ChannelState
|
||||||
bool request = false;
|
bool request = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
union DPCR
|
union DPCRRegister
|
||||||
{
|
{
|
||||||
u32 bits;
|
u32 bits;
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ union DPCR
|
||||||
|
|
||||||
static constexpr u32 DICR_WRITE_MASK = 0b00000000'11111111'10000000'00111111;
|
static constexpr u32 DICR_WRITE_MASK = 0b00000000'11111111'10000000'00111111;
|
||||||
static constexpr u32 DICR_RESET_MASK = 0b01111111'00000000'00000000'00000000;
|
static constexpr u32 DICR_RESET_MASK = 0b01111111'00000000'00000000'00000000;
|
||||||
union DICR
|
union DICRRegister
|
||||||
{
|
{
|
||||||
u32 bits;
|
u32 bits;
|
||||||
|
|
||||||
|
@ -197,16 +197,23 @@ static TickCount TransferMemoryToDevice(u32 address, u32 increment, u32 word_cou
|
||||||
static TickCount GetMaxSliceTicks();
|
static TickCount GetMaxSliceTicks();
|
||||||
|
|
||||||
// configuration
|
// configuration
|
||||||
static TickCount s_max_slice_ticks = 1000;
|
namespace {
|
||||||
static TickCount s_halt_ticks = 100;
|
struct DMAState
|
||||||
|
{
|
||||||
|
TickCount max_slice_ticks = 1000;
|
||||||
|
TickCount halt_ticks = 100;
|
||||||
|
|
||||||
static std::vector<u32> s_transfer_buffer;
|
std::vector<u32> transfer_buffer;
|
||||||
static std::unique_ptr<TimingEvent> s_unhalt_event;
|
std::unique_ptr<TimingEvent> unhalt_event;
|
||||||
static TickCount s_halt_ticks_remaining = 0;
|
TickCount halt_ticks_remaining = 0;
|
||||||
|
|
||||||
static std::array<ChannelState, NUM_CHANNELS> s_state;
|
std::array<ChannelState, NUM_CHANNELS> channels;
|
||||||
static DPCR s_DPCR = {};
|
DPCRRegister DPCR = {};
|
||||||
static DICR s_DICR = {};
|
DICRRegister DICR = {};
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ALIGN_TO_CACHE_LINE static DMAState s_state;
|
||||||
|
|
||||||
static constexpr std::array<bool (*)(), NUM_CHANNELS> s_channel_transfer_functions = {{
|
static constexpr std::array<bool (*)(), NUM_CHANNELS> s_channel_transfer_functions = {{
|
||||||
&TransferChannel<Channel::MDECin>,
|
&TransferChannel<Channel::MDECin>,
|
||||||
|
@ -234,65 +241,65 @@ struct fmt::formatter<DMA::Channel> : fmt::formatter<fmt::string_view>
|
||||||
|
|
||||||
void DMA::Initialize()
|
void DMA::Initialize()
|
||||||
{
|
{
|
||||||
s_max_slice_ticks = g_settings.dma_max_slice_ticks;
|
s_state.max_slice_ticks = g_settings.dma_max_slice_ticks;
|
||||||
s_halt_ticks = g_settings.dma_halt_ticks;
|
s_state.halt_ticks = g_settings.dma_halt_ticks;
|
||||||
|
|
||||||
s_unhalt_event =
|
s_state.unhalt_event = TimingEvents::CreateTimingEvent("DMA Transfer Unhalt", 1, s_state.max_slice_ticks,
|
||||||
TimingEvents::CreateTimingEvent("DMA Transfer Unhalt", 1, s_max_slice_ticks, &DMA::UnhaltTransfer, nullptr, false);
|
&DMA::UnhaltTransfer, nullptr, false);
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::Shutdown()
|
void DMA::Shutdown()
|
||||||
{
|
{
|
||||||
ClearState();
|
ClearState();
|
||||||
s_unhalt_event.reset();
|
s_state.unhalt_event.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::Reset()
|
void DMA::Reset()
|
||||||
{
|
{
|
||||||
ClearState();
|
ClearState();
|
||||||
s_unhalt_event->Deactivate();
|
s_state.unhalt_event->Deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::ClearState()
|
void DMA::ClearState()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
ChannelState& cs = s_state[i];
|
ChannelState& cs = s_state.channels[i];
|
||||||
cs.base_address = 0;
|
cs.base_address = 0;
|
||||||
cs.block_control.bits = 0;
|
cs.block_control.bits = 0;
|
||||||
cs.channel_control.bits = 0;
|
cs.channel_control.bits = 0;
|
||||||
cs.request = false;
|
cs.request = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_DPCR.bits = 0x07654321;
|
s_state.DPCR.bits = 0x07654321;
|
||||||
s_DICR.bits = 0;
|
s_state.DICR.bits = 0;
|
||||||
|
|
||||||
s_halt_ticks_remaining = 0;
|
s_state.halt_ticks_remaining = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DMA::DoState(StateWrapper& sw)
|
bool DMA::DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
sw.Do(&s_halt_ticks_remaining);
|
sw.Do(&s_state.halt_ticks_remaining);
|
||||||
|
|
||||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
ChannelState& cs = s_state[i];
|
ChannelState& cs = s_state.channels[i];
|
||||||
sw.Do(&cs.base_address);
|
sw.Do(&cs.base_address);
|
||||||
sw.Do(&cs.block_control.bits);
|
sw.Do(&cs.block_control.bits);
|
||||||
sw.Do(&cs.channel_control.bits);
|
sw.Do(&cs.channel_control.bits);
|
||||||
sw.Do(&cs.request);
|
sw.Do(&cs.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Do(&s_DPCR.bits);
|
sw.Do(&s_state.DPCR.bits);
|
||||||
sw.Do(&s_DICR.bits);
|
sw.Do(&s_state.DICR.bits);
|
||||||
|
|
||||||
if (sw.IsReading())
|
if (sw.IsReading())
|
||||||
{
|
{
|
||||||
if (s_halt_ticks_remaining > 0)
|
if (s_state.halt_ticks_remaining > 0)
|
||||||
s_unhalt_event->SetIntervalAndSchedule(s_halt_ticks_remaining);
|
s_state.unhalt_event->SetIntervalAndSchedule(s_state.halt_ticks_remaining);
|
||||||
else
|
else
|
||||||
s_unhalt_event->Deactivate();
|
s_state.unhalt_event->Deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
|
@ -308,20 +315,20 @@ u32 DMA::ReadRegister(u32 offset)
|
||||||
case 0x00:
|
case 0x00:
|
||||||
{
|
{
|
||||||
TRACE_LOG("DMA[{}] base address -> 0x{:08X}", static_cast<Channel>(channel_index),
|
TRACE_LOG("DMA[{}] base address -> 0x{:08X}", static_cast<Channel>(channel_index),
|
||||||
s_state[channel_index].base_address);
|
s_state.channels[channel_index].base_address);
|
||||||
return s_state[channel_index].base_address;
|
return s_state.channels[channel_index].base_address;
|
||||||
}
|
}
|
||||||
case 0x04:
|
case 0x04:
|
||||||
{
|
{
|
||||||
TRACE_LOG("DMA[{}] block control -> 0x{:08X}", static_cast<Channel>(channel_index),
|
TRACE_LOG("DMA[{}] block control -> 0x{:08X}", static_cast<Channel>(channel_index),
|
||||||
s_state[channel_index].block_control.bits);
|
s_state.channels[channel_index].block_control.bits);
|
||||||
return s_state[channel_index].block_control.bits;
|
return s_state.channels[channel_index].block_control.bits;
|
||||||
}
|
}
|
||||||
case 0x08:
|
case 0x08:
|
||||||
{
|
{
|
||||||
TRACE_LOG("DMA[{}] channel control -> 0x{:08X}", static_cast<Channel>(channel_index),
|
TRACE_LOG("DMA[{}] channel control -> 0x{:08X}", static_cast<Channel>(channel_index),
|
||||||
s_state[channel_index].channel_control.bits);
|
s_state.channels[channel_index].channel_control.bits);
|
||||||
return s_state[channel_index].channel_control.bits;
|
return s_state.channels[channel_index].channel_control.bits;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -331,13 +338,13 @@ u32 DMA::ReadRegister(u32 offset)
|
||||||
{
|
{
|
||||||
if (offset == 0x70)
|
if (offset == 0x70)
|
||||||
{
|
{
|
||||||
TRACE_LOG("DPCR -> 0x{:08X}", s_DPCR.bits);
|
TRACE_LOG("DPCR -> 0x{:08X}", s_state.DPCR.bits);
|
||||||
return s_DPCR.bits;
|
return s_state.DPCR.bits;
|
||||||
}
|
}
|
||||||
else if (offset == 0x74)
|
else if (offset == 0x74)
|
||||||
{
|
{
|
||||||
TRACE_LOG("DICR -> 0x{:08X}", s_DICR.bits);
|
TRACE_LOG("DICR -> 0x{:08X}", s_state.DICR.bits);
|
||||||
return s_DICR.bits;
|
return s_state.DICR.bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,7 +357,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
const u32 channel_index = offset >> 4;
|
const u32 channel_index = offset >> 4;
|
||||||
if (channel_index < 7)
|
if (channel_index < 7)
|
||||||
{
|
{
|
||||||
ChannelState& state = s_state[channel_index];
|
ChannelState& state = s_state.channels[channel_index];
|
||||||
switch (offset & UINT32_C(0x0F))
|
switch (offset & UINT32_C(0x0F))
|
||||||
{
|
{
|
||||||
case 0x00:
|
case 0x00:
|
||||||
|
@ -426,7 +433,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
case 0x70:
|
case 0x70:
|
||||||
{
|
{
|
||||||
TRACE_LOG("DPCR <- 0x{:08X}", value);
|
TRACE_LOG("DPCR <- 0x{:08X}", value);
|
||||||
s_DPCR.bits = value;
|
s_state.DPCR.bits = value;
|
||||||
|
|
||||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
|
@ -443,8 +450,8 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
case 0x74:
|
case 0x74:
|
||||||
{
|
{
|
||||||
TRACE_LOG("DICR <- 0x{:08X}", value);
|
TRACE_LOG("DICR <- 0x{:08X}", value);
|
||||||
s_DICR.bits = (s_DICR.bits & ~DICR_WRITE_MASK) | (value & DICR_WRITE_MASK);
|
s_state.DICR.bits = (s_state.DICR.bits & ~DICR_WRITE_MASK) | (value & DICR_WRITE_MASK);
|
||||||
s_DICR.bits = s_DICR.bits & ~(value & DICR_RESET_MASK);
|
s_state.DICR.bits = s_state.DICR.bits & ~(value & DICR_RESET_MASK);
|
||||||
UpdateIRQ();
|
UpdateIRQ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -459,7 +466,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
|
|
||||||
void DMA::SetRequest(Channel channel, bool request)
|
void DMA::SetRequest(Channel channel, bool request)
|
||||||
{
|
{
|
||||||
ChannelState& cs = s_state[static_cast<u32>(channel)];
|
ChannelState& cs = s_state.channels[static_cast<u32>(channel)];
|
||||||
if (cs.request == request)
|
if (cs.request == request)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -470,20 +477,20 @@ void DMA::SetRequest(Channel channel, bool request)
|
||||||
|
|
||||||
void DMA::SetMaxSliceTicks(TickCount ticks)
|
void DMA::SetMaxSliceTicks(TickCount ticks)
|
||||||
{
|
{
|
||||||
s_max_slice_ticks = ticks;
|
s_state.max_slice_ticks = ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::SetHaltTicks(TickCount ticks)
|
void DMA::SetHaltTicks(TickCount ticks)
|
||||||
{
|
{
|
||||||
s_halt_ticks = ticks;
|
s_state.halt_ticks = ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE bool DMA::CanTransferChannel(Channel channel, bool ignore_halt)
|
ALWAYS_INLINE_RELEASE bool DMA::CanTransferChannel(Channel channel, bool ignore_halt)
|
||||||
{
|
{
|
||||||
if (!s_DPCR.GetMasterEnable(channel))
|
if (!s_state.DPCR.GetMasterEnable(channel))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const ChannelState& cs = s_state[static_cast<u32>(channel)];
|
const ChannelState& cs = s_state.channels[static_cast<u32>(channel)];
|
||||||
if (!cs.channel_control.enable_busy)
|
if (!cs.channel_control.enable_busy)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -495,16 +502,16 @@ ALWAYS_INLINE_RELEASE bool DMA::CanTransferChannel(Channel channel, bool ignore_
|
||||||
|
|
||||||
bool DMA::IsTransferHalted()
|
bool DMA::IsTransferHalted()
|
||||||
{
|
{
|
||||||
return s_unhalt_event->IsActive();
|
return s_state.unhalt_event->IsActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::UpdateIRQ()
|
void DMA::UpdateIRQ()
|
||||||
{
|
{
|
||||||
[[maybe_unused]] const auto old_dicr = s_DICR;
|
[[maybe_unused]] const auto old_dicr = s_state.DICR;
|
||||||
s_DICR.UpdateMasterFlag();
|
s_state.DICR.UpdateMasterFlag();
|
||||||
if (!old_dicr.master_flag && s_DICR.master_flag)
|
if (!old_dicr.master_flag && s_state.DICR.master_flag)
|
||||||
TRACE_LOG("Firing DMA master interrupt");
|
TRACE_LOG("Firing DMA master interrupt");
|
||||||
InterruptController::SetLineState(InterruptController::IRQ::DMA, s_DICR.master_flag);
|
InterruptController::SetLineState(InterruptController::IRQ::DMA, s_state.DICR.master_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE bool DMA::IsLinkedListTerminator(PhysicalMemoryAddress address)
|
ALWAYS_INLINE_RELEASE bool DMA::IsLinkedListTerminator(PhysicalMemoryAddress address)
|
||||||
|
@ -520,8 +527,8 @@ ALWAYS_INLINE_RELEASE bool DMA::CheckForBusError(Channel channel, ChannelState&
|
||||||
{
|
{
|
||||||
DEBUG_LOG("DMA bus error on channel {} at address 0x{:08X} size {}", channel, address, size);
|
DEBUG_LOG("DMA bus error on channel {} at address 0x{:08X} size {}", channel, address, size);
|
||||||
cs.channel_control.enable_busy = false;
|
cs.channel_control.enable_busy = false;
|
||||||
s_DICR.bus_error = true;
|
s_state.DICR.bus_error = true;
|
||||||
s_DICR.SetIRQFlag(channel);
|
s_state.DICR.SetIRQFlag(channel);
|
||||||
UpdateIRQ();
|
UpdateIRQ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -534,17 +541,17 @@ ALWAYS_INLINE_RELEASE void DMA::CompleteTransfer(Channel channel, ChannelState&
|
||||||
// start/busy bit is cleared on end of transfer
|
// start/busy bit is cleared on end of transfer
|
||||||
DEBUG_LOG("DMA transfer for channel {} complete", channel);
|
DEBUG_LOG("DMA transfer for channel {} complete", channel);
|
||||||
cs.channel_control.enable_busy = false;
|
cs.channel_control.enable_busy = false;
|
||||||
if (s_DICR.ShouldSetIRQFlag(channel))
|
if (s_state.DICR.ShouldSetIRQFlag(channel))
|
||||||
{
|
{
|
||||||
DEBUG_LOG("Setting DMA interrupt for channel {}", channel);
|
DEBUG_LOG("Setting DMA interrupt for channel {}", channel);
|
||||||
s_DICR.SetIRQFlag(channel);
|
s_state.DICR.SetIRQFlag(channel);
|
||||||
UpdateIRQ();
|
UpdateIRQ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TickCount DMA::GetMaxSliceTicks()
|
TickCount DMA::GetMaxSliceTicks()
|
||||||
{
|
{
|
||||||
const TickCount max = Pad::IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : s_max_slice_ticks;
|
const TickCount max = Pad::IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : s_state.max_slice_ticks;
|
||||||
if (!TimingEvents::IsRunningEvents())
|
if (!TimingEvents::IsRunningEvents())
|
||||||
return max;
|
return max;
|
||||||
|
|
||||||
|
@ -556,7 +563,7 @@ TickCount DMA::GetMaxSliceTicks()
|
||||||
template<DMA::Channel channel>
|
template<DMA::Channel channel>
|
||||||
bool DMA::TransferChannel()
|
bool DMA::TransferChannel()
|
||||||
{
|
{
|
||||||
ChannelState& cs = s_state[static_cast<u32>(channel)];
|
ChannelState& cs = s_state.channels[static_cast<u32>(channel)];
|
||||||
|
|
||||||
const bool copy_to_device = cs.channel_control.copy_to_device;
|
const bool copy_to_device = cs.channel_control.copy_to_device;
|
||||||
|
|
||||||
|
@ -653,7 +660,7 @@ bool DMA::TransferChannel()
|
||||||
if (cs.request)
|
if (cs.request)
|
||||||
{
|
{
|
||||||
// stall the transfer for a bit if we ran for too long
|
// stall the transfer for a bit if we ran for too long
|
||||||
HaltTransfer(s_halt_ticks);
|
HaltTransfer(s_state.halt_ticks);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -726,8 +733,8 @@ bool DMA::TransferChannel()
|
||||||
if (cs.request)
|
if (cs.request)
|
||||||
{
|
{
|
||||||
// we got halted
|
// we got halted
|
||||||
if (!s_unhalt_event->IsActive())
|
if (!s_state.unhalt_event->IsActive())
|
||||||
HaltTransfer(s_halt_ticks);
|
HaltTransfer(s_state.halt_ticks);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -748,20 +755,20 @@ bool DMA::TransferChannel()
|
||||||
|
|
||||||
void DMA::HaltTransfer(TickCount duration)
|
void DMA::HaltTransfer(TickCount duration)
|
||||||
{
|
{
|
||||||
s_halt_ticks_remaining += duration;
|
s_state.halt_ticks_remaining += duration;
|
||||||
DEBUG_LOG("Halting DMA for {} ticks", s_halt_ticks_remaining);
|
DEBUG_LOG("Halting DMA for {} ticks", s_state.halt_ticks_remaining);
|
||||||
if (s_unhalt_event->IsActive())
|
if (s_state.unhalt_event->IsActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DebugAssert(!s_unhalt_event->IsActive());
|
DebugAssert(!s_state.unhalt_event->IsActive());
|
||||||
s_unhalt_event->SetIntervalAndSchedule(s_halt_ticks_remaining);
|
s_state.unhalt_event->SetIntervalAndSchedule(s_state.halt_ticks_remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA::UnhaltTransfer(void*, TickCount ticks, TickCount ticks_late)
|
void DMA::UnhaltTransfer(void*, TickCount ticks, TickCount ticks_late)
|
||||||
{
|
{
|
||||||
DEBUG_LOG("Resuming DMA after {} ticks, {} ticks late", ticks, -(s_halt_ticks_remaining - ticks));
|
DEBUG_LOG("Resuming DMA after {} ticks, {} ticks late", ticks, -(s_state.halt_ticks_remaining - ticks));
|
||||||
s_halt_ticks_remaining -= ticks;
|
s_state.halt_ticks_remaining -= ticks;
|
||||||
s_unhalt_event->Deactivate();
|
s_state.unhalt_event->Deactivate();
|
||||||
|
|
||||||
// TODO: Use channel priority. But doing it in ascending order is probably good enough.
|
// TODO: Use channel priority. But doing it in ascending order is probably good enough.
|
||||||
// Main thing is that OTC happens after GPU, because otherwise it'll wipe out the LL.
|
// Main thing is that OTC happens after GPU, because otherwise it'll wipe out the LL.
|
||||||
|
@ -775,7 +782,7 @@ void DMA::UnhaltTransfer(void*, TickCount ticks, TickCount ticks_late)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We didn't run too long, so reset timer.
|
// We didn't run too long, so reset timer.
|
||||||
s_halt_ticks_remaining = 0;
|
s_state.halt_ticks_remaining = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<DMA::Channel channel>
|
template<DMA::Channel channel>
|
||||||
|
@ -795,14 +802,14 @@ TickCount DMA::TransferMemoryToDevice(u32 address, u32 increment, u32 word_count
|
||||||
if (static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & mask) <= address) [[unlikely]]
|
if (static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & mask) <= address) [[unlikely]]
|
||||||
{
|
{
|
||||||
// Use temp buffer if it's wrapping around
|
// Use temp buffer if it's wrapping around
|
||||||
if (s_transfer_buffer.size() < word_count)
|
if (s_state.transfer_buffer.size() < word_count)
|
||||||
s_transfer_buffer.resize(word_count);
|
s_state.transfer_buffer.resize(word_count);
|
||||||
src_pointer = s_transfer_buffer.data();
|
src_pointer = s_state.transfer_buffer.data();
|
||||||
|
|
||||||
u8* ram_pointer = Bus::g_ram;
|
u8* ram_pointer = Bus::g_ram;
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
{
|
{
|
||||||
std::memcpy(&s_transfer_buffer[i], &ram_pointer[address], sizeof(u32));
|
std::memcpy(&s_state.transfer_buffer[i], &ram_pointer[address], sizeof(u32));
|
||||||
address = (address + increment) & mask;
|
address = (address + increment) & mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -879,9 +886,9 @@ TickCount DMA::TransferDeviceToMemory(u32 address, u32 increment, u32 word_count
|
||||||
if (static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & mask) <= address) [[unlikely]]
|
if (static_cast<s32>(increment) < 0 || ((address + (increment * word_count)) & mask) <= address) [[unlikely]]
|
||||||
{
|
{
|
||||||
// Use temp buffer if it's wrapping around
|
// Use temp buffer if it's wrapping around
|
||||||
if (s_transfer_buffer.size() < word_count)
|
if (s_state.transfer_buffer.size() < word_count)
|
||||||
s_transfer_buffer.resize(word_count);
|
s_state.transfer_buffer.resize(word_count);
|
||||||
dest_pointer = s_transfer_buffer.data();
|
dest_pointer = s_state.transfer_buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from device.
|
// Read from device.
|
||||||
|
@ -909,12 +916,12 @@ TickCount DMA::TransferDeviceToMemory(u32 address, u32 increment, u32 word_count
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dest_pointer == s_transfer_buffer.data()) [[unlikely]]
|
if (dest_pointer == s_state.transfer_buffer.data()) [[unlikely]]
|
||||||
{
|
{
|
||||||
u8* ram_pointer = Bus::g_ram;
|
u8* ram_pointer = Bus::g_ram;
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
{
|
{
|
||||||
std::memcpy(&ram_pointer[address], &s_transfer_buffer[i], sizeof(u32));
|
std::memcpy(&ram_pointer[address], &s_state.transfer_buffer[i], sizeof(u32));
|
||||||
address = (address + increment) & mask;
|
address = (address + increment) & mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -961,7 +968,7 @@ void DMA::DrawDebugStateWindow()
|
||||||
|
|
||||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
const ChannelState& cs = s_state[i];
|
const ChannelState& cs = s_state.channels[i];
|
||||||
|
|
||||||
ImGui::TextColored(cs.channel_control.enable_busy ? active : inactive, "%u[%s]", i, s_channel_names[i]);
|
ImGui::TextColored(cs.channel_control.enable_busy ? active : inactive, "%u[%s]", i, s_channel_names[i]);
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
|
@ -981,17 +988,17 @@ void DMA::DrawDebugStateWindow()
|
||||||
cs.channel_control.enable_busy ? "Busy" : "Idle",
|
cs.channel_control.enable_busy ? "Busy" : "Idle",
|
||||||
cs.channel_control.start_trigger ? " (Trigger)" : "");
|
cs.channel_control.start_trigger ? " (Trigger)" : "");
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::TextColored(s_DPCR.GetMasterEnable(static_cast<Channel>(i)) ? active : inactive,
|
ImGui::TextColored(s_state.DPCR.GetMasterEnable(static_cast<Channel>(i)) ? active : inactive,
|
||||||
s_DPCR.GetMasterEnable(static_cast<Channel>(i)) ? "Enabled" : "Disabled");
|
s_state.DPCR.GetMasterEnable(static_cast<Channel>(i)) ? "Enabled" : "Disabled");
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::TextColored(s_DPCR.GetMasterEnable(static_cast<Channel>(i)) ? active : inactive, "%u",
|
ImGui::TextColored(s_state.DPCR.GetMasterEnable(static_cast<Channel>(i)) ? active : inactive, "%u",
|
||||||
s_DPCR.GetPriority(static_cast<Channel>(i)));
|
s_state.DPCR.GetPriority(static_cast<Channel>(i)));
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::TextColored(s_DICR.GetIRQEnabled(static_cast<Channel>(i)) ? active : inactive,
|
ImGui::TextColored(s_state.DICR.GetIRQEnabled(static_cast<Channel>(i)) ? active : inactive,
|
||||||
s_DICR.GetIRQEnabled(static_cast<Channel>(i)) ? "Enabled" : "Disabled");
|
s_state.DICR.GetIRQEnabled(static_cast<Channel>(i)) ? "Enabled" : "Disabled");
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::TextColored(s_DICR.GetIRQFlag(static_cast<Channel>(i)) ? active : inactive,
|
ImGui::TextColored(s_state.DICR.GetIRQFlag(static_cast<Channel>(i)) ? active : inactive,
|
||||||
s_DICR.GetIRQFlag(static_cast<Channel>(i)) ? "IRQ" : "");
|
s_state.DICR.GetIRQFlag(static_cast<Channel>(i)) ? "IRQ" : "");
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue