Browse Source

* 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
master
Gavan Fantom 13 years ago
parent
commit
9f79b3d82e
  1. 2
      Makefile
  2. 47
      crt0.s
  3. 74
      event.c
  4. 19
      event.h
  5. 5
      interrupt.h
  6. 5
      main.c
  7. 10
      swi.h
  8. 10
      timer.c
  9. 2
      types.h

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

@ -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

@ -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

@ -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 */

5
interrupt.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

@ -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

@ -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

@ -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* ");
}

2
types.h

@ -7,4 +7,6 @@ typedef int bool;
#define NULL 0
typedef int size_t;
#endif /* __TYPES_H */

Loading…
Cancel
Save