Starlet: re-sample the ARM IRQ and FIQ lines on interrupt register writes
The core's IRQ and FIQ lines were set from WiiIPC's flags and masks only at the start of each scheduler slice (Starlet::RunSlice, StarletBootstrapProbe). Acknowledging an interrupt (HW_ARMIRQFLAG, write one to clear) or masking it (HW_ARMIRQMASK) left the line asserted until the next slice, so code that acknowledged an interrupt and unmasked IRQ within the same slice took it again with no cause pending. Hollywood's interrupt output is level-sensitive. StarletMemory now re-samples the lines of the core attached with AttachInterruptLines on every write to those two registers, on both its wide and byte-assembled write paths; Starlet and StarletBootstrapProbe attach theirs. Raising a cause still reaches the core at the next slice, as before. ARMCore exposes IsIRQLineAsserted and IsFIQLineAsserted for the unit test. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
bef2c8cf02
commit
d486779f50
6 files changed
+81
No files matched your search
@@ -568,6 +568,53 @@ TEST(StarletRegisters, WideTimerAndInterruptAccessesMatchHardwareSemantics)
|
||||
EXPECT_EQ(memory.Read32(arm_irq_mask), 0x800619efu);
|
||||
}
|
||||
|
||||
TEST(StarletInterrupts, InterruptRegisterWritesResampleTheAttachedCoreLines)
|
||||
{
|
||||
constexpr u32 hardware_base = 0x0d800000;
|
||||
constexpr u32 arm_irq_flag = hardware_base + 0x38;
|
||||
constexpr u32 arm_irq_mask = hardware_base + 0x3c;
|
||||
constexpr u32 arm_fiq_mask = hardware_base + 0x40;
|
||||
Core::DeclareAsCPUThread();
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ipc = system.GetWiiIPC();
|
||||
ipc.Reset();
|
||||
StarletMemory memory(system);
|
||||
memory.Reset();
|
||||
ARMCore core(memory);
|
||||
memory.AttachInterruptLines(&core);
|
||||
|
||||
// A latched, unmasked timer interrupt, sampled at a scheduler slice's start.
|
||||
memory.Write32(arm_irq_mask, INT_CAUSE_TIMER);
|
||||
ipc.SetStarletInterrupt(INT_CAUSE_TIMER, true);
|
||||
core.SetIRQLine(ipc.IsStarletIRQAsserted());
|
||||
ASSERT_TRUE(core.IsIRQLineAsserted());
|
||||
|
||||
// Acknowledging it lowers the line at once, not at the next slice.
|
||||
memory.Write32(arm_irq_flag, INT_CAUSE_TIMER);
|
||||
EXPECT_FALSE(core.IsIRQLineAsserted());
|
||||
|
||||
// Raising a cause still waits for the slice; masking and unmasking a latched cause do not.
|
||||
ipc.SetStarletInterrupt(INT_CAUSE_TIMER, true);
|
||||
EXPECT_FALSE(core.IsIRQLineAsserted());
|
||||
memory.Write32(arm_irq_mask, 0);
|
||||
EXPECT_FALSE(core.IsIRQLineAsserted());
|
||||
memory.Write32(arm_irq_mask, INT_CAUSE_TIMER);
|
||||
EXPECT_TRUE(core.IsIRQLineAsserted());
|
||||
|
||||
// The byte-assembled write path acknowledges as the wide one does.
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
memory.Write8(arm_irq_flag + i, static_cast<u8>(INT_CAUSE_TIMER >> (24 - 8 * i)));
|
||||
EXPECT_FALSE(core.IsIRQLineAsserted());
|
||||
|
||||
// An acknowledgement re-samples the FIQ line from the same flags.
|
||||
memory.Write32(arm_fiq_mask, INT_CAUSE_TIMER);
|
||||
ipc.SetStarletInterrupt(INT_CAUSE_TIMER, true);
|
||||
core.SetFIQLine(ipc.IsStarletFIQAsserted());
|
||||
ASSERT_TRUE(core.IsFIQLineAsserted());
|
||||
memory.Write32(arm_irq_flag, INT_CAUSE_TIMER);
|
||||
EXPECT_FALSE(core.IsFIQLineAsserted());
|
||||
}
|
||||
|
||||
TEST(StarletInterrupts, DriveAndResetUseDistinctHollywoodLines)
|
||||
{
|
||||
// Hollywood IRQ numbers, not the Broadway Processor Interface's DVD line.
|
||||
|
||||
Reference in new issue
Block a user