From aa3fd9876abe2131d2ebda9a418ade6a4b89f72c Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Wed, 22 May 2013 16:43:58 +0900
Subject: Implement interrupt as thread

---
 ChangeLog |  9 +++++++
 chopstx.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 chopstx.h |  3 ++-
 entry.c   | 23 +++++++++++++++---
 4 files changed, 101 insertions(+), 17 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e8f77e2..19274fa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2013-05-22  Niibe Yutaka  <gniibe@fsij.org>
+
+	* chopstx.c (chx_enable_intr, chx_disable_intr): Implement.
+	(chx_set_intr_prio): New.
+	(chx_handle_intr): Use list to register interrupt threads.
+	(chx_init): Set PendSV priority (as minimum: bigger).
+
+	* entry.c (vector_table): set chx_handle_intr for all interrupts.
+
 2013-05-21  Niibe Yutaka  <gniibe@fsij.org>
 
 	* Initial commit.
diff --git a/chopstx.c b/chopstx.c
index cb46f80..80df272 100644
--- a/chopstx.c
+++ b/chopstx.c
@@ -99,6 +99,31 @@ struct chx_stack_regs {
 
 #define INITIAL_XPSR 0x01000000	/* T=1 */
 
+/*
+ * NVIC: Nested Vectored Interrupt Controller
+ */
+struct NVIC {
+  uint32_t ISER[8];
+  uint32_t unused1[24];
+  uint32_t ICER[8];
+  uint32_t unused2[24];
+  uint32_t ISPR[8];
+  uint32_t unused3[24];
+  uint32_t ICPR[8];
+  uint32_t unused4[24];
+  uint32_t IABR[8];
+  uint32_t unused5[56];
+  uint32_t IPR[60];
+};
+
+static struct NVIC *const NVICBase = (struct NVIC *const)0xE000E100;
+#define NVIC_ISER(n)	(NVICBase->ISER[n >> 5])
+#define NVIC_ICER(n)	(NVICBase->ICER[n >> 5])
+#define NVIC_ICPR(n)	(NVICBase->ICPR[n >> 5])
+#define NVIC_IPR(n)	(NVICBase->IPR[n >> 2])
+
+#define USB_LP_CAN1_RX0_IRQn	 20
+
 /*
  * SysTick registers.
  */
@@ -465,21 +490,51 @@ chx_timer_expired (void)
 static void
 chx_enable_intr (uint8_t irq_num)
 {
+  NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
 }
 
 static void
 chx_disable_intr (uint8_t irq_num)
 {
+  NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
 }
 
-void
-chx_handle_intr (chopstix_intr_t *intr)
+#define INTR_PRIO (11<<4)
+
+static void
+chx_set_intr_prio (uint8_t n)
 {
-  chx_disable_intr (intr->irq_num);
-  asm volatile ("cpsid   i" : : : "memory");
-  intr->ready++;
-  if (intr->t)
+  unsigned int sh = (n & 3) << 3;
+
+  NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh)) | (INTR_PRIO << sh);
+}
+
+static chopstix_intr_t *intr_top;
+
+void
+chx_handle_intr (void)
+{
+  chopstix_intr_t *intr;
+  register uint32_t irq_num;
+
+  asm volatile ("cpsid	i\n\t"
+		"mrs	%0, IPSR\n\t"
+		"sub	%0, #16"   /* Exception # - 16 = interrupt number.  */
+		: "=r" (irq_num) : /* no input */ : "memory");
+  chx_disable_intr (irq_num);
+  for (intr = intr_top; intr; intr = intr->next)
+    if (intr->irq_num == irq_num)
+      break;
+
+  if (intr == NULL)
+    {				/* Interrupt from unregistered source.  */
+      asm volatile ("cpsie   i" : : : "memory");
+      return;
+    }
+
+  if (intr->t && intr->t->v == THREAD_WAIT_INT)
     {
+      intr->ready++;
       chx_ready_enqueue (intr->t);
       chx_preempt ();
     }
@@ -494,11 +549,16 @@ chx_systick_init (void)
   *SYST_CSR = 7;
 }
 
+static uint32_t *const SHPR3 = (uint32_t *const)0xE000ED20;
+#define INTR_PRIO_PENDSV (15<<4)
+
 #define PRIO_DEFAULT 1
 
 void
 chx_init (struct chx_thread *tp)
 {
+  *SHPR3 = (INTR_PRIO_PENDSV << 16);
+
   memset (&tp->tc, 0, sizeof (tp->tc));
   q_ready.next = q_ready.prev = (struct chx_thread *)&q_ready;
   q_timer.next = q_timer.prev = (struct chx_thread *)&q_timer;
@@ -784,14 +844,13 @@ chopstx_cond_broadcast (chopstx_cond_t *cond)
 }
 
 
-#define MAX_INTR_NUM 16
-
-chopstix_intr_t *intr_table[MAX_INTR_NUM];
-
 void
 chopstx_intr_register (chopstix_intr_t *intr, uint8_t irq_num)
 {
-  intr_table[irq_num] = intr;
+  chx_disable_intr (irq_num);
+  chx_set_intr_prio (irq_num);
+  intr->next = intr_top;
+  intr_top = intr;
   intr->irq_num = irq_num;
   intr->t = running;
   intr->ready = 0;
@@ -801,8 +860,8 @@ chopstx_intr_register (chopstix_intr_t *intr, uint8_t irq_num)
 void
 chopstx_wait_intr (chopstix_intr_t *intr)
 {
-  chx_enable_intr (intr->irq_num);
   asm volatile ("cpsid   i" : : : "memory");
+  chx_enable_intr (intr->irq_num);
   while (intr->ready == 0)
     {
       intr->t = running;
diff --git a/chopstx.h b/chopstx.h
index 6ab9b87..83c9999 100644
--- a/chopstx.h
+++ b/chopstx.h
@@ -77,8 +77,9 @@ void chopstx_cond_signal (chopstx_cond_t *cond);
 void chopstx_cond_broadcast (chopstx_cond_t *cond);
 
 typedef struct chx_intr {
-  struct chx_thread *t;
+  struct chx_intr *next;
   struct chx_spinlock lock;
+  struct chx_thread *t;
   uint8_t irq_num;
   uint8_t ready;
 } chopstix_intr_t;
diff --git a/entry.c b/entry.c
index 45f0da6..0eceaca 100644
--- a/entry.c
+++ b/entry.c
@@ -314,6 +314,7 @@ extern uint8_t __main_stack_end__;
 extern void svc (void);
 extern void preempt (void);
 extern void chx_timer_expired (void);
+extern void chx_handle_intr (void);
 
 handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
   (handler)&__main_stack_end__,
@@ -333,11 +334,25 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
   preempt,			/* PendSV */
   chx_timer_expired,		/* SysTick */
   /* 0x40 */
-  none, none, none, none,  none, none, none, none,
+  chx_handle_intr /* WWDG */,   chx_handle_intr /* PVD */,
+  chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,
+  chx_handle_intr /* FLASH */,  chx_handle_intr /* RCC */,
+  chx_handle_intr /* EXTI0 */,  chx_handle_intr /* EXTI1 */,
   /* 0x60 */
-  none, none, none, none,  none, none, none, none,
+  chx_handle_intr /* EXTI2 */,    chx_handle_intr /* EXTI3 */,
+  chx_handle_intr /* EXTI4 */,    chx_handle_intr /* DMA1 CH1 */,
+  chx_handle_intr /* DMA1 CH2 */, chx_handle_intr /* DMA1 CH3 */,
+  chx_handle_intr /* DMA1 CH4 */, chx_handle_intr /* DMA1 CH5 */,
   /* 0x80 */
-  none, none, none, none,
+  chx_handle_intr /* DMA1 CH6 */, chx_handle_intr /* DMA1 CH7 */,
+  chx_handle_intr /* ADC1_2 */, chx_handle_intr /* USB HP */,
   /* 0x90 */
-  none,
+  chx_handle_intr,		/* USB LP */
+  /* ... and more.  CAN, EXT9_5, TIMx, I2C, SPI, USART, EXT15_10 */
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,
 };
-- 
cgit v1.2.3