mirror of
https://github.com/azahar-emu/azahar
synced 2025-11-07 07:29:58 +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;
|
PicaCore::~PicaCore() = default;
|
||||||
|
|
||||||
void PicaCore::InitializeRegs() {
|
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_top = regs.framebuffer_config[0];
|
||||||
auto& framebuffer_sub = regs.framebuffer_config[1];
|
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);
|
const u8* head = memory.GetPhysicalPointer(list);
|
||||||
cmd_list.Reset(list, head, size);
|
cmd_list.Reset(list, head, size);
|
||||||
|
|
||||||
|
bool stop_requested = false;
|
||||||
while (cmd_list.current_index < cmd_list.length) {
|
while (cmd_list.current_index < cmd_list.length) {
|
||||||
|
if (stop_requested) [[unlikely]] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Align read pointer to 8 bytes
|
// Align read pointer to 8 bytes
|
||||||
if (cmd_list.current_index % 2 != 0) {
|
if (cmd_list.current_index % 2 != 0) {
|
||||||
cmd_list.current_index++;
|
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++]};
|
const CommandHeader header{cmd_list.head[cmd_list.current_index++]};
|
||||||
|
|
||||||
// Write to the requested PICA register.
|
// 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.
|
// Write any extra paramters as well.
|
||||||
for (u32 i = 0; i < header.extra_data_length; ++i) {
|
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 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
|
||||||
const u32 extra_value = cmd_list.head[cmd_list.current_index++];
|
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) {
|
if (id >= RegsInternal::NUM_REGS) {
|
||||||
LOG_ERROR(
|
LOG_ERROR(
|
||||||
HW_GPU,
|
HW_GPU,
|
||||||
@ -153,8 +169,15 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask) {
|
|||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
// Trigger IRQ
|
// Trigger IRQ
|
||||||
case PICA_REG_INDEX(trigger_irq):
|
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);
|
signal_interrupt(Service::GSP::InterruptId::P3D);
|
||||||
|
if (regs.internal.irq_autostop) [[likely]] {
|
||||||
|
stop_requested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PICA_REG_INDEX(pipeline.triangle_topology):
|
case PICA_REG_INDEX(pipeline.triangle_topology):
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void InitializeRegs();
|
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);
|
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
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
@ -13,6 +13,9 @@ namespace Pica {
|
|||||||
|
|
||||||
static constexpr std::pair<u16, const char*> register_names[] = {
|
static constexpr std::pair<u16, const char*> register_names[] = {
|
||||||
{0x010, "GPUREG_FINALIZE"},
|
{0x010, "GPUREG_FINALIZE"},
|
||||||
|
{0x020, "GPUREG_IRQ_CMP"},
|
||||||
|
{0x020, "GPUREG_IRQ_MASK"},
|
||||||
|
{0x034, "GPUREG_IRQ_AUTOSTOP"},
|
||||||
|
|
||||||
{0x040, "GPUREG_FACECULLING_CONFIG"},
|
{0x040, "GPUREG_FACECULLING_CONFIG"},
|
||||||
{0x041, "GPUREG_VIEWPORT_WIDTH"},
|
{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
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
@ -21,8 +21,14 @@ struct RegsInternal {
|
|||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
INSERT_PADDING_WORDS(0x10);
|
INSERT_PADDING_WORDS(0x10);
|
||||||
u32 trigger_irq;
|
u32 irq_request;
|
||||||
INSERT_PADDING_WORDS(0x2f);
|
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;
|
RasterizerRegs rasterizer;
|
||||||
TexturingRegs texturing;
|
TexturingRegs texturing;
|
||||||
FramebufferRegs framebuffer;
|
FramebufferRegs framebuffer;
|
||||||
@ -46,7 +52,10 @@ static_assert(sizeof(RegsInternal) == RegsInternal::NUM_REGS * sizeof(u32),
|
|||||||
static_assert(offsetof(RegsInternal, field_name) == position * 4, \
|
static_assert(offsetof(RegsInternal, field_name) == position * 4, \
|
||||||
"Field " #field_name " has invalid position")
|
"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, 0x40);
|
||||||
ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40);
|
ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user