plat.c

00001 /*
00002 # This file is Copyright 2010 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 <string.h>
00025 #include <avr/io.h>
00026 #include <avr/interrupt.h>
00027 #include <avr/pgmspace.h>
00028 #include <avr/eeprom.h>
00029 
00030 #include "pm.h"
00031 
00032 
00033 #define UART_BAUD 57600UL
00034 
00035 
00036 /* Hint: 1,000,000 µs/s * 256 T/C0 clock cycles per tick * 8 CPU clocks per
00037  * T/C0 clock cycle / x,000,000 CPU clock cycles per second -> µs per tick
00038  */
00039 #define PLAT_TIME_PER_TICK_USEC (1000000ULL*256ULL*8ULL/F_CPU)
00040 
00041 
00042 /* Configure stdin, stdout, stderr */
00043 static int uart_putc(char c, FILE *stream);
00044 static int uart_getc(FILE *stream);
00045 FILE avr_uart = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);
00046 
00047 
00048 /*
00049  * AVR target shall use stdio for I/O routines.
00050  * The UART or USART must be configured for the interactive interface to work.
00051  */
00052 PmReturn_t
00053 plat_init(void)
00054 {
00055     /* Set the baud rate register */
00056     UBRR0 = (F_CPU / (16UL * UART_BAUD)) - 1;
00057 
00058     /* Set mode Async, 8-N-1 */
00059     UCSR0C = (_BV(UCSZ01) | _BV(UCSZ00));
00060 
00061     /* Enable the transmit and receive pins */
00062     UCSR0B = _BV(TXEN0) | _BV(RXEN0);
00063 
00064     stdin = stdout = stderr = &avr_uart;
00065 
00066     /* Set T/C0 prescaler to div8.  Enable T/C0 interrupt */
00067     TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00));
00068     TCCR0B |= _BV(CS01);
00069     TIMSK0 = _BV(TOIE0);
00070 
00071     /* Global interrupt enable */
00072     sei();
00073 
00074     return PM_RET_OK;
00075 }
00076 
00077 
00078 PmReturn_t
00079 plat_deinit(void)
00080 {
00081     /* Disable UART */
00082     UCSR0B &= ~(_BV(TXEN0) | _BV(RXEN0));
00083 
00084     /* Disable Timer (clear clock source) */
00085     TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00));
00086 
00087     return PM_RET_OK;
00088 }
00089 
00090 
00091 ISR(TIMER0_OVF_vect)
00092 {
00093     /* TODO Find a clever way to handle bad return code, maybe use
00094      * PM_REPORT_IF_ERROR(retval) when that works on AVR inside an
00095      * interrupt.
00096      */
00097     pm_vmPeriodic(PLAT_TIME_PER_TICK_USEC);
00098 }
00099 
00100 
00101 /*
00102  * Gets a byte from the address in the designated memory space
00103  * Post-increments *paddr.
00104  */
00105 uint8_t
00106 plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
00107 {
00108     uint8_t b = 0;
00109 
00110     switch (memspace)
00111     {
00112         case MEMSPACE_RAM:
00113             b = **paddr;
00114             *paddr += 1;
00115             return b;
00116 
00117         case MEMSPACE_PROG:
00118             b = pgm_read_byte(*paddr);
00119             *paddr += 1;
00120             return b;
00121 
00122         case MEMSPACE_EEPROM:
00123             b = eeprom_read_byte(*paddr);
00124             *paddr += 1;
00125             return b;
00126 
00127         case MEMSPACE_SEEPROM:
00128         case MEMSPACE_OTHER0:
00129         case MEMSPACE_OTHER1:
00130         case MEMSPACE_OTHER2:
00131         case MEMSPACE_OTHER3:
00132         default:
00133             return 0;
00134     }
00135 }
00136 
00137 
00138 static int
00139 uart_getc(FILE *stream)
00140 {
00141     char c;
00142 
00143     /* Wait for reception of a byte */
00144     loop_until_bit_is_set(UCSR0A, RXC0);
00145     c = UDR0;
00146 
00147     /* Return errors for Framing error or Overrun */
00148     if (UCSR0A & _BV(FE0)) return _FDEV_EOF;
00149     if (UCSR0A & _BV(DOR0)) return _FDEV_ERR;
00150 
00151     return c;
00152 }
00153 
00154 
00155 static int
00156 uart_putc(char c, FILE *stream)
00157 {
00158     /* Wait until UART can accept the byte */
00159     loop_until_bit_is_set(UCSR0A, UDRE0);
00160 
00161     /* Send the byte */
00162     UDR0 = c;
00163 
00164     return 0;
00165 }
00166 
00167 
00168 /*
00169  * UART receive char routine MUST return exactly and only the received char;
00170  * it should not translate \n to \r\n.
00171  * This is because the interactive interface uses binary transfers.
00172  */
00173 PmReturn_t
00174 plat_getByte(uint8_t *b)
00175 {
00176     PmReturn_t retval = PM_RET_OK;
00177 
00178     /* Loop until serial receive is complete */
00179     loop_until_bit_is_set(UCSR0A, RXC0);
00180 
00181     /* If a framing error or data overrun occur, raise an IOException */
00182     if (UCSR0A & (_BV(FE0) | _BV(DOR0)))
00183     {
00184         PM_RAISE(retval, PM_RET_EX_IO);
00185         return retval;
00186     }
00187     *b = UDR0;
00188 
00189     return retval;
00190 }
00191 
00192 
00193 /*
00194  * UART send char routine MUST send exactly and only the given char;
00195  * it should not translate \n to \r\n.
00196  * This is because the interactive interface uses binary transfers.
00197  */
00198 PmReturn_t
00199 plat_putByte(uint8_t b)
00200 {
00201     /* Loop until serial data reg is empty (from previous transfer) */
00202     loop_until_bit_is_set(UCSR0A, UDRE0);
00203 
00204     /* Put the byte to send into the serial data register */
00205     UDR0 = b;
00206 
00207     return PM_RET_OK;
00208 }
00209 
00210 
00211 /*
00212  * This operation is made atomic by temporarily disabling
00213  * the interrupts. The old state is restored afterwards.
00214  */
00215 PmReturn_t
00216 plat_getMsTicks(uint32_t *r_ticks)
00217 {
00218     /* Critical section start */
00219     unsigned char _sreg = SREG;
00220     cli();
00221     *r_ticks = pm_timerMsTicks;
00222     SREG = _sreg;
00223     /* Critical section end */
00224     return PM_RET_OK;
00225 }
00226 
00227 
00228 #ifdef HAVE_DEBUG_INFO
00229 #define LEN_FNLOOKUP 26
00230 #define LEN_EXNLOOKUP 17
00231 #define FN_MAX_LEN 15
00232 #define EXN_MAX_LEN 18
00233 #ifndef MAX
00234 #define MAX(a,b) (((a) >= (b)) ? (a) : (b))
00235 #endif
00236 
00237 /* This table should match src/vm/fileid.txt */
00238 static char fnstr_00[] PROGMEM = "<no file>";
00239 static char fnstr_01[] PROGMEM = "codeobj.c";
00240 static char fnstr_02[] PROGMEM = "dict.c";
00241 static char fnstr_03[] PROGMEM = "frame.c";
00242 static char fnstr_04[] PROGMEM = "func.c";
00243 static char fnstr_05[] PROGMEM = "global.c";
00244 static char fnstr_06[] PROGMEM = "heap.c";
00245 static char fnstr_07[] PROGMEM = "img.c";
00246 static char fnstr_08[] PROGMEM = "int.c";
00247 static char fnstr_09[] PROGMEM = "interp.c";
00248 static char fnstr_10[] PROGMEM = "pmstdlib_nat.c";
00249 static char fnstr_11[] PROGMEM = "list.c";
00250 static char fnstr_12[] PROGMEM = "main.c";
00251 static char fnstr_13[] PROGMEM = "mem.c";
00252 static char fnstr_14[] PROGMEM = "module.c";
00253 static char fnstr_15[] PROGMEM = "obj.c";
00254 static char fnstr_16[] PROGMEM = "seglist.c";
00255 static char fnstr_17[] PROGMEM = "sli.c";
00256 static char fnstr_18[] PROGMEM = "strobj.c";
00257 static char fnstr_19[] PROGMEM = "tuple.c";
00258 static char fnstr_20[] PROGMEM = "seq.c";
00259 static char fnstr_21[] PROGMEM = "pm.c";
00260 static char fnstr_22[] PROGMEM = "thread.c";
00261 static char fnstr_23[] PROGMEM = "float.c";
00262 static char fnstr_24[] PROGMEM = "class.c";
00263 static char fnstr_25[] PROGMEM = "bytearray.c";
00264 
00265 static PGM_P fnlookup[LEN_FNLOOKUP] PROGMEM =
00266 {
00267     fnstr_00, fnstr_01, fnstr_02, fnstr_03,
00268     fnstr_04, fnstr_05, fnstr_06, fnstr_07,
00269     fnstr_08, fnstr_09, fnstr_10, fnstr_11,
00270     fnstr_12, fnstr_13, fnstr_14, fnstr_15,
00271     fnstr_16, fnstr_17, fnstr_18, fnstr_19,
00272     fnstr_20, fnstr_21, fnstr_22, fnstr_23,
00273     fnstr_24, fnstr_25
00274 };
00275 
00276 /* This table should match src/vm/pm.h PmReturn_t */
00277 static char exnstr_00[] PROGMEM = "Exception";
00278 static char exnstr_01[] PROGMEM = "SystemExit";
00279 static char exnstr_02[] PROGMEM = "IoError";
00280 static char exnstr_03[] PROGMEM = "ZeroDivisionError";
00281 static char exnstr_04[] PROGMEM = "AssertionError";
00282 static char exnstr_05[] PROGMEM = "AttributeError";
00283 static char exnstr_06[] PROGMEM = "ImportError";
00284 static char exnstr_07[] PROGMEM = "IndexError";
00285 static char exnstr_08[] PROGMEM = "KeyError";
00286 static char exnstr_09[] PROGMEM = "MemoryError";
00287 static char exnstr_10[] PROGMEM = "NameError";
00288 static char exnstr_11[] PROGMEM = "SyntaxError";
00289 static char exnstr_12[] PROGMEM = "SystemError";
00290 static char exnstr_13[] PROGMEM = "TypeError";
00291 static char exnstr_14[] PROGMEM = "ValueError";
00292 static char exnstr_15[] PROGMEM = "StopIteration";
00293 static char exnstr_16[] PROGMEM = "Warning";
00294 
00295 static PGM_P exnlookup[LEN_EXNLOOKUP] PROGMEM =
00296 {
00297     exnstr_00, exnstr_01, exnstr_02, exnstr_03,
00298     exnstr_04, exnstr_05, exnstr_06, exnstr_07,
00299     exnstr_08, exnstr_09, exnstr_10, exnstr_11,
00300     exnstr_12, exnstr_13, exnstr_14, exnstr_15,
00301     exnstr_16
00302 };
00303 #endif /* HAVE_DEBUG_INFO */
00304 
00305 
00306 void
00307 plat_reportError(PmReturn_t result)
00308 {
00309 #ifdef HAVE_DEBUG_INFO
00310     uint8_t res;
00311     pPmFrame_t pframe;
00312     pPmObj_t pstr;
00313     PmReturn_t retval;
00314     uint8_t bcindex;
00315     uint16_t bcsum;
00316     uint16_t linesum;
00317     uint16_t len_lnotab;
00318     uint8_t const *plnotab;
00319     uint16_t i;
00320     char pstrbuf[MAX(FN_MAX_LEN, EXN_MAX_LEN)];
00321 
00322     /* Print traceback */
00323     puts_P(PSTR("Traceback (most recent call first):"));
00324 
00325     /* Get the top frame */
00326     pframe = gVmGlobal.pthread->pframe;
00327 
00328     /* If it's the native frame, print the native function name */
00329     if (pframe == (pPmFrame_t)&(gVmGlobal.nativeframe))
00330     {
00331 
00332         /* The last name in the names tuple of the code obj is the name */
00333         retval = tuple_getItem((pPmObj_t)gVmGlobal.nativeframe.nf_func->
00334                                f_co->co_names, -1, &pstr);
00335         if ((retval) != PM_RET_OK)
00336         {
00337             puts_P(PSTR("  Unable to get native func name."));
00338             return;
00339         }
00340         else
00341         {
00342             printf_P(PSTR("  %s() __NATIVE__\n"), ((pPmString_t)pstr)->val);
00343         }
00344 
00345         /* Get the frame that called the native frame */
00346         pframe = (pPmFrame_t)gVmGlobal.nativeframe.nf_back;
00347     }
00348 
00349     /* Print the remaining frame stack */
00350     for (; pframe != C_NULL; pframe = pframe->fo_back)
00351     {
00352         /* The last name in the names tuple of the code obj is the name */
00353         retval = tuple_getItem((pPmObj_t)pframe->fo_func->f_co->co_names,
00354                                -1,
00355                                &pstr);
00356         if ((retval) != PM_RET_OK) break;
00357 
00358         /*
00359          * Get the line number of the current bytecode. Algorithm comes from:
00360          * http://svn.python.org/view/python/trunk/Objects/lnotab_notes.txt?view=markup
00361          */
00362         bcindex = pframe->fo_ip - pframe->fo_func->f_co->co_codeaddr;
00363         plnotab = pframe->fo_func->f_co->co_lnotab;
00364         len_lnotab = mem_getWord(MEMSPACE_PROG, &plnotab);
00365         bcsum = 0;
00366         linesum = pframe->fo_func->f_co->co_firstlineno;
00367         for (i = 0; i < len_lnotab; i += 2)
00368         {
00369             bcsum += mem_getByte(MEMSPACE_PROG, &plnotab);
00370             if (bcsum > bcindex) break;
00371             linesum += mem_getByte(MEMSPACE_PROG, &plnotab);
00372         }
00373 
00374         /* Get the file name of this frame's function */
00375         if (pframe->fo_func->f_co->co_memspace == MEMSPACE_PROG)
00376         {
00377             strncpy_P(pstrbuf,
00378                       (char *)pframe->fo_func->f_co->co_filename,
00379                       MAX(FN_MAX_LEN, EXN_MAX_LEN));
00380         }
00381         printf_P(PSTR("  File \"%s\", line %d, in %s\n"),
00382                  ((pframe->fo_func->f_co->co_memspace == MEMSPACE_PROG)
00383                  ? pstrbuf
00384                  : (char *)pframe->fo_func->f_co->co_filename),
00385                  linesum,
00386                  ((pPmString_t)pstr)->val);
00387     }
00388 
00389     /* Print error */
00390     res = (uint8_t)result;
00391     if ((res > 0) && ((res - PM_RET_EX) < LEN_EXNLOOKUP))
00392     {
00393         strncpy_P(pstrbuf,
00394                   (PGM_P)pgm_read_word(&exnlookup[res - PM_RET_EX]),
00395                   EXN_MAX_LEN);
00396         printf_P(PSTR("%s"), pstrbuf);
00397     }
00398     else
00399     {
00400         printf_P(PSTR("Error code 0x%02X"), result);
00401     }
00402     printf_P(PSTR(" detected by "));
00403 
00404     if ((gVmGlobal.errFileId > 0) && (gVmGlobal.errFileId < LEN_FNLOOKUP))
00405     {
00406         strncpy_P(pstrbuf,
00407                   (PGM_P)pgm_read_word(&fnlookup[gVmGlobal.errFileId]),
00408                   FN_MAX_LEN);
00409         printf_P(PSTR("%s:"), pstrbuf);
00410     }
00411     else
00412     {
00413         printf_P(PSTR("FileId 0x%02X line "), gVmGlobal.errFileId);
00414     }
00415     printf_P(PSTR("%d\n"), gVmGlobal.errLineNum);
00416 
00417 #else /* HAVE_DEBUG_INFO */
00418 
00419     /* Print error */
00420     printf_P(PSTR("Error:     0x%02X\n"), result);
00421     printf_P(PSTR("  Release: 0x%02X\n"), gVmGlobal.errVmRelease);
00422     printf_P(PSTR("  FileId:  0x%02X\n"), gVmGlobal.errFileId);
00423     printf_P(PSTR("  LineNum: %d\n"), gVmGlobal.errLineNum);
00424 
00425     /* Print traceback */
00426     {
00427         pPmObj_t pframe;
00428         pPmObj_t pstr;
00429         PmReturn_t retval;
00430 
00431         puts_P(PSTR("Traceback (top first):"));
00432 
00433         /* Get the top frame */
00434         pframe = (pPmObj_t)gVmGlobal.pthread->pframe;
00435 
00436         /* If it's the native frame, print the native function name */
00437         if (pframe == (pPmObj_t)&(gVmGlobal.nativeframe))
00438         {
00439 
00440             /* The last name in the names tuple of the code obj is the name */
00441             retval = tuple_getItem((pPmObj_t)gVmGlobal.nativeframe.nf_func->
00442                                    f_co->co_names, -1, &pstr);
00443             if ((retval) != PM_RET_OK)
00444             {
00445                 puts_P(PSTR("  Unable to get native func name."));
00446                 return;
00447             }
00448             else
00449             {
00450                 printf_P(PSTR("  %s() __NATIVE__\n"), ((pPmString_t)pstr)->val);
00451             }
00452 
00453             /* Get the frame that called the native frame */
00454             pframe = (pPmObj_t)gVmGlobal.nativeframe.nf_back;
00455         }
00456 
00457         /* Print the remaining frame stack */
00458         for (;
00459              pframe != C_NULL;
00460              pframe = (pPmObj_t)((pPmFrame_t)pframe)->fo_back)
00461         {
00462             /* The last name in the names tuple of the code obj is the name */
00463             retval = tuple_getItem((pPmObj_t)((pPmFrame_t)pframe)->
00464                                    fo_func->f_co->co_names, -1, &pstr);
00465             if ((retval) != PM_RET_OK) break;
00466 
00467             printf_P(PSTR("  %s()\n"), ((pPmString_t)pstr)->val);
00468         }
00469         puts_P(PSTR("  <module>."));
00470     }
00471 #endif /* HAVE_DEBUG_INFO */
00472 }

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