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:
1 parent
d486779f50
commit
6c44367b5c
3 files changed
+75
-6
No files matched your search
@@ -335,6 +335,7 @@ constexpr u64 TIMER_CLOCK_DIVISOR = 128;
|
||||
constexpr u32 HW_ALARM = HW_BASE + 0x14;
|
||||
constexpr u32 HW_ARMIRQFLAG = HW_BASE + 0x38;
|
||||
constexpr u32 HW_ARMIRQMASK = HW_BASE + 0x3c;
|
||||
constexpr u32 HW_ARMFIQMASK = HW_BASE + 0x40;
|
||||
constexpr u32 HW_GPIO_ENABLE = HW_BASE + 0xdc;
|
||||
constexpr u32 HW_GPIO_OUT = HW_BASE + 0xe0;
|
||||
constexpr u32 HW_GPIO_DIR = HW_BASE + 0xe4;
|
||||
@@ -1113,8 +1114,11 @@ void StarletMemory::AttachInterruptLines(ARMCore* core)
|
||||
|
||||
void StarletMemory::UpdateInterruptLines(u32 address)
|
||||
{
|
||||
if (m_interrupt_core == nullptr || (address != HW_ARMIRQFLAG && address != HW_ARMIRQMASK))
|
||||
if (m_interrupt_core == nullptr ||
|
||||
(address != HW_ARMIRQFLAG && address != HW_ARMIRQMASK && address != HW_ARMFIQMASK))
|
||||
{
|
||||
return;
|
||||
}
|
||||
const WiiIPC& ipc = m_system.GetWiiIPC();
|
||||
m_interrupt_core->SetIRQLine(ipc.IsStarletIRQAsserted());
|
||||
m_interrupt_core->SetFIQLine(ipc.IsStarletFIQAsserted());
|
||||
|
||||
@@ -83,11 +83,11 @@ public:
|
||||
// range to its bus slow path, with the instruction address. `core` gives that address.
|
||||
void SetWatchCore(const ARMCore* core);
|
||||
// The core whose IRQ and FIQ lines follow Hollywood's ARM interrupt registers. A write to
|
||||
// HW_ARMIRQFLAG or HW_ARMIRQMASK re-samples both lines at once, as the level-sensitive
|
||||
// Hollywood output follows them on hardware, instead of at the next scheduler slice: an
|
||||
// acknowledged or masked interrupt is never taken again in between. Raising a cause still
|
||||
// reaches the line at the next slice. The owner of both attaches the core once it exists and
|
||||
// destroys it before the memory.
|
||||
// HW_ARMIRQFLAG, HW_ARMIRQMASK or HW_ARMFIQMASK re-samples both lines at once, as the
|
||||
// level-sensitive Hollywood output follows them on hardware, instead of at the next scheduler
|
||||
// slice: an acknowledged or masked interrupt is never taken again in between. Raising a cause
|
||||
// still reaches the line at the next slice. The owner of both attaches the core once it exists
|
||||
// and destroys it before the memory.
|
||||
void AttachInterruptLines(ARMCore* core);
|
||||
void Reset();
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user