plat.c

00001 /*
00002 # This file is Copyright 2006, 2007, 2009 Dean Hall.
00003 #
00004 # This file is part of the Python-on-a-Chip program.
00005 # Python-on-a-Chip is free software: you can redistribute it and/or modify
00006 # it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
00007 #
00008 # Python-on-a-Chip is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00011 # A copy of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
00012 # is seen in the file COPYING up one directory from this.
00013 */
00014 
00015 
00016 #undef __FILE_ID__
00017 #define __FILE_ID__ 0x70
00018 
00019 
00023 #include <stdio.h>
00024 #include <avr/io.h>
00025 #include <avr/interrupt.h>
00026 #include <avr/pgmspace.h>
00027 #include <avr/eeprom.h>
00028 
00029 #include "pm.h"
00030 
00031 
00032 #define UART_BAUD 19200UL
00033 
00034 
00042 #define AVR_DEFAULT_TIMER_SOURCE
00043 
00044 
00045 #ifdef AVR_DEFAULT_TIMER_SOURCE
00046 
00047 /* Hint: 1,000,000 µs/s * 256 T/C0 clock cycles per tick * 8 CPU clocks per
00048  * T/C0 clock cycle / x,000,000 CPU clock cycles per second -> µs per tick
00049  */
00050 #define PLAT_TIME_PER_TICK_USEC (1000000ULL*256ULL*8ULL/F_CPU)
00051 
00052 #endif /* AVR_DEFAULT_TIMER_SOURCE */
00053 
00054 
00055 /* Configure stdin, stdout, stderr */
00056 static int uart_putc(char c, FILE *stream);
00057 static int uart_getc(FILE *stream);
00058 FILE avr_uart = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);
00059 
00060 
00061 /*
00062  * AVR target shall use stdio for I/O routines.
00063  * The UART or USART must be configured for the interactive interface to work.
00064  */
00065 PmReturn_t
00066 plat_init(void)
00067 {
00068     /* PORT BEGIN: Set these UART/USART SFRs properly for your AVR */
00069 
00070     /* Set the baud rate register */
00071     UBRR = (F_CPU / (16UL * UART_BAUD)) - 1;
00072 
00073     /* Enable the transmit and receive pins */
00074     UCR = _BV(TXEN) | _BV(RXEN);
00075 
00076     stdin = stdout = stderr = &avr_uart;
00077     /* PORT END */
00078 
00079 #ifdef AVR_DEFAULT_TIMER_SOURCE
00080     /* PORT BEGIN: Configure a timer that fits your needs. */
00081     /* Use T/C0 in synchronous mode, aim for a tick rate of
00082      * several hundred Hz */
00083 #if (TARGET_MCU == atmega103) || (TARGET_MCU == atmega128)
00084     /* set T/C0 to use synchronous clock */
00085     ASSR &= ~(1<<AS0);
00086     /* set prescaler to /8 */
00087     TCCR0 &= ~0x07;
00088     TCCR0 |= (1<<CS01);
00089 #else
00090 #error No timer configuration is implemented for this AVR.
00091 #endif
00092 #endif /* AVR_DEFAULT_TIMER_SOURCE */
00093     /* PORT END */
00094 
00095     return PM_RET_OK;
00096 }
00097 
00098 
00099 PmReturn_t
00100 plat_deinit(void)
00101 {
00102     /* Disable UART */
00103     UCR &= ~(_BV(TXEN) | _BV(RXEN));
00104 
00105 #ifdef AVR_DEFAULT_TIMER_SOURCE
00106 #if (TARGET_MCU == atmega103) || (TARGET_MCU == atmega128)
00107     /* Disable Timer */
00108     TCCR0 = 0;
00109 #else
00110 #error No timer configuration is implemented for this AVR.
00111 #endif
00112 #endif /* AVR_DEFAULT_TIMER_SOURCE */
00113 
00114     return PM_RET_OK;
00115 }
00116 
00117 
00118 #ifdef AVR_DEFAULT_TIMER_SOURCE
00119 ISR(TIMER0_OVF_vect)
00120 {
00121     /* TODO Find a clever way to handle bad return code, maybe use
00122      * PM_REPORT_IF_ERROR(retval) when that works on AVR inside an
00123      * interrupt.
00124      */
00125     pm_vmPeriodic(PLAT_TIME_PER_TICK_USEC);
00126 }
00127 #endif
00128 
00129 
00130 /*
00131  * Gets a byte from the address in the designated memory space
00132  * Post-increments *paddr.
00133  */
00134 uint8_t
00135 plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
00136 {
00137     uint8_t b = 0;
00138 
00139     switch (memspace)
00140     {
00141         case MEMSPACE_RAM:
00142             b = **paddr;
00143             *paddr += 1;
00144             return b;
00145 
00146         case MEMSPACE_PROG:
00147             b = pgm_read_byte(*paddr);
00148             *paddr += 1;
00149             return b;
00150 
00151         case MEMSPACE_EEPROM:
00152             b = eeprom_read_byte(*paddr);
00153             *paddr += 1;
00154             return b;
00155 
00156         case MEMSPACE_SEEPROM:
00157         case MEMSPACE_OTHER0:
00158         case MEMSPACE_OTHER1:
00159         case MEMSPACE_OTHER2:
00160         case MEMSPACE_OTHER3:
00161         default:
00162             return 0;
00163     }
00164 }
00165 
00166 
00167 static int
00168 uart_getc(FILE *stream)
00169 {
00170     char c;
00171 
00172     /* Wait for reception of a byte */
00173     loop_until_bit_is_set(USR, RXC);
00174     c = UDR;
00175 
00176     /* Return errors for Framing error or Overrun */
00177     if (USR & _BV(FE)) return _FDEV_EOF;
00178     if (USR & _BV(DOR)) return _FDEV_ERR;
00179 
00180     return c;
00181 }
00182 
00183 
00184 static int
00185 uart_putc(char c, FILE *stream)
00186 {
00187     /* Wait until UART can accept the byte */
00188     loop_until_bit_is_set(USR, UDRE);
00189 
00190     /* Send the byte */
00191     UDR = c;
00192 
00193     return 0;
00194 }
00195 
00196 
00197 /*
00198  * UART receive char routine MUST return exactly and only the received char;
00199  * it should not translate \n to \r\n.
00200  * This is because the interactive interface uses binary transfers.
00201  */
00202 PmReturn_t
00203 plat_getByte(uint8_t *b)
00204 {
00205     PmReturn_t retval = PM_RET_OK;
00206 
00207     /* PORT BEGIN: Set these UART/USART SFRs properly for your AVR */
00208     /* Loop until serial receive is complete */
00209     loop_until_bit_is_set(USR, RXC);
00210 
00211     /* If a framing error or data overrun occur, raise an IOException */
00212     if (USR & (_BV(FE) | _BV(DOR)))
00213     {
00214         PM_RAISE(retval, PM_RET_EX_IO);
00215         return retval;
00216     }
00217     *b = UDR;
00218     /* PORT END */
00219 
00220     return retval;
00221 }
00222 
00223 
00224 /*
00225  * UART send char routine MUST send exactly and only the given char;
00226  * it should not translate \n to \r\n.
00227  * This is because the interactive interface uses binary transfers.
00228  */
00229 PmReturn_t
00230 plat_putByte(uint8_t b)
00231 {
00232     /* PORT BEGIN: Set these UART/USART SFRs properly for your AVR */
00233     /* Loop until serial data reg is empty (from previous transfer) */
00234     loop_until_bit_is_set(USR, UDRE);
00235 
00236     /* Put the byte to send into the serial data register */
00237     UDR = b;
00238     /* PORT END */
00239 
00240     return PM_RET_OK;
00241 }
00242 
00243 
00244 /*
00245  * This operation is made atomic by temporarily disabling
00246  * the interrupts. The old state is restored afterwards.
00247  */
00248 PmReturn_t
00249 plat_getMsTicks(uint32_t *r_ticks)
00250 {
00251     /* Critical section start */
00252     unsigned char _sreg = SREG;
00253     cli();
00254     *r_ticks = pm_timerMsTicks;
00255     SREG = _sreg;
00256     /* Critical section end */
00257     return PM_RET_OK;
00258 }
00259 
00260 
00261 void
00262 plat_reportError(PmReturn_t result)
00263 {
00264     /* Print error */
00265     printf_P(PSTR("Error:     0x%02X\n"), result);
00266     printf_P(PSTR("  Release: 0x%02X\n"), gVmGlobal.errVmRelease);
00267     printf_P(PSTR("  FileId:  0x%02X\n"), gVmGlobal.errFileId);
00268     printf_P(PSTR("  LineNum: %d\n"), gVmGlobal.errLineNum);
00269 
00270     /* Print traceback */
00271     {
00272         pPmObj_t pframe;
00273         pPmObj_t pstr;
00274         PmReturn_t retval;
00275 
00276         puts_P(PSTR("Traceback (top first):"));
00277 
00278         /* Get the top frame */
00279         pframe = (pPmObj_t)gVmGlobal.pthread->pframe;
00280 
00281         /* If it's the native frame, print the native function name */
00282         if (pframe == (pPmObj_t)&(gVmGlobal.nativeframe))
00283         {
00284 
00285             /* The last name in the names tuple of the code obj is the name */
00286             retval = tuple_getItem((pPmObj_t)gVmGlobal.nativeframe.nf_func->
00287                                    f_co->co_names, -1, &pstr);
00288             if ((retval) != PM_RET_OK)
00289             {
00290                 puts_P(PSTR("  Unable to get native func name."));
00291                 return;
00292             }
00293             else
00294             {
00295                 printf_P(PSTR("  %s() __NATIVE__\n"), ((pPmString_t)pstr)->val);
00296             }
00297 
00298             /* Get the frame that called the native frame */
00299             pframe = (pPmObj_t)gVmGlobal.nativeframe.nf_back;
00300         }
00301 
00302         /* Print the remaining frame stack */
00303         for (;
00304              pframe != C_NULL;
00305              pframe = (pPmObj_t)((pPmFrame_t)pframe)->fo_back)
00306         {
00307             /* The last name in the names tuple of the code obj is the name */
00308             retval = tuple_getItem((pPmObj_t)((pPmFrame_t)pframe)->
00309                                    fo_func->f_co->co_names, -1, &pstr);
00310             if ((retval) != PM_RET_OK) break;
00311 
00312             printf_P(PSTR("  %s()\n"), ((pPmString_t)pstr)->val);
00313         }
00314         puts_P(PSTR("  <module>."));
00315     }
00316 }

Generated on Mon Oct 18 07:40:46 2010 for Python-on-a-chip by  doxygen 1.5.9