forked from Mirror/GodMode9
event model seems to work
refactors all the ugly "pendingX" atomic operations into a single "Event" subsystem/interface thing with two operations moves all existing code to use this instead also changes the "bkpt" macro to also indicate unreachable code
This commit is contained in:
parent
eadc1ab6b9
commit
31389687ab
@ -19,8 +19,12 @@
|
||||
#include <common.h>
|
||||
#include <arm.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "arm/gic.h"
|
||||
|
||||
#include "system/event.h"
|
||||
|
||||
/* Generic Interrupt Controller Registers */
|
||||
#define REG_GIC(cpu, o, t) REG_ARM_PMR(0x200 + ((cpu) * 0x100) + (o), t)
|
||||
|
||||
@ -72,6 +76,7 @@
|
||||
#define IRQN_IS_VALID(n) ((n) < DIC_MAX_IRQ)
|
||||
|
||||
static gicIrqHandler gicIrqHandlers[DIC_MAX_IRQ];
|
||||
static _Atomic(u32) gicIrqPending[DIC_MAX_IRQ / 32];
|
||||
|
||||
static struct {
|
||||
u8 tgt;
|
||||
@ -106,14 +111,13 @@ static u8 gicGetDefaultIrqCfg(u32 irqn) {
|
||||
return gicDefaultIrqCfg[i].mode;
|
||||
}
|
||||
// TODO: would it be considerably faster to use bsearch?
|
||||
|
||||
return GIC_RISINGEDGE_1N;
|
||||
}
|
||||
|
||||
void gicTopHandler(void)
|
||||
{
|
||||
while(1) {
|
||||
u32 irqn;
|
||||
u32 irqn, irqsource, index, mask;
|
||||
|
||||
/**
|
||||
If more than one of these CPUs reads the Interrupt Acknowledge Register at the
|
||||
@ -121,16 +125,22 @@ void gicTopHandler(void)
|
||||
routine must ensure that only one of them tries to process the interrupt, with the
|
||||
others returning after writing the ID to the End of Interrupt Register.
|
||||
*/
|
||||
irqn = REG_GIC_IRQACK(GIC_THIS_CPU_ALIAS);
|
||||
irqsource = REG_GIC_IRQACK(GIC_THIS_CPU_ALIAS);
|
||||
|
||||
if (irqn == GIC_IRQ_SPURIOUS) // no further processing is needed
|
||||
if (irqsource == GIC_IRQ_SPURIOUS) // no further processing is needed
|
||||
break;
|
||||
|
||||
(gicIrqHandlers[irqn & ~IRQN_SRC_MASK])(irqn);
|
||||
irqn = irqsource & ~IRQN_SRC_MASK;
|
||||
|
||||
index = irqn / 32;
|
||||
mask = BIT(irqn % 32);
|
||||
atomic_fetch_or(&gicIrqPending[index], mask);
|
||||
|
||||
(gicIrqHandlers[irqn])(irqsource);
|
||||
// if the id is < 16, the source CPU can be obtained from irqn
|
||||
// if the handler isn't set, it'll try to branch to 0 and trigger a prefetch abort
|
||||
|
||||
REG_GIC_IRQEND(GIC_THIS_CPU_ALIAS) = irqn;
|
||||
REG_GIC_IRQEND(GIC_THIS_CPU_ALIAS) = irqsource;
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,6 +162,7 @@ void gicGlobalReset(void)
|
||||
gicn = MAX_CPU;
|
||||
|
||||
// clear the interrupt handler and config table
|
||||
getEventIRQ()->reset();
|
||||
memset(gicIrqHandlers, 0, sizeof(gicIrqHandlers));
|
||||
memset(gicIrqConfig, 0, sizeof(gicIrqConfig));
|
||||
|
||||
@ -263,3 +274,27 @@ void gicTriggerSoftInterrupt(u32 softirq)
|
||||
{
|
||||
REG_DIC_SOFTINT = softirq;
|
||||
}
|
||||
|
||||
static void irqEvReset(void) {
|
||||
memset(&gicIrqPending, 0, sizeof(gicIrqPending));
|
||||
}
|
||||
|
||||
static u32 irqEvTest(u32 param, u32 clear) {
|
||||
u32 index, tstmask, clrmask;
|
||||
|
||||
if (param >= DIC_MAX_IRQ)
|
||||
bkpt;
|
||||
index = param / 32;
|
||||
tstmask = BIT(param % 32);
|
||||
clrmask = clear ? tstmask : 0;
|
||||
return !!(atomic_fetch_and(&gicIrqPending[index], ~clrmask) & tstmask);
|
||||
}
|
||||
|
||||
static const EventInterface evIRQ = {
|
||||
.reset = irqEvReset,
|
||||
.test = irqEvTest
|
||||
};
|
||||
|
||||
const EventInterface *getEventIRQ(void) {
|
||||
return &evIRQ;
|
||||
}
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "hw/mcu.h"
|
||||
#include "hw/gpulcd.h"
|
||||
|
||||
#include "system/event.h"
|
||||
|
||||
static struct
|
||||
{
|
||||
u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen.
|
||||
@ -112,13 +114,13 @@ unsigned GFX_init(GfxFbFmt mode)
|
||||
TIMER_WaitMS(10);
|
||||
resetLcdsMaybe();
|
||||
MCU_controlLCDPower(2u); // Power on LCDs.
|
||||
if(mcuEventWait(0x3Fu<<24) != 2u<<24) __builtin_trap();
|
||||
if(eventWait(getEventMCU(), 0x3Fu<<24, 0x3Fu<<24) != 2u<<24) __builtin_trap();
|
||||
|
||||
waitLcdsReady();
|
||||
REG_LCD_ABL0_LIGHT_PWM = 0x1023E;
|
||||
REG_LCD_ABL1_LIGHT_PWM = 0x1023E;
|
||||
MCU_controlLCDPower(0x28u); // Power on backlights.
|
||||
if(mcuEventWait(0x3Fu<<24) != 0x28u<<24) __builtin_trap();
|
||||
if(eventWait(getEventMCU(), 0x3Fu<<24, 0x3Fu<<24) != 0x28u<<24) __builtin_trap();
|
||||
g_gfxState.lcdPower = 0x15; // All on.
|
||||
|
||||
// Make sure the fills finished.
|
||||
@ -212,7 +214,7 @@ void GFX_powerOnBacklights(GfxBlight mask)
|
||||
|
||||
mask <<= 1;
|
||||
MCU_controlLCDPower(mask); // Power on backlights.
|
||||
mcuEventWait(0x3F<<24);
|
||||
eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
|
||||
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
|
||||
__builtin_trap();*/
|
||||
}
|
||||
@ -222,7 +224,7 @@ void GFX_powerOffBacklights(GfxBlight mask)
|
||||
g_gfxState.lcdPower &= ~mask;
|
||||
|
||||
MCU_controlLCDPower(mask); // Power off backlights.
|
||||
mcuEventWait(0x3F<<24);
|
||||
eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
|
||||
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
|
||||
__builtin_trap();*/
|
||||
}
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "hw/gpulcd.h"
|
||||
#include "hw/mcu.h"
|
||||
|
||||
#include "system/event.h"
|
||||
|
||||
#define MCUEV_HID_MASK ( \
|
||||
MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD | \
|
||||
MCUEV_HID_HOME_DOWN | MCUEV_HID_HOME_UP | MCUEV_HID_WIFI_SWITCH)
|
||||
@ -63,13 +65,14 @@ typedef struct {
|
||||
|
||||
static u8 volumeSliderValue;
|
||||
static u32 shellState;
|
||||
static _Atomic(u32) pendingEvents, pendingUpdate;
|
||||
static _Atomic(u32) pendingEvents;
|
||||
|
||||
static void mcuEventUpdate(void)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
if (!atomic_exchange(&pendingUpdate, 0))
|
||||
// lazily update the mask on each test attempt
|
||||
if (!getEventIRQ()->test(MCU_INTERRUPT, true))
|
||||
return;
|
||||
|
||||
// reading the pending mask automagically acknowledges
|
||||
@ -91,27 +94,6 @@ static void mcuEventUpdate(void)
|
||||
atomic_fetch_or(&pendingEvents, mask);
|
||||
}
|
||||
|
||||
u32 mcuEventTest(u32 mask)
|
||||
{
|
||||
mcuEventUpdate();
|
||||
return atomic_load(&pendingEvents) & mask;
|
||||
}
|
||||
|
||||
u32 mcuEventClear(u32 mask)
|
||||
{
|
||||
mcuEventUpdate();
|
||||
return atomic_fetch_and(&pendingEvents, ~mask) & mask;
|
||||
}
|
||||
|
||||
u32 mcuEventWait(u32 mask)
|
||||
{
|
||||
do {
|
||||
mcuEventUpdate();
|
||||
u32 x = mcuEventClear(mask);
|
||||
if (x) return x;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
u8 mcuGetVolumeSlider(void)
|
||||
{
|
||||
mcuEventUpdate();
|
||||
@ -120,7 +102,7 @@ u8 mcuGetVolumeSlider(void)
|
||||
|
||||
u32 mcuGetSpecialHID(void)
|
||||
{
|
||||
u32 ret, pend = mcuEventClear(MCUEV_HID_MASK);
|
||||
u32 ret = 0, pend = getEventMCU()->test(MCUEV_HID_MASK, MCUEV_HID_MASK);
|
||||
|
||||
// hopefully gets unrolled
|
||||
if (pend & (MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD))
|
||||
@ -176,17 +158,11 @@ void mcuResetLEDs(void)
|
||||
mcuSetStatusLED(0, 0);
|
||||
}
|
||||
|
||||
void mcuInterruptHandler(u32 __attribute__((unused)) irqn)
|
||||
{
|
||||
atomic_store(&pendingUpdate, 1);
|
||||
}
|
||||
|
||||
void mcuReset(void)
|
||||
{
|
||||
u32 intmask = 0;
|
||||
|
||||
atomic_init(&pendingEvents, 0);
|
||||
atomic_init(&pendingUpdate, 0);
|
||||
|
||||
// set register mask and clear any pending registers
|
||||
mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask));
|
||||
@ -202,3 +178,22 @@ void mcuReset(void)
|
||||
|
||||
GPIO_setBit(19, 9);
|
||||
}
|
||||
|
||||
static void evReset(void) {
|
||||
atomic_store(&pendingEvents, 0);
|
||||
}
|
||||
|
||||
static u32 evTest(u32 mask, u32 clear) {
|
||||
mcuEventUpdate();
|
||||
return atomic_fetch_and(&pendingEvents, ~clear) & mask;
|
||||
}
|
||||
|
||||
static const EventInterface evMCU = {
|
||||
.reset = evReset,
|
||||
.test = evTest
|
||||
};
|
||||
|
||||
const EventInterface *getEventMCU(void) {
|
||||
return &evMCU;
|
||||
}
|
||||
|
||||
|
@ -37,18 +37,12 @@ enum {
|
||||
MCUEV_HID_VOLUME_SLIDER = BIT(22),
|
||||
};
|
||||
|
||||
u32 mcuEventTest(u32 mask);
|
||||
u32 mcuEventClear(u32 mask);
|
||||
u32 mcuEventWait(u32 mask);
|
||||
|
||||
u8 mcuGetVolumeSlider(void);
|
||||
u32 mcuGetSpecialHID(void);
|
||||
|
||||
void mcuSetStatusLED(u32 period_ms, u32 color);
|
||||
void mcuResetLEDs(void);
|
||||
|
||||
void mcuInterruptHandler(u32 irqn);
|
||||
|
||||
void mcuReset(void);
|
||||
|
||||
static inline u8 mcuReadReg(u8 addr)
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include <arm.h>
|
||||
#include <pxi.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "arm/gic.h"
|
||||
|
||||
#include "hw/hid.h"
|
||||
@ -33,6 +31,7 @@
|
||||
#include "hw/nvram.h"
|
||||
|
||||
#include "system/sys.h"
|
||||
#include "system/event.h"
|
||||
|
||||
static const u8 brightness_lvls[] = {
|
||||
0x10, 0x17, 0x1E, 0x25,
|
||||
@ -48,16 +47,9 @@ static bool auto_brightness;
|
||||
|
||||
static SystemSHMEM __attribute__((section(".shared"))) sharedMem;
|
||||
|
||||
static _Atomic(u32) pendingVblank, pendingPxiRx;
|
||||
|
||||
static void vblankHandler(u32 __attribute__((unused)) irqn)
|
||||
{
|
||||
atomic_store(&pendingVblank, 1);
|
||||
}
|
||||
|
||||
static void vblankUpdate(void)
|
||||
{
|
||||
if (!atomic_exchange(&pendingVblank, 0))
|
||||
if (!getEventIRQ()->test(VBLANK_INTERRUPT, true))
|
||||
return;
|
||||
|
||||
#ifndef FIXED_BRIGHTNESS
|
||||
@ -70,7 +62,8 @@ static void vblankUpdate(void)
|
||||
#endif
|
||||
|
||||
// handle shell events
|
||||
u32 shell = mcuEventClear(MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE);
|
||||
static const u32 mcuEvShell = MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE;
|
||||
u32 shell = getEventMCU()->test(mcuEvShell, mcuEvShell);
|
||||
if (shell & MCUEV_HID_SHELL_CLOSE) {
|
||||
GFX_powerOffBacklights(GFX_BLIGHT_BOTH);
|
||||
} else if (shell & MCUEV_HID_SHELL_OPEN) {
|
||||
@ -80,16 +73,11 @@ static void vblankUpdate(void)
|
||||
sharedMem.hidState.full = HID_GetState();
|
||||
}
|
||||
|
||||
static void pxiRxHandler(u32 __attribute__((unused)) irqn)
|
||||
{
|
||||
atomic_store(&pendingPxiRx, 1);
|
||||
}
|
||||
|
||||
static u32 pxiRxUpdate(u32 *args)
|
||||
{
|
||||
u32 msg, lo, hi;
|
||||
|
||||
if (!atomic_exchange(&pendingPxiRx, 0))
|
||||
if (!getEventIRQ()->test(PXI_RX_INTERRUPT, true))
|
||||
return PXICMD_NONE;
|
||||
|
||||
msg = PXI_Recv();
|
||||
@ -113,14 +101,14 @@ void __attribute__((noreturn)) MainLoop(void)
|
||||
#endif
|
||||
|
||||
// initialize state stuff
|
||||
atomic_init(&pendingVblank, 0);
|
||||
atomic_init(&pendingPxiRx, 0);
|
||||
getEventIRQ()->reset();
|
||||
getEventMCU()->reset();
|
||||
memset(&sharedMem, 0, sizeof(sharedMem));
|
||||
|
||||
// configure interrupts
|
||||
gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO0, pxiRxHandler);
|
||||
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO0, mcuInterruptHandler);
|
||||
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, vblankHandler);
|
||||
gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO0, NULL);
|
||||
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, NULL);
|
||||
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO0, NULL);
|
||||
|
||||
// enable interrupts
|
||||
gicEnableInterrupt(MCU_INTERRUPT);
|
||||
|
26
arm11/source/system/event.h
Normal file
26
arm11/source/system/event.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef struct {
|
||||
void (*reset)(void);
|
||||
u32 (*test)(u32 param, u32 clear);
|
||||
} EventInterface;
|
||||
|
||||
const EventInterface *getEventIRQ(void);
|
||||
const EventInterface *getEventMCU(void);
|
||||
|
||||
static inline void eventReset(const EventInterface *ei) {
|
||||
ei->reset();
|
||||
}
|
||||
|
||||
static inline u32 eventTest(const EventInterface *ei, u32 param, u32 clear) {
|
||||
return ei->test(param, clear);
|
||||
}
|
||||
|
||||
static inline u32 eventWait(const EventInterface *ei, u32 param, u32 clear) {
|
||||
while(1) {
|
||||
u32 ret = ei->test(param, clear);
|
||||
if (ret) return ret;
|
||||
}
|
||||
}
|
@ -53,7 +53,7 @@
|
||||
(sizeof(x) / sizeof(*(x)))
|
||||
|
||||
#define bkpt \
|
||||
__builtin_trap()
|
||||
do{__builtin_trap(); __builtin_unreachable();}while(0)
|
||||
|
||||
#define assert(x) \
|
||||
(!!(x) ? (void)0 : __builtin_trap())
|
||||
|
Loading…
x
Reference in New Issue
Block a user