* Make total stack size available as a symbol
* Implement SWI handler to enable/disable interrupts * Implement event system to deal with kicking non-interrupt code
This commit is contained in:
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@
|
||||
NAME=quad
|
||||
|
||||
SSRCS=crt0.s
|
||||
CSRCS=main.c i2c.c wmp.c timer.c interrupt.c uart.c
|
||||
CSRCS=main.c i2c.c wmp.c timer.c interrupt.c uart.c event.c
|
||||
|
||||
COPTIM?=-O1
|
||||
CFLAGS=-march=armv4t -msoft-float $(COPTIM) -Wall -Werror -Wextra
|
||||
|
||||
47
crt0.s
47
crt0.s
@@ -10,12 +10,24 @@
|
||||
.equ APB_DIVIDER, 4 /* 1, 2 or 4 */
|
||||
|
||||
.equ UND_STACK_SIZE, 0x0004
|
||||
.equ SVC_STACK_SIZE, 0x0004
|
||||
.equ SVC_STACK_SIZE, 0x0010
|
||||
.equ ABT_STACK_SIZE, 0x0004
|
||||
.equ FIQ_STACK_SIZE, 0x0004
|
||||
.equ IRQ_STACK_SIZE, 0x0080
|
||||
.equ USR_STACK_SIZE, 0x0400
|
||||
|
||||
|
||||
.global _stack_size
|
||||
|
||||
.equ _stack_size, 0
|
||||
.equ _stack_size, _stack_size + UND_STACK_SIZE
|
||||
.equ _stack_size, _stack_size + SVC_STACK_SIZE
|
||||
.equ _stack_size, _stack_size + ABT_STACK_SIZE
|
||||
.equ _stack_size, _stack_size + FIQ_STACK_SIZE
|
||||
.equ _stack_size, _stack_size + IRQ_STACK_SIZE
|
||||
.equ _stack_size, _stack_size + USR_STACK_SIZE
|
||||
|
||||
|
||||
# Processor definitions
|
||||
|
||||
.equ Mode_USR, 0x10
|
||||
@@ -174,7 +186,6 @@ lzi:
|
||||
|
||||
# Undefined handlers can just spin for now
|
||||
undefined_handler:
|
||||
swi_handler:
|
||||
prefetch_abort_handler:
|
||||
data_abort_handler:
|
||||
fiq_handler:
|
||||
@@ -182,5 +193,37 @@ fiq_handler:
|
||||
__back:
|
||||
b __back
|
||||
|
||||
|
||||
.equ SWI_MAX, 1
|
||||
|
||||
swi_handler:
|
||||
stmfd sp!, {ip, lr}
|
||||
ldr ip, [lr, #-4]
|
||||
bic ip, #0xff000000
|
||||
|
||||
cmp ip, #SWI_MAX
|
||||
ldmhifd sp!, {ip, pc}^
|
||||
|
||||
add ip, pc, ip, lsl #2
|
||||
ldr pc, [ip]
|
||||
|
||||
swi_branch_table:
|
||||
.word disable_interrupts
|
||||
.word enable_interrupts
|
||||
|
||||
|
||||
disable_interrupts:
|
||||
mrs ip, SPSR
|
||||
orr ip, ip, #I_Bit
|
||||
msr SPSR_c,ip
|
||||
ldmfd sp!, {ip, pc}^
|
||||
|
||||
enable_interrupts:
|
||||
mrs ip, SPSR
|
||||
bic ip, ip, #I_Bit
|
||||
msr SPSR_c,ip
|
||||
ldmfd sp!, {ip, pc}^
|
||||
|
||||
|
||||
.endfunc
|
||||
.end
|
||||
|
||||
74
event.c
Normal file
74
event.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "event.h"
|
||||
#include "interrupt.h"
|
||||
#include "types.h"
|
||||
|
||||
event_handler *event_handler_table[EVENT_MAX+1];
|
||||
|
||||
#define EVENT_WORDS ((EVENT_MAX+1+31)/32)
|
||||
|
||||
unsigned int event_pending[EVENT_WORDS];
|
||||
|
||||
#define EVENT_WORDLEN 32
|
||||
#define EVENT_WORD(x) (x/EVENT_WORDLEN)
|
||||
#define EVENT_BIT(x) (x%EVENT_WORDLEN)
|
||||
#define EVENT_MASK(x) (1<<EVENT_BIT(x))
|
||||
|
||||
void event_set(unsigned int event)
|
||||
{
|
||||
if (event > EVENT_MAX)
|
||||
return;
|
||||
|
||||
interrupt_block();
|
||||
event_pending[EVENT_WORD(event)] |= EVENT_MASK(event);
|
||||
interrupt_unblock();
|
||||
}
|
||||
|
||||
static int bitset(unsigned int x)
|
||||
{
|
||||
x = 0xffffffff - (x-1);
|
||||
x = x - ((x >> 1) & 0x55555555);
|
||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
||||
x = (x + (x >> 4)) & 0x0F0F0F0F;
|
||||
x = x + (x << 8);
|
||||
x = x + (x << 16);
|
||||
return 32 - (x >> 24);
|
||||
}
|
||||
|
||||
bool event_get(unsigned int *event)
|
||||
{
|
||||
int i;
|
||||
unsigned int p;
|
||||
|
||||
for (i = 0; i < EVENT_WORDS; i++) {
|
||||
if ((p = event_pending[i]) != 0) {
|
||||
p = p & (-p);
|
||||
*event = bitset(p) + EVENT_WORDLEN*i;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void event_clear(unsigned int event)
|
||||
{
|
||||
interrupt_block();
|
||||
event_pending[EVENT_WORD(event)] &= ~EVENT_MASK(event);
|
||||
interrupt_unblock();
|
||||
}
|
||||
|
||||
void event_dispatch(void)
|
||||
{
|
||||
unsigned int event;
|
||||
|
||||
if (event_get(&event)) {
|
||||
event_clear(event);
|
||||
(event_handler_table[event])();
|
||||
}
|
||||
}
|
||||
|
||||
void event_register(unsigned int event, event_handler *handler)
|
||||
{
|
||||
if (event > EVENT_MAX)
|
||||
return;
|
||||
event_handler_table[event] = handler;
|
||||
}
|
||||
19
event.h
Normal file
19
event.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __EVENT_H
|
||||
#define __EVENT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define EVENT_TIMER 0
|
||||
#define EVENT_I2C_COMPLETE 1
|
||||
|
||||
#define EVENT_MAX 1
|
||||
|
||||
typedef void event_handler(void);
|
||||
|
||||
void event_set(unsigned int event);
|
||||
bool event_get(unsigned int *event);
|
||||
void event_clear(unsigned int event);
|
||||
void event_dispatch(void);
|
||||
void event_register(unsigned int event, event_handler *handler);
|
||||
|
||||
#endif /* __EVENT_H */
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef __INTERRUPT_H
|
||||
#define __INTERRUPT_H
|
||||
|
||||
#include "swi.h"
|
||||
|
||||
#define VICVectAddr (*(volatile unsigned int *)0xFFFFF030)
|
||||
|
||||
#define I_WDT 0
|
||||
@@ -43,4 +45,7 @@ void interrupt_register_code(unsigned int source, unsigned int priority,
|
||||
#define interrupt_register(x, fn) \
|
||||
interrupt_register_code(I_##x, I_PRIORITY_##x, fn)
|
||||
|
||||
#define interrupt_block() swi_call(SWI_INTERRUPT_BLOCK)
|
||||
#define interrupt_unblock() swi_call(SWI_INTERRUPT_UNBLOCK)
|
||||
|
||||
#endif /* __INTERRUPT_H */
|
||||
|
||||
5
main.c
5
main.c
@@ -4,6 +4,7 @@
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
#include "interrupt.h"
|
||||
#include "event.h"
|
||||
|
||||
#define PINSEL0 (*((volatile unsigned char *) 0xE002C000))
|
||||
#define FP0XDIR (*((volatile unsigned int *) 0x3FFFC000))
|
||||
@@ -255,6 +256,10 @@ int main(void) {
|
||||
timer_set_period(10000*TIMER_MS);
|
||||
reply("done");
|
||||
break;
|
||||
case 'E':
|
||||
event_dispatch();
|
||||
reply("done");
|
||||
break;
|
||||
default:
|
||||
reply("Unrecognised command.");
|
||||
break;
|
||||
|
||||
10
swi.h
Normal file
10
swi.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __SWI_H
|
||||
#define __SWI_H
|
||||
|
||||
#define SWI_INTERRUPT_BLOCK 0
|
||||
#define SWI_INTERRUPT_UNBLOCK 1
|
||||
|
||||
#define swi_call(x) swi_call_(x)
|
||||
#define swi_call_(x) __asm(" swi " #x "\n")
|
||||
|
||||
#endif /* __SWI_H */
|
||||
10
timer.c
10
timer.c
@@ -1,6 +1,7 @@
|
||||
#include "timer.h"
|
||||
#include "interrupt.h"
|
||||
#include "uart.h"
|
||||
#include "event.h"
|
||||
|
||||
#define TIMER0BASE 0xE0004000
|
||||
#define TIMER1BASE 0xE0008000
|
||||
@@ -45,6 +46,8 @@
|
||||
|
||||
void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void);
|
||||
|
||||
void timer_event_handler(void);
|
||||
|
||||
void init_timer(void)
|
||||
{
|
||||
TREG(TCR) = TCR_ENABLE | TCR_RESET;
|
||||
@@ -55,6 +58,7 @@ void init_timer(void)
|
||||
TWREG(PC) = 0;
|
||||
|
||||
TREG(TCR) = TCR_ENABLE;
|
||||
event_register(EVENT_TIMER, timer_event_handler);
|
||||
}
|
||||
|
||||
unsigned int timer_read(void)
|
||||
@@ -86,6 +90,12 @@ void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void)
|
||||
putstr(" *timer0* ");
|
||||
}
|
||||
|
||||
event_set(EVENT_TIMER);
|
||||
|
||||
interrupt_clear();
|
||||
}
|
||||
|
||||
void timer_event_handler(void)
|
||||
{
|
||||
putstr(" *t0event* ");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user