Contiki 2.6

mtarch.c

00001 /*
00002  * Copyright (c) 2006, Technical University of Munich
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  *
00031  * \file AVR specific implementation of multithreading architecture
00032  *
00033  * \author Adam Dunkels <adam@sics.se>
00034  * \author Simon Barner <barner@in.tum.de>
00035  *
00036  */
00037 
00038 #include <avr/io.h>
00039 #include <avr/interrupt.h>
00040 #include <stdio.h>
00041 #include "sys/mt.h"
00042 #include "dev/rs232.h"
00043 
00044 /*--------------------------------------------------------------------------*/
00045 void
00046 mtarch_init(void)
00047 {
00048   
00049 }
00050 /*--------------------------------------------------------------------------*/
00051 void
00052 mtarch_start(struct mtarch_thread *t,
00053              void (*function)(void *), void *data)
00054 {
00055   /* Initialize stack with number sequence (used for
00056    * measuring stack usage */
00057   uint8_t i;
00058 
00059   for(i = 0; i < MTARCH_STACKSIZE; ++i) {
00060     t->stack[i] = i;
00061   }
00062 
00063   /*
00064    * Push pointer to mt_exit and the thread onto our stack:
00065    * Caveats:
00066    *  - The stack is defined as an array of bytes, but pointers are 16 bit wide
00067    *  - Function pointers are 16-bit addresses in flash ROM, but e.g.
00068    *    avr-objdump displays byte addresses
00069    *  - Get the high and low byte of the addresses onto the stack in the
00070    *    right order
00071    */
00072 
00073   /* Initialize stack. This is done in reverse order ("pushing") the
00074    *  pre-allocated array */
00075 
00076   /* mt_exit function that is to be invoked if the thread dies */
00077   t->stack[MTARCH_STACKSIZE -  1] = (unsigned char)((unsigned short)mt_exit) & 0xff;
00078   t->stack[MTARCH_STACKSIZE -  2] = (unsigned char)((unsigned short)mt_exit >> 8) & 0xff;
00079 
00080   /* The thread handler. Invoked when RET is called in mtarch_exec */
00081   t->stack[MTARCH_STACKSIZE -  3] = (unsigned char)((unsigned short)function) & 0xff;
00082   t->stack[MTARCH_STACKSIZE -  4] = (unsigned char)((unsigned short)function >> 8) & 0xff;
00083 
00084   /* Register r0-r23 in t->stack[MTARCH_STACKSIZE -  5] to
00085    *  t->stack[MTARCH_STACKSIZE -  28].
00086    *
00087    * Per calling convention, the argument to the thread handler function 
00088    *  (i.e. the 'data' pointer) is passed via r24-r25.
00089    * See http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage) */
00090   t->stack[MTARCH_STACKSIZE - 29] = (unsigned char)((unsigned short)data) & 0xff;
00091   t->stack[MTARCH_STACKSIZE - 30] = (unsigned char)((unsigned short)data >> 8) & 0xff;
00092 
00093   /* Initialize stack pointer: Space for 2 2-byte-addresses and 32 registers,
00094    * post-decrement POP / pre-increment PUSH scheme */
00095   t->sp = &t->stack[MTARCH_STACKSIZE - 1 - 4 - 32];
00096 }
00097 
00098 /*--------------------------------------------------------------------------*/
00099 static unsigned char *sptmp;
00100 static struct mtarch_thread *running;
00101 
00102 static void
00103 sw(void)
00104 {
00105   /* Disable interrupts while we perform the context switch */
00106   cli ();
00107 
00108   /* Push 32 general purpuse registers */
00109   __asm__("push r0");
00110   __asm__("push r1");
00111   __asm__("push r2");
00112   __asm__("push r3");
00113   __asm__("push r4");
00114   __asm__("push r5");
00115   __asm__("push r6");
00116   __asm__("push r7");
00117   __asm__("push r8");
00118   __asm__("push r9");
00119   __asm__("push r10");
00120   __asm__("push r11");
00121   __asm__("push r12");
00122   __asm__("push r13");
00123   __asm__("push r14");
00124   __asm__("push r15");
00125   __asm__("push r16");
00126   __asm__("push r17");
00127   __asm__("push r18");
00128   __asm__("push r19");
00129   __asm__("push r20");
00130   __asm__("push r21");
00131   __asm__("push r22");
00132   __asm__("push r23");
00133   __asm__("push r24");
00134   __asm__("push r25");
00135   __asm__("push r26");
00136   __asm__("push r27");
00137   __asm__("push r28");
00138   __asm__("push r29");
00139   __asm__("push r30");
00140   __asm__("push r31");
00141 
00142   /* Switch stack pointer */
00143   sptmp = running->sp;
00144   running->sp = (unsigned char*)SP;
00145   SP = (unsigned short)sptmp;
00146 
00147   /* Pop 32 general purpose registers */
00148   __asm__("pop r31");
00149   __asm__("pop r30");
00150   __asm__("pop r29");
00151   __asm__("pop r28");
00152   __asm__("pop r27");
00153   __asm__("pop r26");
00154   __asm__("pop r25");
00155   __asm__("pop r24");
00156   __asm__("pop r23");
00157   __asm__("pop r22");
00158   __asm__("pop r21");
00159   __asm__("pop r20");
00160   __asm__("pop r19");
00161   __asm__("pop r18");
00162   __asm__("pop r17");
00163   __asm__("pop r16");
00164   __asm__("pop r15");
00165   __asm__("pop r14");
00166   __asm__("pop r13");
00167   __asm__("pop r12");
00168   __asm__("pop r11");
00169   __asm__("pop r10");
00170   __asm__("pop r9");
00171   __asm__("pop r8");
00172   __asm__("pop r7");
00173   __asm__("pop r6");
00174   __asm__("pop r5");
00175   __asm__("pop r4");
00176   __asm__("pop r3");
00177   __asm__("pop r2");
00178   __asm__("pop r1");
00179   __asm__("pop r0");
00180 
00181   /* Renable interrupts */
00182   sei ();
00183 }
00184 /*--------------------------------------------------------------------------*/
00185 void
00186 mtarch_exec(struct mtarch_thread *t)
00187 {
00188   running = t;
00189   sw();
00190   running = NULL;
00191 }
00192 
00193 /*--------------------------------------------------------------------------*/
00194 void
00195 mtarch_remove(void)
00196 {
00197 
00198 }
00199 /*--------------------------------------------------------------------------*/
00200 void
00201 mtarch_yield(void)
00202 {
00203   sw();
00204 }
00205 /*--------------------------------------------------------------------------*/
00206 void
00207 mtarch_pstop(void)
00208 {
00209   
00210 }
00211 /*--------------------------------------------------------------------------*/
00212 void
00213 mtarch_pstart(void)
00214 {
00215   
00216 }
00217 /*--------------------------------------------------------------------------*/
00218 void
00219 mtarch_stop(struct mtarch_thread *t)
00220 {
00221   
00222 }
00223 /*--------------------------------------------------------------------------*/
00224 int
00225 mtarch_stack_usage(struct mt_thread *t)
00226 {
00227   uint8_t i;
00228   for(i = 0; i < MTARCH_STACKSIZE; ++i) {
00229     if(t->thread.stack[i] != i) {
00230       break;
00231     }
00232   }
00233   return MTARCH_STACKSIZE - i;
00234 }
00235 /*--------------------------------------------------------------------------*/