mirror of
https://github.com/azahar-emu/azahar
synced 2025-11-06 23:19:57 +01:00
pica: Fix irq request register behaviour (#1216)
This commit is contained in:
parent
df134acefe
commit
d8bef418a7
@ -54,6 +54,10 @@ PicaCore::PicaCore(Memory::MemorySystem& memory_, std::shared_ptr<DebugContext>
|
||||
PicaCore::~PicaCore() = default;
|
||||
|
||||
void PicaCore::InitializeRegs() {
|
||||
// Values initialized by GSP
|
||||
regs.internal.irq_autostop = 1;
|
||||
regs.internal.irq_mask = 0xFFFFFFF0;
|
||||
|
||||
auto& framebuffer_top = regs.framebuffer_config[0];
|
||||
auto& framebuffer_sub = regs.framebuffer_config[1];
|
||||
|
||||
@ -100,7 +104,11 @@ void PicaCore::ProcessCmdList(PAddr list, u32 size, bool ignore_list) {
|
||||
const u8* head = memory.GetPhysicalPointer(list);
|
||||
cmd_list.Reset(list, head, size);
|
||||
|
||||
bool stop_requested = false;
|
||||
while (cmd_list.current_index < cmd_list.length) {
|
||||
if (stop_requested) [[unlikely]] {
|
||||
break;
|
||||
}
|
||||
// Align read pointer to 8 bytes
|
||||
if (cmd_list.current_index % 2 != 0) {
|
||||
cmd_list.current_index++;
|
||||
@ -111,18 +119,26 @@ void PicaCore::ProcessCmdList(PAddr list, u32 size, bool ignore_list) {
|
||||
const CommandHeader header{cmd_list.head[cmd_list.current_index++]};
|
||||
|
||||
// Write to the requested PICA register.
|
||||
WriteInternalReg(header.cmd_id, value, header.parameter_mask);
|
||||
WriteInternalReg(header.cmd_id, value, header.parameter_mask, stop_requested);
|
||||
|
||||
// Write any extra paramters as well.
|
||||
for (u32 i = 0; i < header.extra_data_length; ++i) {
|
||||
if (stop_requested) [[unlikely]] {
|
||||
break;
|
||||
}
|
||||
const u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
|
||||
const u32 extra_value = cmd_list.head[cmd_list.current_index++];
|
||||
WriteInternalReg(cmd, extra_value, header.parameter_mask);
|
||||
WriteInternalReg(cmd, extra_value, header.parameter_mask, stop_requested);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask) {
|
||||
static bool any_byte_match(u32 a, u32 b) {
|
||||
return ((a & 0xFF) == (b & 0xFF)) || (((a >> 8) & 0xFF) == ((b >> 8) & 0xFF)) ||
|
||||
(((a >> 16) & 0xFF) == ((b >> 16) & 0xFF)) || (((a >> 24) & 0xFF) == ((b >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requested) {
|
||||
if (id >= RegsInternal::NUM_REGS) {
|
||||
LOG_ERROR(
|
||||
HW_GPU,
|
||||
@ -153,8 +169,15 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask) {
|
||||
|
||||
switch (id) {
|
||||
// Trigger IRQ
|
||||
case PICA_REG_INDEX(trigger_irq):
|
||||
signal_interrupt(Service::GSP::InterruptId::P3D);
|
||||
case PICA_REG_INDEX(irq_request):
|
||||
// TODO(PabloMK7): This logic is not fully accurate, but close enough:
|
||||
// https://problemkaputt.de/gbatek-3ds-gpu-internal-registers-finalize-interrupt-registers.htm
|
||||
if (any_byte_match(regs.internal.reg_array[id], regs.internal.irq_compare)) [[likely]] {
|
||||
signal_interrupt(Service::GSP::InterruptId::P3D);
|
||||
if (regs.internal.irq_autostop) [[likely]] {
|
||||
stop_requested = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PICA_REG_INDEX(pipeline.triangle_topology):
|
||||
|
||||
@ -43,7 +43,7 @@ public:
|
||||
private:
|
||||
void InitializeRegs();
|
||||
|
||||
void WriteInternalReg(u32 id, u32 value, u32 mask);
|
||||
void WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requested);
|
||||
|
||||
void SubmitImmediate(u32 data);
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -13,6 +13,9 @@ namespace Pica {
|
||||
|
||||
static constexpr std::pair<u16, const char*> register_names[] = {
|
||||
{0x010, "GPUREG_FINALIZE"},
|
||||
{0x020, "GPUREG_IRQ_CMP"},
|
||||
{0x020, "GPUREG_IRQ_MASK"},
|
||||
{0x034, "GPUREG_IRQ_AUTOSTOP"},
|
||||
|
||||
{0x040, "GPUREG_FACECULLING_CONFIG"},
|
||||
{0x041, "GPUREG_VIEWPORT_WIDTH"},
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -21,8 +21,14 @@ struct RegsInternal {
|
||||
union {
|
||||
struct {
|
||||
INSERT_PADDING_WORDS(0x10);
|
||||
u32 trigger_irq;
|
||||
INSERT_PADDING_WORDS(0x2f);
|
||||
u32 irq_request;
|
||||
INSERT_PADDING_WORDS(0xf);
|
||||
u32 irq_compare;
|
||||
INSERT_PADDING_WORDS(0xf);
|
||||
u32 irq_mask;
|
||||
INSERT_PADDING_WORDS(0x3);
|
||||
u32 irq_autostop;
|
||||
INSERT_PADDING_WORDS(0xb);
|
||||
RasterizerRegs rasterizer;
|
||||
TexturingRegs texturing;
|
||||
FramebufferRegs framebuffer;
|
||||
@ -46,7 +52,10 @@ static_assert(sizeof(RegsInternal) == RegsInternal::NUM_REGS * sizeof(u32),
|
||||
static_assert(offsetof(RegsInternal, field_name) == position * 4, \
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
ASSERT_REG_POSITION(trigger_irq, 0x10);
|
||||
ASSERT_REG_POSITION(irq_request, 0x10);
|
||||
ASSERT_REG_POSITION(irq_compare, 0x20);
|
||||
ASSERT_REG_POSITION(irq_mask, 0x30);
|
||||
ASSERT_REG_POSITION(irq_autostop, 0x34);
|
||||
|
||||
ASSERT_REG_POSITION(rasterizer, 0x40);
|
||||
ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user