Skip to content
This repository has been archived by the owner on Oct 24, 2023. It is now read-only.

Commit

Permalink
libseven 0.11.0: split IRQ module for LTO, API rework
Browse files Browse the repository at this point in the history
- removed CriticalSection functions
- rewrote IRQ API functions in C, for readability/LTO
- renamed IRQ function types, Callback -> Handler
- renamed ISR related macros and types
  • Loading branch information
LunarLambda committed Nov 16, 2022
1 parent 1add6e6 commit 062b7b8
Show file tree
Hide file tree
Showing 10 changed files with 346 additions and 430 deletions.
2 changes: 1 addition & 1 deletion dist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ make_dist() {

[ ! -d "$DIST" ] && mkdir "$DIST"

(PROJECT=libseven VERSION=0.10.0 make_dist)
(PROJECT=libseven VERSION=0.11.0 make_dist)
(PROJECT=minrt VERSION=0.2.0 make_dist)
2 changes: 1 addition & 1 deletion examples/vsync-callback/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ int main(void)
// Set up the necessary interrupt handling
irqInitDefault();
irqEnableFull(IRQ_VBLANK);
irqCallbackSet(IRQ_VBLANK, vblank_callback);
irqHandlerSet(IRQ_VBLANK, vblank_callback);

// Clear the force-blank bit
REG_DISPCNT = 0;
Expand Down
5 changes: 3 additions & 2 deletions libseven/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ add_library(seven STATIC
src/hw/bios.s
src/hw/dma.s
src/hw/input.s
src/hw/irq.s
src/hw/irq.c
src/hw/isr.s
src/hw/sram.s
src/hw/timer.s
src/util/assert.c
Expand All @@ -32,7 +33,7 @@ target_include_directories(seven PUBLIC include/)
target_include_directories(seven PRIVATE src/)

target_compile_options(seven PRIVATE
$<$<COMPILE_LANGUAGE:C>:-Os -g3 -gdwarf-4 -ffunction-sections -fdata-sections -ffreestanding -std=c99 -Wall -Wpedantic -mabi=aapcs -mcpu=arm7tdmi -mthumb>
$<$<COMPILE_LANGUAGE:C>:-Os -g3 -gdwarf-4 -ffunction-sections -fdata-sections -std=c99 -Wall -Wpedantic -mabi=aapcs -mcpu=arm7tdmi -mthumb>
)

# Allow the string "libseven" as a parameter for target_link_libraries
Expand Down
4 changes: 3 additions & 1 deletion libseven/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ SOURCES = \
src/hw/bios.s \
src/hw/dma.s \
src/hw/input.s \
src/hw/irq.s \
src/hw/irq.c \
src/hw/isr.s \
src/hw/sram.s \
src/hw/timer.s \
src/util/assert.c \
Expand Down Expand Up @@ -48,6 +49,7 @@ CFLAGS = \
BUILD = build
LIB = lib


#
# You don't need to touch anything below this point!
#
Expand Down
82 changes: 28 additions & 54 deletions libseven/include/seven/hw/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

_LIBSEVEN_EXTERN_C

// Attribute for compiling functions in a way that is suitable for IRQ handlers.
// Attribute for compiling functions in a way that is suitable for ISRs.
//
#define IRQ_HANDLER IWRAM_CODE ARM_CODE
#define ISR_FUNCTION IWRAM_CODE ARM_CODE

// Interrupt Enable
//
Expand All @@ -27,6 +27,10 @@ _LIBSEVEN_EXTERN_C
//
#define REG_IME VOLADDR(0x04000208, u16)

// Interrupt Service Routine Function Pointer
//
#define MEM_ISR MEMADDR(0x03FFFFFC, IsrFn*)

// IRQ bitflags
//
enum IRQ
Expand Down Expand Up @@ -83,100 +87,70 @@ enum IRQIndex
//
// Function must be ARM code, and ideally be placed in IWRAM.
//
// Use the IRQ_HANDLER attribute to mark the function appropriately.
typedef void IrqHandlerFn(void);
// Use the ISR_FUNCTION attribute to mark the function appropriately.
typedef void IsrFn(void);

// Function type for interrupt callbacks.
//
// The function receives the triggered IRQs as the first parameter.
typedef void IrqCallbackFn(u16);
typedef void IrqHandlerFn(u16);

// Initialize interrupt handling with a user-provided function.
//
extern void irqInit(IrqHandlerFn *isr);
extern void irqInit(IsrFn *isr);

// Initialize interrupt handling using a callback system.
// Initialize interrupt handling using a handler system.
//
// Used with the irqHandler* functions.
extern void irqInitDefault(void);

// Initialize interrupt handling using a single callback function.
//
// irqInitSimple(my_callback) is roughly similar to
// irqCallbackSet(IRQS_ALL, my_callback, 0),
// but has a lower overhead.
// Initialize interrupt handling using a single handler function.
//
extern void irqInitSimple(IrqCallbackFn *fn);
extern void irqInitSimple(IrqHandlerFn *fn);

// Initialize interrupt handling using a stub handler
// that only acknowledges the IRQs and returns.
//
// This is enough for svcHalt, svcIntrWait, and svcVBlankIntrWait to work.
//
// This is enough for the BIOS interrupt wait functions to work.
extern void irqInitStub(void);

// Set the callback associated with the specified irq.
// Set the handler associated with the specified irq.
//
// Fails if irq specifies more than one interrupt.
//
extern bool irqCallbackSet(u16 irq, IrqCallbackFn *fn);
extern bool irqHandlerSet(u16 irq, IrqHandlerFn *fn);

// Get the callback associated with the specified irq.
//
// Returns null if irq specifies more than one interrupt, or no callback is set.
extern IrqCallbackFn* irqCallbackGet(u16 irq);
// Fails if irq specifies more than one interrupt.
extern bool irqHandlerGet(u16 irq, IrqHandlerFn **fn);

// Swap the handler associated with the specified irq, returning the old one.
//
// Fails if irq specifies more than one interrupt.
extern bool irqHandlerSwap(u16, IrqHandlerFn **fn);

// Enable the specified IRQs.
//
// Returns the old value of the IE register.
//
extern u16 irqEnable(u16 irqs);

// Disable the specified IRQs.
//
// Returns the old value of the IE register.
//
extern u16 irqDisable(u16 irqs);

// Enable the specified IRQs and set the matching I/O registers.
// Enable the specified IRQs and IRQ enable bits in the respective IO registers.
//
// Returns the old value of the IE register.
//
extern u16 irqEnableFull(u16 irqs);

// Disable the specified IRQs and set the matching I/O registers.
// Disable the specified IRQs and IRQ enable bits in the respective IO registers.
//
// Returns the old value of the IE register.
//
extern u16 irqDisableFull(u16 irqs);

// Saves the current value of the IME register and disables it until
// a call to irqCriticalSectionExit.
//
// Calls can be nested. Only the outermost call affects IME.
//
extern void irqCriticalSectionEnter(void);

// Restores the value of IME saved by a
// previous call to irqCriticalSectionEnter.
//
// Only the outermost call affects IME.
//
extern void irqCriticalSectionExit(void);

// Returns true if currently inside a critical section.
//
extern bool irqCriticalSectionActive(void);

// Calls the function f with IRQs disabled, passing data as an argument.
//
// Equivalent to
//
// bool i = REG_IME;
// REG_IME = 0;
// f(data);
// REG_IME = i;
// return;
extern void irqFree(void (*f)(void*), void *data);
// Calls a function with IRQs disabled, passing data as an argument.
extern void irqFree(void (*f)(void*), void *arg);

_LIBSEVEN_EXTERN_C_END

Expand Down
5 changes: 3 additions & 2 deletions libseven/meson.build
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
version = '0.10.0'
version = '0.11.0'

sources = [
'src/hw/bios.s',
'src/hw/dma.s',
'src/hw/input.s',
'src/hw/irq.s',
'src/hw/irq.c',
'src/hw/isr.s',
'src/hw/sram.s',
'src/hw/timer.s',
'src/util/assert.c',
Expand Down
131 changes: 131 additions & 0 deletions libseven/src/hw/irq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#include <seven/base.h>
#include <seven/hw/irq.h>

extern IsrFn isrDefault;
extern IsrFn isrSimple;
extern IsrFn isrStub;

extern IrqHandlerFn* ISR_SIMPLE_HANDLER;
extern IrqHandlerFn* ISR_DEFAULT_HANDLERS[16];

extern void irqInit(IsrFn *isr)
{
REG_IME = 0;
REG_IE = 0;
REG_IF = 0xFFFF;

MEM_ISR = isr;

REG_IME = 1;
return;
}

extern void irqInitDefault(void)
{
REG_IME = 0;

for (usize i = 0; i < 16; i++)
{
ISR_DEFAULT_HANDLERS[i] = NULL;
}

irqInit(isrDefault);
}

extern void irqInitSimple(IrqHandlerFn *handler)
{
REG_IME = 0;

ISR_SIMPLE_HANDLER = handler;

irqInit(isrSimple);
}

extern void irqInitStub(void)
{
irqInit(isrStub);
}

extern bool irqHandlerSet(u16 irq, IrqHandlerFn *fn)
{
if (!irq || (irq & (irq - 1)))
{
return false;
}

ISR_DEFAULT_HANDLERS[(0x09AF0000 * irq) >> 28] = fn;

return true;
}

extern bool irqHandlerGet(u16 irq, IrqHandlerFn **fn)
{
if (!irq || (irq & (irq - 1)))
{
return false;
}

*fn = ISR_DEFAULT_HANDLERS[(0x09AF0000 * irq) >> 28];

return true;
}

extern bool irqHandlerSwap(u16 irq, IrqHandlerFn **fn)
{
if (!irq || (irq & (irq - 1)))
{
return false;
}

u32 idx = (0x09AF0000 * irq) >> 28;

IrqHandlerFn *p = ISR_DEFAULT_HANDLERS[idx];
ISR_DEFAULT_HANDLERS[idx] = *fn;
*fn = p;

return true;
}

extern u16 irqEnable(u16 irqs)
{
u32 ime = REG_IME;
REG_IME = 0;

u16 old = REG_IE;
REG_IE = old | irqs;

REG_IME = ime;

return old;
}

extern u16 irqDisable(u16 irqs)
{
u32 ime = REG_IME;
REG_IME = 0;

u16 old = REG_IE;
REG_IE = old & ~irqs;

REG_IME = ime;

return old;
}

extern void irqFree(void (*f)(void*), void *arg)
{
u32 ime = REG_IME;
REG_IME = 0;

f(arg);

REG_IME = ime;

return;
}
Loading

0 comments on commit 062b7b8

Please sign in to comment.