The unified diff between revisions [8760ae92..] and [961b04dd..] is displayed below. It can also be downloaded as a raw diff.

#
# old_revision [8760ae9232295422550b79f09e55122390704b3c]
# new_revision [961b04ddb07ba2b5dd6bccfa66a03e442e40d8f0]
#
# add_file "interrupt.c"
#  content [cd7c20769cf360122ade5179a795a26b7f28f260]
# 
# add_file "interrupt.h"
#  content [faeb61e4d25cc1baced72430fd4ff30c169ea721]
# 
# add_file "uart.c"
#  content [b336e227dc442fef728c0a695671328c7a265dd1]
# 
# add_file "uart.h"
#  content [2d08795e26e7e976bded494c773936c5f91d1b69]
# 
# patch "Makefile"
#  from [de7747e757f0f60e45c426582c5736214e14d050]
#    to [b5d08d5d0ac834ea39ee009f56ef0e3780848f88]
# 
# patch "crt0.s"
#  from [adfe53d34fb8bcfcb9ecc9f2824f484661f0ec94]
#    to [5b6b789fc104e92e95e61047448c05cbcfb0e3db]
# 
# patch "main.c"
#  from [ef5435dd23ece2876b0d557328e6c83a7ee04ab6]
#    to [f3f04a92cb8f9ba8fdecd0b2fd95773011c1e076]
# 
# patch "timer.c"
#  from [cd7a8d69e6c6dcdc33683f9f6dfcc98c62d77b4d]
#    to [bbb624ceb301647f8ffb240074c02ed3c3200135]
# 
# patch "timer.h"
#  from [95b887ab46f9dbd390b5a152bc1dc36793949c19]
#    to [c2e75d36a6314f29f490f12d9d98f4bb50b843fc]
#
============================================================
--- Makefile	de7747e757f0f60e45c426582c5736214e14d050
+++ Makefile	b5d08d5d0ac834ea39ee009f56ef0e3780848f88
@@ -3,7 +3,7 @@ SSRCS=crt0.s
 NAME=quad
 
 SSRCS=crt0.s
-CSRCS=main.c i2c.c wmp.c timer.c
+CSRCS=main.c i2c.c wmp.c timer.c interrupt.c uart.c
 
 COPTIM?=-O1
 CFLAGS=-march=armv4t -msoft-float $(COPTIM) -Wall -Werror -Wextra
============================================================
--- crt0.s	adfe53d34fb8bcfcb9ecc9f2824f484661f0ec94
+++ crt0.s	5b6b789fc104e92e95e61047448c05cbcfb0e3db
@@ -69,7 +69,7 @@ vectors:
 	b	prefetch_abort_handler
 	b	data_abort_handler
 	nop	/* reserved */
-	b	irq_handler
+	ldr	pc, [pc, #-0xff0] /* branch through VICVectAddr register */
 	b	fiq_handler
 
 
@@ -177,7 +177,6 @@ data_abort_handler:
 swi_handler:
 prefetch_abort_handler:
 data_abort_handler:
-irq_handler:
 fiq_handler:
 
 __back:
============================================================
--- /dev/null	
+++ interrupt.c	cd7c20769cf360122ade5179a795a26b7f28f260
@@ -0,0 +1,84 @@
+#include "interrupt.h"
+
+#define VICBASE	0xFFFFF000
+
+#define IRQStatus	0x00
+#define FIQStatus	0x04
+#define RawIntr		0x08
+#define IntSelect	0x0c
+#define IntEnable	0x10
+#define IntEnClr	0x14
+#define SoftInt		0x18
+#define SoftIntClear	0x1c
+#define Protection	0x20
+#define VectAddr	0x30
+#define DefVectAddr	0x34
+#define VectAddr0	0x100
+#define VectAddr1	0x104
+#define VectAddr2	0x108
+#define VectAddr3	0x10c
+#define VectAddr4	0x110
+#define VectAddr5	0x114
+#define VectAddr6	0x118
+#define VectAddr7	0x11c
+#define VectAddr8	0x120
+#define VectAddr9	0x124
+#define VectAddr10	0x128
+#define VectAddr11	0x12c
+#define VectAddr12	0x130
+#define VectAddr13	0x134
+#define VectAddr14	0x138
+#define VectAddr15	0x13c
+#define VectCntl0	0x200
+#define VectCntl1	0x204
+#define VectCntl2	0x208
+#define VectCntl3	0x20c
+#define VectCntl4	0x210
+#define VectCntl5	0x214
+#define VectCntl6	0x218
+#define VectCntl7	0x21c
+#define VectCntl8	0x220
+#define VectCntl9	0x224
+#define VectCntl10	0x228
+#define VectCntl11	0x22c
+#define VectCntl12	0x230
+#define VectCntl13	0x234
+#define VectCntl14	0x238
+#define VectCntl15	0x23c
+
+#define VWREG(x) (((volatile unsigned int *)VICBASE)[(x)/sizeof(unsigned int)])
+#define VADDRREG(x) VWREG(VectAddr0 + (x) * 4)
+#define VCNTLREG(x) VWREG(VectCntl0 + (x) * 4)
+
+#define IRQslot_en (1<<5)
+
+
+void __attribute__((interrupt("IRQ"))) interrupt_default_handler(void);
+
+
+void init_interrupt(void)
+{
+	VWREG(IntSelect) = 0;
+	VWREG(IntEnable) = 0;
+	VWREG(DefVectAddr) = (unsigned int) &interrupt_default_handler;
+}
+
+void __attribute__((interrupt("IRQ"))) interrupt_default_handler(void)
+{
+	/* Do nothing. Assume that if there is a genuine interrupt
+	 * request that it will be asserted again soon.
+	 */
+	interrupt_clear();
+}
+
+
+/* Call as interrupt_register(SOURCE, fn) */
+
+void interrupt_register_code(unsigned int source, unsigned int priority,
+			     void(*handler)(void))
+{
+	VADDRREG(priority) = (unsigned int) handler;
+	VCNTLREG(priority) = source | IRQslot_en;
+	VWREG(IntEnable) |= (1<<source);
+}
+
============================================================
--- /dev/null	
+++ interrupt.h	faeb61e4d25cc1baced72430fd4ff30c169ea721
@@ -0,0 +1,46 @@
+#ifndef __INTERRUPT_H
+#define __INTERRUPT_H
+
+#define VICVectAddr (*(volatile unsigned int *)0xFFFFF030)
+
+#define I_WDT		0
+
+#define I_ARMCore0	2
+#define I_ARMCore1	3
+#define I_TIMER0	4
+#define I_TIMER1	5
+#define I_UART0		6
+#define I_UART1		7
+
+#define I_I2C0		9
+#define I_SPI0		10
+#define I_SPI1		11
+#define I_SSP		11
+#define I_PLL		12
+#define I_RTC		13
+#define I_EINT0		14
+#define I_EINT1		15
+#define I_EINT2		16
+
+#define I_AD0		18
+#define I_I2C1		19
+
+#define I_TIMER2	26
+#define I_TIMER3	27
+
+/* Assign interrupt priorities here to avoid clashes */
+
+#define I_PRIORITY_I2C0		0
+#define I_PRIORITY_UART0	1
+#define I_PRIORITY_TIMER0	2
+
+#define interrupt_clear() do { VICVectAddr = 0xff; } while (0)
+
+void init_interrupt(void);
+void interrupt_register_code(unsigned int source, unsigned int priority,
+			void(*handler)(void));
+
+#define interrupt_register(x, fn) \
+	interrupt_register_code(I_##x, I_PRIORITY_##x, fn)
+
+#endif /* __INTERRUPT_H */
============================================================
--- main.c	ef5435dd23ece2876b0d557328e6c83a7ee04ab6
+++ main.c	f3f04a92cb8f9ba8fdecd0b2fd95773011c1e076
@@ -2,93 +2,17 @@
 #include "wmp.h"
 #include "i2c.h"
 #include "timer.h"
+#include "uart.h"
+#include "interrupt.h"
 
-#define UARTBASE 0xE000C000
-
-#define RBR 0x00
-#define THR 0x00
-#define DLL 0x00
-#define DLM 0x04
-#define IER 0x04
-#define IIR 0x08
-#define FCR 0x08
-
-#define LCR 0x0c
-#define LSR 0x14
-#define SCR 0x1c
-#define ACR 0x20
-#define FDR 0x28
-#define TER 0x30
-
-#define UREG(x) (((volatile unsigned char *)UARTBASE)[x])
-
-#define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */
-#define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */
-
 #define PINSEL0 (*((volatile unsigned char *) 0xE002C000))
 
-void init_uart(void)
-{
-	UREG(FDR) = 0x10; /* DivAddVal = 0, MulVal = 1 */
-
-	UREG(LCR) = 0x80;
-	UREG(DLM) = 0x00;
-	UREG(DLL) = 0x08; /* 14745600 / (16*115200) */
-	UREG(LCR) = 0x13;
-	UREG(FCR) = 0x07;
-}
-
 void init_pins(void)
 {
 	PINSEL0 = 0x00000055; /* P0.0 and P0.1 assigned to UART */
 			      /* P0.2 and P0.3 assigned to I2C  */
 }
 
-void putch(char c) {
-	while (!U0THRE);
-	UREG(THR) = c;
-}
-
-void putstr(char *s) {
-	while (*s) putch(*s++);
-}
-
-void putint(unsigned int n) {
-	char s[11];
-	int i;
-
-	i = 10;
-	s[i] = '\0';
-
-	do {
-		s[--i] = n % 10 + '0';
-	} while ((n /= 10) > 0);
-
-	putstr(s+i);
-}
-
-void puthex(unsigned int n) {
-	char s[9];
-	int i;
-
-	i = 8;
-	s[i] = '\0';
-
-	do {
-		int x = n % 16;
-		if (x > 9)
-			x += 'A' - '0' - 10;
-		s[--i] = x + '0';
-	} while ((n /= 16) > 0);
-
-	putstr(s+i);
-}
-
-char getch(void) {
-	while (!U0DR);
-	return UREG(RBR);
-}
-
 void reply(char *str)
 {
 	putstr(str);
@@ -228,6 +152,7 @@ int main(void) {
 
 int main(void) {
 	int i;
+	init_interrupt();
 	init_uart();
 	init_i2c();
 	init_pins();
@@ -330,6 +255,11 @@ int main(void) {
 			puthex(timer_read());
 			reply(".");
 			break;
+		case 'P':
+			putstr("Initialising timer... ");
+			timer_set_period(10000*TIMER_MS);
+			reply("done");
+			break;
 		default:
 			reply("Unrecognised command.");
 			break;
============================================================
--- timer.c	cd7a8d69e6c6dcdc33683f9f6dfcc98c62d77b4d
+++ timer.c	bbb624ceb301647f8ffb240074c02ed3c3200135
@@ -1,4 +1,6 @@
 #include "timer.h"
+#include "interrupt.h"
+#include "uart.h"
 
 #define TIMER0BASE  0xE0004000
 #define TIMER1BASE  0xE0008000
@@ -28,14 +30,29 @@
 #define TCR_ENABLE (1<<0)
 #define TCR_RESET  (1<<1)
 
+#define MR0I (1<<0)
+#define MR0R (1<<1)
+#define MR0S (1<<2)
+#define MR1I (1<<3)
+#define MR1R (1<<4)
+#define MR1S (1<<5)
+#define MR2I (1<<6)
+#define MR2R (1<<7)
+#define MR2S (1<<8)
+#define MR3I (1<<9)
+#define MR3R (1<<10)
+#define MR3S (1<<11)
+
+void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void);
+
 void init_timer(void)
 {
 	TREG(TCR) = TCR_ENABLE | TCR_RESET;
 
 	TREG(CTCR) = 0; /* Use PCLK */
-	TREG(TC) = 0;
-	TREG(PR) = TIMER_PRESCALE ;
-	TREG(PC) = 0;
+	TWREG(TC) = 0;
+	TWREG(PR) = TIMER_PRESCALE ;
+	TWREG(PC) = 0;
 
 	TREG(TCR) = TCR_ENABLE;
 }
@@ -51,3 +68,24 @@ void timer_delay_clocks(unsigned int clo
 	while (((signed int) (time-TWREG(TC))) > 0);
 }
 
+void timer_set_period(unsigned int period)
+{
+	TWREG(MR0) = period;
+	TWREG(MCR) = MR0I | MR0R;
+	interrupt_register(TIMER0, timer_interrupt_handler);
+}
+
+void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void)
+{
+	unsigned int ir;
+	ir = TREG(IR);
+	TREG(IR) = ir;
+
+	if (ir & (1<<0)) {
+		/* Match channel 0 */
+		putstr(" *timer0* ");
+	}
+
+	interrupt_clear();
+}
+
============================================================
--- timer.h	95b887ab46f9dbd390b5a152bc1dc36793949c19
+++ timer.h	c2e75d36a6314f29f490f12d9d98f4bb50b843fc
@@ -11,6 +11,7 @@ void timer_delay_clocks(unsigned int clo
 void init_timer(void);
 unsigned int timer_read(void);
 void timer_delay_clocks(unsigned int clocks);
+void timer_set_period(unsigned int period);
 
 #define timer_delay_us(x) timer_delay_clocks((x)*TIMER_US)
 #define timer_delay_ms(x) timer_delay_clocks((x)*TIMER_MS)
============================================================
--- /dev/null	
+++ uart.c	b336e227dc442fef728c0a695671328c7a265dd1
@@ -0,0 +1,79 @@
+#include "uart.h"
+
+#define UARTBASE 0xE000C000
+
+#define RBR 0x00
+#define THR 0x00
+#define DLL 0x00
+#define DLM 0x04
+#define IER 0x04
+#define IIR 0x08
+#define FCR 0x08
+
+#define LCR 0x0c
+#define LSR 0x14
+#define SCR 0x1c
+#define ACR 0x20
+#define FDR 0x28
+#define TER 0x30
+
+#define UREG(x) (((volatile unsigned char *)UARTBASE)[x])
+
+#define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */
+#define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */
+
+void init_uart(void)
+{
+	UREG(FDR) = 0x10; /* DivAddVal = 0, MulVal = 1 */
+
+	UREG(LCR) = 0x80;
+	UREG(DLM) = 0x00;
+	UREG(DLL) = 0x08; /* 14745600 / (16*115200) */
+	UREG(LCR) = 0x13;
+	UREG(FCR) = 0x07;
+}
+
+void putch(char c) {
+	while (!U0THRE);
+	UREG(THR) = c;
+}
+
+void putstr(char *s) {
+	while (*s) putch(*s++);
+}
+
+void putint(unsigned int n) {
+	char s[11];
+	int i;
+
+	i = 10;
+	s[i] = '\0';
+
+	do {
+		s[--i] = n % 10 + '0';
+	} while ((n /= 10) > 0);
+
+	putstr(s+i);
+}
+
+void puthex(unsigned int n) {
+	char s[9];
+	int i;
+
+	i = 8;
+	s[i] = '\0';
+
+	do {
+		int x = n % 16;
+		if (x > 9)
+			x += 'A' - '0' - 10;
+		s[--i] = x + '0';
+	} while ((n /= 16) > 0);
+
+	putstr(s+i);
+}
+
+char getch(void) {
+	while (!U0DR);
+	return UREG(RBR);
+}
============================================================
--- /dev/null	
+++ uart.h	2d08795e26e7e976bded494c773936c5f91d1b69
@@ -0,0 +1,11 @@
+#ifndef __UART_H
+#define __UART_H
+
+void init_uart(void);
+void putch(char c);
+void putstr(char *s);
+void putint(unsigned int n);
+void puthex(unsigned int n);
+char getch(void);
+
+#endif /* __UART_H */