* 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
|
NAME=quad
|
||||||
|
|
||||||
SSRCS=crt0.s
|
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
|
COPTIM?=-O1
|
||||||
CFLAGS=-march=armv4t -msoft-float $(COPTIM) -Wall -Werror -Wextra
|
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 APB_DIVIDER, 4 /* 1, 2 or 4 */
|
||||||
|
|
||||||
.equ UND_STACK_SIZE, 0x0004
|
.equ UND_STACK_SIZE, 0x0004
|
||||||
.equ SVC_STACK_SIZE, 0x0004
|
.equ SVC_STACK_SIZE, 0x0010
|
||||||
.equ ABT_STACK_SIZE, 0x0004
|
.equ ABT_STACK_SIZE, 0x0004
|
||||||
.equ FIQ_STACK_SIZE, 0x0004
|
.equ FIQ_STACK_SIZE, 0x0004
|
||||||
.equ IRQ_STACK_SIZE, 0x0080
|
.equ IRQ_STACK_SIZE, 0x0080
|
||||||
.equ USR_STACK_SIZE, 0x0400
|
.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
|
# Processor definitions
|
||||||
|
|
||||||
.equ Mode_USR, 0x10
|
.equ Mode_USR, 0x10
|
||||||
@@ -174,7 +186,6 @@ lzi:
|
|||||||
|
|
||||||
# Undefined handlers can just spin for now
|
# Undefined handlers can just spin for now
|
||||||
undefined_handler:
|
undefined_handler:
|
||||||
swi_handler:
|
|
||||||
prefetch_abort_handler:
|
prefetch_abort_handler:
|
||||||
data_abort_handler:
|
data_abort_handler:
|
||||||
fiq_handler:
|
fiq_handler:
|
||||||
@@ -182,5 +193,37 @@ fiq_handler:
|
|||||||
__back:
|
__back:
|
||||||
b __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
|
.endfunc
|
||||||
.end
|
.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
|
#ifndef __INTERRUPT_H
|
||||||
#define __INTERRUPT_H
|
#define __INTERRUPT_H
|
||||||
|
|
||||||
|
#include "swi.h"
|
||||||
|
|
||||||
#define VICVectAddr (*(volatile unsigned int *)0xFFFFF030)
|
#define VICVectAddr (*(volatile unsigned int *)0xFFFFF030)
|
||||||
|
|
||||||
#define I_WDT 0
|
#define I_WDT 0
|
||||||
@@ -43,4 +45,7 @@ void interrupt_register_code(unsigned int source, unsigned int priority,
|
|||||||
#define interrupt_register(x, fn) \
|
#define interrupt_register(x, fn) \
|
||||||
interrupt_register_code(I_##x, I_PRIORITY_##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 */
|
#endif /* __INTERRUPT_H */
|
||||||
|
|||||||
5
main.c
5
main.c
@@ -4,6 +4,7 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
#define PINSEL0 (*((volatile unsigned char *) 0xE002C000))
|
#define PINSEL0 (*((volatile unsigned char *) 0xE002C000))
|
||||||
#define FP0XDIR (*((volatile unsigned int *) 0x3FFFC000))
|
#define FP0XDIR (*((volatile unsigned int *) 0x3FFFC000))
|
||||||
@@ -255,6 +256,10 @@ int main(void) {
|
|||||||
timer_set_period(10000*TIMER_MS);
|
timer_set_period(10000*TIMER_MS);
|
||||||
reply("done");
|
reply("done");
|
||||||
break;
|
break;
|
||||||
|
case 'E':
|
||||||
|
event_dispatch();
|
||||||
|
reply("done");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
reply("Unrecognised command.");
|
reply("Unrecognised command.");
|
||||||
break;
|
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 "timer.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
#define TIMER0BASE 0xE0004000
|
#define TIMER0BASE 0xE0004000
|
||||||
#define TIMER1BASE 0xE0008000
|
#define TIMER1BASE 0xE0008000
|
||||||
@@ -45,6 +46,8 @@
|
|||||||
|
|
||||||
void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void);
|
void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void);
|
||||||
|
|
||||||
|
void timer_event_handler(void);
|
||||||
|
|
||||||
void init_timer(void)
|
void init_timer(void)
|
||||||
{
|
{
|
||||||
TREG(TCR) = TCR_ENABLE | TCR_RESET;
|
TREG(TCR) = TCR_ENABLE | TCR_RESET;
|
||||||
@@ -55,6 +58,7 @@ void init_timer(void)
|
|||||||
TWREG(PC) = 0;
|
TWREG(PC) = 0;
|
||||||
|
|
||||||
TREG(TCR) = TCR_ENABLE;
|
TREG(TCR) = TCR_ENABLE;
|
||||||
|
event_register(EVENT_TIMER, timer_event_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int timer_read(void)
|
unsigned int timer_read(void)
|
||||||
@@ -86,6 +90,12 @@ void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void)
|
|||||||
putstr(" *timer0* ");
|
putstr(" *timer0* ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event_set(EVENT_TIMER);
|
||||||
|
|
||||||
interrupt_clear();
|
interrupt_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void timer_event_handler(void)
|
||||||
|
{
|
||||||
|
putstr(" *t0event* ");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user