The unified diff between revisions [cc8258a6..] and [1dfe3b7e..] is displayed below. It can also be downloaded as a raw diff.

#
# old_revision [cc8258a6c3643514892e84cf24fed008bc6f9660]
# new_revision [1dfe3b7eee76f3c8aea3b33932857682ee17701c]
#
# add_file "event.c"
#  content [36ab52fd83585734fc7b199852099d76470bf398]
# 
# add_file "event.h"
#  content [b92070564927535f836fe3cfc7b9460703f7afa0]
# 
# add_file "swi.h"
#  content [1198af2b0bcc19ab77033a4a390f0a2f32bc9305]
# 
# patch "Makefile"
#  from [b5d08d5d0ac834ea39ee009f56ef0e3780848f88]
#    to [bd708913eaf7c1bac787cd82ff2b7e23c57ddc59]
# 
# patch "crt0.s"
#  from [5b6b789fc104e92e95e61047448c05cbcfb0e3db]
#    to [0dec978fe999503c2346f42cb3588323205db715]
# 
# patch "interrupt.h"
#  from [faeb61e4d25cc1baced72430fd4ff30c169ea721]
#    to [3735115d09df71f1da6b5ed670f9df7c4aafb82c]
# 
# patch "main.c"
#  from [0a896cdc054a7e9fc0211de74469c22eef83a867]
#    to [cc6bdc935c17a517544beb8e177fc1093fff5249]
# 
# patch "timer.c"
#  from [bbb624ceb301647f8ffb240074c02ed3c3200135]
#    to [9ef2a6c50a8a227103c6c98477c1ce62327a0977]
# 
# patch "types.h"
#  from [410b58a239e1dd3e76ed5c6c9f7cfa28d09ef6c7]
#    to [00b92d607bdb71185e8326714de30eb16d3329ff]
#
============================================================
--- Makefile	b5d08d5d0ac834ea39ee009f56ef0e3780848f88
+++ Makefile	bd708913eaf7c1bac787cd82ff2b7e23c57ddc59
@@ -3,7 +3,7 @@ SSRCS=crt0.s
 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
============================================================
--- crt0.s	5b6b789fc104e92e95e61047448c05cbcfb0e3db
+++ crt0.s	0dec978fe999503c2346f42cb3588323205db715
@@ -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 @@ undefined_handler:
 
 # Undefined handlers can just spin for now
 undefined_handler:
-swi_handler:
 prefetch_abort_handler:
 data_abort_handler:
 fiq_handler:
@@ -182,5 +193,37 @@ __back:
 __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
============================================================
--- /dev/null	
+++ event.c	36ab52fd83585734fc7b199852099d76470bf398
@@ -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;
+}
============================================================
--- /dev/null	
+++ event.h	b92070564927535f836fe3cfc7b9460703f7afa0
@@ -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 */
============================================================
--- interrupt.h	faeb61e4d25cc1baced72430fd4ff30c169ea721
+++ interrupt.h	3735115d09df71f1da6b5ed670f9df7c4aafb82c
@@ -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 in
 #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 */
============================================================
--- main.c	0a896cdc054a7e9fc0211de74469c22eef83a867
+++ main.c	cc6bdc935c17a517544beb8e177fc1093fff5249
@@ -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;
============================================================
--- /dev/null	
+++ swi.h	1198af2b0bcc19ab77033a4a390f0a2f32bc9305
@@ -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 */
============================================================
--- timer.c	bbb624ceb301647f8ffb240074c02ed3c3200135
+++ timer.c	9ef2a6c50a8a227103c6c98477c1ce62327a0977
@@ -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"))) t
 
 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"))) t
 		putstr(" *timer0* ");
 	}
 
+	event_set(EVENT_TIMER);
+
 	interrupt_clear();
 }
 
+void timer_event_handler(void)
+{
+	putstr(" *t0event* ");
+}
============================================================
--- types.h	410b58a239e1dd3e76ed5c6c9f7cfa28d09ef6c7
+++ types.h	00b92d607bdb71185e8326714de30eb16d3329ff
@@ -7,4 +7,6 @@ typedef int bool;
 
 #define NULL 0
 
+typedef int size_t;
+
 #endif /* __TYPES_H */