Starlet: re-sample the interrupt lines on HW_ARMFIQMASK writes too

Review of d486779f50 (StarOS decision 44):
- A write to HW_ARMFIQMASK re-samples the attached core's IRQ and FIQ lines,
  as writes to HW_ARMIRQFLAG and HW_ARMIRQMASK do.
- Tests: FIQ masking and unmasking of a latched cause (wide and
  byte-assembled writes, then an acknowledgement); two pending IRQ sources,
  where acknowledging one keeps the line asserted and acknowledging the
  last lowers it.

The attached core cannot be used after it is destroyed: Starlet::Shutdown
resets m_core then m_memory with nothing in between, ~Starlet destroys
m_core (declared after m_memory) first, Init attaches only after the last
path that can fail, StarletMemory::Reset keeps the core, which is still
alive, and the probe's core is a local declared after its memory.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Yaya48andClaude Opus 5.5 committed 2026-10-16 02:49:39 +02:00
1 parent d486779f50
commit 6c44367b5c
3 files changed
+75 -6

No files matched your search

@@ -615,6 +615,71 @@ TEST(StarletInterrupts, InterruptRegisterWritesResampleTheAttachedCoreLines)
EXPECT_FALSE(core.IsFIQLineAsserted());
}
TEST(StarletInterrupts, FIQMaskWritesResampleTheAttachedCoreLine)
{
constexpr u32 hardware_base = 0x0d800000;
constexpr u32 arm_irq_flag = hardware_base + 0x38;
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 cause routed to no FIQ, sampled at a scheduler slice's start.
ipc.SetStarletInterrupt(INT_CAUSE_TIMER, true);
core.SetFIQLine(ipc.IsStarletFIQAsserted());
ASSERT_FALSE(core.IsFIQLineAsserted());
// Unmasking it as an FIQ raises the line at once; masking it lowers the line at once.
memory.Write32(arm_fiq_mask, INT_CAUSE_TIMER);
EXPECT_TRUE(core.IsFIQLineAsserted());
EXPECT_FALSE(core.IsIRQLineAsserted());
memory.Write32(arm_fiq_mask, 0);
EXPECT_FALSE(core.IsFIQLineAsserted());
// The byte-assembled write path re-samples the same way.
for (u32 i = 0; i < 4; ++i)
memory.Write8(arm_fiq_mask + i, static_cast<u8>(INT_CAUSE_TIMER >> (24 - 8 * i)));
EXPECT_TRUE(core.IsFIQLineAsserted());
memory.Write32(arm_irq_flag, INT_CAUSE_TIMER);
EXPECT_FALSE(core.IsFIQLineAsserted());
}
TEST(StarletInterrupts, AcknowledgingOneOfTwoPendingSourcesKeepsIRQAsserted)
{
constexpr u32 hardware_base = 0x0d800000;
constexpr u32 arm_irq_flag = hardware_base + 0x38;
constexpr u32 arm_irq_mask = hardware_base + 0x3c;
Core::DeclareAsCPUThread();
auto& system = Core::System::GetInstance();
auto& ipc = system.GetWiiIPC();
ipc.Reset();
StarletMemory memory(system);
memory.Reset();
ARMCore core(memory);
memory.AttachInterruptLines(&core);
memory.Write32(arm_irq_mask, INT_CAUSE_TIMER | INT_CAUSE_NAND);
ipc.SetStarletInterrupt(INT_CAUSE_TIMER, true);
ipc.SetStarletInterrupt(INT_CAUSE_NAND, true);
core.SetIRQLine(ipc.IsStarletIRQAsserted());
ASSERT_TRUE(core.IsIRQLineAsserted());
// One source acknowledged: the other still holds the line.
memory.Write32(arm_irq_flag, INT_CAUSE_TIMER);
EXPECT_TRUE(core.IsIRQLineAsserted());
EXPECT_EQ(memory.Read32(arm_irq_flag) & (INT_CAUSE_TIMER | INT_CAUSE_NAND), INT_CAUSE_NAND);
// The last one acknowledged: the line drops.
memory.Write32(arm_irq_flag, INT_CAUSE_NAND);
EXPECT_FALSE(core.IsIRQLineAsserted());
EXPECT_EQ(memory.Read32(arm_irq_flag) & (INT_CAUSE_TIMER | INT_CAUSE_NAND), 0u);
}
TEST(StarletInterrupts, DriveAndResetUseDistinctHollywoodLines)
{
// Hollywood IRQ numbers, not the Broadway Processor Interface's DVD line.