Commits

Anonymous committed 8529fe9

Big Rewrite: moved all platforms except desktop to _unmaintained.
- Renamed desktop to posix
- Updated posix/README

Comments (0)

Files changed (753)

 
 import os, string
 
-DEFAULT_PLATFORM = "desktop"
+DEFAULT_PLATFORM = "posix"
 
-supported_platforms = Glob("src/platform/*")
-allowed_platforms = [os.path.split(x)[1] for x in map(str, supported_platforms)]
-allowed_platforms.remove("_unmaintained")
-allowed_platforms.remove("COPYING")
+valid_platforms = [os.path.split(x)[1] for x in map(str, Glob("src/platform/*"))
+                   if x not in ("_unmaintained", "COPYING")]
 
 vars = Variables()
 
     Alias('TAGS', tags)
 
 
-elif "docs" in COMMAND_LINE_TARGETS or "html" in COMMAND_LINE_TARGETS:
-    srcpath = os.path.join("docs", "src")
-    rstfiles = Glob(os.path.join(srcpath, "*.txt"))
-    htmlpath = os.path.join("docs", "html")
-    Mkdir(htmlpath)
-    htmlfiles = [string.replace(string.replace(str(s), ".txt", ".html", 1), srcpath, htmlpath, 1)
-                 for s in rstfiles]
-    html = [Command(htmlfiles[i], rstfiles[i], "rst2html.py $SOURCE $TARGET")
-            for i in range(len(rstfiles))]
-    htmlalias = Alias("html", html)
-    Alias("docs", htmlalias)
+#elif "docs" in COMMAND_LINE_TARGETS or "html" in COMMAND_LINE_TARGETS:
+#    srcpath = os.path.join("docs", "src")
+#    rstfiles = Glob(os.path.join(srcpath, "*.txt"))
+#    htmlpath = os.path.join("docs", "html")
+#    Mkdir(htmlpath)
+#    htmlfiles = [string.replace(string.replace(str(s), ".txt", ".html", 1), srcpath, htmlpath, 1)
+#                 for s in rstfiles]
+#    html = [Command(htmlfiles[i], rstfiles[i], "rst2html.py $SOURCE $TARGET")
+#            for i in range(len(rstfiles))]
+#    htmlalias = Alias("html", html)
+#    Alias("docs", htmlalias)
 
 
-elif "dist" in COMMAND_LINE_TARGETS:
-    assert "PM_RELEASE" in vars.args.keys(), "Must define PM_RELEASE=RR"
-    dist = Command("pymite-%s.tar.gz" % vars.args["PM_RELEASE"], None,
-                   "src/tools/pmDist.py %s" % vars.args["PM_RELEASE"])
-    AlwaysBuild(dist)
-    Alias("dist", dist)
+#elif "dist" in COMMAND_LINE_TARGETS:
+#    assert "PM_RELEASE" in vars.args.keys(), "Must define PM_RELEASE=RR"
+#    dist = Command("pymite-%s.tar.gz" % vars.args["PM_RELEASE"], None,
+#                   "src/tools/pmDist.py %s" % vars.args["PM_RELEASE"])
+#    AlwaysBuild(dist)
+#    Alias("dist", dist)
 
 
 elif "check" in COMMAND_LINE_TARGETS:
     Clean("check", build_path)
 
 
-# Default: build a platform; desktop by default
+# Default: build a platform; posix is the default platform
 else:
     if len(vars.args) == 0:
         vars.args["PLATFORM"] = DEFAULT_PLATFORM
     else:
-        if vars.args["PLATFORM"] not in allowed_platforms:
+        if vars.args["PLATFORM"] not in valid_platforms:
             print "Error: must define PLATFORM=<plat> where <plat> is from %s" \
-                % str(allowed_platforms)
+                % str(valid_platforms)
             Exit(1)
     platform_path = os.path.join("src", "platform", vars.args["PLATFORM"])
     sconscript_path = os.path.join(platform_path, "SConscript")
Add a comment to this file

docs/img/BuildOverview.png

Removed
Old image

src/platform/_unmaintained/arduino_mega/Makefile

+# Hey Emacs, this is a -*- makefile -*-
+
+# AVR-GCC Makefile template, derived from the WinAVR template (which
+# is public domain), believed to be neutral to any flavor of "make"
+# (GNU make, BSD make, SysV make)
+
+
+# PyMite Configuration
+PLATFORM := $(notdir $(CURDIR))
+PM_LIB_ROOT = pmvm_$(PLATFORM)
+PM_LIB_FN = lib$(PM_LIB_ROOT).a
+PM_LIB_PATH = ../../vm/$(PM_LIB_FN)
+PM_USR_SOURCES = main.py ../../lib/avr.py
+PMIMGCREATOR := ../../tools/pmImgCreator.py
+PMGENPMFEATURES := ../../tools/pmGenPmFeatures.py
+IPM=true
+
+
+# Platform Configuration
+MCU = atmega1280
+FORMAT = ihex
+TARGET = main
+F_CPU = 16000000UL
+SRC = $(TARGET).c plat.c $(TARGET)_nat.c $(TARGET)_img.c
+ASRC =
+OPT = s
+
+# Debugging format.
+# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
+# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
+DEBUG_FMT = stabs
+
+# Compiler flag to set the C Standard level.
+# c89   - "ANSI" C
+# gnu89 - c89 plus GCC extensions
+# c99   - ISO C99 standard (not yet fully implemented)
+# gnu99 - c99 plus GCC extensions
+CSTANDARD = -std=gnu99
+
+# Place -D or -U options here
+CDEFS = -DF_CPU=$(F_CPU)
+# PyMite CDEFS
+ifeq ($(DEBUG),true)
+	CDEFS += -g -g$(DEBUG_FMT) -D__DEBUG__=1
+endif
+
+# Place -I options here
+CINCS = -I../../vm -I$(abspath .)
+
+
+CDEBUG = -g$(DEBUG_FMT)
+CWARN = -Wall -Wstrict-prototypes -Werror
+CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
+#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
+CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CTUNING) $(CEXTRA)
+
+
+#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
+
+
+#Additional libraries.
+
+# Minimalistic printf version
+PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
+
+# Floating point printf version (requires MATH_LIB = -lm below)
+PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
+
+PRINTF_LIB =
+
+# Minimalistic scanf version
+SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
+
+# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
+SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
+
+SCANF_LIB =
+
+#MATH_LIB = -lm
+
+# External memory options
+
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),
+# used for variables (.data/.bss) and heap (malloc()).
+#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
+
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),
+# only used for heap (malloc()).
+#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
+
+EXTMEMOPTS =
+
+#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref
+LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
+# PyMite
+LDFLAGS += -L../../vm -l$(PM_LIB_ROOT) -L.
+
+
+# Programming support using avrdude. Settings and variables.
+
+AVRDUDE_PROGRAMMER = stk500v1
+AVRDUDE_PORT = /dev/tty.usbserial-A6008hox
+AVRDUDE_BAUD = 57600
+AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
+#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
+
+
+# Uncomment the following if you want avrdude's erase cycle counter.
+# Note that this counter needs to be initialized first using -Yn,
+# see avrdude manual.
+#AVRDUDE_ERASE_COUNTER = -y
+
+# Uncomment the following if you do /not/ wish a verification to be
+# performed after programming the device.
+#AVRDUDE_NO_VERIFY = -V
+
+# Increase verbosity level.  Please use this when submitting bug
+# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
+# to submit bug reports.
+#AVRDUDE_VERBOSE = -v -v
+
+AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -b $(AVRDUDE_BAUD) -c $(AVRDUDE_PROGRAMMER)
+AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER)
+
+
+SHELL = sh
+CC = avr-gcc
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+SIZE = avr-size
+AR = avr-ar
+NM = avr-nm
+AVRDUDE = avrdude
+REMOVE = rm -f
+MV = mv -f
+COPY = cp
+
+# Define all object files.
+OBJ = $(SRC:.c=.o) $(ASRC:.S=.o)
+
+# Define all listing files.
+LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
+
+# Combine all necessary flags and optional flags.
+# Add target processor to flags.
+ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
+ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
+
+
+# Default target.
+all: pmfeatures.h pmvm build
+
+build: elf hex eep
+
+elf: $(TARGET).elf
+hex: $(TARGET).hex
+eep: $(TARGET).eep
+lss: $(TARGET).lss
+sym: $(TARGET).sym
+
+
+# Program the device.  
+program: $(TARGET).hex $(TARGET).eep
+	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
+
+
+
+
+# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
+COFFCONVERT=$(OBJCOPY) --debugging \
+--change-section-address .data-0x800000 \
+--change-section-address .bss-0x800000 \
+--change-section-address .noinit-0x800000 \
+--change-section-address .eeprom-0x810000 
+
+
+# PyMite: Build the VM archive if it doesn't exist
+pmvm : $(PM_LIB_PATH)
+
+$(PM_LIB_PATH) : ../../vm/*.c ../../vm/*.h
+	make -C ../../vm
+
+$(TARGET)_nat.c $(TARGET)_img.c: $(PM_USR_SOURCES) pmfeatures.py
+	$(PMIMGCREATOR) -f pmfeatures.py -c -u --memspace=flash -o $(TARGET)_img.c --native-file=$(TARGET)_nat.c $(PM_USR_SOURCES)
+
+pmfeatures.h : pmfeatures.py $(PMGENPMFEATURES)
+	$(PMGENPMFEATURES) pmfeatures.py > $@
+
+coff: $(TARGET).elf
+	$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
+
+
+extcoff: $(TARGET).elf
+	$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
+
+
+.SUFFIXES: .elf .hex .eep .lss .sym
+
+.elf.hex:
+	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
+
+.elf.eep:
+	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
+	--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
+
+# Create extended listing file from ELF output file.
+.elf.lss:
+	$(OBJDUMP) -h -S $< > $@
+
+# Create a symbol table from ELF output file.
+.elf.sym:
+	$(NM) -n $< > $@
+
+
+
+# Link: create ELF output file from object files.
+$(TARGET).elf: $(OBJ)
+	$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
+
+
+# Compile: create object files from C source files.
+.c.o:
+	$(CC) -c $(ALL_CFLAGS) $< -o $@ 
+
+
+# Compile: create assembler files from C source files.
+.c.s:
+	$(CC) -S $(ALL_CFLAGS) $< -o $@
+
+
+# Assemble: create object files from assembler source files.
+.S.o:
+	$(CC) -c $(ALL_ASFLAGS) $< -o $@
+
+
+# Target: clean project.
+clean:
+	$(MAKE) -C ../../vm clean
+	$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
+	$(TARGET).map $(TARGET).sym $(TARGET).lss \
+	$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d)
+	$(REMOVE) $(TARGET)_img.*
+	$(REMOVE) $(TARGET)_nat.*
+
+depend:
+	if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
+	then \
+		sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
+			$(MAKEFILE).$$$$ && \
+		$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
+	fi
+	echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
+		>> $(MAKEFILE); \
+	$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
+
+.PHONY:	all build elf hex eep lss sym program coff extcoff clean depend pmvm
+
+export CC OBJCOPY NM CFLAGS ALL_CFLAGS AR IPM PM_LIB_FN

src/platform/_unmaintained/arduino_mega/README

+===============================
+The Arduino Mega Sample Project
+===============================
+
+:Author:    Dean Hall
+:Id:        $Id$
+
+
+Purpose
+-------
+
+This is a sample project that demonstrates the use of PyMite on the
+`Arduino Mega`_ platform.
+
+.. _`Arduino Mega`: http://arduino.cc/en/Main/ArduinoBoardMega
+
+
+Details
+-------
+
+This sample project demonstrates running the interactive prompt (ipm).
+The file ``main.c`` is used to initialize the PyMite VM
+and indicate the name of the module it should run.  In this case, it
+will run the module ``main.py`` which prints "Hello World" and then runs
+the interactive prompt.
+
+
+Requirements
+------------
+
+The Arduino Mega has an FTDI USB-to-Serial device on-board.  You will need
+to install `FTDI device drivers`_ for your operating system.
+
+You also need to make sure you have PySerial_ installed so that Python 
+can talk to your target device over the serial port::
+
+    $ easy_install pyserial
+
+.. _PySerial: http://pyserial.sourceforge.net/
+.. _`FTDI device drivers`: http://www.ftdichip.com/Drivers/VCP.htm
+
+
+Building the Project
+--------------------
+
+From the project root directory::
+
+    $ make PLATFORM=arduino_mega
+
+
+Flashing the Binary
+-------------------
+
+The steps above result in the binary file that needs to go on the Arduino Mega.
+The Arduino Mega should have the Arduino serial bootloader installed already.
+This bootloader is compatible with the stk500v1 protocol so we will use
+avrdude from within the makefile.  Edit the Makefile to set ``AVRDUDE_PORT``
+to match your serial port or give the serial device path on the command line::
+
+    $ cd src/platform/arduino_mega
+
+    # Reset the Arduino Mega, and do the next line within 2 seconds
+
+    $ make program AVRDUDE_PORT=/dev/tty.usbserial
+
+If the program did not load onto the Arduino Mega, first check if you have a 
+bootloader: press and release the reset button and watch the LED labeled "L"
+on the opposite end of the FTDI chip from the USB plug.  If it does not flash, 
+a bootloader is not present and one must be installed.  See instructions on 
+`the Bootloader page`_ to install a bootloader.
+
+The Arduino Bootloader waits about 2 seconds after reset to execute the binary.
+So, while experimenting with ipm, be sure to give the board those two seconds
+after reset before you issue commands.
+
+.. _`the Bootloader page`: http://arduino.cc/en/Hacking/Bootloader
+
+
+Connect via ipm
+---------------
+
+Now, the Arduino Mega is running ipm and waiting for input from the host
+computer.  So on your computer you need to run the host-side ipm
+(the name of your serial device may vary)::
+
+    $ ../../tools/ipm.py -f pmfeatures.py --serial /dev/tty.usbserial --baud=57600
+
+
+Using ipm
+---------
+
+The following is an example session using ipm::
+    
+    ipm> import avr, sys
+    ipm> avr.ddrA(0xff)
+    ipm> avr.portA(0)       # Pins 22-29 all at 0 V
+    ipm> avr.portA(0xa5)
+    ipm> sys.heap()
+    (2622, 7424)
+
+After setting port A, the pin voltages are close to what you'd expect
+(0xa5 = 0b10100101):
+
+======= ======= =======
+Pin     Label   [Volts]
+======= ======= =======
+PA0     22      4.8
+PA1     23      0
+PA2     24      4.8
+PA3     25      0
+PA4     26      0
+PA5     27      4.8
+PA6     28      0
+PA7     29      4.8
+======= ======= =======
+
+.. :mode=rest:

src/platform/_unmaintained/arduino_mega/main.c

+/*
+# This file is Copyright 2007, 2009 Dean Hall.
+#
+# This file is part of the Python-on-a-Chip program.
+# Python-on-a-Chip is free software: you can redistribute it and/or modify
+# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
+# 
+# Python-on-a-Chip is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# A copy of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
+# is seen in the file COPYING up one directory from this.
+*/
+
+/** Sample PyMite application */
+
+
+#include "pm.h"
+
+#define HEAP_SIZE 0x1D00
+
+
+extern unsigned char usrlib_img[];
+
+
+int main(void)
+{
+    uint8_t heap[HEAP_SIZE];
+    PmReturn_t retval;
+
+    retval = pm_init(heap, HEAP_SIZE, MEMSPACE_PROG, usrlib_img);
+    PM_RETURN_IF_ERROR(retval);
+
+    retval = pm_run((uint8_t *)"main");
+    return (int)retval;
+}

src/platform/_unmaintained/arduino_mega/main.py

+# This file is Copyright 2010 Dean Hall.
+#
+# This file is part of the Python-on-a-Chip program.
+# Python-on-a-Chip is free software: you can redistribute it and/or modify
+# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
+# 
+# Python-on-a-Chip is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# A copy of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
+# is seen in the file COPYING up one directory from this.
+
+import ipm
+
+ipm.ipm()

src/platform/_unmaintained/arduino_mega/plat.c

+/*
+# This file is Copyright 2010 Dean Hall.
+#
+# This file is part of the Python-on-a-Chip program.
+# Python-on-a-Chip is free software: you can redistribute it and/or modify
+# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
+#
+# Python-on-a-Chip is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# A copy of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
+# is seen in the file COPYING up one directory from this.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x70
+
+
+/** PyMite platform-specific routines for AVR target */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <avr/eeprom.h>
+
+#include "pm.h"
+
+
+#define UART_BAUD 57600UL
+
+
+/* Hint: 1,000,000 �s/s * 256 T/C0 clock cycles per tick * 8 CPU clocks per
+ * T/C0 clock cycle / x,000,000 CPU clock cycles per second -> �s per tick
+ */
+#define PLAT_TIME_PER_TICK_USEC (1000000ULL*256ULL*8ULL/F_CPU)
+
+
+/* Configure stdin, stdout, stderr */
+static int uart_putc(char c, FILE *stream);
+static int uart_getc(FILE *stream);
+FILE avr_uart = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);
+
+
+/*
+ * AVR target shall use stdio for I/O routines.
+ * The UART or USART must be configured for the interactive interface to work.
+ */
+PmReturn_t
+plat_init(void)
+{
+    /* Set the baud rate register */
+    UBRR0 = (F_CPU / (16UL * UART_BAUD)) - 1;
+
+    /* Set mode Async, 8-N-1 */
+    UCSR0C = (_BV(UCSZ01) | _BV(UCSZ00));
+
+    /* Enable the transmit and receive pins */
+    UCSR0B = _BV(TXEN0) | _BV(RXEN0);
+
+    stdin = stdout = stderr = &avr_uart;
+
+    /* Set T/C0 prescaler to div8.  Enable T/C0 interrupt */
+    TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00));
+    TCCR0B |= _BV(CS01);
+    TIMSK0 = _BV(TOIE0);
+
+    /* Global interrupt enable */
+    sei();
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+plat_deinit(void)
+{
+    /* Disable UART */
+    UCSR0B &= ~(_BV(TXEN0) | _BV(RXEN0));
+
+    /* Disable Timer (clear clock source) */
+    TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00));
+
+    return PM_RET_OK;
+}
+
+
+ISR(TIMER0_OVF_vect)
+{
+    /* TODO Find a clever way to handle bad return code, maybe use
+     * PM_REPORT_IF_ERROR(retval) when that works on AVR inside an
+     * interrupt.
+     */
+    pm_vmPeriodic(PLAT_TIME_PER_TICK_USEC);
+}
+
+
+/*
+ * Gets a byte from the address in the designated memory space
+ * Post-increments *paddr.
+ */
+uint8_t
+plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
+{
+    uint8_t b = 0;
+
+    switch (memspace)
+    {
+        case MEMSPACE_RAM:
+            b = **paddr;
+            *paddr += 1;
+            return b;
+
+        case MEMSPACE_PROG:
+            b = pgm_read_byte(*paddr);
+            *paddr += 1;
+            return b;
+
+        case MEMSPACE_EEPROM:
+            b = eeprom_read_byte(*paddr);
+            *paddr += 1;
+            return b;
+
+        case MEMSPACE_SEEPROM:
+        case MEMSPACE_OTHER0:
+        case MEMSPACE_OTHER1:
+        case MEMSPACE_OTHER2:
+        case MEMSPACE_OTHER3:
+        default:
+            return 0;
+    }
+}
+
+
+static int
+uart_getc(FILE *stream)
+{
+    char c;
+
+    /* Wait for reception of a byte */
+    loop_until_bit_is_set(UCSR0A, RXC0);
+    c = UDR0;
+
+    /* Return errors for Framing error or Overrun */
+    if (UCSR0A & _BV(FE0)) return _FDEV_EOF;
+    if (UCSR0A & _BV(DOR0)) return _FDEV_ERR;
+
+    return c;
+}
+
+
+static int
+uart_putc(char c, FILE *stream)
+{
+    /* Wait until UART can accept the byte */
+    loop_until_bit_is_set(UCSR0A, UDRE0);
+
+    /* Send the byte */
+    UDR0 = c;
+
+    return 0;
+}
+
+
+/*
+ * UART receive char routine MUST return exactly and only the received char;
+ * it should not translate \n to \r\n.
+ * This is because the interactive interface uses binary transfers.
+ */
+PmReturn_t
+plat_getByte(uint8_t *b)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    /* Loop until serial receive is complete */
+    loop_until_bit_is_set(UCSR0A, RXC0);
+
+    /* If a framing error or data overrun occur, raise an IOException */
+    if (UCSR0A & (_BV(FE0) | _BV(DOR0)))
+    {
+        PM_RAISE(retval, PM_RET_EX_IO);
+        return retval;
+    }
+    *b = UDR0;
+
+    return retval;
+}
+
+
+/*
+ * UART send char routine MUST send exactly and only the given char;
+ * it should not translate \n to \r\n.
+ * This is because the interactive interface uses binary transfers.
+ */
+PmReturn_t
+plat_putByte(uint8_t b)
+{
+    /* Loop until serial data reg is empty (from previous transfer) */
+    loop_until_bit_is_set(UCSR0A, UDRE0);
+
+    /* Put the byte to send into the serial data register */
+    UDR0 = b;
+
+    return PM_RET_OK;
+}
+
+
+/*
+ * This operation is made atomic by temporarily disabling
+ * the interrupts. The old state is restored afterwards.
+ */
+PmReturn_t
+plat_getMsTicks(uint32_t *r_ticks)
+{
+    /* Critical section start */
+    unsigned char _sreg = SREG;
+    cli();
+    *r_ticks = pm_timerMsTicks;
+    SREG = _sreg;
+    /* Critical section end */
+    return PM_RET_OK;
+}
+
+
+#ifdef HAVE_DEBUG_INFO
+#define LEN_FNLOOKUP 26
+#define LEN_EXNLOOKUP 18
+#define FN_MAX_LEN 15
+#define EXN_MAX_LEN 18
+#ifndef MAX
+#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
+#endif
+
+/* This table should match src/vm/fileid.txt */
+static char fnstr_00[] PROGMEM = "<no file>";
+static char fnstr_01[] PROGMEM = "codeobj.c";
+static char fnstr_02[] PROGMEM = "dict.c";
+static char fnstr_03[] PROGMEM = "frame.c";
+static char fnstr_04[] PROGMEM = "func.c";
+static char fnstr_05[] PROGMEM = "global.c";
+static char fnstr_06[] PROGMEM = "heap.c";
+static char fnstr_07[] PROGMEM = "img.c";
+static char fnstr_08[] PROGMEM = "int.c";
+static char fnstr_09[] PROGMEM = "interp.c";
+static char fnstr_10[] PROGMEM = "pmstdlib_nat.c";
+static char fnstr_11[] PROGMEM = "list.c";
+static char fnstr_12[] PROGMEM = "main.c";
+static char fnstr_13[] PROGMEM = "mem.c";
+static char fnstr_14[] PROGMEM = "module.c";
+static char fnstr_15[] PROGMEM = "obj.c";
+static char fnstr_16[] PROGMEM = "seglist.c";
+static char fnstr_17[] PROGMEM = "sli.c";
+static char fnstr_18[] PROGMEM = "strobj.c";
+static char fnstr_19[] PROGMEM = "tuple.c";
+static char fnstr_20[] PROGMEM = "seq.c";
+static char fnstr_21[] PROGMEM = "pm.c";
+static char fnstr_22[] PROGMEM = "thread.c";
+static char fnstr_23[] PROGMEM = "float.c";
+static char fnstr_24[] PROGMEM = "class.c";
+static char fnstr_25[] PROGMEM = "bytearray.c";
+
+static PGM_P fnlookup[LEN_FNLOOKUP] PROGMEM =
+{
+    fnstr_00, fnstr_01, fnstr_02, fnstr_03,
+    fnstr_04, fnstr_05, fnstr_06, fnstr_07,
+    fnstr_08, fnstr_09, fnstr_10, fnstr_11,
+    fnstr_12, fnstr_13, fnstr_14, fnstr_15,
+    fnstr_16, fnstr_17, fnstr_18, fnstr_19,
+    fnstr_20, fnstr_21, fnstr_22, fnstr_23,
+    fnstr_24, fnstr_25
+};
+
+/* This table should match src/vm/pm.h PmReturn_t */
+static char exnstr_00[] PROGMEM = "Exception";
+static char exnstr_01[] PROGMEM = "SystemExit";
+static char exnstr_02[] PROGMEM = "IoError";
+static char exnstr_03[] PROGMEM = "ZeroDivisionError";
+static char exnstr_04[] PROGMEM = "AssertionError";
+static char exnstr_05[] PROGMEM = "AttributeError";
+static char exnstr_06[] PROGMEM = "ImportError";
+static char exnstr_07[] PROGMEM = "IndexError";
+static char exnstr_08[] PROGMEM = "KeyError";
+static char exnstr_09[] PROGMEM = "MemoryError";
+static char exnstr_10[] PROGMEM = "NameError";
+static char exnstr_11[] PROGMEM = "SyntaxError";
+static char exnstr_12[] PROGMEM = "SystemError";
+static char exnstr_13[] PROGMEM = "TypeError";
+static char exnstr_14[] PROGMEM = "ValueError";
+static char exnstr_15[] PROGMEM = "StopIteration";
+static char exnstr_16[] PROGMEM = "Warning";
+static char exnstr_17[] PROGMEM = "OverflowError";
+
+static PGM_P exnlookup[LEN_EXNLOOKUP] PROGMEM =
+{
+    exnstr_00, exnstr_01, exnstr_02, exnstr_03,
+    exnstr_04, exnstr_05, exnstr_06, exnstr_07,
+    exnstr_08, exnstr_09, exnstr_10, exnstr_11,
+    exnstr_12, exnstr_13, exnstr_14, exnstr_15,
+    exnstr_16, exnstr_17
+};
+#endif /* HAVE_DEBUG_INFO */
+
+
+void
+plat_reportError(PmReturn_t result)
+{
+#ifdef HAVE_DEBUG_INFO
+    uint8_t res;
+    pPmFrame_t pframe;
+    pPmObj_t pstr;
+    PmReturn_t retval;
+    uint8_t bcindex;
+    uint16_t bcsum;
+    uint16_t linesum;
+    uint16_t len_lnotab;
+    uint8_t const *plnotab;
+    uint16_t i;
+    char pstrbuf[MAX(FN_MAX_LEN, EXN_MAX_LEN)];
+
+    /* Print traceback */
+    puts_P(PSTR("Traceback (most recent call first):"));
+
+    /* Get the top frame */
+    pframe = gVmGlobal.pthread->pframe;
+
+    /* If it's the native frame, print the native function name */
+    if (pframe == (pPmFrame_t)&(gVmGlobal.nativeframe))
+    {
+
+        /* The last name in the names tuple of the code obj is the name */
+        retval = tuple_getItem((pPmObj_t)gVmGlobal.nativeframe.nf_func->
+                               f_co->co_names, -1, &pstr);
+        if ((retval) != PM_RET_OK)
+        {
+            puts_P(PSTR("  Unable to get native func name."));
+            return;
+        }
+        else
+        {
+            printf_P(PSTR("  %s() __NATIVE__\n"), ((pPmString_t)pstr)->val);
+        }
+
+        /* Get the frame that called the native frame */
+        pframe = (pPmFrame_t)gVmGlobal.nativeframe.nf_back;
+    }
+
+    /* Print the remaining frame stack */
+    for (; pframe != C_NULL; pframe = pframe->fo_back)
+    {
+        /* The last name in the names tuple of the code obj is the name */
+        retval = tuple_getItem((pPmObj_t)pframe->fo_func->f_co->co_names,
+                               -1,
+                               &pstr);
+        if ((retval) != PM_RET_OK) break;
+
+        /*
+         * Get the line number of the current bytecode. Algorithm comes from:
+         * http://svn.python.org/view/python/trunk/Objects/lnotab_notes.txt?view=markup
+         */
+        bcindex = pframe->fo_ip - pframe->fo_func->f_co->co_codeaddr;
+        plnotab = pframe->fo_func->f_co->co_lnotab;
+        len_lnotab = mem_getWord(MEMSPACE_PROG, &plnotab);
+        bcsum = 0;
+        linesum = pframe->fo_func->f_co->co_firstlineno;
+        for (i = 0; i < len_lnotab; i += 2)
+        {
+            bcsum += mem_getByte(MEMSPACE_PROG, &plnotab);
+            if (bcsum > bcindex) break;
+            linesum += mem_getByte(MEMSPACE_PROG, &plnotab);
+        }
+
+        /* Get the file name of this frame's function */
+        if (pframe->fo_func->f_co->co_memspace == MEMSPACE_PROG)
+        {
+            strncpy_P(pstrbuf,
+                      (char *)pframe->fo_func->f_co->co_filename,
+                      MAX(FN_MAX_LEN, EXN_MAX_LEN));
+        }
+        printf_P(PSTR("  File \"%s\", line %d, in %s\n"),
+                 ((pframe->fo_func->f_co->co_memspace == MEMSPACE_PROG)
+                 ? pstrbuf
+                 : (char *)pframe->fo_func->f_co->co_filename),
+                 linesum,
+                 ((pPmString_t)pstr)->val);
+    }
+
+    /* Print error */
+    res = (uint8_t)result;
+    if ((res > 0) && ((res - PM_RET_EX) < LEN_EXNLOOKUP))
+    {
+        strncpy_P(pstrbuf,
+                  (PGM_P)pgm_read_word(&exnlookup[res - PM_RET_EX]),
+                  EXN_MAX_LEN);
+        printf_P(PSTR("%s"), pstrbuf);
+    }
+    else
+    {
+        printf_P(PSTR("Error code 0x%02X"), result);
+    }
+    printf_P(PSTR(" detected by "));
+
+    if ((gVmGlobal.errFileId > 0) && (gVmGlobal.errFileId < LEN_FNLOOKUP))
+    {
+        strncpy_P(pstrbuf,
+                  (PGM_P)pgm_read_word(&fnlookup[gVmGlobal.errFileId]),
+                  FN_MAX_LEN);
+        printf_P(PSTR("%s:"), pstrbuf);
+    }
+    else
+    {
+        printf_P(PSTR("FileId 0x%02X line "), gVmGlobal.errFileId);
+    }
+    printf_P(PSTR("%d\n"), gVmGlobal.errLineNum);
+
+#else /* HAVE_DEBUG_INFO */
+
+    /* Print error */
+    printf_P(PSTR("Error:     0x%02X\n"), result);
+    printf_P(PSTR("  Release: 0x%02X\n"), gVmGlobal.errVmRelease);
+    printf_P(PSTR("  FileId:  0x%02X\n"), gVmGlobal.errFileId);
+    printf_P(PSTR("  LineNum: %d\n"), gVmGlobal.errLineNum);
+
+    /* Print traceback */
+    {