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:
Wolfvak 2020-11-18 16:47:00 -03:00 committed by d0k3
parent eadc1ab6b9
commit 31389687ab
7 changed files with 109 additions and 69 deletions

View File

@ -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;
}

View File

@ -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();*/
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View 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;
}
}

View File

@ -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())