From 062b7b8a4d6a2ddc134316f443db68bcc4c4978e Mon Sep 17 00:00:00 2001 From: LunarLambda Date: Wed, 16 Nov 2022 18:05:37 +0100 Subject: [PATCH] libseven 0.11.0: split IRQ module for LTO, API rework - removed CriticalSection functions - rewrote IRQ API functions in C, for readability/LTO - renamed IRQ function types, Callback -> Handler - renamed ISR related macros and types --- dist.sh | 2 +- examples/vsync-callback/src/main.c | 2 +- libseven/CMakeLists.txt | 5 +- libseven/Makefile | 4 +- libseven/include/seven/hw/irq.h | 82 ++--- libseven/meson.build | 5 +- libseven/src/hw/irq.c | 131 ++++++++ libseven/src/hw/{irq.s => isr.s} | 493 +++++++++-------------------- libseven/src/macros.s | 34 +- meson.build | 18 +- 10 files changed, 346 insertions(+), 430 deletions(-) create mode 100644 libseven/src/hw/irq.c rename libseven/src/hw/{irq.s => isr.s} (63%) diff --git a/dist.sh b/dist.sh index 81cc5ce..d320444 100755 --- a/dist.sh +++ b/dist.sh @@ -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) diff --git a/examples/vsync-callback/src/main.c b/examples/vsync-callback/src/main.c index 14d8bd3..23018f5 100644 --- a/examples/vsync-callback/src/main.c +++ b/examples/vsync-callback/src/main.c @@ -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; diff --git a/libseven/CMakeLists.txt b/libseven/CMakeLists.txt index 60128dc..a0ad645 100644 --- a/libseven/CMakeLists.txt +++ b/libseven/CMakeLists.txt @@ -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 @@ -32,7 +33,7 @@ target_include_directories(seven PUBLIC include/) target_include_directories(seven PRIVATE src/) target_compile_options(seven PRIVATE - $<$:-Os -g3 -gdwarf-4 -ffunction-sections -fdata-sections -ffreestanding -std=c99 -Wall -Wpedantic -mabi=aapcs -mcpu=arm7tdmi -mthumb> + $<$:-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 diff --git a/libseven/Makefile b/libseven/Makefile index ec785d8..a41c887 100644 --- a/libseven/Makefile +++ b/libseven/Makefile @@ -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 \ @@ -48,6 +49,7 @@ CFLAGS = \ BUILD = build LIB = lib + # # You don't need to touch anything below this point! # diff --git a/libseven/include/seven/hw/irq.h b/libseven/include/seven/hw/irq.h index c44331b..13bc862 100644 --- a/libseven/include/seven/hw/irq.h +++ b/libseven/include/seven/hw/irq.h @@ -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 // @@ -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 @@ -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 diff --git a/libseven/meson.build b/libseven/meson.build index 03fdf85..da4e0cd 100644 --- a/libseven/meson.build +++ b/libseven/meson.build @@ -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', diff --git a/libseven/src/hw/irq.c b/libseven/src/hw/irq.c new file mode 100644 index 0000000..2f4963c --- /dev/null +++ b/libseven/src/hw/irq.c @@ -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 +#include + +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; +} diff --git a/libseven/src/hw/irq.s b/libseven/src/hw/isr.s similarity index 63% rename from libseven/src/hw/irq.s rename to libseven/src/hw/isr.s index 27f03de..867da72 100644 --- a/libseven/src/hw/irq.s +++ b/libseven/src/hw/isr.s @@ -15,10 +15,151 @@ .equiv OFF_IE_IME, REG_IME - REG_IE .equiv OFF_IE_IFBIOS, REG_IFBIOS - REG_IE -bss IRQ_CRITICAL_SECTION - .byte 0 - .byte 0 -endb +fn isrDefault arm + mov r1, REG_BASE @ 1 + @ Post-increment so we can reach IF + ldr r0, [r1, OFF_IE]! @ 3 + and r0, r0, r0, lsr 16 @ 4 + + @ Isolate lowest set bit, that's the one we'll handle + rsb r2, r0, 0 @ 5 + and r0, r0, r2 @ 6 + + @ Acknowlegde IF + strh r0, [r1, OFF_IE_IF] @ 8 + + @ This little dance leaves us with REG_BASE back in r1, + @ and also lets us write only to IFBIOS, + @ just in case that could ever be a correctness issue. + ldr r2, [r1, OFF_IE_IFBIOS]! @ 11 + orr r2, r2, r0 @ 12 + strh r2, [r1], 8 @ 14 + + @ Lookup the IRQ-flag in the handler table using a 16-bit Debruijn sequence. + mov r2, 0x09000000 @ 15 + add r2, r2, 0xAF0000 @ 16 + + @ Faster to do r2 * r0 than r0 * r2 + @ This is because the ARM7 has a 32x8 multiplier. + @ So the number of used bytes in the second operand + @ determines the number of cycles taken to do the multiply. + @ + @ The ARM ARM says "it is believed" to be valid to make Rd = Rn, although + @ it used to be marked as UNPREDICTABLE. + @ (THUMB-mode muls forces Rd = Rn anyway?) + mul r3, r2, r0 @ 18/19 + lsr r2, r3, 28 @ 20 + adr r3, ISR_DEFAULT_HANDLERS @ 21 + ldr r2, [r3, r2, lsl 2] @ 24 + + @ Quick exit if NULL + cmp r2, 0 @ 25 + bxeq lr @ 26 28 (Exit) + + @ Save some time by assuming IME is always 1 at this point + @ + @ Only single-cycle race conditions, async DMA, or a debugger + @ could really cause IME to be 0 here. + str r1, [r1, OFF_IME] @ 28 + + @ Only needed for nested IRQs. + mrs r3, spsr @ 29 + @ Default IRQ Stack allows up to 6 nested IRQs, but only if we use the + @ system mode stack for dispatch. + msr cpsr_c, #0x5F @ 29 + push {r3, lr} @ 33 + + mov lr, pc @ 34 + bx r2 @ 37+ + + pop {r3, lr} @ 41 + msr cpsr_c, #0xD2 @ 42 + msr spsr, r3 @ 43 + + @ Spending 2 cycles resynthesizing these is faster + @ than spending 4 cycles pushing/popping them. + mov r1, REG_BASE @ 44 + mov r0, 1 @ 45 + str r0, [r1, OFF_IME] @ 47 + bx lr @ 50+ + +@ 0000 0 VBLANK +@ 0001 1 HBLANK +@ 0010 2 VCOUNT +@ 0011 5 TIMER2 +@ 0100 3 TIMER0 +@ 0101 9 DMA1 +@ 0110 6 TIMER3 +@ 0111 11 DMA3 +@ 1000 15 NONE +@ 1001 4 TIMER1 +@ 1010 8 DMA0 +@ 1011 10 DMA2 +@ 1100 14 NONE +@ 1101 7 SERIAL +@ 1110 13 CART +@ 1111 12 KEY +data ISR_DEFAULT_HANDLERS global .inline=1 + .fill 16, 4, 0 +endd +endfn + +fn isrSimple arm + mov r1, #REG_BASE + + @ Get IE & IF + ldr r0, [r1, #OFF_IE]! + and r0, r0, r0, lsr #16 + + @ Ack IF + strh r0, [r1, #OFF_IE_IF] + + @ Ack IFBIOS + ldr r2, [r1, #OFF_IE_IFBIOS] + orr r2, r2, r0 + str r2, [r1, #OFF_IE_IFBIOS] + + ldr r2, ISR_SIMPLE_HANDLER + + @ Disable IME (r12) + ldr r12, [r1, #OFF_IE_IME] + str r1, [r1, #OFF_IE_IME] + + mrs r3, spsr + msr cpsr_c, #0x5F + push {r1, r3, r12, lr} + + mov lr, pc + bx r2 + + pop {r1, r3, r12, lr} + msr cpsr_c, #0xD2 + msr spsr, r3 + + str r12, [r1, #OFF_IE_IME] + bx lr +data ISR_SIMPLE_HANDLER global .inline=1 + .word 0 +endd +endfn + +fn isrStub arm + mov r1, #REG_BASE + + @ Get IE & IF + ldr r0, [r1, #OFF_IE]! + and r0, r0, r0, lsr #16 + + @ Ack IF + strh r0, [r1, #OFF_IE_IF] + + @ Ack IFBIOS + ldr r2, [r1, #OFF_IE_IFBIOS]! + orr r2, r2, r0 + strh r2, [r1], 8 + + bx lr +endfn .macro reg_ie_offset val .hword \val - OFF_IE @@ -41,136 +182,6 @@ rodata IRQ_SOURCES .align=2 .hword 0x0000; reg_ie_offset 0x0000 @ Cartridge, - endr -@ void irqInit(IRQHandler *isr); -@ -fn irqInit thumb - movs r1, #0 - mvns r2, r1 - ldr r3, =REG_IE - - @ REG_IME = 0 - strh r1, [r3, #OFF_IE_IME] - @ REG_IE = 0 - strh r1, [r3] - @ REG_IF = 0xFFFF - strh r2, [r3, #OFF_IE_IF] - - @ IRQ_HANDLER = r0 - ldr r1, =IRQ_HANDLER - str r0, [r1] - - @ REG_IME = 1 - strh r2, [r3, #OFF_IE_IME] - bx lr -endfn - -@ void irqInitDefault(void) -@ -fn irqInitDefault thumb - ldr r0, =irqDefaultHandler - b irqInit -endfn - -@ void irqInitSimple(IrqCallbackFn *f) -@ -fn irqInitSimple thumb - ldr r1, =IRQ_CALLBACK_FN - str r0, [r1] - ldr r0, =irqSimpleHandler - b irqInit -endfn - -@ void irqInitStub(void) -@ -fn irqInitStub thumb - ldr r0, =irqStubHandler - b irqInit -endfn - -@ typedef void IrqCallbackFn(u16 irqs); -@ -@ bool irqCallbackSet(u16 irq, IrqCallbackFn *fn) -fn irqCallbackSet thumb - subs r2, r0, 1 - blo 1f - ands r2, r2, r0 - bne 1f - - ldr r2, =0x09AF0000 - muls r0, r2 - lsrs r0, r0, 28 - lsls r0, r0, 2 - ldr r2, =IRQ_TABLE - str r1, [r2, r0] - - movs r0, 1 - bx lr -1: - movs r0, 0 - bx lr -endfn - -fn irqCallbackGet thumb - subs r2, r0, 1 - blo 1f - ands r2, r2, r0 - bne 1f - - ldr r2, =0x09AF0000 - muls r0, r2 - lsrs r0, r0, 28 - lsls r0, r0, 2 - ldr r2, =IRQ_TABLE - ldr r0, [r2, r0] - - bx lr -1: - movs r0, 0 - bx lr -endfn - -@ u16 irqEnable(u16 irqs) -@ -@ r0 REG_IE (previous) -@ r1 ®_IE -@ r2 REG_IME -@ r3 irqs, REG_IE (new) -fn irqEnable thumb - @ REG_IME = 0; - ldr r1, =REG_IE - ldrh r2, [r1, #OFF_IE_IME] - strh r1, [r1, #OFF_IE_IME] - @ REG_IE |= irqs; - movs r3, r0 - ldrh r0, [r1] - orrs r3, r3, r0 - strh r3, [r1] - @ REG_IME = old_ime; - strh r2, [r1, #OFF_IE_IME] - bx lr -endfn - -@ u16 irqDisable(u16 irqs) -@ -@ r0 REG_IE (previous) -@ r1 ®_IE -@ r2 REG_IME -@ r3 irqs, REG_IE (new) -fn irqDisable thumb - @ REG_IME = 0; - ldr r1, =REG_IE - ldrh r2, [r1, #OFF_IE_IME] - strh r1, [r1, #OFF_IE_IME] - @ REG_IE &= ~irqs; - mvns r3, r0 - ldrh r0, [r1] - ands r3, r3, r0 - strh r3, [r1] - @ REG_IME = old_ime - strh r2, [r1, #OFF_IE_IME] - bx lr -endfn - @ u16 irqEnableFull(u16 irqs) @ @ r0 REG_IE (previous) @@ -286,218 +297,4 @@ fn irqDisableFull thumb bx lr endfn -@ void irqCriticalSectionEnter(void) -@ -fn irqCriticalSectionEnter thumb - ldr r0, =REG_IME - ldrh r1, [r0] - strh r0, [r0] - - ldr r2, =IRQ_CRITICAL_SECTION - ldrb r3, [r2] - cmp r3, #0 - bne .Lecs_inc - - @ Save IME - strb r1, [r2, #1] - -.Lecs_inc: - adds r3, r3, #1 - strb r3, [r2] - bx lr -endfn - -@ void irqCriticalSectionExit(void) -@ -fn irqCriticalSectionExit thumb - ldr r0, =REG_IME - ldrh r1, [r0] - strh r0, [r0] - - ldr r2, =IRQ_CRITICAL_SECTION - ldrb r3, [r2] - subs r3, r3, #1 - blo .Lxcs_ret - @ Store - strb r3, [r2] - bne .Lxcs_ret - @ Restore IME - ldrb r1, [r2, #1] - strh r1, [r0] -.Lxcs_ret: - bx lr -endfn - -@ bool irqCriticalSectionActive(void) -@ -fn irqCriticalSectionActive thumb - ldr r0, =IRQ_CRITICAL_SECTION - ldrb r0, [r0] - subs r1, r0, #1 - sbcs r0, r0, r1 -.Lcsa_out: - bx lr -endfn - -@ void irqFree(void (*f)(void*), void *data) -@ -fn irqFree thumb - push {r4, r5} - movs r3, r0 - movs r0, r1 - ldr r4, =REG_IME - ldr r5, [r4] - str r4, [r4] - bl .Lif_bxr3 - str r5, [r4] - pop {r4, r5} - bx lr -.Lif_bxr3: - bx r3 -endfn - -fn irqDefaultHandler arm local - mov r1, REG_BASE @ 1 - @ Post-increment so we can reach IF - ldr r0, [r1, OFF_IE]! @ 3 - and r0, r0, r0, lsr 16 @ 4 - - @ Isolate lowest set bit, that's the one we'll handle - rsb r2, r0, 0 @ 5 - and r0, r0, r2 @ 6 - - @ Acknowlegde IF - strh r0, [r1, OFF_IE_IF] @ 8 - - @ This little dance leaves us with REG_BASE back in r1, - @ and also lets us write only to IFBIOS, - @ just in case that could ever be a correctness issue. - ldr r2, [r1, OFF_IE_IFBIOS]! @ 11 - orr r2, r2, r0 @ 12 - strh r2, [r1], 8 @ 14 - - @ Lookup the IRQ-flag in the handler table using a 16-bit Debruijn sequence. - mov r2, 0x09000000 @ 15 - add r2, r2, 0xAF0000 @ 16 - - @ Faster to do r2 * r0 than r0 * r2 - @ This is because the ARM7 has a 32x8 multiplier. - @ So the number of used bytes in the second operand - @ determines the number of cycles taken to do the multiply. - @ - @ The ARM ARM says "it is believed" to be valid to make Rd = Rn, although - @ it used to be marked as UNPREDICTABLE. - @ (THUMB-mode muls forces Rd = Rn anyway?) - mul r2, r2, r0 @ 18/19 - lsr r2, r2, 28 @ 20 - adr r3, IRQ_TABLE @ 21 - ldr r2, [r3, r2, lsl 2] @ 24 - - @ Quick exit if NULL - cmp r2, 0 @ 25 - bxeq lr @ 26 28 (Exit) - - @ Save some time by assuming IME is always 1 at this point - @ - @ Only single-cycle race conditions, async DMA, or a debugger - @ could really cause IME to be 0 here. - str r1, [r1, OFF_IME] @ 28 - - @ Only needed for nested IRQs. - mrs r3, spsr @ 29 - @ Default IRQ Stack allows up to 6 nested IRQs, but only if we use the - @ system mode stack for dispatch. - msr cpsr_c, #0x5F @ 29 - push {r3, lr} @ 33 - - mov lr, pc @ 34 - bx r2 @ 37+ - - pop {r3, lr} @ 41 - msr cpsr_c, #0xD2 @ 42 - msr spsr, r3 @ 43 - - @ Spending 2 cycles resynthesizing these is faster - @ than spending 4 cycles pushing/popping them. - mov r1, REG_BASE @ 44 - mov r0, 1 @ 45 - str r0, [r1, OFF_IME] @ 47 - bx lr @ 50+ - -@ 0000 0 VBLANK -@ 0001 1 HBLANK -@ 0010 2 VCOUNT -@ 0011 5 TIMER2 -@ 0100 3 TIMER0 -@ 0101 9 DMA1 -@ 0110 6 TIMER3 -@ 0111 11 DMA3 -@ 1000 15 NONE -@ 1001 4 TIMER1 -@ 1010 8 DMA0 -@ 1011 10 DMA2 -@ 1100 14 NONE -@ 1101 7 SERIAL -@ 1110 13 CART -@ 1111 12 KEY -IRQ_TABLE: - .fill 16, 4, 0 -endfn - -fn irqSimpleHandler arm local - mov r1, #REG_BASE - - @ Get IE & IF - ldr r0, [r1, #OFF_IE]! - and r0, r0, r0, lsr #16 - - @ Ack IF - strh r0, [r1, #OFF_IE_IF] - - @ Ack IFBIOS - ldr r2, [r1, #OFF_IE_IFBIOS] - orr r2, r2, r0 - str r2, [r1, #OFF_IE_IFBIOS] - - ldr r2, IRQ_CALLBACK_FN - - @ Disable IME (r12) - ldr r12, [r1, #OFF_IE_IME] - str r1, [r1, #OFF_IE_IME] - - mrs r3, spsr - msr cpsr_c, #0x5F - push {r1, r3, r12, lr} - - mov lr, pc - bx r2 - - pop {r1, r3, r12, lr} - msr cpsr_c, #0xD2 - msr spsr, r3 - - str r12, [r1, #OFF_IE_IME] - bx lr -IRQ_CALLBACK_FN: - .word 0 -endfn - -fn irqStubHandler arm local - mov r1, #REG_BASE - - @ Get IE & IF - ldr r0, [r1, #OFF_IE]! - and r0, r0, r0, lsr #16 - - @ Ack IF - strh r0, [r1, #OFF_IE_IF] - - @ Ack IFBIOS - ldr r2, [r1, #OFF_IE_IFBIOS]! - orr r2, r2, r0 - strh r2, [r1], 8 - - bx lr -endfn - @ vim: ft=armv4 et sta sw=4 sts=8 diff --git a/libseven/src/macros.s b/libseven/src/macros.s index c4878db..fbada3f 100644 --- a/libseven/src/macros.s +++ b/libseven/src/macros.s @@ -93,10 +93,12 @@ .endm @ Declares read-writable data. -.macro data .name:req .linkage=local .section .align +.macro data .name:req .linkage=local .section .align .inline .macro endd .size \.name,.-\.name - .previous + .ifb \.inline + .previous + .endif .purgem endd .endm @@ -110,10 +112,12 @@ .endif .endif - .ifnb \.section - .section \.section,"aw",%progbits - .else - .section .data.\.name,"aw",%progbits + .ifb \.inline + .ifnb \.section + .section \.section,"aw",%progbits + .else + .section .data.\.name,"aw",%progbits + .endif .endif .ifnb \.align @@ -125,10 +129,12 @@ .endm @ Declares read-only data. -.macro rodata .name:req .linkage=local .section .align +.macro rodata .name:req .linkage=local .section .align .inline .macro endr .size \.name,.-\.name - .previous + .ifb \.inline + .previous + .endif .purgem endr .endm @@ -138,14 +144,16 @@ .ifc \.linkage,local .local \.name .else - .error "please specify linkage of \.name `local` or `global`" + .error "please specify linkage of \.name as `local` or `global`" .endif .endif - .ifnb \.section - .section \.section,"a",%progbits - .else - .section .rodata.\.name,"a",%progbits + .ifb \.inline + .ifnb \.section + .section \.section,"a",%progbits + .else + .section .rodata.\.name,"a",%progbits + .endif .endif .ifnb \.align diff --git a/meson.build b/meson.build index ee093eb..80b6b14 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('sdk-seven', 'c', - version: '0.6.0', + version: '0.7.0', license: 'Zlib', meson_version: '>=0.60.0', default_options: ['warning_level=2', 'c_std=c99']) @@ -13,18 +13,20 @@ add_project_arguments( add_project_link_arguments( '-mthumb', '-Wl,--gc-sections', - '-Wl,--no-warn-rwx-segments', - '-specs=nosys.specs', language: 'c') cc = meson.get_compiler('c') -# Detect newlib-nano +# devkitARM has nano.specs, but no libc_nano # -if cc.has_argument('-specs=nano.specs') - add_project_link_arguments( - '-specs=nano.specs', - language: 'c') +if cc.find_library('c_nano', required: false).found() + add_project_link_arguments('-specs=nano.specs', language: 'c') +endif + +# Remove warnings on newer toolchains +# +if find_program('ld', version: '>=2.39', required: false).found() + add_project_link_arguments('-Wl,--no-warn-rwx-segments', language: 'c') endif subdir('libseven')