Improved MPcore interrupt handler

This commit is contained in:
Wolfvak 2017-08-08 23:04:17 -03:00 committed by d0k3
parent e36b2c347f
commit 930b646008
11 changed files with 106 additions and 78 deletions

View File

@ -28,13 +28,12 @@ INCLUDES := common source source/common source/font source/filesys source/crypto
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# options for code generation # options for code generation
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork -flto ARCH := -DARM9 -march=armv5te -mthumb -mthumb-interwork -flto
CFLAGS := -g -Wall -Wextra -Wpedantic -Wcast-align -Wno-main -O2\ ASFLAGS := $(ARCH) -g -x assembler-with-cpp $(INCLUDE)
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math -std=gnu11\ CFLAGS := $(ARCH) -g -Wall -Wextra -Wpedantic -Wcast-align -Wno-main -O2 \
$(ARCH) -mtune=arm946e-s -fomit-frame-pointer -ffast-math -std=gnu11 \
$(INCLUDE)
CFLAGS += $(INCLUDE) -DARM9
CFLAGS += -DBUILD_NAME="\"$(TARGET) (`date +'%Y/%m/%d'`)\"" CFLAGS += -DBUILD_NAME="\"$(TARGET) (`date +'%Y/%m/%d'`)\""
@ -64,7 +63,6 @@ endif
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -T../link.ld -nostartfiles -g $(ARCH) -Wl,-Map,$(TARGET).map LDFLAGS = -T../link.ld -nostartfiles -g $(ARCH) -Wl,-Map,$(TARGET).map
LIBS := LIBS :=

15
common/arm.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
/* Status Register flags */
#define SR_USR_MODE (0x10)
#define SR_FIQ_MODE (0x11)
#define SR_IRQ_MODE (0x12)
#define SR_SVC_MODE (0x13)
#define SR_ABT_MODE (0x17)
#define SR_UND_MODE (0x1B)
#define SR_SYS_MODE (0x1F)
#define SR_PMODE_MASK (0x1F)
#define SR_THUMB (1 << 5)
#define SR_FIQ (1 << 6)
#define SR_IRQ (1 << 7)

View File

@ -7,6 +7,7 @@
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#define BIT(x) (1<<(x)) #define BIT(x) (1<<(x))

View File

@ -12,10 +12,12 @@ dir_source := source
dir_build := build dir_build := build
dir_out := ../$(dir_build) dir_out := ../$(dir_build)
ASFLAGS := -mcpu=mpcore -mfloat-abi=soft ARCH := -DARM11 -mcpu=mpcore -mfloat-abi=soft -marm -mno-thumb-interwork
CFLAGS := -DARM11 -Wall -Wextra -MMD -MP -marm -mno-thumb-interwork \ INCLUDE := -I$(dir_source) -I../common
$(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math \
-I$(dir_source) -I../common ASFLAGS := $(ARCH) -x assembler-with-cpp $(INCLUDE)
CFLAGS := $(ARCH) -Wall -Wextra -MMD -MP -fno-builtin \
-std=c11 -O2 -flto -ffast-math -Wno-main $(INCLUDE)
LDFLAGS := -nostdlib -nostartfiles LDFLAGS := -nostdlib -nostartfiles
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
@ -37,8 +39,8 @@ $(dir_out)/$(name).elf: $(objects)
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $< $(CC) -c $(CFLAGS) -o $@ $<
$(dir_build)/%.o: $(dir_source)/%.s $(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $< $(CC) -c $(ASFLAGS) -o $@ $<

View File

@ -6,13 +6,12 @@ SECTIONS
{ {
. = 0x1FF80000; . = 0x1FF80000;
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } .text : ALIGN(4) { *(.text.boot) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); } .data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
.bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; } .bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; }
. = ALIGN(4); . = ALIGN(4);
__irq_stack = 0x1FFFF800; __stack_top = 0x1FFFF800;
__prg_stack = 0x1FFFF400;
} }

View File

@ -3,10 +3,12 @@
.section .text.boot .section .text.boot
.arm .arm
#include <arm.h>
.global __boot .global __boot
__boot: __boot:
@ Disable interrupts and switch to IRQ @ Disable interrupts and switch to IRQ
cpsid aif, #0x12 cpsid aif, #(SR_SVC_MODE)
@ Writeback and invalidate caches @ Writeback and invalidate caches
mov r0, #0 mov r0, #0
@ -14,11 +16,7 @@ __boot:
mcr p15, 0, r0, c7, c14, 0 mcr p15, 0, r0, c7, c14, 0
mcr p15, 0, r0, c7, c10, 4 mcr p15, 0, r0, c7, c10, 4
ldr sp, =__irq_stack ldr sp, =__stack_top
@ Switch to SVC
cpsid aif, #0x13
ldr sp, =__prg_stack
@ Reset values @ Reset values
ldr r0, =0x00054078 ldr r0, =0x00054078

View File

@ -10,18 +10,17 @@
#define IRQ_BASE ((vu32*)0x1FFFFFA0) #define IRQ_BASE ((vu32*)0x1FFFFFA0)
irq_handler handler_table[MAX_IRQ]; irq_handler handler_table[MAX_IRQ];
extern void (*main_irq_handler)(void);
void __attribute__((interrupt("IRQ"))) gic_irq_handler(void) irq_handler GIC_AckIRQ(void)
{ {
u32 xrq, ss; u32 xrq = *GIC_IRQACK;
CPU_EnterCritical(&ss); irq_handler ret = NULL;
xrq = *GIC_IRQACK;
if (xrq < MAX_IRQ && handler_table[xrq]) { if (xrq < MAX_IRQ && handler_table[xrq]) {
(handler_table[xrq])(xrq); ret = handler_table[xrq];
}
*GIC_IRQEND = xrq; *GIC_IRQEND = xrq;
CPU_LeaveCritical(&ss); }
return; return ret;
} }
void GIC_Configure(u32 irq_id, irq_handler hndl) void GIC_Configure(u32 irq_id, irq_handler hndl)
@ -35,23 +34,30 @@ void GIC_Configure(u32 irq_id, irq_handler hndl)
void GIC_Reset(void) void GIC_Reset(void)
{ {
*DIC_CONTROL = 0;
*GIC_CONTROL = 0; *GIC_CONTROL = 0;
*GIC_PRIOMASK = ~0;
for (int i = 0; i < (BIT(9)-1); i++) { *GIC_PRIOMASK = ~0;
*GIC_IRQEND |= i; for (int i = 0; i < 0x80; i++) {
*GIC_IRQEND = i;
} }
*DIC_CONTROL = 0;
for (int i = 0; i < (0x20/4); i++) { for (int i = 0; i < (0x20/4); i++) {
DIC_CLRENABLE[i] = ~0; DIC_CLRENABLE[i] = ~0;
DIC_PRIORITY[i] = 0; DIC_PRIORITY[i] = 0;
} }
*DIC_CONTROL = 1; while(*GIC_PENDING != SPURIOUS_IRQ) {
*GIC_CONTROL = 1; for (int i=0; i < (0x20/4); i++) {
DIC_CLRPENDING[i] = ~0;
}
}
IRQ_BASE[1] = (u32)gic_irq_handler; IRQ_BASE[1] = (u32)&main_irq_handler;
IRQ_BASE[0] = 0xE51FF004; IRQ_BASE[0] = 0xE51FF004;
*GIC_CONTROL = 1;
*DIC_CONTROL = 1;
return; return;
} }

View File

@ -6,51 +6,29 @@
#pragma once #pragma once
#include <types.h> #include <types.h>
typedef void (*irq_handler)(u32); typedef void (*irq_handler)(void);
#define MAX_IRQ (0x80) #define MAX_IRQ (0x80)
#define SPURIOUS_IRQ (1023)
#define GIC_BASE (0x17E00100) #define GIC_BASE (0x17E00100)
#define DIC_BASE (0x17E01000) #define DIC_BASE (0x17E01000)
/* Setting bit 0 enables the GIC */
#define GIC_CONTROL ((vu32*)(GIC_BASE + 0x00)) #define GIC_CONTROL ((vu32*)(GIC_BASE + 0x00))
/* Bits [7:0] control the min priority accepted */
#define GIC_PRIOMASK ((vu32*)(GIC_BASE + 0x04)) #define GIC_PRIOMASK ((vu32*)(GIC_BASE + 0x04))
/* When an IRQ occurrs, this register holds the IRQ ID */
#define GIC_IRQACK ((vu32*)(GIC_BASE + 0x0C)) #define GIC_IRQACK ((vu32*)(GIC_BASE + 0x0C))
/* Write the IRQ ID here to acknowledge it */
#define GIC_IRQEND ((vu32*)(GIC_BASE + 0x10)) #define GIC_IRQEND ((vu32*)(GIC_BASE + 0x10))
#define GIC_PENDING ((vu32*)(GIC_BASE + 0x18))
/* Setting bit 0 enables the DIC */
#define DIC_CONTROL ((vu32*)(DIC_BASE + 0x000)) #define DIC_CONTROL ((vu32*)(DIC_BASE + 0x000))
/*
Write here to enable an IRQ ID
The register address is DIC_SETENABLE + (N/32)*4 and its
corresponding bit index is (N%32)
*/
#define DIC_SETENABLE ((vu32*)(DIC_BASE + 0x100)) #define DIC_SETENABLE ((vu32*)(DIC_BASE + 0x100))
/* same as above but disables the IRQ */
#define DIC_CLRENABLE ((vu32*)(DIC_BASE + 0x180)) #define DIC_CLRENABLE ((vu32*)(DIC_BASE + 0x180))
#define DIC_SETPENDING ((vu32*)(DIC_BASE + 0x200))
/* sets the IRQ priority */ #define DIC_CLRPENDING ((vu32*)(DIC_BASE + 0x280))
#define DIC_PRIORITY ((vu32*)(DIC_BASE + 0x400)) #define DIC_PRIORITY ((vu32*)(DIC_BASE + 0x400))
#define DIC_PROCTGT ((vu8*) (DIC_BASE + 0x800))
/* specifies which CPUs are allowed to be forwarded the IRQ */
#define DIC_PROCTGT ((vu8*)(DIC_BASE + 0x800))
/*
each irq has 2 bits assigned
bit 0 = 0: uses 1-N model
1: uses N-N model
bit 1 = 0: level high active
1: rising edge sensitive
*/
#define DIC_CFGREG ((vu32*)(DIC_BASE + 0xC00)) #define DIC_CFGREG ((vu32*)(DIC_BASE + 0xC00))
void gic_irq_handler(void);
void GIC_Configure(u32 irq_id, irq_handler hndl); void GIC_Configure(u32 irq_id, irq_handler hndl);
void GIC_Reset(void); void GIC_Reset(void);

29
screeninit/source/irq.s Normal file
View File

@ -0,0 +1,29 @@
.section .text
.arm
#include <arm.h>
.global main_irq_handler
.type main_irq_handler, %function
main_irq_handler:
sub lr, lr, #4 @ Fix return address
srsdb sp!, #(SR_SVC_MODE) @ Store IRQ mode LR and SPSR on the SVC stack
cps #(SR_SVC_MODE) @ Switch to SVC mode
push {r0-r3,r12} @ Preserve registers
and r1, sp, #4
sub sp, sp, r1 @ Word-align stack
push {r1,lr}
bl GIC_AckIRQ @ Acknowledge interrupt, get handler address
cmp r0, #0
beq .Lskip_irq
cpsie i
blx r0 @ Branch to interrupt handler with IRQs enabled
cpsid i
.Lskip_irq:
pop {r1,lr}
add sp, sp, r1 @ Restore stack pointer
pop {r0-r3,lr} @ Restore registers
rfeia sp! @ Return From Exception

View File

@ -133,7 +133,7 @@ void set_brightness(u8 brightness)
*(vu32 *)0x10202A40 = brightness; *(vu32 *)0x10202A40 = brightness;
} }
void pxi_interrupt_handler(__attribute__((unused)) u32 xrq_n) void pxi_interrupt_handler(void)
{ {
u8 msg = PXI_GetRemote(); u8 msg = PXI_GetRemote();
switch(msg) { switch(msg) {

View File

@ -2,11 +2,13 @@
.align 4 .align 4
.arm .arm
#include <arm.h>
@ make sure not to clobber r0-r2 @ make sure not to clobber r0-r2
.global _start .global _start
_start: _start:
@ Switch to supervisor mode and disable interrupts @ Switch to supervisor mode and disable interrupts
msr cpsr_c, #0xD3 msr cpsr_c, #(SR_SVC_MODE | SR_IRQ | SR_FIQ)
@ Short delay (not always necessary, just in case) @ Short delay (not always necessary, just in case)
mov r3, #0x40000 mov r3, #0x40000