Basic interrupt handling; enough so that timers work.
authorDavid Given <dg@cowlark.com>
Sun, 21 Jun 2015 21:56:38 +0000 (23:56 +0200)
committerDavid Given <dg@cowlark.com>
Sun, 21 Jun 2015 21:56:38 +0000 (23:56 +0200)
Kernel/kernel430x.def
Kernel/lowlevel-msp430x.S [new file with mode: 0644]
Kernel/platform-msp430fr5969/build.mk
Kernel/platform-msp430fr5969/config.h
Kernel/platform-msp430fr5969/crt0.S
Kernel/platform-msp430fr5969/devices.c
Kernel/platform-msp430fr5969/globals.h [new file with mode: 0644]
Kernel/platform-msp430fr5969/msp430fr5969.ld

index 7f3f74a..f0431a3 100644 (file)
@@ -1,3 +1,5 @@
+U_DATA = udata
+
 ; Keep these in sync with struct u_data!!
 #define U_DATA__U_PTAB         (U_DATA+0)   ; struct p_tab*
 #define U_DATA__U_PAGE         (U_DATA+2)   ; uint16_t
diff --git a/Kernel/lowlevel-msp430x.S b/Kernel/lowlevel-msp430x.S
new file mode 100644 (file)
index 0000000..b269fdc
--- /dev/null
@@ -0,0 +1,21 @@
+#include "kernel430x.def"
+
+.section ".lowtext"
+.globl interrupt_handler
+interrupt_handler:
+       /* Interrupts are off here and we're running on... a... stack. This
+        * may be the user process or the kernel's. We haven't saved any
+        * registers yet. */
+
+       mov SP, &istack_switched_sp        ; save old stack (16 bit!)
+       mov #istack_top, SP                ; load new one
+
+       pushm.a #13, r15                   ; save all registers (r15 to r3)
+
+       calla #platform_interrupt
+
+       popm.a #13, r15                    ; restore all registers (r15 to r3)
+       
+       mov &istack_switched_sp, SP        ; restore stack
+       reti
+
index 3db60b5..b6c4b7e 100644 (file)
@@ -17,6 +17,7 @@ kernel.srcs = \
        ../dev/mbr.c \
        ../devio.c \
        ../filesys.c \
+       ../lowlevel-msp430x.S \
        ../kdata.c \
        ../process.c \
        ../simple.c \
index 77aa7b3..701f137 100644 (file)
@@ -41,7 +41,7 @@ extern unsigned char vt_mangle_6847(unsigned char c);
 
 extern int __user_base;
 
-#define TICKSPERSEC 100   /* Ticks per second */
+#define TICKSPERSEC 64   /* Ticks per second */
 #define PROGBASE    ((uint16_t)(size_t)&__user_base)  /* also data base */
 #define PROGLOAD    PROGBASE /* also data base */
 #define PROGTOP     0xfe00  /* Top of program */
index c748f1b..d7910a9 100644 (file)
@@ -1,6 +1,7 @@
 #include "msp430fr5969.h"
 #include "kernel.def"
 #include "kernel430x.def"
+#include "globals.h"
 
 ; imported symbols
 .globl fuzix_main
 .section ".noinit"
 
 ; The interrupt stack.
+.globl istack_top
 istack_base:
        .fill 254
 istack_top:
 
-; The saved interrupt pointer.
-.globl istack_switch_sp
-.comm istack_switch_sp, 2
+; The saved interrupt pointer. Stacks must be in low memory.
+.globl istack_switched_sp
+.comm istack_switched_sp, 2
 
 ; The userdata/system stack structure. See Kernel/include/kernel.h.
 .globl udata
@@ -37,8 +39,23 @@ __main:
        mov.b #CSKEY>>8, &CSCTL0_H                      ; Unlock clock registers
        mov.w #DCOFSEL_3 | DCORSEL, &CSCTL1             ; DCO to 8MHz
        ; ACLK = VLO; SMCLK = MCLK = DCO
-       mov.w #(SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK), &CSCTL2
+       mov.w #(SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK), &CSCTL2
        mov.w #(DIVA__1 | DIVS__1 | DIVM__1), &CSCTL3
+
+       ; Configure the LFXT.
+       mov.w #0, &PJSEL1
+       mov.w #BIT4|BIT5, &PJSEL0
+       bis.w #LFXTDRIVE_3|HFXTOFF, &CSCTL4
+       bic.w #LFXTBYPASS|LFXTOFF, &CSCTL4
+
+       ; Wait for oscillators to settle.
+
+1:
+       bic.w #LFXTOFFG|HFXTOFFG, &CSCTL5
+       bic.w #OFIFG, &SFRIFG1
+       bit.w #OFIFG, &SFRIFG1
+       jnz 1b
+       
        mov.b #0, &CSCTL0_H                             ; Relock clock registers
 
        ; Init stack.
@@ -108,6 +125,18 @@ irqrestore:
        .word __main
 .text
 
+.globl last_interrupt
+.comm last_interrupt, 1
+
+#define standard_interrupt(name, irq) \
+       .globl name ## _trampoline { \
+       .section ".lowtext", "ax", @progbits { \
+       name ## _trampoline: \
+       mov.b #(irq), &last_interrupt { \
+       bra #interrupt_handler { \
+       .section #name, "ax", @progbits { \
+               .word name ## _trampoline
+
 #define fallback_interrupt(name) \
        .text { \
        1: mov #3f, r12 { \
@@ -115,11 +144,13 @@ irqrestore:
           calla #kprintf { \
        2: jmp 2b { \
        .data { \
-       3: .asciz name { \
-       .section name, "ax", @progbits { \
+       3: .asciz #name { \
+       .section #name, "ax", @progbits { \
           .word 1b
 
 ;fallback_interrupt("__interrupt_vector_comp_e")
-fallback_interrupt("__interrupt_vector_unmi")
-fallback_interrupt("__interrupt_vector_sysnmi")
+fallback_interrupt(__interrupt_vector_unmi)
+fallback_interrupt(__interrupt_vector_sysnmi)
+
+standard_interrupt(__interrupt_vector_wdt, INTERRUPT_WDT)
 
index 5381b2e..5f67129 100644 (file)
@@ -4,6 +4,12 @@
 #include <tty.h>
 #include <devsd.h>
 #include <blkdev.h>
+#include <printf.h>
+#include <timer.h>
+#include "msp430fr5969.h"
+#include "globals.h"
+
+extern uint8_t last_interrupt;
 
 struct devsw dev_tab[] =  /* The device driver switch table */
 {
@@ -34,7 +40,26 @@ bool validdev(uint16_t dev)
 
 void device_init(void)
 {
+       /* Configure the watchdog timer to use ACLK as the system interrupt.
+        * ACLK was set up in the boot sequence to use the LFXT clock, which runs
+        * (relatively accurately) at 32kHz. 512 ticks at 32kHz is 64Hz.
+        */
+
+       WDTCTL = WDTPW | WDTSSEL__ACLK | WDTTMSEL | WDTCNTCL | WDTIS__512;
+       SFRIE1 |= WDTIE;
+
        devsd_init();
 }
 
+/* This is called with interrupts off. */
+void platform_interrupt(void)
+{
+       switch (last_interrupt)
+       {
+               case INTERRUPT_WDT:
+                       timer_interrupt();
+                       break;
+       }
+}
+
 
diff --git a/Kernel/platform-msp430fr5969/globals.h b/Kernel/platform-msp430fr5969/globals.h
new file mode 100644 (file)
index 0000000..7db9257
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+#define INTERRUPT_WDT 0
+
+#endif
+
index f7deec5..ed363cd 100644 (file)
@@ -221,8 +221,7 @@ SECTIONS
     KEEP (*(.dtors))
   } > HIROM
 
-  .text           :
-  {
+  .text : {
     . = ALIGN(2);
     PROVIDE (_start = .);
     KEEP (*(SORT(.crt_*)))